about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--clippy_lints/src/methods/search_is_some.rs22
-rw-r--r--tests/ui/search_is_some_fixable.fixed35
-rw-r--r--tests/ui/search_is_some_fixable.rs35
-rw-r--r--tests/ui/search_is_some_fixable.stderr14
4 files changed, 103 insertions, 3 deletions
diff --git a/clippy_lints/src/methods/search_is_some.rs b/clippy_lints/src/methods/search_is_some.rs
index 0f2e58d8983..42a0a09f385 100644
--- a/clippy_lints/src/methods/search_is_some.rs
+++ b/clippy_lints/src/methods/search_is_some.rs
@@ -45,9 +45,27 @@ pub(super) fn check<'tcx>(
                 then {
                     if let hir::PatKind::Ref(..) = closure_arg.pat.kind {
                         Some(search_snippet.replacen('&', "", 1))
-                    } else if let PatKind::Binding(_, _, ident, _) = strip_pat_refs(closure_arg.pat).kind {
+                    } else if let PatKind::Binding(annotation, _, ident, _) = strip_pat_refs(closure_arg.pat).kind {
                         let name = &*ident.name.as_str();
-                        Some(search_snippet.replace(&format!("*{}", name), name))
+                        let old_search_snippet = search_snippet.clone();
+                        let search_snippet = search_snippet.replace(&format!("*{}", name), name);
+
+                        if_chain! {
+                            // if there is no dereferencing used in closure body
+                            if old_search_snippet == search_snippet;
+                            if annotation == hir::BindingAnnotation::Unannotated;
+                            if let ty::Ref(_, inner_ty, _) = cx.typeck_results().node_type(closure_arg.hir_id).kind();
+                            if let ty::Ref(..) = inner_ty.kind();
+                            // put an `&` in the closure body, but skip closure params
+                            if let Some((start, end)) = old_search_snippet.split_once(&name);
+
+                            then {
+                                let end = end.replace(name, &format!("&{}", name));
+                                Some(format!("{}{}{}", start, name, end))
+                            } else {
+                                Some(search_snippet)
+                            }
+                        }
                     } else {
                         None
                     }
diff --git a/tests/ui/search_is_some_fixable.fixed b/tests/ui/search_is_some_fixable.fixed
index 62ff16f67f4..029f557ffa6 100644
--- a/tests/ui/search_is_some_fixable.fixed
+++ b/tests/ui/search_is_some_fixable.fixed
@@ -66,3 +66,38 @@ fn is_none() {
     let _ = !s1[2..].contains(&s2);
     let _ = !s1[2..].contains(&s2[2..]);
 }
+
+#[allow(clippy::clone_on_copy, clippy::map_clone)]
+mod issue7392 {
+    struct Player {
+        hand: Vec<usize>,
+    }
+    fn filter() {
+        let p = Player {
+            hand: vec![1, 2, 3, 4, 5],
+        };
+        let filter_hand = vec![5];
+        let _ = p
+            .hand
+            .iter()
+            .filter(|c| !filter_hand.iter().any(|cc| c == &cc))
+            .map(|c| c.clone())
+            .collect::<Vec<_>>();
+    }
+
+    struct PlayerTuple {
+        hand: Vec<(usize, char)>,
+    }
+    fn filter_tuple() {
+        let p = PlayerTuple {
+            hand: vec![(1, 'a'), (2, 'b'), (3, 'c'), (4, 'd'), (5, 'e')],
+        };
+        let filter_hand = vec![5];
+        let _ = p
+            .hand
+            .iter()
+            .filter(|(c, _)| !filter_hand.iter().any(|cc| c == cc))
+            .map(|c| c.clone())
+            .collect::<Vec<_>>();
+    }
+}
diff --git a/tests/ui/search_is_some_fixable.rs b/tests/ui/search_is_some_fixable.rs
index 8407f716647..b8f8fe3d3c1 100644
--- a/tests/ui/search_is_some_fixable.rs
+++ b/tests/ui/search_is_some_fixable.rs
@@ -66,3 +66,38 @@ fn is_none() {
     let _ = s1[2..].find(&s2).is_none();
     let _ = s1[2..].find(&s2[2..]).is_none();
 }
+
+#[allow(clippy::clone_on_copy, clippy::map_clone)]
+mod issue7392 {
+    struct Player {
+        hand: Vec<usize>,
+    }
+    fn filter() {
+        let p = Player {
+            hand: vec![1, 2, 3, 4, 5],
+        };
+        let filter_hand = vec![5];
+        let _ = p
+            .hand
+            .iter()
+            .filter(|c| filter_hand.iter().find(|cc| c == cc).is_none())
+            .map(|c| c.clone())
+            .collect::<Vec<_>>();
+    }
+
+    struct PlayerTuple {
+        hand: Vec<(usize, char)>,
+    }
+    fn filter_tuple() {
+        let p = PlayerTuple {
+            hand: vec![(1, 'a'), (2, 'b'), (3, 'c'), (4, 'd'), (5, 'e')],
+        };
+        let filter_hand = vec![5];
+        let _ = p
+            .hand
+            .iter()
+            .filter(|(c, _)| filter_hand.iter().find(|cc| c == *cc).is_none())
+            .map(|c| c.clone())
+            .collect::<Vec<_>>();
+    }
+}
diff --git a/tests/ui/search_is_some_fixable.stderr b/tests/ui/search_is_some_fixable.stderr
index bd1b6955a97..0d92722229c 100644
--- a/tests/ui/search_is_some_fixable.stderr
+++ b/tests/ui/search_is_some_fixable.stderr
@@ -180,5 +180,17 @@ error: called `is_none()` after calling `find()` on a string
 LL |     let _ = s1[2..].find(&s2[2..]).is_none();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.contains()` instead: `!s1[2..].contains(&s2[2..])`
 
-error: aborting due to 30 previous errors
+error: called `is_none()` after searching an `Iterator` with `find`
+  --> $DIR/search_is_some_fixable.rs:83:25
+   |
+LL |             .filter(|c| filter_hand.iter().find(|cc| c == cc).is_none())
+   |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!filter_hand.iter().any(|cc| c == &cc)`
+
+error: called `is_none()` after searching an `Iterator` with `find`
+  --> $DIR/search_is_some_fixable.rs:99:30
+   |
+LL |             .filter(|(c, _)| filter_hand.iter().find(|cc| c == *cc).is_none())
+   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!filter_hand.iter().any(|cc| c == cc)`
+
+error: aborting due to 32 previous errors