Skip to content

Commit 6b5778e

Browse files
committed
Fix explicit_into_iter_loop
Only lint when `into_iter` is an implementation of `IntoIterator` Minor cleanups
1 parent 6ae0835 commit 6b5778e

File tree

5 files changed

+77
-27
lines changed

5 files changed

+77
-27
lines changed

clippy_lints/src/loops/explicit_into_iter_loop.rs

+7-6
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,25 @@
11
use super::EXPLICIT_INTO_ITER_LOOP;
22
use clippy_utils::diagnostics::span_lint_and_sugg;
33
use clippy_utils::source::snippet_with_applicability;
4+
use clippy_utils::{match_trait_method, paths};
45
use rustc_errors::Applicability;
56
use rustc_hir::Expr;
67
use rustc_lint::LateContext;
78
use rustc_middle::ty::TyS;
89

9-
pub(super) fn check(cx: &LateContext<'_>, args: &'hir [Expr<'hir>], arg: &Expr<'_>) {
10-
let receiver_ty = cx.typeck_results().expr_ty(&args[0]);
11-
let receiver_ty_adjusted = cx.typeck_results().expr_ty_adjusted(&args[0]);
12-
if !TyS::same_type(receiver_ty, receiver_ty_adjusted) {
10+
pub(super) fn check(cx: &LateContext<'_>, self_arg: &'hir Expr<'hir>, call_expr: &Expr<'_>) {
11+
let self_ty = cx.typeck_results().expr_ty(self_arg);
12+
let self_ty_adjusted = cx.typeck_results().expr_ty_adjusted(self_arg);
13+
if !(TyS::same_type(self_ty, self_ty_adjusted) && match_trait_method(cx, call_expr, &paths::INTO_ITERATOR)) {
1314
return;
1415
}
1516

1617
let mut applicability = Applicability::MachineApplicable;
17-
let object = snippet_with_applicability(cx, args[0].span, "_", &mut applicability);
18+
let object = snippet_with_applicability(cx, self_arg.span, "_", &mut applicability);
1819
span_lint_and_sugg(
1920
cx,
2021
EXPLICIT_INTO_ITER_LOOP,
21-
arg.span,
22+
call_expr.span,
2223
"it is more concise to loop over containers instead of using explicit \
2324
iteration methods",
2425
"to write this more concisely, try",

clippy_lints/src/loops/explicit_iter_loop.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,12 @@ use rustc_lint::LateContext;
99
use rustc_middle::ty::{self, Ty, TyS};
1010
use rustc_span::sym;
1111

12-
pub(super) fn check(cx: &LateContext<'_>, args: &[Expr<'_>], arg: &Expr<'_>, method_name: &str) {
12+
pub(super) fn check(cx: &LateContext<'_>, self_arg: &Expr<'_>, arg: &Expr<'_>, method_name: &str) {
1313
let should_lint = match method_name {
14-
"iter" | "iter_mut" => is_ref_iterable_type(cx, &args[0]),
14+
"iter" | "iter_mut" => is_ref_iterable_type(cx, self_arg),
1515
"into_iter" if match_trait_method(cx, arg, &paths::INTO_ITERATOR) => {
16-
let receiver_ty = cx.typeck_results().expr_ty(&args[0]);
17-
let receiver_ty_adjusted = cx.typeck_results().expr_ty_adjusted(&args[0]);
16+
let receiver_ty = cx.typeck_results().expr_ty(self_arg);
17+
let receiver_ty_adjusted = cx.typeck_results().expr_ty_adjusted(self_arg);
1818
let ref_receiver_ty = cx.tcx.mk_ref(
1919
cx.tcx.lifetimes.re_erased,
2020
ty::TypeAndMut {
@@ -32,7 +32,7 @@ pub(super) fn check(cx: &LateContext<'_>, args: &[Expr<'_>], arg: &Expr<'_>, met
3232
}
3333

3434
let mut applicability = Applicability::MachineApplicable;
35-
let object = snippet_with_applicability(cx, args[0].span, "_", &mut applicability);
35+
let object = snippet_with_applicability(cx, self_arg.span, "_", &mut applicability);
3636
let muta = if method_name == "iter_mut" { "mut " } else { "" };
3737
span_lint_and_sugg(
3838
cx,

clippy_lints/src/loops/mod.rs

+13-16
Original file line numberDiff line numberDiff line change
@@ -602,22 +602,19 @@ fn check_for_loop<'tcx>(
602602
fn check_for_loop_arg(cx: &LateContext<'_>, pat: &Pat<'_>, arg: &Expr<'_>, expr: &Expr<'_>) {
603603
let mut next_loop_linted = false; // whether or not ITER_NEXT_LOOP lint was used
604604

605-
if let ExprKind::MethodCall(method, _, args, _) = arg.kind {
606-
// just the receiver, no arguments
607-
if args.len() == 1 {
608-
let method_name = &*method.ident.as_str();
609-
// check for looping over x.iter() or x.iter_mut(), could use &x or &mut x
610-
match method_name {
611-
"iter" | "iter_mut" => explicit_iter_loop::check(cx, args, arg, method_name),
612-
"into_iter" => {
613-
explicit_iter_loop::check(cx, args, arg, method_name);
614-
explicit_into_iter_loop::check(cx, args, arg);
615-
},
616-
"next" => {
617-
next_loop_linted = iter_next_loop::check(cx, arg, expr);
618-
},
619-
_ => {},
620-
}
605+
if let ExprKind::MethodCall(method, _, [self_arg], _) = arg.kind {
606+
let method_name = &*method.ident.as_str();
607+
// check for looping over x.iter() or x.iter_mut(), could use &x or &mut x
608+
match method_name {
609+
"iter" | "iter_mut" => explicit_iter_loop::check(cx, self_arg, arg, method_name),
610+
"into_iter" => {
611+
explicit_iter_loop::check(cx, self_arg, arg, method_name);
612+
explicit_into_iter_loop::check(cx, self_arg, arg);
613+
},
614+
"next" => {
615+
next_loop_linted = iter_next_loop::check(cx, arg, expr);
616+
},
617+
_ => {},
621618
}
622619
}
623620

tests/ui/for_loop_fixable.fixed

+26
Original file line numberDiff line numberDiff line change
@@ -281,3 +281,29 @@ mod issue_4958 {
281281
for _ in rr.into_iter() {}
282282
}
283283
}
284+
285+
// explicit_into_iter_loop
286+
#[warn(clippy::explicit_into_iter_loop)]
287+
mod issue_6900 {
288+
struct S;
289+
impl S {
290+
#[allow(clippy::should_implement_trait)]
291+
pub fn into_iter<T>(self) -> I<T> {
292+
unimplemented!()
293+
}
294+
}
295+
296+
struct I<T>(T);
297+
impl<T> Iterator for I<T> {
298+
type Item = T;
299+
fn next(&mut self) -> Option<Self::Item> {
300+
unimplemented!()
301+
}
302+
}
303+
304+
fn f() {
305+
for _ in S.into_iter::<u32>() {
306+
unimplemented!()
307+
}
308+
}
309+
}

tests/ui/for_loop_fixable.rs

+26
Original file line numberDiff line numberDiff line change
@@ -281,3 +281,29 @@ mod issue_4958 {
281281
for _ in rr.into_iter() {}
282282
}
283283
}
284+
285+
// explicit_into_iter_loop
286+
#[warn(clippy::explicit_into_iter_loop)]
287+
mod issue_6900 {
288+
struct S;
289+
impl S {
290+
#[allow(clippy::should_implement_trait)]
291+
pub fn into_iter<T>(self) -> I<T> {
292+
unimplemented!()
293+
}
294+
}
295+
296+
struct I<T>(T);
297+
impl<T> Iterator for I<T> {
298+
type Item = T;
299+
fn next(&mut self) -> Option<Self::Item> {
300+
unimplemented!()
301+
}
302+
}
303+
304+
fn f() {
305+
for _ in S.into_iter::<u32>() {
306+
unimplemented!()
307+
}
308+
}
309+
}

0 commit comments

Comments
 (0)