about summary refs log tree commit diff
diff options
context:
space:
mode:
authorHMPerson1 <hmperson1@gmail.com>2018-10-19 14:51:25 -0400
committerHMPerson1 <hmperson1@gmail.com>2018-10-19 14:51:25 -0400
commit2a9dec681fe8a7bd1985790fc70f671975c68da0 (patch)
tree7643bd2e24fadcfe781c313c0679dfd7d6b32480
parenta2be0509657c4b100ba9b81b34aa0262700da83c (diff)
downloadrust-2a9dec681fe8a7bd1985790fc70f671975c68da0.tar.gz
rust-2a9dec681fe8a7bd1985790fc70f671975c68da0.zip
Fix suggestion for multiple derefs
-rw-r--r--clippy_lints/src/methods/mod.rs15
-rw-r--r--tests/ui/unnecessary_clone.rs32
-rw-r--r--tests/ui/unnecessary_clone.stderr8
3 files changed, 52 insertions, 3 deletions
diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs
index a0d57e0916b..dd44aad351c 100644
--- a/clippy_lints/src/methods/mod.rs
+++ b/clippy_lints/src/methods/mod.rs
@@ -1250,7 +1250,7 @@ fn lint_clone_on_copy(cx: &LateContext<'_, '_>, expr: &hir::Expr, arg: &hir::Exp
     if is_copy(cx, ty) {
         let snip;
         if let Some(snippet) = sugg::Sugg::hir_opt(cx, arg) {
-            // x.clone() might have dereferenced x, possibly through a Deref impl
+            // x.clone() might have dereferenced x, possibly through Deref impls
             if cx.tables.expr_ty(arg) != ty {
                 let parent = cx.tcx.hir.get_parent_node(expr.id);
                 match cx.tcx.hir.get(parent) {
@@ -1273,7 +1273,18 @@ fn lint_clone_on_copy(cx: &LateContext<'_, '_>, expr: &hir::Expr, arg: &hir::Exp
                     },
                     _ => {},
                 }
-                snip = Some(("try dereferencing it", format!("{}", snippet.deref())));
+
+                let deref_count = cx.tables.expr_adjustments(arg).iter()
+                    .filter(|adj| {
+                        if let ty::adjustment::Adjust::Deref(_) = adj.kind {
+                            true
+                        } else {
+                            false
+                        }
+                    })
+                    .count();
+                let derefs: String = iter::repeat('*').take(deref_count).collect();
+                snip = Some(("try dereferencing it", format!("{}{}", derefs, snippet)));
             } else {
                 snip = Some(("try removing the `clone` call", format!("{}", snippet)));
             }
diff --git a/tests/ui/unnecessary_clone.rs b/tests/ui/unnecessary_clone.rs
index 2dd2213e138..28cad1d881f 100644
--- a/tests/ui/unnecessary_clone.rs
+++ b/tests/ui/unnecessary_clone.rs
@@ -79,3 +79,35 @@ fn iter_clone_collect() {
     let v3 : HashSet<isize> = v.iter().cloned().collect();
     let v4 : VecDeque<isize> = v.iter().cloned().collect();
 }
+
+mod many_derefs {
+    struct A;
+    struct B;
+    struct C;
+    struct D;
+    #[derive(Copy, Clone)]
+    struct E;
+
+    macro_rules! impl_deref {
+        ($src:ident, $dst:ident) => {
+            impl std::ops::Deref for $src {
+                type Target = $dst;
+                fn deref(&self) -> &Self::Target { &$dst }
+            }
+        }
+    }
+
+    impl_deref!(A, B);
+    impl_deref!(B, C);
+    impl_deref!(C, D);
+    impl std::ops::Deref for D {
+        type Target = &'static E;
+        fn deref(&self) -> &Self::Target { &&E }
+    }
+
+    fn go1() {
+        let a = A;
+        let _: E = a.clone();
+        let _: E = *****a;
+    }
+}
diff --git a/tests/ui/unnecessary_clone.stderr b/tests/ui/unnecessary_clone.stderr
index 63e6f3d8bd5..5dcd5cae463 100644
--- a/tests/ui/unnecessary_clone.stderr
+++ b/tests/ui/unnecessary_clone.stderr
@@ -86,5 +86,11 @@ error: called `cloned().collect()` on a slice to create a `Vec`. Calling `to_vec
    |
    = note: `-D clippy::iter-cloned-collect` implied by `-D warnings`
 
-error: aborting due to 12 previous errors
+error: using `clone` on a `Copy` type
+   --> $DIR/unnecessary_clone.rs:110:20
+    |
+110 |         let _: E = a.clone();
+    |                    ^^^^^^^^^ help: try dereferencing it: `*****a`
+
+error: aborting due to 13 previous errors