Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit 1ccef58

Browse files
committed
useless_conversion: add needed adjustments to suggestion
1 parent e692cd4 commit 1ccef58

File tree

4 files changed

+187
-3
lines changed

4 files changed

+187
-3
lines changed

clippy_lints/src/useless_conversion.rs

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -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,15 +252,19 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion {
251252
// ^^^
252253
let (into_iter_recv, depth) = into_iter_deep_call(cx, into_iter_recv);
253254

255+
// The receiver may not implement `IntoIterator`, it may have been
256+
// auto-dereferenced.
257+
let adjustments = adjustments(cx, into_iter_recv);
258+
254259
let plural = if depth == 0 { "" } else { "s" };
255260
let mut applicability = Applicability::MachineApplicable;
256261
let sugg = snippet_with_applicability(
257262
cx,
258263
into_iter_recv.span.source_callsite(),
259264
"<expr>",
260265
&mut applicability,
261-
)
262-
.into_owned();
266+
);
267+
let sugg = format!("{adjustments}{sugg}");
263268
span_lint_and_then(
264269
cx,
265270
USELESS_CONVERSION,
@@ -431,3 +436,16 @@ fn has_eligible_receiver(cx: &LateContext<'_>, recv: &Expr<'_>, expr: &Expr<'_>)
431436
}
432437
false
433438
}
439+
440+
fn adjustments(cx: &LateContext<'_>, expr: &Expr<'_>) -> String {
441+
let mut prefix = String::new();
442+
for adj in cx.typeck_results().expr_adjustments(expr) {
443+
match adj.kind {
444+
Adjust::Deref(_) => prefix = format!("*{prefix}"),
445+
Adjust::Borrow(AutoBorrow::Ref(AutoBorrowMutability::Mut { .. })) => prefix = format!("&mut {prefix}"),
446+
Adjust::Borrow(AutoBorrow::Ref(AutoBorrowMutability::Not)) => prefix = format!("&{prefix}"),
447+
_ => {},
448+
}
449+
}
450+
prefix
451+
}

tests/ui/useless_conversion.fixed

Lines changed: 53 additions & 0 deletions
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

Lines changed: 53 additions & 0 deletions
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

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -274,5 +274,65 @@ error: useless conversion to the same type: `T`
274274
LL | x.into_iter().map(Into::into).collect()
275275
| ^^^^^^^^^^^^^^^^ help: consider removing
276276

277-
error: aborting due to 36 previous errors
277+
error: explicit call to `.into_iter()` in function argument accepting `IntoIterator`
278+
--> tests/ui/useless_conversion.rs:358:29
279+
|
280+
LL | takes_into_iter(self.my_field.into_iter());
281+
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing the `.into_iter()`: `&self.my_field`
282+
|
283+
note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()`
284+
--> tests/ui/useless_conversion.rs:347:32
285+
|
286+
LL | fn takes_into_iter(_: impl IntoIterator<Item = String>) {}
287+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
288+
289+
error: explicit call to `.into_iter()` in function argument accepting `IntoIterator`
290+
--> tests/ui/useless_conversion.rs:366:29
291+
|
292+
LL | takes_into_iter(self.my_field.into_iter());
293+
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing the `.into_iter()`: `&mut self.my_field`
294+
|
295+
note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()`
296+
--> tests/ui/useless_conversion.rs:347:32
297+
|
298+
LL | fn takes_into_iter(_: impl IntoIterator<Item = String>) {}
299+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
300+
301+
error: explicit call to `.into_iter()` in function argument accepting `IntoIterator`
302+
--> tests/ui/useless_conversion.rs:375:29
303+
|
304+
LL | takes_into_iter(self.my_field.into_iter());
305+
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing the `.into_iter()`: `*self.my_field`
306+
|
307+
note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()`
308+
--> tests/ui/useless_conversion.rs:347:32
309+
|
310+
LL | fn takes_into_iter(_: impl IntoIterator<Item = String>) {}
311+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
312+
313+
error: explicit call to `.into_iter()` in function argument accepting `IntoIterator`
314+
--> tests/ui/useless_conversion.rs:384:29
315+
|
316+
LL | takes_into_iter(self.my_field.into_iter());
317+
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing the `.into_iter()`: `&*self.my_field`
318+
|
319+
note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()`
320+
--> tests/ui/useless_conversion.rs:347:32
321+
|
322+
LL | fn takes_into_iter(_: impl IntoIterator<Item = String>) {}
323+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
324+
325+
error: explicit call to `.into_iter()` in function argument accepting `IntoIterator`
326+
--> tests/ui/useless_conversion.rs:393:29
327+
|
328+
LL | takes_into_iter(self.my_field.into_iter());
329+
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing the `.into_iter()`: `&mut *self.my_field`
330+
|
331+
note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()`
332+
--> tests/ui/useless_conversion.rs:347:32
333+
|
334+
LL | fn takes_into_iter(_: impl IntoIterator<Item = String>) {}
335+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
336+
337+
error: aborting due to 41 previous errors
278338

0 commit comments

Comments
 (0)