Skip to content

Commit 8239b76

Browse files
committed
Auto merge of #4454 - BO41:search_is_some, r=flip1995
Dereference one less on search_is_some and make it auto-fixable Fixes #4453 changelog: none
2 parents 11da8c1 + 64cd9e4 commit 8239b76

File tree

6 files changed

+94
-59
lines changed

6 files changed

+94
-59
lines changed

clippy_lints/src/methods/mod.rs

Lines changed: 50 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1033,7 +1033,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Methods {
10331033
return;
10341034
}
10351035

1036-
let (method_names, arg_lists) = method_calls(expr, 2);
1036+
let (method_names, arg_lists, method_spans) = method_calls(expr, 2);
10371037
let method_names: Vec<LocalInternedString> = method_names.iter().map(|s| s.as_str()).collect();
10381038
let method_names: Vec<&str> = method_names.iter().map(std::convert::AsRef::as_ref).collect();
10391039

@@ -1053,11 +1053,15 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Methods {
10531053
["map", "find"] => lint_find_map(cx, expr, arg_lists[1], arg_lists[0]),
10541054
["flat_map", "filter"] => lint_filter_flat_map(cx, expr, arg_lists[1], arg_lists[0]),
10551055
["flat_map", "filter_map"] => lint_filter_map_flat_map(cx, expr, arg_lists[1], arg_lists[0]),
1056-
["flat_map", ..] => lint_flat_map_identity(cx, expr, arg_lists[0]),
1056+
["flat_map", ..] => lint_flat_map_identity(cx, expr, arg_lists[0], method_spans[0]),
10571057
["flatten", "map"] => lint_map_flatten(cx, expr, arg_lists[1]),
1058-
["is_some", "find"] => lint_search_is_some(cx, expr, "find", arg_lists[1], arg_lists[0]),
1059-
["is_some", "position"] => lint_search_is_some(cx, expr, "position", arg_lists[1], arg_lists[0]),
1060-
["is_some", "rposition"] => lint_search_is_some(cx, expr, "rposition", arg_lists[1], arg_lists[0]),
1058+
["is_some", "find"] => lint_search_is_some(cx, expr, "find", arg_lists[1], arg_lists[0], method_spans[1]),
1059+
["is_some", "position"] => {
1060+
lint_search_is_some(cx, expr, "position", arg_lists[1], arg_lists[0], method_spans[1])
1061+
},
1062+
["is_some", "rposition"] => {
1063+
lint_search_is_some(cx, expr, "rposition", arg_lists[1], arg_lists[0], method_spans[1])
1064+
},
10611065
["extend", ..] => lint_extend(cx, expr, arg_lists[0]),
10621066
["as_ptr", "unwrap"] | ["as_ptr", "expect"] => {
10631067
lint_cstring_as_ptr(cx, expr, &arg_lists[1][0], &arg_lists[0][0])
@@ -1068,7 +1072,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Methods {
10681072
["collect", "cloned"] => lint_iter_cloned_collect(cx, expr, arg_lists[1]),
10691073
["as_ref"] => lint_asref(cx, expr, "as_ref", arg_lists[0]),
10701074
["as_mut"] => lint_asref(cx, expr, "as_mut", arg_lists[0]),
1071-
["fold", ..] => lint_unnecessary_fold(cx, expr, arg_lists[0]),
1075+
["fold", ..] => lint_unnecessary_fold(cx, expr, arg_lists[0], method_spans[0]),
10721076
["filter_map", ..] => unnecessary_filter_map::lint(cx, expr, arg_lists[0]),
10731077
["count", "map"] => lint_suspicious_map(cx, expr),
10741078
["assume_init"] => lint_maybe_uninit(cx, &arg_lists[0][0], expr),
@@ -1746,11 +1750,12 @@ fn lint_iter_cloned_collect<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &hir::Ex
17461750
}
17471751
}
17481752

1749-
fn lint_unnecessary_fold(cx: &LateContext<'_, '_>, expr: &hir::Expr, fold_args: &[hir::Expr]) {
1753+
fn lint_unnecessary_fold(cx: &LateContext<'_, '_>, expr: &hir::Expr, fold_args: &[hir::Expr], fold_span: Span) {
17501754
fn check_fold_with_op(
17511755
cx: &LateContext<'_, '_>,
17521756
expr: &hir::Expr,
17531757
fold_args: &[hir::Expr],
1758+
fold_span: Span,
17541759
op: hir::BinOpKind,
17551760
replacement_method_name: &str,
17561761
replacement_has_args: bool,
@@ -1772,8 +1777,6 @@ fn lint_unnecessary_fold(cx: &LateContext<'_, '_>, expr: &hir::Expr, fold_args:
17721777
if match_var(&*left_expr, first_arg_ident);
17731778
if replacement_has_args || match_var(&*right_expr, second_arg_ident);
17741779

1775-
if let hir::ExprKind::MethodCall(_, span, _) = &expr.node;
1776-
17771780
then {
17781781
let mut applicability = Applicability::MachineApplicable;
17791782
let sugg = if replacement_has_args {
@@ -1793,7 +1796,7 @@ fn lint_unnecessary_fold(cx: &LateContext<'_, '_>, expr: &hir::Expr, fold_args:
17931796
span_lint_and_sugg(
17941797
cx,
17951798
UNNECESSARY_FOLD,
1796-
span.with_hi(expr.span.hi()),
1799+
fold_span.with_hi(expr.span.hi()),
17971800
// TODO #2371 don't suggest e.g., .any(|x| f(x)) if we can suggest .any(f)
17981801
"this `.fold` can be written more succinctly using another method",
17991802
"try",
@@ -1817,10 +1820,18 @@ fn lint_unnecessary_fold(cx: &LateContext<'_, '_>, expr: &hir::Expr, fold_args:
18171820
// Check if the first argument to .fold is a suitable literal
18181821
if let hir::ExprKind::Lit(ref lit) = fold_args[1].node {
18191822
match lit.node {
1820-
ast::LitKind::Bool(false) => check_fold_with_op(cx, expr, fold_args, hir::BinOpKind::Or, "any", true),
1821-
ast::LitKind::Bool(true) => check_fold_with_op(cx, expr, fold_args, hir::BinOpKind::And, "all", true),
1822-
ast::LitKind::Int(0, _) => check_fold_with_op(cx, expr, fold_args, hir::BinOpKind::Add, "sum", false),
1823-
ast::LitKind::Int(1, _) => check_fold_with_op(cx, expr, fold_args, hir::BinOpKind::Mul, "product", false),
1823+
ast::LitKind::Bool(false) => {
1824+
check_fold_with_op(cx, expr, fold_args, fold_span, hir::BinOpKind::Or, "any", true)
1825+
},
1826+
ast::LitKind::Bool(true) => {
1827+
check_fold_with_op(cx, expr, fold_args, fold_span, hir::BinOpKind::And, "all", true)
1828+
},
1829+
ast::LitKind::Int(0, _) => {
1830+
check_fold_with_op(cx, expr, fold_args, fold_span, hir::BinOpKind::Add, "sum", false)
1831+
},
1832+
ast::LitKind::Int(1, _) => {
1833+
check_fold_with_op(cx, expr, fold_args, fold_span, hir::BinOpKind::Mul, "product", false)
1834+
},
18241835
_ => (),
18251836
}
18261837
}
@@ -2357,22 +2368,21 @@ fn lint_flat_map_identity<'a, 'tcx>(
23572368
cx: &LateContext<'a, 'tcx>,
23582369
expr: &'tcx hir::Expr,
23592370
flat_map_args: &'tcx [hir::Expr],
2371+
flat_map_span: Span,
23602372
) {
23612373
if match_trait_method(cx, expr, &paths::ITERATOR) {
23622374
let arg_node = &flat_map_args[1].node;
23632375

23642376
let apply_lint = |message: &str| {
2365-
if let hir::ExprKind::MethodCall(_, span, _) = &expr.node {
2366-
span_lint_and_sugg(
2367-
cx,
2368-
FLAT_MAP_IDENTITY,
2369-
span.with_hi(expr.span.hi()),
2370-
message,
2371-
"try",
2372-
"flatten()".to_string(),
2373-
Applicability::MachineApplicable,
2374-
);
2375-
}
2377+
span_lint_and_sugg(
2378+
cx,
2379+
FLAT_MAP_IDENTITY,
2380+
flat_map_span.with_hi(expr.span.hi()),
2381+
message,
2382+
"try",
2383+
"flatten()".to_string(),
2384+
Applicability::MachineApplicable,
2385+
);
23762386
};
23772387

23782388
if_chain! {
@@ -2409,6 +2419,7 @@ fn lint_search_is_some<'a, 'tcx>(
24092419
search_method: &str,
24102420
search_args: &'tcx [hir::Expr],
24112421
is_some_args: &'tcx [hir::Expr],
2422+
method_span: Span,
24122423
) {
24132424
// lint if caller of search is an Iterator
24142425
if match_trait_method(cx, &is_some_args[0], &paths::ITERATOR) {
@@ -2420,31 +2431,36 @@ fn lint_search_is_some<'a, 'tcx>(
24202431
let search_snippet = snippet(cx, search_args[1].span, "..");
24212432
if search_snippet.lines().count() <= 1 {
24222433
// suggest `any(|x| ..)` instead of `any(|&x| ..)` for `find(|&x| ..).is_some()`
2434+
// suggest `any(|..| *..)` instead of `any(|..| **..)` for `find(|..| **..).is_some()`
24232435
let any_search_snippet = if_chain! {
24242436
if search_method == "find";
24252437
if let hir::ExprKind::Closure(_, _, body_id, ..) = search_args[1].node;
24262438
let closure_body = cx.tcx.hir().body(body_id);
24272439
if let Some(closure_arg) = closure_body.params.get(0);
2428-
if let hir::PatKind::Ref(..) = closure_arg.pat.node;
24292440
then {
2430-
Some(search_snippet.replacen('&', "", 1))
2441+
if let hir::PatKind::Ref(..) = closure_arg.pat.node {
2442+
Some(search_snippet.replacen('&', "", 1))
2443+
} else if let Some(name) = get_arg_name(&closure_arg.pat) {
2444+
Some(search_snippet.replace(&format!("*{}", name), &name.as_str()))
2445+
} else {
2446+
None
2447+
}
24312448
} else {
24322449
None
24332450
}
24342451
};
24352452
// add note if not multi-line
2436-
span_note_and_lint(
2453+
span_lint_and_sugg(
24372454
cx,
24382455
SEARCH_IS_SOME,
2439-
expr.span,
2456+
method_span.with_hi(expr.span.hi()),
24402457
&msg,
2441-
expr.span,
2442-
&format!(
2443-
"replace `{0}({1}).is_some()` with `any({2})`",
2444-
search_method,
2445-
search_snippet,
2458+
"try this",
2459+
format!(
2460+
"any({})",
24462461
any_search_snippet.as_ref().map_or(&*search_snippet, String::as_str)
24472462
),
2463+
Applicability::MachineApplicable,
24482464
);
24492465
} else {
24502466
span_lint(cx, SEARCH_IS_SOME, expr.span, &msg);

clippy_lints/src/utils/internal_lints.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -280,7 +280,7 @@ impl_lint_pass!(OuterExpnDataPass => [OUTER_EXPN_EXPN_DATA]);
280280

281281
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for OuterExpnDataPass {
282282
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr) {
283-
let (method_names, arg_lists) = method_calls(expr, 2);
283+
let (method_names, arg_lists, spans) = method_calls(expr, 2);
284284
let method_names: Vec<LocalInternedString> = method_names.iter().map(|s| s.as_str()).collect();
285285
let method_names: Vec<&str> = method_names.iter().map(std::convert::AsRef::as_ref).collect();
286286
if_chain! {
@@ -294,10 +294,10 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for OuterExpnDataPass {
294294
span_lint_and_sugg(
295295
cx,
296296
OUTER_EXPN_EXPN_DATA,
297-
expr.span.trim_start(self_arg.span).unwrap_or(expr.span),
297+
spans[1].with_hi(expr.span.hi()),
298298
"usage of `outer_expn().expn_data()`",
299299
"try",
300-
".outer_expn_data()".to_string(),
300+
"outer_expn_data()".to_string(),
301301
Applicability::MachineApplicable,
302302
);
303303
}

clippy_lints/src/utils/mod.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -342,26 +342,28 @@ pub fn resolve_node(cx: &LateContext<'_, '_>, qpath: &QPath, id: HirId) -> Res {
342342
}
343343

344344
/// Returns the method names and argument list of nested method call expressions that make up
345-
/// `expr`.
346-
pub fn method_calls(expr: &Expr, max_depth: usize) -> (Vec<Symbol>, Vec<&[Expr]>) {
345+
/// `expr`. method/span lists are sorted with the most recent call first.
346+
pub fn method_calls(expr: &Expr, max_depth: usize) -> (Vec<Symbol>, Vec<&[Expr]>, Vec<Span>) {
347347
let mut method_names = Vec::with_capacity(max_depth);
348348
let mut arg_lists = Vec::with_capacity(max_depth);
349+
let mut spans = Vec::with_capacity(max_depth);
349350

350351
let mut current = expr;
351352
for _ in 0..max_depth {
352-
if let ExprKind::MethodCall(path, _, args) = &current.node {
353+
if let ExprKind::MethodCall(path, span, args) = &current.node {
353354
if args.iter().any(|e| e.span.from_expansion()) {
354355
break;
355356
}
356357
method_names.push(path.ident.name);
357358
arg_lists.push(&**args);
359+
spans.push(*span);
358360
current = &args[0];
359361
} else {
360362
break;
361363
}
362364
}
363365

364-
(method_names, arg_lists)
366+
(method_names, arg_lists, spans)
365367
}
366368

367369
/// Matches an `Expr` against a chain of methods, and return the matched `Expr`s.

tests/ui/methods.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,9 +260,13 @@ fn filter_next() {
260260
#[rustfmt::skip]
261261
fn search_is_some() {
262262
let v = vec![3, 2, 1, 0, -1, -2, -3];
263+
let y = &&42;
263264

264265
// Check `find().is_some()`, single-line case.
265266
let _ = v.iter().find(|&x| *x < 0).is_some();
267+
let _ = (0..1).find(|x| **y == *x).is_some(); // one dereference less
268+
let _ = (0..1).find(|x| *x == 0).is_some();
269+
let _ = v.iter().find(|x| **x == 0).is_some();
266270

267271
// Check `find().is_some()`, multi-line case.
268272
let _ = v.iter().find(|&x| {

tests/ui/methods.stderr

Lines changed: 29 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -139,16 +139,33 @@ LL | | ).next();
139139
| |___________________________^
140140

141141
error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`.
142-
--> $DIR/methods.rs:265:13
142+
--> $DIR/methods.rs:266:22
143143
|
144144
LL | let _ = v.iter().find(|&x| *x < 0).is_some();
145-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
145+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|x| *x < 0)`
146146
|
147147
= note: `-D clippy::search-is-some` implied by `-D warnings`
148-
= note: replace `find(|&x| *x < 0).is_some()` with `any(|x| *x < 0)`
149148

150149
error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`.
151-
--> $DIR/methods.rs:268:13
150+
--> $DIR/methods.rs:267:20
151+
|
152+
LL | let _ = (0..1).find(|x| **y == *x).is_some(); // one dereference less
153+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|x| **y == x)`
154+
155+
error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`.
156+
--> $DIR/methods.rs:268:20
157+
|
158+
LL | let _ = (0..1).find(|x| *x == 0).is_some();
159+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|x| x == 0)`
160+
161+
error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`.
162+
--> $DIR/methods.rs:269:22
163+
|
164+
LL | let _ = v.iter().find(|x| **x == 0).is_some();
165+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|x| *x == 0)`
166+
167+
error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`.
168+
--> $DIR/methods.rs:272:13
152169
|
153170
LL | let _ = v.iter().find(|&x| {
154171
| _____________^
@@ -158,15 +175,13 @@ LL | | ).is_some();
158175
| |______________________________^
159176

160177
error: called `is_some()` after searching an `Iterator` with position. This is more succinctly expressed by calling `any()`.
161-
--> $DIR/methods.rs:274:13
178+
--> $DIR/methods.rs:278:22
162179
|
163180
LL | let _ = v.iter().position(|&x| x < 0).is_some();
164-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
165-
|
166-
= note: replace `position(|&x| x < 0).is_some()` with `any(|&x| x < 0)`
181+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|&x| x < 0)`
167182

168183
error: called `is_some()` after searching an `Iterator` with position. This is more succinctly expressed by calling `any()`.
169-
--> $DIR/methods.rs:277:13
184+
--> $DIR/methods.rs:281:13
170185
|
171186
LL | let _ = v.iter().position(|&x| {
172187
| _____________^
@@ -176,15 +191,13 @@ LL | | ).is_some();
176191
| |______________________________^
177192

178193
error: called `is_some()` after searching an `Iterator` with rposition. This is more succinctly expressed by calling `any()`.
179-
--> $DIR/methods.rs:283:13
194+
--> $DIR/methods.rs:287:22
180195
|
181196
LL | let _ = v.iter().rposition(|&x| x < 0).is_some();
182-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
183-
|
184-
= note: replace `rposition(|&x| x < 0).is_some()` with `any(|&x| x < 0)`
197+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|&x| x < 0)`
185198

186199
error: called `is_some()` after searching an `Iterator` with rposition. This is more succinctly expressed by calling `any()`.
187-
--> $DIR/methods.rs:286:13
200+
--> $DIR/methods.rs:290:13
188201
|
189202
LL | let _ = v.iter().rposition(|&x| {
190203
| _____________^
@@ -194,12 +207,12 @@ LL | | ).is_some();
194207
| |______________________________^
195208

196209
error: used unwrap() on an Option value. If you don't want to handle the None case gracefully, consider using expect() to provide a better panic message
197-
--> $DIR/methods.rs:301:13
210+
--> $DIR/methods.rs:305:13
198211
|
199212
LL | let _ = opt.unwrap();
200213
| ^^^^^^^^^^^^
201214
|
202215
= note: `-D clippy::option-unwrap-used` implied by `-D warnings`
203216

204-
error: aborting due to 21 previous errors
217+
error: aborting due to 24 previous errors
205218

tests/ui/outer_expn_data.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
error: usage of `outer_expn().expn_data()`
2-
--> $DIR/outer_expn_data.rs:21:33
2+
--> $DIR/outer_expn_data.rs:21:34
33
|
44
LL | let _ = expr.span.ctxt().outer_expn().expn_data();
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `.outer_expn_data()`
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `outer_expn_data()`
66
|
77
note: lint level defined here
88
--> $DIR/outer_expn_data.rs:3:9

0 commit comments

Comments
 (0)