about summary refs log tree commit diff
diff options
context:
space:
mode:
authorThibsG <Thibs@debian.com>2021-08-09 12:00:35 +0200
committerThibsG <thibsg@pm.me>2021-11-20 09:40:10 +0100
commit5ed93af9c41e552c8d85390e2387d01eb9429174 (patch)
tree383b889afe1b830531932f490b753aed4ddd0365
parentf4c75cde5e5226912995f6809e96efd2ac2c2348 (diff)
downloadrust-5ed93af9c41e552c8d85390e2387d01eb9429174.tar.gz
rust-5ed93af9c41e552c8d85390e2387d01eb9429174.zip
Use `ExprUseVisitor` and multipart suggestion to avoid iffy `String` replacement
-rw-r--r--clippy_lints/src/methods/search_is_some.rs186
-rw-r--r--tests/ui/search_is_some.rs45
-rw-r--r--tests/ui/search_is_some.stderr128
-rw-r--r--tests/ui/search_is_some_fixable.fixed43
-rw-r--r--tests/ui/search_is_some_fixable.rs43
-rw-r--r--tests/ui/search_is_some_fixable.stderr98
6 files changed, 334 insertions, 209 deletions
diff --git a/clippy_lints/src/methods/search_is_some.rs b/clippy_lints/src/methods/search_is_some.rs
index 42a0a09f385..71fca601747 100644
--- a/clippy_lints/src/methods/search_is_some.rs
+++ b/clippy_lints/src/methods/search_is_some.rs
@@ -1,15 +1,19 @@
-use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg};
+use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg, span_lint_and_then};
 use clippy_utils::source::{snippet, snippet_with_applicability};
 use clippy_utils::ty::is_type_diagnostic_item;
 use clippy_utils::{is_trait_method, strip_pat_refs};
 use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir as hir;
-use rustc_hir::PatKind;
+use rustc_hir::{self, HirId, HirIdMap, HirIdSet, PatKind};
+use rustc_infer::infer::TyCtxtInferExt;
 use rustc_lint::LateContext;
+use rustc_middle::hir::place::ProjectionKind;
+use rustc_middle::mir::FakeReadCause;
 use rustc_middle::ty;
 use rustc_span::source_map::Span;
 use rustc_span::symbol::sym;
+use rustc_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId};
 
 use super::SEARCH_IS_SOME;
 
@@ -42,30 +46,42 @@ pub(super) fn check<'tcx>(
                 if let hir::ExprKind::Closure(_, _, body_id, ..) = search_arg.kind;
                 let closure_body = cx.tcx.hir().body(body_id);
                 if let Some(closure_arg) = closure_body.params.get(0);
+
                 then {
                     if let hir::PatKind::Ref(..) = closure_arg.pat.kind {
-                        Some(search_snippet.replacen('&', "", 1))
-                    } else if let PatKind::Binding(annotation, _, ident, _) = strip_pat_refs(closure_arg.pat).kind {
-                        let name = &*ident.name.as_str();
-                        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)
+                        Some((search_snippet.replacen('&', "", 1), None))
+                    } else if let PatKind::Binding(..) = strip_pat_refs(closure_arg.pat).kind {
+                        let mut visitor = DerefDelegate {
+                            cx,
+                            set: HirIdSet::default(),
+                            deref_suggs: HirIdMap::default(),
+                            borrow_suggs: HirIdMap::default()
+                        };
+
+                        let fn_def_id = cx.tcx.hir().local_def_id(search_arg.hir_id);
+                        cx.tcx.infer_ctxt().enter(|infcx| {
+                            ExprUseVisitor::new(
+                                &mut visitor, &infcx, fn_def_id, cx.param_env, cx.typeck_results()
+                            ).consume_body(closure_body);
+                        });
+
+                        let replacements = if visitor.set.is_empty() {
+                            None
+                        } else {
+                            let mut deref_suggs = Vec::new();
+                            let mut borrow_suggs = Vec::new();
+                            for node in visitor.set {
+                                let span = cx.tcx.hir().span(node);
+                                if let Some(sugg) = visitor.deref_suggs.get(&node) {
+                                    deref_suggs.push((span, sugg.clone()));
+                                }
+                                if let Some(sugg) = visitor.borrow_suggs.get(&node) {
+                                    borrow_suggs.push((span, sugg.clone()));
+                                }
                             }
-                        }
+                            Some((deref_suggs, borrow_suggs))
+                        };
+                        Some((search_snippet.to_string(), replacements))
                     } else {
                         None
                     }
