about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--clippy_lints/src/methods/useless_asref.rs26
-rw-r--r--tests/ui/useless_asref.fixed31
-rw-r--r--tests/ui/useless_asref.rs31
-rw-r--r--tests/ui/useless_asref.stderr20
4 files changed, 104 insertions, 4 deletions
diff --git a/clippy_lints/src/methods/useless_asref.rs b/clippy_lints/src/methods/useless_asref.rs
index 66727e5a29d..d6c79db4d70 100644
--- a/clippy_lints/src/methods/useless_asref.rs
+++ b/clippy_lints/src/methods/useless_asref.rs
@@ -1,7 +1,7 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::ty::walk_ptrs_ty_depth;
-use clippy_utils::{get_parent_expr, is_diag_trait_item, match_def_path, paths, peel_blocks};
+use clippy_utils::{get_parent_expr, is_diag_trait_item, match_def_path, path_to_local_id, paths, peel_blocks};
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_lint::LateContext;
@@ -111,6 +111,23 @@ fn is_calling_clone(cx: &LateContext<'_>, arg: &hir::Expr<'_>) -> bool {
         hir::ExprKind::Closure(&hir::Closure { body, .. }) => {
             // If it's a closure, we need to check what is called.
             let closure_body = cx.tcx.hir().body(body);
+
+            // |x| ...
+            //  ^
+            let [
+                hir::Param {
+                    pat:
+                        hir::Pat {
+                            kind: hir::PatKind::Binding(_, local_id, ..),
+                            ..
+                        },
+                    ..
+                },
+            ] = closure_body.params
+            else {
+                return false;
+            };
+
             let closure_expr = peel_blocks(closure_body.value);
             match closure_expr.kind {
                 hir::ExprKind::MethodCall(method, obj, [], _) => {
@@ -122,14 +139,17 @@ fn is_calling_clone(cx: &LateContext<'_>, arg: &hir::Expr<'_>) -> bool {
                         // no autoderefs
                         && !cx.typeck_results().expr_adjustments(obj).iter()
                             .any(|a| matches!(a.kind, Adjust::Deref(Some(..))))
+                        && path_to_local_id(obj, *local_id)
                     {
                         true
                     } else {
                         false
                     }
                 },
-                hir::ExprKind::Call(call, [_]) => {
-                    if let hir::ExprKind::Path(qpath) = call.kind {
+                hir::ExprKind::Call(call, [recv]) => {
+                    if let hir::ExprKind::Path(qpath) = call.kind
+                        && path_to_local_id(recv, *local_id)
+                    {
                         check_qpath(cx, qpath, call.hir_id)
                     } else {
                         false
diff --git a/tests/ui/useless_asref.fixed b/tests/ui/useless_asref.fixed
index 88b95095bc0..d39d8a74b26 100644
--- a/tests/ui/useless_asref.fixed
+++ b/tests/ui/useless_asref.fixed
@@ -144,6 +144,37 @@ fn foo() {
     //~^ ERROR: this call to `as_ref.map(...)` does nothing
 }
 
+mod issue12135 {
+    pub struct Struct {
+        field: Option<InnerStruct>,
+    }
+
+    #[derive(Clone)]
+    pub struct Foo;
+
+    #[derive(Clone)]
+    struct InnerStruct {
+        x: Foo,
+    }
+
+    impl InnerStruct {
+        fn method(&self) -> &Foo {
+            &self.x
+        }
+    }
+
+    pub fn f(x: &Struct) -> Option<Foo> {
+        x.field.clone();
+        //~^ ERROR: this call to `as_ref.map(...)` does nothing
+        x.field.clone();
+        //~^ ERROR: this call to `as_ref.map(...)` does nothing
+        x.field.clone();
+        //~^ ERROR: this call to `as_ref.map(...)` does nothing
+
+        x.field.as_ref().map(|v| v.method().clone())
+    }
+}
+
 fn main() {
     not_ok();
     ok();
diff --git a/tests/ui/useless_asref.rs b/tests/ui/useless_asref.rs
index 504dc1f5cbf..76277e7b7a4 100644
--- a/tests/ui/useless_asref.rs
+++ b/tests/ui/useless_asref.rs
@@ -144,6 +144,37 @@ fn foo() {
     //~^ ERROR: this call to `as_ref.map(...)` does nothing
 }
 
+mod issue12135 {
+    pub struct Struct {
+        field: Option<InnerStruct>,
+    }
+
+    #[derive(Clone)]
+    pub struct Foo;
+
+    #[derive(Clone)]
+    struct InnerStruct {
+        x: Foo,
+    }
+
+    impl InnerStruct {
+        fn method(&self) -> &Foo {
+            &self.x
+        }
+    }
+
+    pub fn f(x: &Struct) -> Option<Foo> {
+        x.field.as_ref().map(|v| v.clone());
+        //~^ ERROR: this call to `as_ref.map(...)` does nothing
+        x.field.as_ref().map(Clone::clone);
+        //~^ ERROR: this call to `as_ref.map(...)` does nothing
+        x.field.as_ref().map(|v| Clone::clone(v));
+        //~^ ERROR: this call to `as_ref.map(...)` does nothing
+
+        x.field.as_ref().map(|v| v.method().clone())
+    }
+}
+
 fn main() {
     not_ok();
     ok();
diff --git a/tests/ui/useless_asref.stderr b/tests/ui/useless_asref.stderr
index deb5d90f2f6..583b48732d4 100644
--- a/tests/ui/useless_asref.stderr
+++ b/tests/ui/useless_asref.stderr
@@ -88,5 +88,23 @@ error: this call to `as_ref.map(...)` does nothing
 LL |     let z = x.as_ref().map(|z| String::clone(z));
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `x.clone()`
 
-error: aborting due to 14 previous errors
+error: this call to `as_ref.map(...)` does nothing
+  --> $DIR/useless_asref.rs:167:9
+   |
+LL |         x.field.as_ref().map(|v| v.clone());
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `x.field.clone()`
+
+error: this call to `as_ref.map(...)` does nothing
+  --> $DIR/useless_asref.rs:169:9
+   |
+LL |         x.field.as_ref().map(Clone::clone);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `x.field.clone()`
+
+error: this call to `as_ref.map(...)` does nothing
+  --> $DIR/useless_asref.rs:171:9
+   |
+LL |         x.field.as_ref().map(|v| Clone::clone(v));
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `x.field.clone()`
+
+error: aborting due to 17 previous errors