diff options
| author | llogiq <bogusandre@gmail.com> | 2025-05-16 06:49:42 +0000 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-05-16 06:49:42 +0000 |
| commit | ff5e626837e282f78b86745f5fac5edf19785474 (patch) | |
| tree | 6d41ee1c7bb294b2c0d01bce6cee3ba9cefb0fd2 | |
| parent | 0450db33a5d8587f7c1d4b6d233dac963605766b (diff) | |
| parent | f6e95a5b23d99081765ff746e18c34c8aaec7b68 (diff) | |
| download | rust-ff5e626837e282f78b86745f5fac5edf19785474.tar.gz rust-ff5e626837e282f78b86745f5fac5edf19785474.zip | |
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()`.
| -rw-r--r-- | clippy_lints/src/useless_conversion.rs | 29 | ||||
| -rw-r--r-- | tests/ui/useless_conversion.fixed | 15 | ||||
| -rw-r--r-- | tests/ui/useless_conversion.rs | 15 | ||||
| -rw-r--r-- | tests/ui/useless_conversion.stderr | 14 |
4 files changed, 71 insertions, 2 deletions
diff --git a/clippy_lints/src/useless_conversion.rs b/clippy_lints/src/useless_conversion.rs index 3a9c997a579..c04fcf622b9 100644 --- a/clippy_lints/src/useless_conversion.rs +++ b/clippy_lints/src/useless_conversion.rs @@ -7,7 +7,7 @@ use clippy_utils::{ }; 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 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { // 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, diff --git a/tests/ui/useless_conversion.fixed b/tests/ui/useless_conversion.fixed index 489caacf212..ad30c94f347 100644 --- a/tests/ui/useless_conversion.fixed +++ b/tests/ui/useless_conversion.fixed @@ -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 +} diff --git a/tests/ui/useless_conversion.rs b/tests/ui/useless_conversion.rs index 4f3a3b00ea2..505afb34000 100644 --- a/tests/ui/useless_conversion.rs +++ b/tests/ui/useless_conversion.rs @@ -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.into_iter().for_each(|_x| {}); + //~^ useless_conversion + let _ = R.into_iter().map(|_x| 0); + //~^ useless_conversion +} diff --git a/tests/ui/useless_conversion.stderr b/tests/ui/useless_conversion.stderr index 3cde2a786e4..3bfaf1411c2 100644 --- a/tests/ui/useless_conversion.stderr +++ b/tests/ui/useless_conversion.stderr @@ -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 |
