Skip to content

Commit ac45a83

Browse files
committed
Handle multiple reference levels into binding type and add more tests
1 parent 788c9cc commit ac45a83

7 files changed

+94
-7
lines changed

clippy_lints/src/methods/search_is_some.rs

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -50,12 +50,26 @@ pub(super) fn check<'tcx>(
5050
then {
5151
if let hir::PatKind::Ref(..) = closure_arg.pat.kind {
5252
Some(search_snippet.replacen('&', "", 1))
53-
} else if let PatKind::Binding(..) = strip_pat_refs(closure_arg.pat).kind {
53+
} else if let PatKind::Binding(_, binding_id, _, _) = strip_pat_refs(closure_arg.pat).kind {
54+
// this binding is composed of at least two levels of references, so we need to remove one
55+
let binding_type = cx.typeck_results().node_type(binding_id);
56+
let innermost_is_ref = if let ty::Ref(_, inner,_) = binding_type.kind() {
57+
matches!(inner.kind(), ty::Ref(_, innermost, _) if innermost.is_ref())
58+
} else {
59+
false
60+
};
61+
5462
// `find()` provides a reference to the item, but `any` does not,
5563
// so we should fix item usages for suggestion
5664
if let Some(closure_sugg) = get_closure_suggestion(cx, search_arg, closure_body) {
5765
applicability = closure_sugg.applicability;
58-
Some(closure_sugg.suggestion)
66+
if innermost_is_ref {
67+
Some(closure_sugg.suggestion.replacen('&', "", 1))
68+
} else {
69+
Some(closure_sugg.suggestion)
70+
}
71+
} else if innermost_is_ref {
72+
Some(search_snippet.replacen('&', "", 1))
5973
} else {
6074
Some(search_snippet.to_string())
6175
}
@@ -230,7 +244,7 @@ impl<'tcx> Delegate<'tcx> for DerefDelegate<'_, 'tcx> {
230244
// cases where a parent call is using the item
231245
// i.e.: suggest `.contains(&x)` for `.find(|x| [1, 2, 3].contains(x)).is_none()`
232246
if let Some(parent_expr) = get_parent_expr_for_hir(self.cx, cmt.hir_id) {
233-
if let ExprKind::Call(..) | ExprKind::MethodCall(..) = parent_expr.kind {
247+
if let ExprKind::Call(_, call_args) | ExprKind::MethodCall(_, _, call_args, _) = parent_expr.kind {
234248
let expr = self.cx.tcx.hir().expect_expr(cmt.hir_id);
235249
let arg_ty_kind = self.cx.typeck_results().expr_ty(expr).kind();
236250

@@ -239,8 +253,13 @@ impl<'tcx> Delegate<'tcx> for DerefDelegate<'_, 'tcx> {
239253
let start_span = Span::new(self.next_pos, span.lo(), span.ctxt());
240254
let start_snip =
241255
snippet_with_applicability(self.cx, start_span, "..", &mut self.applicability);
242-
243-
self.suggestion_start.push_str(&format!("{}&{}", start_snip, ident_str));
256+
// do not suggest ampersand if the ident is the method caller
257+
let ident_sugg = if !call_args.is_empty() && call_args[0].hir_id == cmt.hir_id {
258+
format!("{}{}", start_snip, ident_str)
259+
} else {
260+
format!("{}&{}", start_snip, ident_str)
261+
};
262+
self.suggestion_start.push_str(&ident_sugg);
244263
self.next_pos = span.hi();
245264
} else {
246265
self.applicability = Applicability::Unspecified;

tests/ui/search_is_some_fixable_none.fixed

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,4 +97,15 @@ mod issue7392 {
9797
let vfoo = vec![[0, 1, 2, 3, 0, 1, 2, 3]];
9898
let _ = !vfoo.iter().any(|sub| sub[1..4].len() == 3);
9999
}
100+
101+
fn please(x: &u32) -> bool {
102+
*x == 9
103+
}
104+
105+
fn more_projections() {
106+
let x = 19;
107+
let ppx: &u32 = &x;
108+
let _ = ![ppx].iter().any(|ppp_x: &&u32| please(ppp_x));
109+
let _ = ![String::from("Hey hey")].iter().any(|s| s.len() == 2);
110+
}
100111
}

tests/ui/search_is_some_fixable_none.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,4 +101,15 @@ mod issue7392 {
101101
let vfoo = vec![[0, 1, 2, 3, 0, 1, 2, 3]];
102102
let _ = vfoo.iter().find(|sub| sub[1..4].len() == 3).is_none();
103103
}
104+
105+
fn please(x: &u32) -> bool {
106+
*x == 9
107+
}
108+
109+
fn more_projections() {
110+
let x = 19;
111+
let ppx: &u32 = &x;
112+
let _ = [ppx].iter().find(|ppp_x: &&&u32| please(**ppp_x)).is_none();
113+
let _ = [String::from("Hey hey")].iter().find(|s| s.len() == 2).is_none();
114+
}
104115
}

tests/ui/search_is_some_fixable_none.stderr

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,5 +169,17 @@ error: called `is_none()` after searching an `Iterator` with `find`
169169
LL | let _ = vfoo.iter().find(|sub| sub[1..4].len() == 3).is_none();
170170
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!vfoo.iter().any(|sub| sub[1..4].len() == 3)`
171171

172-
error: aborting due to 26 previous errors
172+
error: called `is_none()` after searching an `Iterator` with `find`
173+
--> $DIR/search_is_some_fixable_none.rs:112:17
174+
|
175+
LL | let _ = [ppx].iter().find(|ppp_x: &&&u32| please(**ppp_x)).is_none();
176+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `![ppx].iter().any(|ppp_x: &&u32| please(ppp_x))`
177+
178+
error: called `is_none()` after searching an `Iterator` with `find`
179+
--> $DIR/search_is_some_fixable_none.rs:113:17
180+
|
181+
LL | let _ = [String::from("Hey hey")].iter().find(|s| s.len() == 2).is_none();
182+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `![String::from("Hey hey")].iter().any(|s| s.len() == 2)`
183+
184+
error: aborting due to 28 previous errors
173185

tests/ui/search_is_some_fixable_some.fixed

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,4 +98,15 @@ mod issue7392 {
9898
let vfoo = vec![[0, 1, 2, 3, 0, 1, 2, 3]];
9999
let _ = vfoo.iter().any(|sub| sub[1..4].len() == 3);
100100
}
101+
102+
fn please(x: &u32) -> bool {
103+
*x == 9
104+
}
105+
106+
fn more_projections() {
107+
let x = 19;
108+
let ppx: &u32 = &x;
109+
let _ = [ppx].iter().any(|ppp_x: &&u32| please(ppp_x));
110+
let _ = [String::from("Hey hey")].iter().any(|s| s.len() == 2);
111+
}
101112
}

tests/ui/search_is_some_fixable_some.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,4 +100,15 @@ mod issue7392 {
100100
let vfoo = vec![[0, 1, 2, 3, 0, 1, 2, 3]];
101101
let _ = vfoo.iter().find(|sub| sub[1..4].len() == 3).is_some();
102102
}
103+
104+
fn please(x: &u32) -> bool {
105+
*x == 9
106+
}
107+
108+
fn more_projections() {
109+
let x = 19;
110+
let ppx: &u32 = &x;
111+
let _ = [ppx].iter().find(|ppp_x: &&&u32| please(**ppp_x)).is_some();
112+
let _ = [String::from("Hey hey")].iter().find(|s| s.len() == 2).is_some();
113+
}
103114
}

tests/ui/search_is_some_fixable_some.stderr

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,5 +160,17 @@ error: called `is_some()` after searching an `Iterator` with `find`
160160
LL | let _ = vfoo.iter().find(|sub| sub[1..4].len() == 3).is_some();
161161
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|sub| sub[1..4].len() == 3)`
162162

163-
error: aborting due to 26 previous errors
163+
error: called `is_some()` after searching an `Iterator` with `find`
164+
--> $DIR/search_is_some_fixable_some.rs:111:30
165+
|
166+
LL | let _ = [ppx].iter().find(|ppp_x: &&&u32| please(**ppp_x)).is_some();
167+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|ppp_x: &&u32| please(ppp_x))`
168+
169+
error: called `is_some()` after searching an `Iterator` with `find`
170+
--> $DIR/search_is_some_fixable_some.rs:112:50
171+
|
172+
LL | let _ = [String::from("Hey hey")].iter().find(|s| s.len() == 2).is_some();
173+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|s| s.len() == 2)`
174+
175+
error: aborting due to 28 previous errors
164176

0 commit comments

Comments
 (0)