Skip to content

Commit ff5e626

Browse files
authored
Fix false positive of useless_conversion when using .into_iter().any() (#14800)
Fixes: #14656 changelog: Fix [`useless_conversion`] false positive when using `.into_iter().any()`.
2 parents 0450db3 + f6e95a5 commit ff5e626

File tree

4 files changed

+71
-2
lines changed

4 files changed

+71
-2
lines changed

clippy_lints/src/useless_conversion.rs

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use clippy_utils::{
77
};
88
use rustc_errors::Applicability;
99
use rustc_hir::def_id::DefId;
10-
use rustc_hir::{BindingMode, Expr, ExprKind, HirId, MatchSource, Node, PatKind};
10+
use rustc_hir::{BindingMode, Expr, ExprKind, HirId, MatchSource, Mutability, Node, PatKind};
1111
use rustc_infer::infer::TyCtxtInferExt;
1212
use rustc_infer::traits::Obligation;
1313
use rustc_lint::{LateContext, LateLintPass};
@@ -298,6 +298,33 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion {
298298
// implements Copy, in which case .into_iter() returns a copy of the receiver and
299299
// cannot be safely omitted.
300300
if same_type_and_consts(a, b) && !is_copy(cx, b) {
301+
// Below we check if the parent method call meets the following conditions:
302+
// 1. First parameter is `&mut self` (requires mutable reference)
303+
// 2. Second parameter implements the `FnMut` trait (e.g., Iterator::any)
304+
// For methods satisfying these conditions (like any), .into_iter() must be preserved.
305+
if let Some(parent) = get_parent_expr(cx, e)
306+
&& let ExprKind::MethodCall(_, recv, _, _) = parent.kind
307+
&& recv.hir_id == e.hir_id
308+
&& let Some(def_id) = cx.typeck_results().type_dependent_def_id(parent.hir_id)
309+
&& let sig = cx.tcx.fn_sig(def_id).skip_binder().skip_binder()
310+
&& let inputs = sig.inputs()
311+
&& inputs.len() >= 2
312+
&& let Some(self_ty) = inputs.first()
313+
&& let ty::Ref(_, _, Mutability::Mut) = self_ty.kind()
314+
&& let Some(second_ty) = inputs.get(1)
315+
&& let predicates = cx.tcx.param_env(def_id).caller_bounds()
316+
&& predicates.iter().any(|pred| {
317+
if let ty::ClauseKind::Trait(trait_pred) = pred.kind().skip_binder() {
318+
trait_pred.self_ty() == *second_ty
319+
&& cx.tcx.lang_items().fn_mut_trait() == Some(trait_pred.def_id())
320+
} else {
321+
false
322+
}
323+
})
324+
{
325+
return;
326+
}
327+
301328
let sugg = snippet(cx, recv.span, "<expr>").into_owned();
302329
span_lint_and_sugg(
303330
cx,

tests/ui/useless_conversion.fixed

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -427,3 +427,18 @@ mod issue11819 {
427427
}
428428
}
429429
}
430+
431+
fn issue14739() {
432+
use std::ops::Range;
433+
434+
const R: Range<u32> = 2..7;
435+
436+
R.into_iter().all(|_x| true); // no lint
437+
438+
R.into_iter().any(|_x| true); // no lint
439+
440+
R.for_each(|_x| {});
441+
//~^ useless_conversion
442+
let _ = R.map(|_x| 0);
443+
//~^ useless_conversion
444+
}

tests/ui/useless_conversion.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -427,3 +427,18 @@ mod issue11819 {
427427
}
428428
}
429429
}
430+
431+
fn issue14739() {
432+
use std::ops::Range;
433+
434+
const R: Range<u32> = 2..7;
435+
436+
R.into_iter().all(|_x| true); // no lint
437+
438+
R.into_iter().any(|_x| true); // no lint
439+
440+
R.into_iter().for_each(|_x| {});
441+
//~^ useless_conversion
442+
let _ = R.into_iter().map(|_x| 0);
443+
//~^ useless_conversion
444+
}

tests/ui/useless_conversion.stderr

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -377,5 +377,17 @@ LL - takes_into_iter(self.my_field.into_iter());
377377
LL + takes_into_iter(&mut *self.my_field);
378378
|
379379

380-
error: aborting due to 41 previous errors
380+
error: useless conversion to the same type: `std::ops::Range<u32>`
381+
--> tests/ui/useless_conversion.rs:440:5
382+
|
383+
LL | R.into_iter().for_each(|_x| {});
384+
| ^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `R`
385+
386+
error: useless conversion to the same type: `std::ops::Range<u32>`
387+
--> tests/ui/useless_conversion.rs:442:13
388+
|
389+
LL | let _ = R.into_iter().map(|_x| 0);
390+
| ^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `R`
391+
392+
error: aborting due to 43 previous errors
381393

0 commit comments

Comments
 (0)