@@ -74,35 +90,38 @@ pub(super) fn check<'tcx>(
                 }
             };
             // add note if not multi-line
-            if is_some {
-                span_lint_and_sugg(
-                    cx,
-                    SEARCH_IS_SOME,
+            let (closure_snippet, replacements) = any_search_snippet
+                .as_ref()
+                .map_or((&*search_snippet, None), |s| (&s.0, s.1.clone()));
+            let (span, help, sugg) = if is_some {
+                (
                     method_span.with_hi(expr.span.hi()),
-                    &msg,
                     "use `any()` instead",
-                    format!(
-                        "any({})",
-                        any_search_snippet.as_ref().map_or(&*search_snippet, String::as_str)
-                    ),
-                    Applicability::MachineApplicable,
-                );
+                    format!("any({})", closure_snippet),
+                )
             } else {
                 let iter = snippet(cx, search_recv.span, "..");
-                span_lint_and_sugg(
-                    cx,
-                    SEARCH_IS_SOME,
+                (
                     expr.span,
-                    &msg,
                     "use `!_.any()` instead",
-                    format!(
-                        "!{}.any({})",
-                        iter,
-                        any_search_snippet.as_ref().map_or(&*search_snippet, String::as_str)
-                    ),
-                    Applicability::MachineApplicable,
-                );
-            }
+                    format!("!{}.any({})", iter, closure_snippet),
+                )
+            };
+
+            span_lint_and_then(cx, SEARCH_IS_SOME, span, &msg, |db| {
+                if let Some((deref_suggs, borrow_suggs)) = replacements {
+                    db.span_suggestion(span, help, sugg, Applicability::MaybeIncorrect);
+
+                    if !deref_suggs.is_empty() {
+                        db.multipart_suggestion("...and remove deref", deref_suggs, Applicability::MaybeIncorrect);
+                    }
+                    if !borrow_suggs.is_empty() {
+                        db.multipart_suggestion("...and borrow variable", borrow_suggs, Applicability::MaybeIncorrect);
+                    }
+                } else {
+                    db.span_suggestion(span, help, sugg, Applicability::MachineApplicable);
+                }
+            });
         } else {
             let hint = format!(
                 "this is more succinctly expressed by calling `any()`{}",
@@ -164,3 +183,78 @@ pub(super) fn check<'tcx>(
         }
     }
 }
