Skip to content

Fix explicit_into_iter_loop #6982

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 12, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 7 additions & 6 deletions clippy_lints/src/loops/explicit_into_iter_loop.rs
Original file line number Diff line number Diff line change
@@ -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",
Expand Down
10 changes: 5 additions & 5 deletions clippy_lints/src/loops/explicit_iter_loop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@ use rustc_lint::LateContext;
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 {
Expand All @@ -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,
Expand Down
29 changes: 13 additions & 16 deletions clippy_lints/src/loops/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
},
_ => {},
}
}

Expand Down
26 changes: 26 additions & 0 deletions tests/ui/for_loop_fixable.fixed
Original file line number Diff line number Diff line change
Expand Up @@ -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<T>(self) -> I<T> {
unimplemented!()
}
}

struct I<T>(T);
impl<T> Iterator for I<T> {
type Item = T;
fn next(&mut self) -> Option<Self::Item> {
unimplemented!()
}
}

fn f() {
for _ in S.into_iter::<u32>() {
unimplemented!()
}
}
}
26 changes: 26 additions & 0 deletions tests/ui/for_loop_fixable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<T>(self) -> I<T> {
unimplemented!()
}
}

struct I<T>(T);
impl<T> Iterator for I<T> {
type Item = T;
fn next(&mut self) -> Option<Self::Item> {
unimplemented!()
}
}

fn f() {
for _ in S.into_iter::<u32>() {
unimplemented!()
}
}
}