Skip to content

Commit

Permalink
Add necessary adjustments to suggestion to remove redundant `.into_it…
Browse files Browse the repository at this point in the history
…er()` calls (#14035)

Fix #11819

changelog: [`useless_conversion`]: add necessary adjustments to
suggestion to remove redundant `.into_iter()` calls
  • Loading branch information
y21 authored Jan 23, 2025
2 parents 92fac5c + 01907f7 commit 4b05f50
Show file tree
Hide file tree
Showing 4 changed files with 245 additions and 23 deletions.
39 changes: 26 additions & 13 deletions clippy_lints/src/useless_conversion.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg, span_lint_and_then};
use clippy_utils::source::{snippet, snippet_with_applicability, snippet_with_context};
use clippy_utils::source::{snippet, snippet_with_context};
use clippy_utils::sugg::{DiagExt as _, Sugg};
use clippy_utils::ty::{is_copy, is_type_diagnostic_item, same_type_and_consts};
use clippy_utils::{
Expand All @@ -12,6 +12,7 @@ use rustc_infer::infer::TyCtxtInferExt;
use rustc_infer::traits::Obligation;
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::traits::ObligationCause;
use rustc_middle::ty::adjustment::{Adjust, AutoBorrow, AutoBorrowMutability};
use rustc_middle::ty::{self, AdtDef, EarlyBinder, GenericArg, GenericArgsRef, Ty, TypeVisitableExt};
use rustc_session::impl_lint_pass;
use rustc_span::{Span, sym};
Expand Down Expand Up @@ -251,26 +252,25 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion {
// ^^^
let (into_iter_recv, depth) = into_iter_deep_call(cx, into_iter_recv);

let plural = if depth == 0 { "" } else { "s" };
let mut applicability = Applicability::MachineApplicable;
let sugg = snippet_with_applicability(
cx,
into_iter_recv.span.source_callsite(),
"<expr>",
&mut applicability,
)
.into_owned();
span_lint_and_then(
cx,
USELESS_CONVERSION,
e.span,
"explicit call to `.into_iter()` in function argument accepting `IntoIterator`",
|diag| {
diag.span_suggestion(
e.span,
let receiver_span = into_iter_recv.span.source_callsite();
let adjustments = adjustments(cx, into_iter_recv);
let mut sugg = if adjustments.is_empty() {
vec![]
} else {
vec![(receiver_span.shrink_to_lo(), adjustments)]
};
let plural = if depth == 0 { "" } else { "s" };
sugg.push((e.span.with_lo(receiver_span.hi()), String::new()));
diag.multipart_suggestion(
format!("consider removing the `.into_iter()`{plural}"),
sugg,
applicability,
Applicability::MachineApplicable,
);
diag.span_note(span, "this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()`");
},
Expand Down Expand Up @@ -431,3 +431,16 @@ fn has_eligible_receiver(cx: &LateContext<'_>, recv: &Expr<'_>, expr: &Expr<'_>)
}
false
}

fn adjustments(cx: &LateContext<'_>, expr: &Expr<'_>) -> String {
let mut prefix = String::new();
for adj in cx.typeck_results().expr_adjustments(expr) {
match adj.kind {
Adjust::Deref(_) => prefix = format!("*{prefix}"),
Adjust::Borrow(AutoBorrow::Ref(AutoBorrowMutability::Mut { .. })) => prefix = format!("&mut {prefix}"),
Adjust::Borrow(AutoBorrow::Ref(AutoBorrowMutability::Not)) => prefix = format!("&{prefix}"),
_ => {},
}
}
prefix
}
53 changes: 53 additions & 0 deletions tests/ui/useless_conversion.fixed
Original file line number Diff line number Diff line change
Expand Up @@ -342,3 +342,56 @@ fn gen_identity<T>(x: [T; 3]) -> Vec<T> {
x.into_iter().collect()
//~^ useless_conversion
}

mod issue11819 {
fn takes_into_iter(_: impl IntoIterator<Item = String>) {}

pub struct MyStruct<T> {
my_field: T,
}

impl<T> MyStruct<T> {
pub fn with_ref<'a>(&'a mut self)
where
&'a T: IntoIterator<Item = String>,
{
takes_into_iter(&self.my_field);
//~^ useless_conversion
}

pub fn with_ref_mut<'a>(&'a mut self)
where
&'a mut T: IntoIterator<Item = String>,
{
takes_into_iter(&mut self.my_field);
//~^ useless_conversion
}

pub fn with_deref<Y>(&mut self)
where
T: std::ops::Deref<Target = Y>,
Y: IntoIterator<Item = String> + Copy,
{
takes_into_iter(*self.my_field);
//~^ useless_conversion
}

pub fn with_reborrow<'a, Y: 'a>(&'a mut self)
where
T: std::ops::Deref<Target = Y>,
&'a Y: IntoIterator<Item = String>,
{
takes_into_iter(&*self.my_field);
//~^ useless_conversion
}

pub fn with_reborrow_mut<'a, Y: 'a>(&'a mut self)
where
T: std::ops::Deref<Target = Y> + std::ops::DerefMut,
&'a mut Y: IntoIterator<Item = String>,
{
takes_into_iter(&mut *self.my_field);
//~^ useless_conversion
}
}
}
53 changes: 53 additions & 0 deletions tests/ui/useless_conversion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -342,3 +342,56 @@ fn gen_identity<T>(x: [T; 3]) -> Vec<T> {
x.into_iter().map(Into::into).collect()
//~^ useless_conversion
}

mod issue11819 {
fn takes_into_iter(_: impl IntoIterator<Item = String>) {}

pub struct MyStruct<T> {
my_field: T,
}

impl<T> MyStruct<T> {
pub fn with_ref<'a>(&'a mut self)
where
&'a T: IntoIterator<Item = String>,
{
takes_into_iter(self.my_field.into_iter());
//~^ useless_conversion
}

pub fn with_ref_mut<'a>(&'a mut self)
where
&'a mut T: IntoIterator<Item = String>,
{
takes_into_iter(self.my_field.into_iter());
//~^ useless_conversion
}

pub fn with_deref<Y>(&mut self)
where
T: std::ops::Deref<Target = Y>,
Y: IntoIterator<Item = String> + Copy,
{
takes_into_iter(self.my_field.into_iter());
//~^ useless_conversion
}

pub fn with_reborrow<'a, Y: 'a>(&'a mut self)
where
T: std::ops::Deref<Target = Y>,
&'a Y: IntoIterator<Item = String>,
{
takes_into_iter(self.my_field.into_iter());
//~^ useless_conversion
}

pub fn with_reborrow_mut<'a, Y: 'a>(&'a mut self)
where
T: std::ops::Deref<Target = Y> + std::ops::DerefMut,
&'a mut Y: IntoIterator<Item = String>,
{
takes_into_iter(self.my_field.into_iter());
//~^ useless_conversion
}
}
}
123 changes: 113 additions & 10 deletions tests/ui/useless_conversion.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,9 @@ error: explicit call to `.into_iter()` in function argument accepting `IntoItera
--> tests/ui/useless_conversion.rs:189:7
|
LL | b(vec![1, 2].into_iter());
| ^^^^^^^^^^^^^^^^^^^^^^ help: consider removing the `.into_iter()`: `vec![1, 2]`
| ^^^^^^^^^^------------
| |
| help: consider removing the `.into_iter()`
|
note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()`
--> tests/ui/useless_conversion.rs:179:13
Expand All @@ -134,7 +136,9 @@ error: explicit call to `.into_iter()` in function argument accepting `IntoItera
--> tests/ui/useless_conversion.rs:190:7
|
LL | c(vec![1, 2].into_iter());
| ^^^^^^^^^^^^^^^^^^^^^^ help: consider removing the `.into_iter()`: `vec![1, 2]`
| ^^^^^^^^^^------------
| |
| help: consider removing the `.into_iter()`
|
note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()`
--> tests/ui/useless_conversion.rs:180:18
Expand All @@ -146,7 +150,9 @@ error: explicit call to `.into_iter()` in function argument accepting `IntoItera
--> tests/ui/useless_conversion.rs:191:7
|
LL | d(vec![1, 2].into_iter());
| ^^^^^^^^^^^^^^^^^^^^^^ help: consider removing the `.into_iter()`: `vec![1, 2]`
| ^^^^^^^^^^------------
| |
| help: consider removing the `.into_iter()`
|
note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()`
--> tests/ui/useless_conversion.rs:183:12
Expand All @@ -158,7 +164,9 @@ error: explicit call to `.into_iter()` in function argument accepting `IntoItera
--> tests/ui/useless_conversion.rs:194:7
|
LL | b(vec![1, 2].into_iter().into_iter());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing the `.into_iter()`s: `vec![1, 2]`
| ^^^^^^^^^^------------------------
| |
| help: consider removing the `.into_iter()`s
|
note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()`
--> tests/ui/useless_conversion.rs:179:13
Expand All @@ -170,7 +178,9 @@ error: explicit call to `.into_iter()` in function argument accepting `IntoItera
--> tests/ui/useless_conversion.rs:195:7
|
LL | b(vec![1, 2].into_iter().into_iter().into_iter());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing the `.into_iter()`s: `vec![1, 2]`
| ^^^^^^^^^^------------------------------------
| |
| help: consider removing the `.into_iter()`s
|
note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()`
--> tests/ui/useless_conversion.rs:179:13
Expand All @@ -182,7 +192,9 @@ error: explicit call to `.into_iter()` in function argument accepting `IntoItera
--> tests/ui/useless_conversion.rs:241:24
|
LL | foo2::<i32, _>([1, 2, 3].into_iter());
| ^^^^^^^^^^^^^^^^^^^^^ help: consider removing the `.into_iter()`: `[1, 2, 3]`
| ^^^^^^^^^------------
| |
| help: consider removing the `.into_iter()`
|
note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()`
--> tests/ui/useless_conversion.rs:220:12
Expand All @@ -194,7 +206,9 @@ error: explicit call to `.into_iter()` in function argument accepting `IntoItera
--> tests/ui/useless_conversion.rs:249:14
|
LL | foo3([1, 2, 3].into_iter());
| ^^^^^^^^^^^^^^^^^^^^^ help: consider removing the `.into_iter()`: `[1, 2, 3]`
| ^^^^^^^^^------------
| |
| help: consider removing the `.into_iter()`
|
note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()`
--> tests/ui/useless_conversion.rs:229:12
Expand All @@ -206,7 +220,9 @@ error: explicit call to `.into_iter()` in function argument accepting `IntoItera
--> tests/ui/useless_conversion.rs:258:16
|
LL | S1.foo([1, 2].into_iter());
| ^^^^^^^^^^^^^^^^^^ help: consider removing the `.into_iter()`: `[1, 2]`
| ^^^^^^------------
| |
| help: consider removing the `.into_iter()`
|
note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()`
--> tests/ui/useless_conversion.rs:255:27
Expand All @@ -218,7 +234,9 @@ error: explicit call to `.into_iter()` in function argument accepting `IntoItera
--> tests/ui/useless_conversion.rs:277:44
|
LL | v0.into_iter().interleave_shortest(v1.into_iter());
| ^^^^^^^^^^^^^^ help: consider removing the `.into_iter()`: `v1`
| ^^------------
| |
| help: consider removing the `.into_iter()`
|
note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()`
--> tests/ui/useless_conversion.rs:264:20
Expand Down Expand Up @@ -274,5 +292,90 @@ error: useless conversion to the same type: `T`
LL | x.into_iter().map(Into::into).collect()
| ^^^^^^^^^^^^^^^^ help: consider removing

error: aborting due to 36 previous errors
error: explicit call to `.into_iter()` in function argument accepting `IntoIterator`
--> tests/ui/useless_conversion.rs:358:29
|
LL | takes_into_iter(self.my_field.into_iter());
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()`
--> tests/ui/useless_conversion.rs:347:32
|
LL | fn takes_into_iter(_: impl IntoIterator<Item = String>) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
help: consider removing the `.into_iter()`
|
LL - takes_into_iter(self.my_field.into_iter());
LL + takes_into_iter(&self.my_field);
|

error: explicit call to `.into_iter()` in function argument accepting `IntoIterator`
--> tests/ui/useless_conversion.rs:366:29
|
LL | takes_into_iter(self.my_field.into_iter());
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()`
--> tests/ui/useless_conversion.rs:347:32
|
LL | fn takes_into_iter(_: impl IntoIterator<Item = String>) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
help: consider removing the `.into_iter()`
|
LL - takes_into_iter(self.my_field.into_iter());
LL + takes_into_iter(&mut self.my_field);
|

error: explicit call to `.into_iter()` in function argument accepting `IntoIterator`
--> tests/ui/useless_conversion.rs:375:29
|
LL | takes_into_iter(self.my_field.into_iter());
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()`
--> tests/ui/useless_conversion.rs:347:32
|
LL | fn takes_into_iter(_: impl IntoIterator<Item = String>) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
help: consider removing the `.into_iter()`
|
LL - takes_into_iter(self.my_field.into_iter());
LL + takes_into_iter(*self.my_field);
|

error: explicit call to `.into_iter()` in function argument accepting `IntoIterator`
--> tests/ui/useless_conversion.rs:384:29
|
LL | takes_into_iter(self.my_field.into_iter());
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()`
--> tests/ui/useless_conversion.rs:347:32
|
LL | fn takes_into_iter(_: impl IntoIterator<Item = String>) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
help: consider removing the `.into_iter()`
|
LL - takes_into_iter(self.my_field.into_iter());
LL + takes_into_iter(&*self.my_field);
|

error: explicit call to `.into_iter()` in function argument accepting `IntoIterator`
--> tests/ui/useless_conversion.rs:393:29
|
LL | takes_into_iter(self.my_field.into_iter());
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()`
--> tests/ui/useless_conversion.rs:347:32
|
LL | fn takes_into_iter(_: impl IntoIterator<Item = String>) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
help: consider removing the `.into_iter()`
|
LL - takes_into_iter(self.my_field.into_iter());
LL + takes_into_iter(&mut *self.my_field);
|

error: aborting due to 41 previous errors

0 comments on commit 4b05f50

Please sign in to comment.