+
+struct DerefDelegate<'a, 'tcx> {
+    cx: &'a LateContext<'tcx>,
+    set: HirIdSet,
+    deref_suggs: HirIdMap<String>,
+    borrow_suggs: HirIdMap<String>,
+}
+
+impl<'tcx> Delegate<'tcx> for DerefDelegate<'_, 'tcx> {
+    fn consume(&mut self, cmt: &PlaceWithHirId<'tcx>, _: HirId) {
+        if let PlaceBase::Local(id) = cmt.place.base {
+            let map = self.cx.tcx.hir();
+            if cmt.place.projections.is_empty() {
+                self.set.insert(cmt.hir_id);
+            } else {
+                let mut replacement_str = map.name(id).to_string();
+                let last_deref = cmt
+                    .place
+                    .projections
+                    .iter()
+                    .rposition(|proj| proj.kind == ProjectionKind::Deref);
+
+                if let Some(pos) = last_deref {
+                    let mut projections = cmt.place.projections.clone();
+                    projections.truncate(pos);
+
+                    for item in projections {
+                        if item.kind == ProjectionKind::Deref {
+                            replacement_str = format!("*{}", replacement_str);
+                        }
+                    }
+
+                    self.set.insert(cmt.hir_id);
+                    self.deref_suggs.insert(cmt.hir_id, replacement_str);
+                }
+            }
+        }
+    }
+
+    fn borrow(&mut self, cmt: &PlaceWithHirId<'tcx>, _: HirId, _: ty::BorrowKind) {
+        if let PlaceBase::Local(id) = cmt.place.base {
+            let map = self.cx.tcx.hir();
+            if cmt.place.projections.is_empty() {
+                let replacement_str = format!("&{}", map.name(id).to_string());
+                self.set.insert(cmt.hir_id);
+                self.borrow_suggs.insert(cmt.hir_id, replacement_str);
+            } else {
+                let mut replacement_str = map.name(id).to_string();
+                let last_deref = cmt
+                    .place
+                    .projections
+                    .iter()
+                    .rposition(|proj| proj.kind == ProjectionKind::Deref);
+
+                if let Some(pos) = last_deref {
+                    let mut projections = cmt.place.projections.clone();
+                    projections.truncate(pos);
+
+                    for item in projections {
+                        if item.kind == ProjectionKind::Deref {
+                            replacement_str = format!("*{}", replacement_str);
+                        }
+                    }
+
+                    self.set.insert(cmt.hir_id);
+                    self.deref_suggs.insert(cmt.hir_id, replacement_str);
+                }
+            }
+        }
+    }
+
+    fn mutate(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {}
+
+    fn fake_read(&mut self, _: rustc_typeck::expr_use_visitor::Place<'tcx>, _: FakeReadCause, _: HirId) {}
+}
diff --git a/tests/ui/search_is_some.rs b/tests/ui/search_is_some.rs
index 72bc6ef35d3..dfc79207ca7 100644
--- a/tests/ui/search_is_some.rs
+++ b/tests/ui/search_is_some.rs
@@ -36,6 +36,11 @@ fn main() {
     // check that we don't lint if `find()` is called with
     // `Pattern` that is not a string
     let _ = "hello world".find(|c: char| c == 'o' || c == 'l').is_some();
+
+    // Check `find().is_some()`, single-line case.
+    let _ = (0..1).find(|x| **y == *x).is_some(); // one dereference less
+    let _ = (0..1).find(|x| *x == 0).is_some();
+    let _ = v.iter().find(|x| **x == 0).is_some();
 }
 
 #[rustfmt::skip]
@@ -70,4 +75,44 @@ fn is_none() {
     // check that we don't lint if `find()` is called with
     // `Pattern` that is not a string
     let _ = "hello world".find(|c: char| c == 'o' || c == 'l').is_none();
+
+    // Check `find().is_none()`, single-line case.
+    let _ = (0..1).find(|x| **y == *x).is_none(); // one dereference less
+    let _ = (0..1).find(|x| *x == 0).is_none();
+    let _ = v.iter().find(|x| **x == 0).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.stderr b/tests/ui/search_is_some.stderr
index f3c758e451e..8db936fd948 100644
--- a/tests/ui/search_is_some.stderr
+++ b/tests/ui/search_is_some.stderr
@@ -35,8 +35,53 @@ LL | |                    ).is_some();
    |
    = help: this is more succinctly expressed by calling `any()`
 
+error: called `is_some()` after searching an `Iterator` with `find`
+  --> $DIR/search_is_some.rs:41:20
+   |
+LL |     let _ = (0..1).find(|x| **y == *x).is_some(); // one dereference less
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: use `any()` instead
+   |
+LL |     let _ = (0..1).any(|x| **y == *x); // one dereference less
+   |                    ^^^^^^^^^^^^^^^^^^
+help: ...and remove deref
+   |
+LL |     let _ = (0..1).find(|x| **y == x).is_some(); // one dereference less
+   |                                    ^
+
+error: called `is_some()` after searching an `Iterator` with `find`
+  --> $DIR/search_is_some.rs:42:20
+   |
+LL |     let _ = (0..1).find(|x| *x == 0).is_some();
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: use `any()` instead
+   |
+LL |     let _ = (0..1).any(|x| *x == 0);
+   |                    ^^^^^^^^^^^^^^^^
+help: ...and remove deref
+   |
+LL |     let _ = (0..1).find(|x| x == 0).is_some();
+   |                             ^
+
+error: called `is_some()` after searching an `Iterator` with `find`
+  --> $DIR/search_is_some.rs:43:22
+   |
+LL |     let _ = v.iter().find(|x| **x == 0).is_some();
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: use `any()` instead
+   |
+LL |     let _ = v.iter().any(|x| **x == 0);
+   |                      ^^^^^^^^^^^^^^^^^
+help: ...and remove deref
+   |
+LL |     let _ = v.iter().find(|x| *x == 0).is_some();
+   |                               ^^
+
 error: called `is_none()` after searching an `Iterator` with `find`
-  --> $DIR/search_is_some.rs:48:13
+  --> $DIR/search_is_some.rs:53:13
    |
 LL |       let _ = v.iter().find(|&x| {
    |  _____________^
@@ -48,7 +93,7 @@ LL | |                    ).is_none();
    = help: this is more succinctly expressed by calling `any()` with negation
 
 error: called `is_none()` after searching an `Iterator` with `position`
-  --> $DIR/search_is_some.rs:54:13
+  --> $DIR/search_is_some.rs:59:13
    |
 LL |       let _ = v.iter().position(|&x| {
    |  _____________^
@@ -60,7 +105,7 @@ LL | |                    ).is_none();
    = help: this is more succinctly expressed by calling `any()` with negation
 
 error: called `is_none()` after searching an `Iterator` with `rposition`
-  --> $DIR/search_is_some.rs:60:13
+  --> $DIR/search_is_some.rs:65:13
    |
 LL |       let _ = v.iter().rposition(|&x| {
    |  _____________^
@@ -71,5 +116,80 @@ LL | |                    ).is_none();
    |
    = help: this is more succinctly expressed by calling `any()` with negation
 
-error: aborting due to 6 previous errors
+error: called `is_none()` after searching an `Iterator` with `find`
+  --> $DIR/search_is_some.rs:80:13
+   |
+LL |     let _ = (0..1).find(|x| **y == *x).is_none(); // one dereference less
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: use `!_.any()` instead
+   |
+LL |     let _ = !(0..1).any(|x| **y == *x); // one dereference less
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: ...and remove deref
+   |
+LL |     let _ = (0..1).find(|x| **y == x).is_none(); // one dereference less
+   |                                    ^
+
+error: called `is_none()` after searching an `Iterator` with `find`
+  --> $DIR/search_is_some.rs:81:13
+   |
+LL |     let _ = (0..1).find(|x| *x == 0).is_none();
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: use `!_.any()` instead
+   |
+LL |     let _ = !(0..1).any(|x| *x == 0);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^
+help: ...and remove deref
+   |
+LL |     let _ = (0..1).find(|x| x == 0).is_none();
+   |                             ^
+
+error: called `is_none()` after searching an `Iterator` with `find`
+  --> $DIR/search_is_some.rs:82:13
+   |
+LL |     let _ = v.iter().find(|x| **x == 0).is_none();
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: use `!_.any()` instead
+   |
+LL |     let _ = !v.iter().any(|x| **x == 0);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: ...and remove deref
+   |
+LL |     let _ = v.iter().find(|x| *x == 0).is_none();
+   |                               ^^
+
+error: called `is_none()` after searching an `Iterator` with `find`
+  --> $DIR/search_is_some.rs:98:25
+   |
+LL |             .filter(|c| filter_hand.iter().find(|cc| c == cc).is_none())
+   |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: use `!_.any()` instead
+   |
+LL |             .filter(|c| !filter_hand.iter().any(|cc| c == cc))
+   |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: ...and borrow variable
+   |
+LL |             .filter(|c| filter_hand.iter().find(|cc| c == &cc).is_none())
+   |                                                           ^^^
+
+error: called `is_none()` after searching an `Iterator` with `find`
+  --> $DIR/search_is_some.rs:114:30
+   |
+LL |             .filter(|(c, _)| filter_hand.iter().find(|cc| c == *cc).is_none())
+   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: use `!_.any()` instead
+   |
+LL |             .filter(|(c, _)| !filter_hand.iter().any(|cc| c == *cc))
+   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: ...and remove deref
+   |
+LL |             .filter(|(c, _)| filter_hand.iter().find(|cc| c == cc).is_none())
+   |                                                                ^^
+
+error: aborting due to 14 previous errors
 
diff --git a/tests/ui/search_is_some_fixable.fixed b/tests/ui/search_is_some_fixable.fixed
index 029f557ffa6..6994df427ba 100644
--- a/tests/ui/search_is_some_fixable.fixed
+++ b/tests/ui/search_is_some_fixable.fixed
@@ -4,13 +4,9 @@
 
 fn main() {
     let v = vec![3, 2, 1, 0, -1, -2, -3];
-    let y = &&42;
 
     // Check `find().is_some()`, single-line case.
     let _ = v.iter().any(|x| *x < 0);
-    let _ = (0..1).any(|x| **y == x); // one dereference less
-    let _ = (0..1).any(|x| x == 0);
-    let _ = v.iter().any(|x| *x == 0);
 
     // Check `position().is_some()`, single-line case.
     let _ = v.iter().any(|&x| x < 0);
@@ -36,13 +32,9 @@ fn main() {
 
 fn is_none() {
     let v = vec![3, 2, 1, 0, -1, -2, -3];
-    let y = &&42;
 
     // Check `find().is_none()`, single-line case.
     let _ = !v.iter().any(|x| *x < 0);
-    let _ = !(0..1).any(|x| **y == x); // one dereference less
-    let _ = !(0..1).any(|x| x == 0);
-    let _ = !v.iter().any(|x| *x == 0);
 
     // Check `position().is_none()`, single-line case.
     let _ = !v.iter().any(|&x| x < 0);
@@ -66,38 +58,3 @@ 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 b8f8fe3d3c1..d4c9d89e7b8 100644
--- a/tests/ui/search_is_some_fixable.rs
+++ b/tests/ui/search_is_some_fixable.rs
@@ -4,13 +4,9 @@
 
 fn main() {
     let v = vec![3, 2, 1, 0, -1, -2, -3];
-    let y = &&42;
 
     // Check `find().is_some()`, single-line case.
     let _ = v.iter().find(|&x| *x < 0).is_some();
-    let _ = (0..1).find(|x| **y == *x).is_some(); // one dereference less
-    let _ = (0..1).find(|x| *x == 0).is_some();
-    let _ = v.iter().find(|x| **x == 0).is_some();
 
     // Check `position().is_some()`, single-line case.
     let _ = v.iter().position(|&x| x < 0).is_some();
@@ -36,13 +32,9 @@ fn main() {
 
 fn is_none() {
     let v = vec![3, 2, 1, 0, -1, -2, -3];
-    let y = &&42;
 
     // Check `find().is_none()`, single-line case.
     let _ = v.iter().find(|&x| *x < 0).is_none();
-    let _ = (0..1).find(|x| **y == *x).is_none(); // one dereference less
-    let _ = (0..1).find(|x| *x == 0).is_none();
-    let _ = v.iter().find(|x| **x == 0).is_none();
 
     // Check `position().is_none()`, single-line case.
     let _ = v.iter().position(|&x| x < 0).is_none();
@@ -66,38 +58,3 @@ 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 0d92722229c..5e77c9a5bac 100644
--- a/tests/ui/search_is_some_fixable.stderr
+++ b/tests/ui/search_is_some_fixable.stderr
@@ -1,196 +1,148 @@
 error: called `is_some()` after searching an `Iterator` with `find`
-  --> $DIR/search_is_some_fixable.rs:10:22
+  --> $DIR/search_is_some_fixable.rs:9:22
    |
 LL |     let _ = v.iter().find(|&x| *x < 0).is_some();
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x| *x < 0)`
    |
    = note: `-D clippy::search-is-some` implied by `-D warnings`
 
-error: called `is_some()` after searching an `Iterator` with `find`
-  --> $DIR/search_is_some_fixable.rs:11:20
-   |
-LL |     let _ = (0..1).find(|x| **y == *x).is_some(); // one dereference less
-   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x| **y == x)`
-
-error: called `is_some()` after searching an `Iterator` with `find`
-  --> $DIR/search_is_some_fixable.rs:12:20
-   |
-LL |     let _ = (0..1).find(|x| *x == 0).is_some();
-   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x| x == 0)`
-
-error: called `is_some()` after searching an `Iterator` with `find`
-  --> $DIR/search_is_some_fixable.rs:13:22
-   |
-LL |     let _ = v.iter().find(|x| **x == 0).is_some();
-   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x| *x == 0)`
-
 error: called `is_some()` after searching an `Iterator` with `position`
-  --> $DIR/search_is_some_fixable.rs:16:22
+  --> $DIR/search_is_some_fixable.rs:12:22
    |
 LL |     let _ = v.iter().position(|&x| x < 0).is_some();
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|&x| x < 0)`
 
 error: called `is_some()` after searching an `Iterator` with `rposition`
-  --> $DIR/search_is_some_fixable.rs:19:22
+  --> $DIR/search_is_some_fixable.rs:15:22
    |
 LL |     let _ = v.iter().rposition(|&x| x < 0).is_some();
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|&x| x < 0)`
 
 error: called `is_some()` after calling `find()` on a string
-  --> $DIR/search_is_some_fixable.rs:24:27
+  --> $DIR/search_is_some_fixable.rs:20:27
    |
 LL |     let _ = "hello world".find("world").is_some();
    |                           ^^^^^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains("world")`
 
 error: called `is_some()` after calling `find()` on a string
-  --> $DIR/search_is_some_fixable.rs:25:27
+  --> $DIR/search_is_some_fixable.rs:21:27
    |
 LL |     let _ = "hello world".find(&s2).is_some();
    |                           ^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains(&s2)`
 
 error: called `is_some()` after calling `find()` on a string
-  --> $DIR/search_is_some_fixable.rs:26:27
+  --> $DIR/search_is_some_fixable.rs:22:27
    |
 LL |     let _ = "hello world".find(&s2[2..]).is_some();
    |                           ^^^^^^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains(&s2[2..])`
 
 error: called `is_some()` after calling `find()` on a string
-  --> $DIR/search_is_some_fixable.rs:28:16
+  --> $DIR/search_is_some_fixable.rs:24:16
    |
 LL |     let _ = s1.find("world").is_some();
    |                ^^^^^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains("world")`
 
 error: called `is_some()` after calling `find()` on a string
-  --> $DIR/search_is_some_fixable.rs:29:16
+  --> $DIR/search_is_some_fixable.rs:25:16
    |
 LL |     let _ = s1.find(&s2).is_some();
    |                ^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains(&s2)`
 
 error: called `is_some()` after calling `find()` on a string
-  --> $DIR/search_is_some_fixable.rs:30:16
+  --> $DIR/search_is_some_fixable.rs:26:16
    |
 LL |     let _ = s1.find(&s2[2..]).is_some();
    |                ^^^^^^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains(&s2[2..])`
 
 error: called `is_some()` after calling `find()` on a string
-  --> $DIR/search_is_some_fixable.rs:32:21
+  --> $DIR/search_is_some_fixable.rs:28:21
    |
 LL |     let _ = s1[2..].find("world").is_some();
    |                     ^^^^^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains("world")`
 
 error: called `is_some()` after calling `find()` on a string
-  --> $DIR/search_is_some_fixable.rs:33:21
+  --> $DIR/search_is_some_fixable.rs:29:21
    |
 LL |     let _ = s1[2..].find(&s2).is_some();
    |                     ^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains(&s2)`
 
 error: called `is_some()` after calling `find()` on a string
-  --> $DIR/search_is_some_fixable.rs:34:21
+  --> $DIR/search_is_some_fixable.rs:30:21
    |
 LL |     let _ = s1[2..].find(&s2[2..]).is_some();
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains(&s2[2..])`
 
 error: called `is_none()` after searching an `Iterator` with `find`
-  --> $DIR/search_is_some_fixable.rs:42:13
+  --> $DIR/search_is_some_fixable.rs:37:13
    |
 LL |     let _ = v.iter().find(|&x| *x < 0).is_none();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!v.iter().any(|x| *x < 0)`
 
-error: called `is_none()` after searching an `Iterator` with `find`
-  --> $DIR/search_is_some_fixable.rs:43:13
-   |
-LL |     let _ = (0..1).find(|x| **y == *x).is_none(); // one dereference less
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!(0..1).any(|x| **y == x)`
-
-error: called `is_none()` after searching an `Iterator` with `find`
-  --> $DIR/search_is_some_fixable.rs:44:13
-   |
-LL |     let _ = (0..1).find(|x| *x == 0).is_none();
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!(0..1).any(|x| x == 0)`
-
-error: called `is_none()` after searching an `Iterator` with `find`
-  --> $DIR/search_is_some_fixable.rs:45:13
-   |
-LL |     let _ = v.iter().find(|x| **x == 0).is_none();
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!v.iter().any(|x| *x == 0)`
-
 error: called `is_none()` after searching an `Iterator` with `position`
-  --> $DIR/search_is_some_fixable.rs:48:13
+  --> $DIR/search_is_some_fixable.rs:40:13
    |
 LL |     let _ = v.iter().position(|&x| x < 0).is_none();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!v.iter().any(|&x| x < 0)`
 
 error: called `is_none()` after searching an `Iterator` with `rposition`
-  --> $DIR/search_is_some_fixable.rs:51:13
+  --> $DIR/search_is_some_fixable.rs:43:13
    |
 LL |     let _ = v.iter().rposition(|&x| x < 0).is_none();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!v.iter().any(|&x| x < 0)`
 
 error: called `is_none()` after calling `find()` on a string
-  --> $DIR/search_is_some_fixable.rs:57:13
+  --> $DIR/search_is_some_fixable.rs:49:13
    |
 LL |     let _ = "hello world".find("world").is_none();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.contains()` instead: `!"hello world".contains("world")`
 
 error: called `is_none()` after calling `find()` on a string
-  --> $DIR/search_is_some_fixable.rs:58:13
+  --> $DIR/search_is_some_fixable.rs:50:13
    |
 LL |     let _ = "hello world".find(&s2).is_none();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.contains()` instead: `!"hello world".contains(&s2)`
 
 error: called `is_none()` after calling `find()` on a string
-  --> $DIR/search_is_some_fixable.rs:59:13
+  --> $DIR/search_is_some_fixable.rs:51:13
    |
 LL |     let _ = "hello world".find(&s2[2..]).is_none();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.contains()` instead: `!"hello world".contains(&s2[2..])`
 
 error: called `is_none()` after calling `find()` on a string
-  --> $DIR/search_is_some_fixable.rs:61:13
+  --> $DIR/search_is_some_fixable.rs:53:13
    |
 LL |     let _ = s1.find("world").is_none();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.contains()` instead: `!s1.contains("world")`
 
 error: called `is_none()` after calling `find()` on a string
-  --> $DIR/search_is_some_fixable.rs:62:13
+  --> $DIR/search_is_some_fixable.rs:54:13
    |
 LL |     let _ = s1.find(&s2).is_none();
    |             ^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.contains()` instead: `!s1.contains(&s2)`
 
 error: called `is_none()` after calling `find()` on a string
-  --> $DIR/search_is_some_fixable.rs:63:13
+  --> $DIR/search_is_some_fixable.rs:55:13
    |
 LL |     let _ = s1.find(&s2[2..]).is_none();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.contains()` instead: `!s1.contains(&s2[2..])`
 
 error: called `is_none()` after calling `find()` on a string
-  --> $DIR/search_is_some_fixable.rs:65:13
+  --> $DIR/search_is_some_fixable.rs:57:13
    |
 LL |     let _ = s1[2..].find("world").is_none();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.contains()` instead: `!s1[2..].contains("world")`
 
 error: called `is_none()` after calling `find()` on a string
-  --> $DIR/search_is_some_fixable.rs:66:13
+  --> $DIR/search_is_some_fixable.rs:58:13
    |
 LL |     let _ = s1[2..].find(&s2).is_none();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.contains()` instead: `!s1[2..].contains(&s2)`
 
 error: called `is_none()` after calling `find()` on a string
-  --> $DIR/search_is_some_fixable.rs:67:13
+  --> $DIR/search_is_some_fixable.rs:59:13
    |
 LL |     let _ = s1[2..].find(&s2[2..]).is_none();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.contains()` instead: `!s1[2..].contains(&s2[2..])`
 
-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
+error: aborting due to 24 previous errors