Skip to content

Commit 4b05f50

Browse files
authored
Add necessary adjustments to suggestion to remove redundant .into_iter() calls (#14035)
Fix #11819 changelog: [`useless_conversion`]: add necessary adjustments to suggestion to remove redundant `.into_iter()` calls
2 parents 92fac5c + 01907f7 commit 4b05f50

File tree

4 files changed

+245
-23
lines changed

4 files changed

+245
-23
lines changed

clippy_lints/src/useless_conversion.rs

+26-13
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg, span_lint_and_then};
2-
use clippy_utils::source::{snippet, snippet_with_applicability, snippet_with_context};
2+
use clippy_utils::source::{snippet, snippet_with_context};
33
use clippy_utils::sugg::{DiagExt as _, Sugg};
44
use clippy_utils::ty::{is_copy, is_type_diagnostic_item, same_type_and_consts};
55
use clippy_utils::{
@@ -12,6 +12,7 @@ use rustc_infer::infer::TyCtxtInferExt;
1212
use rustc_infer::traits::Obligation;
1313
use rustc_lint::{LateContext, LateLintPass};
1414
use rustc_middle::traits::ObligationCause;
15+
use rustc_middle::ty::adjustment::{Adjust, AutoBorrow, AutoBorrowMutability};
1516
use rustc_middle::ty::{self, AdtDef, EarlyBinder, GenericArg, GenericArgsRef, Ty, TypeVisitableExt};
1617
use rustc_session::impl_lint_pass;
1718
use rustc_span::{Span, sym};
@@ -251,26 +252,25 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion {
251252
// ^^^
252253
let (into_iter_recv, depth) = into_iter_deep_call(cx, into_iter_recv);
253254

254-
let plural = if depth == 0 { "" } else { "s" };
255-
let mut applicability = Applicability::MachineApplicable;
256-
let sugg = snippet_with_applicability(
257-
cx,
258-
into_iter_recv.span.source_callsite(),
259-
"<expr>",
260-
&mut applicability,
261-
)
262-
.into_owned();
263255
span_lint_and_then(
264256
cx,
265257
USELESS_CONVERSION,
266258
e.span,
267259
"explicit call to `.into_iter()` in function argument accepting `IntoIterator`",
268260
|diag| {
269-
diag.span_suggestion(
270-
e.span,
261+
let receiver_span = into_iter_recv.span.source_callsite();
262+
let adjustments = adjustments(cx, into_iter_recv);
263+
let mut sugg = if adjustments.is_empty() {
264+
vec![]
265+
} else {
266+
vec![(receiver_span.shrink_to_lo(), adjustments)]
267+
};
268+
let plural = if depth == 0 { "" } else { "s" };
269+
sugg.push((e.span.with_lo(receiver_span.hi()), String::new()));
270+
diag.multipart_suggestion(
271271
format!("consider removing the `.into_iter()`{plural}"),
272272
sugg,
273-
applicability,
273+
Applicability::MachineApplicable,
274274
);
275275
diag.span_note(span, "this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()`");
276276
},
@@ -431,3 +431,16 @@ fn has_eligible_receiver(cx: &LateContext<'_>, recv: &Expr<'_>, expr: &Expr<'_>)
431431
}
432432
false
433433
}
434+
435+
fn adjustments(cx: &LateContext<'_>, expr: &Expr<'_>) -> String {
436+
let mut prefix = String::new();
437+
for adj in cx.typeck_results().expr_adjustments(expr) {
438+
match adj.kind {
439+
Adjust::Deref(_) => prefix = format!("*{prefix}"),
440+
Adjust::Borrow(AutoBorrow::Ref(AutoBorrowMutability::Mut { .. })) => prefix = format!("&mut {prefix}"),
441+
Adjust::Borrow(AutoBorrow::Ref(AutoBorrowMutability::Not)) => prefix = format!("&{prefix}"),
442+
_ => {},
443+
}
444+
}
445+
prefix
446+
}

tests/ui/useless_conversion.fixed

+53
Original file line numberDiff line numberDiff line change
@@ -342,3 +342,56 @@ fn gen_identity<T>(x: [T; 3]) -> Vec<T> {
342342
x.into_iter().collect()
343343
//~^ useless_conversion
344344
}
345+
346+
mod issue11819 {
347+
fn takes_into_iter(_: impl IntoIterator<Item = String>) {}
348+
349+
pub struct MyStruct<T> {
350+
my_field: T,
351+
}
352+
353+
impl<T> MyStruct<T> {
354+
pub fn with_ref<'a>(&'a mut self)
355+
where
356+
&'a T: IntoIterator<Item = String>,
357+
{
358+
takes_into_iter(&self.my_field);
359+
//~^ useless_conversion
360+
}
361+
362+
pub fn with_ref_mut<'a>(&'a mut self)
363+
where
364+
&'a mut T: IntoIterator<Item = String>,
365+
{
366+
takes_into_iter(&mut self.my_field);
367+
//~^ useless_conversion
368+
}
369+
370+
pub fn with_deref<Y>(&mut self)
371+
where
372+
T: std::ops::Deref<Target = Y>,
373+
Y: IntoIterator<Item = String> + Copy,
374+
{
375+
takes_into_iter(*self.my_field);
376+
//~^ useless_conversion
377+
}
378+
379+
pub fn with_reborrow<'a, Y: 'a>(&'a mut self)
380+
where
381+
T: std::ops::Deref<Target = Y>,
382+
&'a Y: IntoIterator<Item = String>,
383+
{
384+
takes_into_iter(&*self.my_field);
385+
//~^ useless_conversion
386+
}
387+
388+
pub fn with_reborrow_mut<'a, Y: 'a>(&'a mut self)
389+
where
390+
T: std::ops::Deref<Target = Y> + std::ops::DerefMut,
391+
&'a mut Y: IntoIterator<Item = String>,
392+
{
393+
takes_into_iter(&mut *self.my_field);
394+
//~^ useless_conversion
395+
}
396+
}
397+
}

tests/ui/useless_conversion.rs

+53
Original file line numberDiff line numberDiff line change
@@ -342,3 +342,56 @@ fn gen_identity<T>(x: [T; 3]) -> Vec<T> {
342342
x.into_iter().map(Into::into).collect()
343343
//~^ useless_conversion
344344
}
345+
346+
mod issue11819 {
347+
fn takes_into_iter(_: impl IntoIterator<Item = String>) {}
348+
349+
pub struct MyStruct<T> {
350+
my_field: T,
351+
}
352+
353+
impl<T> MyStruct<T> {
354+
pub fn with_ref<'a>(&'a mut self)
355+
where
356+
&'a T: IntoIterator<Item = String>,
357+
{
358+
takes_into_iter(self.my_field.into_iter());
359+
//~^ useless_conversion
360+
}
361+
362+
pub fn with_ref_mut<'a>(&'a mut self)
363+
where
364+
&'a mut T: IntoIterator<Item = String>,
365+
{
366+
takes_into_iter(self.my_field.into_iter());
367+
//~^ useless_conversion
368+
}
369+
370+
pub fn with_deref<Y>(&mut self)
371+
where
372+
T: std::ops::Deref<Target = Y>,
373+
Y: IntoIterator<Item = String> + Copy,
374+
{
375+
takes_into_iter(self.my_field.into_iter());
376+
//~^ useless_conversion
377+
}
378+
379+
pub fn with_reborrow<'a, Y: 'a>(&'a mut self)
380+
where
381+
T: std::ops::Deref<Target = Y>,
382+
&'a Y: IntoIterator<Item = String>,
383+
{
384+
takes_into_iter(self.my_field.into_iter());
385+
//~^ useless_conversion
386+
}
387+
388+
pub fn with_reborrow_mut<'a, Y: 'a>(&'a mut self)
389+
where
390+
T: std::ops::Deref<Target = Y> + std::ops::DerefMut,
391+
&'a mut Y: IntoIterator<Item = String>,
392+
{
393+
takes_into_iter(self.my_field.into_iter());
394+
//~^ useless_conversion
395+
}
396+
}
397+
}

tests/ui/useless_conversion.stderr

+113-10
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,9 @@ error: explicit call to `.into_iter()` in function argument accepting `IntoItera
122122
--> tests/ui/useless_conversion.rs:189:7
123123
|
124124
LL | b(vec![1, 2].into_iter());
125-
| ^^^^^^^^^^^^^^^^^^^^^^ help: consider removing the `.into_iter()`: `vec![1, 2]`
125+
| ^^^^^^^^^^------------
126+
| |
127+
| help: consider removing the `.into_iter()`
126128
|
127129
note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()`
128130
--> tests/ui/useless_conversion.rs:179:13
@@ -134,7 +136,9 @@ error: explicit call to `.into_iter()` in function argument accepting `IntoItera
134136
--> tests/ui/useless_conversion.rs:190:7
135137
|
136138
LL | c(vec![1, 2].into_iter());
137-
| ^^^^^^^^^^^^^^^^^^^^^^ help: consider removing the `.into_iter()`: `vec![1, 2]`
139+
| ^^^^^^^^^^------------
140+
| |
141+
| help: consider removing the `.into_iter()`
138142
|
139143
note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()`
140144
--> tests/ui/useless_conversion.rs:180:18
@@ -146,7 +150,9 @@ error: explicit call to `.into_iter()` in function argument accepting `IntoItera
146150
--> tests/ui/useless_conversion.rs:191:7
147151
|
148152
LL | d(vec![1, 2].into_iter());
149-
| ^^^^^^^^^^^^^^^^^^^^^^ help: consider removing the `.into_iter()`: `vec![1, 2]`
153+
| ^^^^^^^^^^------------
154+
| |
155+
| help: consider removing the `.into_iter()`
150156
|
151157
note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()`
152158
--> tests/ui/useless_conversion.rs:183:12
@@ -158,7 +164,9 @@ error: explicit call to `.into_iter()` in function argument accepting `IntoItera
158164
--> tests/ui/useless_conversion.rs:194:7
159165
|
160166
LL | b(vec![1, 2].into_iter().into_iter());
161-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing the `.into_iter()`s: `vec![1, 2]`
167+
| ^^^^^^^^^^------------------------
168+
| |
169+
| help: consider removing the `.into_iter()`s
162170
|
163171
note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()`
164172
--> tests/ui/useless_conversion.rs:179:13
@@ -170,7 +178,9 @@ error: explicit call to `.into_iter()` in function argument accepting `IntoItera
170178
--> tests/ui/useless_conversion.rs:195:7
171179
|
172180
LL | b(vec![1, 2].into_iter().into_iter().into_iter());
173-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing the `.into_iter()`s: `vec![1, 2]`
181+
| ^^^^^^^^^^------------------------------------
182+
| |
183+
| help: consider removing the `.into_iter()`s
174184
|
175185
note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()`
176186
--> tests/ui/useless_conversion.rs:179:13
@@ -182,7 +192,9 @@ error: explicit call to `.into_iter()` in function argument accepting `IntoItera
182192
--> tests/ui/useless_conversion.rs:241:24
183193
|
184194
LL | foo2::<i32, _>([1, 2, 3].into_iter());
185-
| ^^^^^^^^^^^^^^^^^^^^^ help: consider removing the `.into_iter()`: `[1, 2, 3]`
195+
| ^^^^^^^^^------------
196+
| |
197+
| help: consider removing the `.into_iter()`
186198
|
187199
note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()`
188200
--> tests/ui/useless_conversion.rs:220:12
@@ -194,7 +206,9 @@ error: explicit call to `.into_iter()` in function argument accepting `IntoItera
194206
--> tests/ui/useless_conversion.rs:249:14
195207
|
196208
LL | foo3([1, 2, 3].into_iter());
197-
| ^^^^^^^^^^^^^^^^^^^^^ help: consider removing the `.into_iter()`: `[1, 2, 3]`
209+
| ^^^^^^^^^------------
210+
| |
211+
| help: consider removing the `.into_iter()`
198212
|
199213
note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()`
200214
--> tests/ui/useless_conversion.rs:229:12
@@ -206,7 +220,9 @@ error: explicit call to `.into_iter()` in function argument accepting `IntoItera
206220
--> tests/ui/useless_conversion.rs:258:16
207221
|
208222
LL | S1.foo([1, 2].into_iter());
209-
| ^^^^^^^^^^^^^^^^^^ help: consider removing the `.into_iter()`: `[1, 2]`
223+
| ^^^^^^------------
224+
| |
225+
| help: consider removing the `.into_iter()`
210226
|
211227
note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()`
212228
--> tests/ui/useless_conversion.rs:255:27
@@ -218,7 +234,9 @@ error: explicit call to `.into_iter()` in function argument accepting `IntoItera
218234
--> tests/ui/useless_conversion.rs:277:44
219235
|
220236
LL | v0.into_iter().interleave_shortest(v1.into_iter());
221-
| ^^^^^^^^^^^^^^ help: consider removing the `.into_iter()`: `v1`
237+
| ^^------------
238+
| |
239+
| help: consider removing the `.into_iter()`
222240
|
223241
note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()`
224242
--> tests/ui/useless_conversion.rs:264:20
@@ -274,5 +292,90 @@ error: useless conversion to the same type: `T`
274292
LL | x.into_iter().map(Into::into).collect()
275293
| ^^^^^^^^^^^^^^^^ help: consider removing
276294

277-
error: aborting due to 36 previous errors
295+
error: explicit call to `.into_iter()` in function argument accepting `IntoIterator`
296+
--> tests/ui/useless_conversion.rs:358:29
297+
|
298+
LL | takes_into_iter(self.my_field.into_iter());
299+
| ^^^^^^^^^^^^^^^^^^^^^^^^^
300+
|
301+
note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()`
302+
--> tests/ui/useless_conversion.rs:347:32
303+
|
304+
LL | fn takes_into_iter(_: impl IntoIterator<Item = String>) {}
305+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
306+
help: consider removing the `.into_iter()`
307+
|
308+
LL - takes_into_iter(self.my_field.into_iter());
309+
LL + takes_into_iter(&self.my_field);
310+
|
311+
312+
error: explicit call to `.into_iter()` in function argument accepting `IntoIterator`
313+
--> tests/ui/useless_conversion.rs:366:29
314+
|
315+
LL | takes_into_iter(self.my_field.into_iter());
316+
| ^^^^^^^^^^^^^^^^^^^^^^^^^
317+
|
318+
note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()`
319+
--> tests/ui/useless_conversion.rs:347:32
320+
|
321+
LL | fn takes_into_iter(_: impl IntoIterator<Item = String>) {}
322+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
323+
help: consider removing the `.into_iter()`
324+
|
325+
LL - takes_into_iter(self.my_field.into_iter());
326+
LL + takes_into_iter(&mut self.my_field);
327+
|
328+
329+
error: explicit call to `.into_iter()` in function argument accepting `IntoIterator`
330+
--> tests/ui/useless_conversion.rs:375:29
331+
|
332+
LL | takes_into_iter(self.my_field.into_iter());
333+
| ^^^^^^^^^^^^^^^^^^^^^^^^^
334+
|
335+
note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()`
336+
--> tests/ui/useless_conversion.rs:347:32
337+
|
338+
LL | fn takes_into_iter(_: impl IntoIterator<Item = String>) {}
339+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
340+
help: consider removing the `.into_iter()`
341+
|
342+
LL - takes_into_iter(self.my_field.into_iter());
343+
LL + takes_into_iter(*self.my_field);
344+
|
345+
346+
error: explicit call to `.into_iter()` in function argument accepting `IntoIterator`
347+
--> tests/ui/useless_conversion.rs:384:29
348+
|
349+
LL | takes_into_iter(self.my_field.into_iter());
350+
| ^^^^^^^^^^^^^^^^^^^^^^^^^
351+
|
352+
note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()`
353+
--> tests/ui/useless_conversion.rs:347:32
354+
|
355+
LL | fn takes_into_iter(_: impl IntoIterator<Item = String>) {}
356+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
357+
help: consider removing the `.into_iter()`
358+
|
359+
LL - takes_into_iter(self.my_field.into_iter());
360+
LL + takes_into_iter(&*self.my_field);
361+
|
362+
363+
error: explicit call to `.into_iter()` in function argument accepting `IntoIterator`
364+
--> tests/ui/useless_conversion.rs:393:29
365+
|
366+
LL | takes_into_iter(self.my_field.into_iter());
367+
| ^^^^^^^^^^^^^^^^^^^^^^^^^
368+
|
369+
note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()`
370+
--> tests/ui/useless_conversion.rs:347:32
371+
|
372+
LL | fn takes_into_iter(_: impl IntoIterator<Item = String>) {}
373+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
374+
help: consider removing the `.into_iter()`
375+
|
376+
LL - takes_into_iter(self.my_field.into_iter());
377+
LL + takes_into_iter(&mut *self.my_field);
378+
|
379+
380+
error: aborting due to 41 previous errors
278381

0 commit comments

Comments
 (0)