Fix false positive of useless_conversion when using .into_iter().any() (#14800)

Fixes: rust-lang/rust-clippy#14656

changelog: Fix [`useless_conversion`] false positive when using
`.into_iter().any()`.
This commit is contained in:
llogiq
2025-05-16 06:49:42 +00:00
committed by GitHub
4 changed files with 71 additions and 2 deletions
+28 -1
View File
@@ -7,7 +7,7 @@
};
use rustc_errors::Applicability;
use rustc_hir::def_id::DefId;
use rustc_hir::{BindingMode, Expr, ExprKind, HirId, MatchSource, Node, PatKind};
use rustc_hir::{BindingMode, Expr, ExprKind, HirId, MatchSource, Mutability, Node, PatKind};
use rustc_infer::infer::TyCtxtInferExt;
use rustc_infer::traits::Obligation;
use rustc_lint::{LateContext, LateLintPass};
@@ -298,6 +298,33 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
// implements Copy, in which case .into_iter() returns a copy of the receiver and
// cannot be safely omitted.
if same_type_and_consts(a, b) && !is_copy(cx, b) {
// Below we check if the parent method call meets the following conditions:
// 1. First parameter is `&mut self` (requires mutable reference)
// 2. Second parameter implements the `FnMut` trait (e.g., Iterator::any)
// For methods satisfying these conditions (like any), .into_iter() must be preserved.
if let Some(parent) = get_parent_expr(cx, e)
&& let ExprKind::MethodCall(_, recv, _, _) = parent.kind
&& recv.hir_id == e.hir_id
&& let Some(def_id) = cx.typeck_results().type_dependent_def_id(parent.hir_id)
&& let sig = cx.tcx.fn_sig(def_id).skip_binder().skip_binder()
&& let inputs = sig.inputs()
&& inputs.len() >= 2
&& let Some(self_ty) = inputs.first()
&& let ty::Ref(_, _, Mutability::Mut) = self_ty.kind()
&& let Some(second_ty) = inputs.get(1)
&& let predicates = cx.tcx.param_env(def_id).caller_bounds()
&& predicates.iter().any(|pred| {
if let ty::ClauseKind::Trait(trait_pred) = pred.kind().skip_binder() {
trait_pred.self_ty() == *second_ty
&& cx.tcx.lang_items().fn_mut_trait() == Some(trait_pred.def_id())
} else {
false
}
})
{
return;
}
let sugg = snippet(cx, recv.span, "<expr>").into_owned();
span_lint_and_sugg(
cx,
+15
View File
@@ -427,3 +427,18 @@ mod issue11819 {
}
}
}
fn issue14739() {
use std::ops::Range;
const R: Range<u32> = 2..7;
R.into_iter().all(|_x| true); // no lint
R.into_iter().any(|_x| true); // no lint
R.for_each(|_x| {});
//~^ useless_conversion
let _ = R.map(|_x| 0);
//~^ useless_conversion
}
+15
View File
@@ -427,3 +427,18 @@ pub fn with_reborrow_mut<'a, Y: 'a>(&'a mut self)
}
}
}
fn issue14739() {
use std::ops::Range;
const R: Range<u32> = 2..7;
R.into_iter().all(|_x| true); // no lint
R.into_iter().any(|_x| true); // no lint
R.into_iter().for_each(|_x| {});
//~^ useless_conversion
let _ = R.into_iter().map(|_x| 0);
//~^ useless_conversion
}
+13 -1
View File
@@ -377,5 +377,17 @@ LL - takes_into_iter(self.my_field.into_iter());
LL + takes_into_iter(&mut *self.my_field);
|
error: aborting due to 41 previous errors
error: useless conversion to the same type: `std::ops::Range<u32>`
--> tests/ui/useless_conversion.rs:440:5
|
LL | R.into_iter().for_each(|_x| {});
| ^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `R`
error: useless conversion to the same type: `std::ops::Range<u32>`
--> tests/ui/useless_conversion.rs:442:13
|
LL | let _ = R.into_iter().map(|_x| 0);
| ^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `R`
error: aborting due to 43 previous errors