about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorMara <m-ou.se@m-ou.se>2021-03-05 10:57:14 +0100
committerGitHub <noreply@github.com>2021-03-05 10:57:14 +0100
commite6a6df5daad01472e93f19802b0ce25f7a9b020c (patch)
treef2dac9a65dfa7eb1586bfc799dfba67c931a3776 /src
parenta0d66b54fb3acc2125972b88ff543a2c04d14af5 (diff)
parent25637b228d68e9bdf2d3ce1ba421cbd115fcb81e (diff)
downloadrust-e6a6df5daad01472e93f19802b0ce25f7a9b020c.tar.gz
rust-e6a6df5daad01472e93f19802b0ce25f7a9b020c.zip
Rollup merge of #80723 - rylev:noop-lint-pass, r=estebank
Implement NOOP_METHOD_CALL lint

Implements the beginnings of https://github.com/rust-lang/lang-team/issues/67 - a lint for detecting noop method calls (e.g, calling `<&T as Clone>::clone()` when `T: !Clone`).

This PR does not fully realize the vision and has a few limitations that need to be addressed either before merging or in subsequent PRs:
* [ ] No UFCS support
* [ ] The warning message is pretty plain
* [ ] Doesn't work for `ToOwned`

The implementation uses [`Instance::resolve`](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/instance/struct.Instance.html#method.resolve) which is normally later in the compiler. It seems that there are some invariants that this function relies on that we try our best to respect. For instance, it expects substitutions to have happened, which haven't yet performed, but we check first for `needs_subst` to ensure we're dealing with a monomorphic type.

Thank you to ```@davidtwco,``` ```@Aaron1011,``` and ```@wesleywiser``` for helping me at various points through out this PR ❤️.
Diffstat (limited to 'src')
-rw-r--r--src/test/ui/lint/noop-method-call.rs54
-rw-r--r--src/test/ui/lint/noop-method-call.stderr39
-rw-r--r--src/test/ui/underscore-imports/hygiene-2.rs1
3 files changed, 94 insertions, 0 deletions
diff --git a/src/test/ui/lint/noop-method-call.rs b/src/test/ui/lint/noop-method-call.rs
new file mode 100644
index 00000000000..9870c813572
--- /dev/null
+++ b/src/test/ui/lint/noop-method-call.rs
@@ -0,0 +1,54 @@
+// check-pass
+
+#![allow(unused)]
+#![warn(noop_method_call)]
+
+use std::borrow::Borrow;
+use std::ops::Deref;
+
+struct PlainType<T>(T);
+
+#[derive(Clone)]
+struct CloneType<T>(T);
+
+fn main() {
+    let non_clone_type_ref = &PlainType(1u32);
+    let non_clone_type_ref_clone: &PlainType<u32> = non_clone_type_ref.clone();
+    //~^ WARNING call to `.clone()` on a reference in this situation does nothing
+
+    let clone_type_ref = &CloneType(1u32);
+    let clone_type_ref_clone: CloneType<u32> = clone_type_ref.clone();
+
+    // Calling clone on a double reference doesn't warn since the method call itself
+    // peels the outer reference off
+    let clone_type_ref = &&CloneType(1u32);
+    let clone_type_ref_clone: &CloneType<u32> = clone_type_ref.clone();
+
+    let non_deref_type = &PlainType(1u32);
+    let non_deref_type_deref: &PlainType<u32> = non_deref_type.deref();
+    //~^ WARNING call to `.deref()` on a reference in this situation does nothing
+
+    // Dereferencing a &&T does not warn since it has collapsed the double reference
+    let non_deref_type = &&PlainType(1u32);
+    let non_deref_type_deref: &PlainType<u32> = non_deref_type.deref();
+
+    let non_borrow_type = &PlainType(1u32);
+    let non_borrow_type_borrow: &PlainType<u32> = non_borrow_type.borrow();
+    //~^ WARNING call to `.borrow()` on a reference in this situation does nothing
+
+    // Borrowing a &&T does not warn since it has collapsed the double reference
+    let non_borrow_type = &&PlainType(1u32);
+    let non_borrow_type_borrow: &PlainType<u32> = non_borrow_type.borrow();
+
+    let xs = ["a", "b", "c"];
+    let _v: Vec<&str> = xs.iter().map(|x| x.clone()).collect(); // ok, but could use `*x` instead
+}
+
+fn generic<T>(non_clone_type: &PlainType<T>) {
+    non_clone_type.clone();
+}
+
+fn non_generic(non_clone_type: &PlainType<u32>) {
+    non_clone_type.clone();
+    //~^ WARNING call to `.clone()` on a reference in this situation does nothing
+}
diff --git a/src/test/ui/lint/noop-method-call.stderr b/src/test/ui/lint/noop-method-call.stderr
new file mode 100644
index 00000000000..7f6f96bf1d1
--- /dev/null
+++ b/src/test/ui/lint/noop-method-call.stderr
@@ -0,0 +1,39 @@
+warning: call to `.clone()` on a reference in this situation does nothing
+  --> $DIR/noop-method-call.rs:16:71
+   |
+LL |     let non_clone_type_ref_clone: &PlainType<u32> = non_clone_type_ref.clone();
+   |                                                                       ^^^^^^^^ unnecessary method call
+   |
+note: the lint level is defined here
+  --> $DIR/noop-method-call.rs:4:9
+   |
+LL | #![warn(noop_method_call)]
+   |         ^^^^^^^^^^^^^^^^
+   = note: the type `&PlainType<u32>` which `clone` is being called on is the same as the type returned from `clone`, so the method call does not do anything and can be removed
+
+warning: call to `.deref()` on a reference in this situation does nothing
+  --> $DIR/noop-method-call.rs:28:63
+   |
+LL |     let non_deref_type_deref: &PlainType<u32> = non_deref_type.deref();
+   |                                                               ^^^^^^^^ unnecessary method call
+   |
+   = note: the type `&PlainType<u32>` which `deref` is being called on is the same as the type returned from `deref`, so the method call does not do anything and can be removed
+
+warning: call to `.borrow()` on a reference in this situation does nothing
+  --> $DIR/noop-method-call.rs:36:66
+   |
+LL |     let non_borrow_type_borrow: &PlainType<u32> = non_borrow_type.borrow();
+   |                                                                  ^^^^^^^^^ unnecessary method call
+   |
+   = note: the type `&PlainType<u32>` which `borrow` is being called on is the same as the type returned from `borrow`, so the method call does not do anything and can be removed
+
+warning: call to `.clone()` on a reference in this situation does nothing
+  --> $DIR/noop-method-call.rs:52:19
+   |
+LL |     non_clone_type.clone();
+   |                   ^^^^^^^^ unnecessary method call
+   |
+   = note: the type `&PlainType<u32>` which `clone` is being called on is the same as the type returned from `clone`, so the method call does not do anything and can be removed
+
+warning: 4 warnings emitted
+
diff --git a/src/test/ui/underscore-imports/hygiene-2.rs b/src/test/ui/underscore-imports/hygiene-2.rs
index bea61eae6b5..510d91d0d46 100644
--- a/src/test/ui/underscore-imports/hygiene-2.rs
+++ b/src/test/ui/underscore-imports/hygiene-2.rs
@@ -29,5 +29,6 @@ m!(y);
 
 fn main() {
     use crate::y::*;
+    #[allow(noop_method_call)]
     (&()).deref();
 }