Skip to content
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!()
}
}
}