Fix explicit_into_iter_loop
Only lint when `into_iter` is an implementation of `IntoIterator` Minor cleanups
This commit is contained in:
parent
6ae0835df0
commit
6b5778eb17
@ -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",
|
||||
|
@ -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,
|
||||
|
@ -602,16 +602,14 @@ 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 {
|
||||
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, args, arg, method_name),
|
||||
"iter" | "iter_mut" => explicit_iter_loop::check(cx, self_arg, arg, method_name),
|
||||
"into_iter" => {
|
||||
explicit_iter_loop::check(cx, args, arg, method_name);
|
||||
explicit_into_iter_loop::check(cx, args, arg);
|
||||
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);
|
||||
@ -619,7 +617,6 @@ fn check_for_loop_arg(cx: &LateContext<'_>, pat: &Pat<'_>, arg: &Expr<'_>, expr:
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !next_loop_linted {
|
||||
for_loops_over_fallibles::check(cx, pat, arg);
|
||||
|
@ -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!()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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<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!()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user