diff --git a/clippy_lints/src/loops/explicit_into_iter_loop.rs b/clippy_lints/src/loops/explicit_into_iter_loop.rs index 4871a031187..c7a28f42ea1 100644 --- a/clippy_lints/src/loops/explicit_into_iter_loop.rs +++ b/clippy_lints/src/loops/explicit_into_iter_loop.rs @@ -1,24 +1,25 @@ use super::EXPLICIT_INTO_ITER_LOOP; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; +use clippy_utils::{match_trait_method, paths}; use rustc_errors::Applicability; use rustc_hir::Expr; use rustc_lint::LateContext; use rustc_middle::ty::TyS; -pub(super) fn check(cx: &LateContext<'_>, args: &'hir [Expr<'hir>], arg: &Expr<'_>) { - let receiver_ty = cx.typeck_results().expr_ty(&args[0]); - let receiver_ty_adjusted = cx.typeck_results().expr_ty_adjusted(&args[0]); - if !TyS::same_type(receiver_ty, receiver_ty_adjusted) { +pub(super) fn check(cx: &LateContext<'_>, self_arg: &'hir Expr<'hir>, call_expr: &Expr<'_>) { + let self_ty = cx.typeck_results().expr_ty(self_arg); + let self_ty_adjusted = cx.typeck_results().expr_ty_adjusted(self_arg); + if !(TyS::same_type(self_ty, self_ty_adjusted) && match_trait_method(cx, call_expr, &paths::INTO_ITERATOR)) { return; } let mut applicability = Applicability::MachineApplicable; - let object = snippet_with_applicability(cx, args[0].span, "_", &mut applicability); + let object = snippet_with_applicability(cx, self_arg.span, "_", &mut applicability); span_lint_and_sugg( cx, EXPLICIT_INTO_ITER_LOOP, - arg.span, + call_expr.span, "it is more concise to loop over containers instead of using explicit \ iteration methods", "to write this more concisely, try", diff --git a/clippy_lints/src/loops/explicit_iter_loop.rs b/clippy_lints/src/loops/explicit_iter_loop.rs index 92aa2beb66d..ce02ad013be 100644 --- a/clippy_lints/src/loops/explicit_iter_loop.rs +++ b/clippy_lints/src/loops/explicit_iter_loop.rs @@ -9,12 +9,12 @@ use rustc_middle::ty::{self, Ty, TyS}; use rustc_span::sym; -pub(super) fn check(cx: &LateContext<'_>, args: &[Expr<'_>], arg: &Expr<'_>, method_name: &str) { +pub(super) fn check(cx: &LateContext<'_>, self_arg: &Expr<'_>, arg: &Expr<'_>, method_name: &str) { let should_lint = match method_name { - "iter" | "iter_mut" => is_ref_iterable_type(cx, &args[0]), + "iter" | "iter_mut" => is_ref_iterable_type(cx, self_arg), "into_iter" if match_trait_method(cx, arg, &paths::INTO_ITERATOR) => { - let receiver_ty = cx.typeck_results().expr_ty(&args[0]); - let receiver_ty_adjusted = cx.typeck_results().expr_ty_adjusted(&args[0]); + let receiver_ty = cx.typeck_results().expr_ty(self_arg); + let receiver_ty_adjusted = cx.typeck_results().expr_ty_adjusted(self_arg); let ref_receiver_ty = cx.tcx.mk_ref( cx.tcx.lifetimes.re_erased, ty::TypeAndMut { @@ -32,7 +32,7 @@ pub(super) fn check(cx: &LateContext<'_>, args: &[Expr<'_>], arg: &Expr<'_>, met } let mut applicability = Applicability::MachineApplicable; - let object = snippet_with_applicability(cx, args[0].span, "_", &mut applicability); + let object = snippet_with_applicability(cx, self_arg.span, "_", &mut applicability); let muta = if method_name == "iter_mut" { "mut " } else { "" }; span_lint_and_sugg( cx, diff --git a/clippy_lints/src/loops/mod.rs b/clippy_lints/src/loops/mod.rs index 28acefd51fe..a4bc3e6bd10 100644 --- a/clippy_lints/src/loops/mod.rs +++ b/clippy_lints/src/loops/mod.rs @@ -602,22 +602,19 @@ fn check_for_loop<'tcx>( fn check_for_loop_arg(cx: &LateContext<'_>, pat: &Pat<'_>, arg: &Expr<'_>, expr: &Expr<'_>) { let mut next_loop_linted = false; // whether or not ITER_NEXT_LOOP lint was used - if let ExprKind::MethodCall(method, _, args, _) = arg.kind { - // just the receiver, no arguments - if args.len() == 1 { - let method_name = &*method.ident.as_str(); - // check for looping over x.iter() or x.iter_mut(), could use &x or &mut x - match method_name { - "iter" | "iter_mut" => explicit_iter_loop::check(cx, args, arg, method_name), - "into_iter" => { - explicit_iter_loop::check(cx, args, arg, method_name); - explicit_into_iter_loop::check(cx, args, arg); - }, - "next" => { - next_loop_linted = iter_next_loop::check(cx, arg, expr); - }, - _ => {}, - } + if let ExprKind::MethodCall(method, _, [self_arg], _) = arg.kind { + let method_name = &*method.ident.as_str(); + // check for looping over x.iter() or x.iter_mut(), could use &x or &mut x + match method_name { + "iter" | "iter_mut" => explicit_iter_loop::check(cx, self_arg, arg, method_name), + "into_iter" => { + explicit_iter_loop::check(cx, self_arg, arg, method_name); + explicit_into_iter_loop::check(cx, self_arg, arg); + }, + "next" => { + next_loop_linted = iter_next_loop::check(cx, arg, expr); + }, + _ => {}, } } diff --git a/tests/ui/for_loop_fixable.fixed b/tests/ui/for_loop_fixable.fixed index 249a88a0b39..f44928d4083 100644 --- a/tests/ui/for_loop_fixable.fixed +++ b/tests/ui/for_loop_fixable.fixed @@ -281,3 +281,29 @@ mod issue_4958 { for _ in rr.into_iter() {} } } + +// explicit_into_iter_loop +#[warn(clippy::explicit_into_iter_loop)] +mod issue_6900 { + struct S; + impl S { + #[allow(clippy::should_implement_trait)] + pub fn into_iter(self) -> I { + unimplemented!() + } + } + + struct I(T); + impl Iterator for I { + type Item = T; + fn next(&mut self) -> Option { + unimplemented!() + } + } + + fn f() { + for _ in S.into_iter::() { + unimplemented!() + } + } +} diff --git a/tests/ui/for_loop_fixable.rs b/tests/ui/for_loop_fixable.rs index 306d85a6351..5b1eb3ee4dc 100644 --- a/tests/ui/for_loop_fixable.rs +++ b/tests/ui/for_loop_fixable.rs @@ -281,3 +281,29 @@ fn more_tests() { for _ in rr.into_iter() {} } } + +// explicit_into_iter_loop +#[warn(clippy::explicit_into_iter_loop)] +mod issue_6900 { + struct S; + impl S { + #[allow(clippy::should_implement_trait)] + pub fn into_iter(self) -> I { + unimplemented!() + } + } + + struct I(T); + impl Iterator for I { + type Item = T; + fn next(&mut self) -> Option { + unimplemented!() + } + } + + fn f() { + for _ in S.into_iter::() { + unimplemented!() + } + } +}