From f4c75cde5e5226912995f6809e96efd2ac2c2348 Mon Sep 17 00:00:00 2001 From: ThibsG Date: Tue, 13 Jul 2021 11:26:24 +0200 Subject: [PATCH] Fix `any()` not taking reference in `search_is_some` lint --- clippy_lints/src/methods/search_is_some.rs | 22 ++++++++++++-- tests/ui/search_is_some_fixable.fixed | 35 ++++++++++++++++++++++ tests/ui/search_is_some_fixable.rs | 35 ++++++++++++++++++++++ tests/ui/search_is_some_fixable.stderr | 14 ++++++++- 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 0f2e58d8983f..42a0a09f3854 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 62ff16f67f41..029f557ffa62 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, + } + 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::>(); + } + + 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::>(); + } +} diff --git a/tests/ui/search_is_some_fixable.rs b/tests/ui/search_is_some_fixable.rs index 8407f7166474..b8f8fe3d3c19 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, + } + 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::>(); + } + + 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::>(); + } +} diff --git a/tests/ui/search_is_some_fixable.stderr b/tests/ui/search_is_some_fixable.stderr index bd1b6955a972..0d92722229c3 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