Skip to content

Commit bcf3c08

Browse files
authored
Improve useless_conversion .into_iter() suggestion for nested references (rust-lang#16238)
### Description I updated the `useless_conversion` lint to stop applying adjustment prefixes once it reaches the final target type. Previously, the lint would continue applying adjustments even after the type requirements were met, which often resulted in over-borrowed suggestions like `&**y`. By breaking the loop early once the target type is reached, we now emit the minimal, idiomatic suggestion (e.g., `*y`). fixes rust-lang#14847 ### Test Plan I added a targeted UI regression test: `tests/ui/useless_conversion.rs`. This covers `.into_iter()` usage on nested slice references (`&&[T]`) and verifies that Clippy now suggests `*items` instead of the previous incorrect suggestion. ### Checklist - [x] Added passing UI tests (including committed `.stderr` file) - [x] `cargo test` passes locally - [x] Run `cargo dev fmt` [lint_naming]: https://rust-lang.github.io/rfcs/0344-conventions-galore.html#lints --- changelog: [`useless_conversion`]: refine `.into_iter()` suggestions to stop at the final target type (fixing over-borrowed suggestions like `&**y`)
2 parents 327c558 + 1f207ed commit bcf3c08

File tree

4 files changed

+109
-60
lines changed

4 files changed

+109
-60
lines changed

clippy_lints/src/useless_conversion.rs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -456,13 +456,25 @@ fn has_eligible_receiver(cx: &LateContext<'_>, recv: &Expr<'_>, expr: &Expr<'_>)
456456

457457
fn adjustments(cx: &LateContext<'_>, expr: &Expr<'_>) -> String {
458458
let mut prefix = String::new();
459-
for adj in cx.typeck_results().expr_adjustments(expr) {
459+
460+
let adjustments = cx.typeck_results().expr_adjustments(expr);
461+
462+
let [.., last] = adjustments else { return prefix };
463+
let target = last.target;
464+
465+
for adj in adjustments {
460466
match adj.kind {
461467
Adjust::Deref(_) => prefix = format!("*{prefix}"),
462468
Adjust::Borrow(AutoBorrow::Ref(AutoBorrowMutability::Mut { .. })) => prefix = format!("&mut {prefix}"),
463469
Adjust::Borrow(AutoBorrow::Ref(AutoBorrowMutability::Not)) => prefix = format!("&{prefix}"),
464470
_ => {},
465471
}
472+
473+
// Stop once we reach the final target type.
474+
// This prevents over-adjusting (e.g. suggesting &**y instead of *y).
475+
if adj.target == target {
476+
break;
477+
}
466478
}
467479
prefix
468480
}

tests/ui/useless_conversion.fixed

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#![deny(clippy::useless_conversion)]
2+
#![allow(clippy::into_iter_on_ref)]
23
#![allow(clippy::needless_ifs, clippy::unnecessary_wraps, unused)]
34
// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint
45
#![allow(static_mut_refs)]
@@ -131,6 +132,15 @@ fn main() {
131132
dont_lint_into_iter_on_copy_iter();
132133
dont_lint_into_iter_on_static_copy_iter();
133134

135+
{
136+
// triggers the IntoIterator trait
137+
fn consume(_: impl IntoIterator) {}
138+
139+
// Should suggest `*items` instead of `&**items`
140+
let items = &&[1, 2, 3];
141+
consume(*items); //~ useless_conversion
142+
}
143+
134144
let _: String = "foo".into();
135145
let _: String = From::from("foo");
136146
let _ = String::from("foo");

tests/ui/useless_conversion.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#![deny(clippy::useless_conversion)]
2+
#![allow(clippy::into_iter_on_ref)]
23
#![allow(clippy::needless_ifs, clippy::unnecessary_wraps, unused)]
34
// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint
45
#![allow(static_mut_refs)]
@@ -131,6 +132,15 @@ fn main() {
131132
dont_lint_into_iter_on_copy_iter();
132133
dont_lint_into_iter_on_static_copy_iter();
133134

135+
{
136+
// triggers the IntoIterator trait
137+
fn consume(_: impl IntoIterator) {}
138+
139+
// Should suggest `*items` instead of `&**items`
140+
let items = &&[1, 2, 3];
141+
consume(items.into_iter()); //~ useless_conversion
142+
}
143+
134144
let _: String = "foo".into();
135145
let _: String = From::from("foo");
136146
let _ = String::from("foo");

0 commit comments

Comments
 (0)