diff options
Diffstat (limited to 'src/tools/clippy/clippy_lints/src/loops')
12 files changed, 90 insertions, 56 deletions
diff --git a/src/tools/clippy/clippy_lints/src/loops/manual_find.rs b/src/tools/clippy/clippy_lints/src/loops/manual_find.rs index 215c83a7e..09b2376d5 100644 --- a/src/tools/clippy/clippy_lints/src/loops/manual_find.rs +++ b/src/tools/clippy/clippy_lints/src/loops/manual_find.rs @@ -106,7 +106,7 @@ fn get_binding(pat: &Pat<'_>) -> Option<HirId> { hir_id = None; return; } - if let BindingAnnotation::Unannotated = annotation { + if let BindingAnnotation::NONE = annotation { hir_id = Some(id); } }); diff --git a/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs b/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs index b31015d19..3fc569af8 100644 --- a/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs +++ b/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs @@ -119,11 +119,9 @@ fn build_manual_memcpy_suggestion<'tcx>( let print_limit = |end: &Expr<'_>, end_str: &str, base: &Expr<'_>, sugg: MinifyingSugg<'static>| { if_chain! { - if let ExprKind::MethodCall(method, len_args, _) = end.kind; + if let ExprKind::MethodCall(method, recv, [], _) = end.kind; if method.ident.name == sym::len; - if len_args.len() == 1; - if let Some(arg) = len_args.get(0); - if path_to_local(arg) == path_to_local(base); + if path_to_local(recv) == path_to_local(base); then { if sugg.to_string() == end_str { sugg::EMPTY.into() @@ -343,10 +341,8 @@ fn get_slice_like_element_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Opti fn fetch_cloned_expr<'tcx>(expr: &'tcx Expr<'tcx>) -> &'tcx Expr<'tcx> { if_chain! { - if let ExprKind::MethodCall(method, args, _) = expr.kind; + if let ExprKind::MethodCall(method, arg, [], _) = expr.kind; if method.ident.name == sym::clone; - if args.len() == 1; - if let Some(arg) = args.get(0); then { arg } else { expr } } } diff --git a/src/tools/clippy/clippy_lints/src/loops/missing_spin_loop.rs b/src/tools/clippy/clippy_lints/src/loops/missing_spin_loop.rs index 0696afa39..8412875b1 100644 --- a/src/tools/clippy/clippy_lints/src/loops/missing_spin_loop.rs +++ b/src/tools/clippy/clippy_lints/src/loops/missing_spin_loop.rs @@ -33,7 +33,7 @@ fn unpack_cond<'tcx>(cond: &'tcx Expr<'tcx>) -> &'tcx Expr<'tcx> { pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, cond: &'tcx Expr<'_>, body: &'tcx Expr<'_>) { if_chain! { if let ExprKind::Block(Block { stmts: [], expr: None, ..}, _) = body.kind; - if let ExprKind::MethodCall(method, [callee, ..], _) = unpack_cond(cond).kind; + if let ExprKind::MethodCall(method, callee, ..) = unpack_cond(cond).kind; if [sym::load, sym::compare_exchange, sym::compare_exchange_weak].contains(&method.ident.name); if let ty::Adt(def, _substs) = cx.typeck_results().expr_ty(callee).kind(); if cx.tcx.is_diagnostic_item(sym::AtomicBool, def.did()); diff --git a/src/tools/clippy/clippy_lints/src/loops/mod.rs b/src/tools/clippy/clippy_lints/src/loops/mod.rs index ed270bd49..74f3bda9f 100644 --- a/src/tools/clippy/clippy_lints/src/loops/mod.rs +++ b/src/tools/clippy/clippy_lints/src/loops/mod.rs @@ -742,7 +742,7 @@ fn check_for_loop<'tcx>( fn check_for_loop_arg(cx: &LateContext<'_>, pat: &Pat<'_>, arg: &Expr<'_>) { let mut next_loop_linted = false; // whether or not ITER_NEXT_LOOP lint was used - if let ExprKind::MethodCall(method, [self_arg], _) = arg.kind { + 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 { diff --git a/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs b/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs index aedf3810b..fce2d5463 100644 --- a/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs +++ b/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs @@ -44,7 +44,7 @@ fn check_for_mutability(cx: &LateContext<'_>, bound: &Expr<'_>) -> Option<HirId> if_chain! { if let Some(hir_id) = path_to_local(bound); if let Node::Pat(pat) = cx.tcx.hir().get(hir_id); - if let PatKind::Binding(BindingAnnotation::Mutable, ..) = pat.kind; + if let PatKind::Binding(BindingAnnotation::MUT, ..) = pat.kind; then { return Some(hir_id); } diff --git a/src/tools/clippy/clippy_lints/src/loops/needless_collect.rs b/src/tools/clippy/clippy_lints/src/loops/needless_collect.rs index ddaffc751..6e6faa79a 100644 --- a/src/tools/clippy/clippy_lints/src/loops/needless_collect.rs +++ b/src/tools/clippy/clippy_lints/src/loops/needless_collect.rs @@ -1,5 +1,6 @@ use super::NEEDLESS_COLLECT; use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then}; +use clippy_utils::higher; use clippy_utils::source::{snippet, snippet_with_applicability}; use clippy_utils::sugg::Sugg; use clippy_utils::ty::is_type_diagnostic_item; @@ -24,11 +25,11 @@ pub(super) fn check<'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) { } fn check_needless_collect_direct_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) { if_chain! { - if let ExprKind::MethodCall(method, args, _) = expr.kind; - if let ExprKind::MethodCall(chain_method, _, _) = args[0].kind; - if chain_method.ident.name == sym!(collect) && is_trait_method(cx, &args[0], sym::Iterator); + if let ExprKind::MethodCall(method, receiver, args, _) = expr.kind; + if let ExprKind::MethodCall(chain_method, ..) = receiver.kind; + if chain_method.ident.name == sym!(collect) && is_trait_method(cx, receiver, sym::Iterator); then { - let ty = cx.typeck_results().expr_ty(&args[0]); + let ty = cx.typeck_results().expr_ty(receiver); let mut applicability = Applicability::MaybeIncorrect; let is_empty_sugg = "next().is_none()".to_string(); let method_name = method.ident.name.as_str(); @@ -40,7 +41,7 @@ fn check_needless_collect_direct_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateCont "len" => "count()".to_string(), "is_empty" => is_empty_sugg, "contains" => { - let contains_arg = snippet_with_applicability(cx, args[1].span, "??", &mut applicability); + let contains_arg = snippet_with_applicability(cx, args[0].span, "??", &mut applicability); let (arg, pred) = contains_arg .strip_prefix('&') .map_or(("&x", &*contains_arg), |s| ("x", s)); @@ -79,7 +80,7 @@ fn check_needless_collect_indirect_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateCo if let StmtKind::Local(local) = stmt.kind; if let PatKind::Binding(_, id, ..) = local.pat.kind; if let Some(init_expr) = local.init; - if let ExprKind::MethodCall(method_name, &[ref iter_source], ..) = init_expr.kind; + if let ExprKind::MethodCall(method_name, iter_source, [], ..) = init_expr.kind; if method_name.ident.name == sym!(collect) && is_trait_method(cx, init_expr, sym::Iterator); let ty = cx.typeck_results().expr_ty(init_expr); if is_type_diagnostic_item(cx, ty, sym::Vec) || @@ -184,16 +185,25 @@ struct IterFunctionVisitor<'a, 'tcx> { impl<'tcx> Visitor<'tcx> for IterFunctionVisitor<'_, 'tcx> { fn visit_block(&mut self, block: &'tcx Block<'tcx>) { for (expr, hir_id) in block.stmts.iter().filter_map(get_expr_and_hir_id_from_stmt) { + if check_loop_kind(expr).is_some() { + continue; + } self.visit_block_expr(expr, hir_id); } if let Some(expr) = block.expr { - self.visit_block_expr(expr, None); + if let Some(loop_kind) = check_loop_kind(expr) { + if let LoopKind::Conditional(block_expr) = loop_kind { + self.visit_block_expr(block_expr, None); + } + } else { + self.visit_block_expr(expr, None); + } } } fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) { // Check function calls on our collection - if let ExprKind::MethodCall(method_name, [recv, args @ ..], _) = &expr.kind { + if let ExprKind::MethodCall(method_name, recv, [args @ ..], _) = &expr.kind { if method_name.ident.name == sym!(collect) && is_trait_method(self.cx, expr, sym::Iterator) { self.current_mutably_captured_ids = get_captured_ids(self.cx, self.cx.typeck_results().expr_ty(recv)); self.visit_expr(recv); @@ -264,6 +274,28 @@ impl<'tcx> Visitor<'tcx> for IterFunctionVisitor<'_, 'tcx> { } } +enum LoopKind<'tcx> { + Conditional(&'tcx Expr<'tcx>), + Loop, +} + +fn check_loop_kind<'tcx>(expr: &Expr<'tcx>) -> Option<LoopKind<'tcx>> { + if let Some(higher::WhileLet { let_expr, .. }) = higher::WhileLet::hir(expr) { + return Some(LoopKind::Conditional(let_expr)); + } + if let Some(higher::While { condition, .. }) = higher::While::hir(expr) { + return Some(LoopKind::Conditional(condition)); + } + if let Some(higher::ForLoop { arg, .. }) = higher::ForLoop::hir(expr) { + return Some(LoopKind::Conditional(arg)); + } + if let ExprKind::Loop { .. } = expr.kind { + return Some(LoopKind::Loop); + } + + None +} + impl<'tcx> IterFunctionVisitor<'_, 'tcx> { fn visit_block_expr(&mut self, expr: &'tcx Expr<'tcx>, hir_id: Option<HirId>) { self.current_statement_hir_id = hir_id; diff --git a/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs b/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs index a7ef562b2..8ab640051 100644 --- a/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs +++ b/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs @@ -188,10 +188,9 @@ pub(super) fn check<'tcx>( fn is_len_call(expr: &Expr<'_>, var: Symbol) -> bool { if_chain! { - if let ExprKind::MethodCall(method, len_args, _) = expr.kind; - if len_args.len() == 1; + if let ExprKind::MethodCall(method, recv, [], _) = expr.kind; if method.ident.name == sym::len; - if let ExprKind::Path(QPath::Resolved(_, path)) = len_args[0].kind; + if let ExprKind::Path(QPath::Resolved(_, path)) = recv.kind; if path.segments.len() == 1; if path.segments[0].ident.name == var; then { @@ -302,7 +301,7 @@ impl<'a, 'tcx> Visitor<'tcx> for VarVisitor<'a, 'tcx> { fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { if_chain! { // a range index op - if let ExprKind::MethodCall(meth, [args_0, args_1, ..], _) = &expr.kind; + if let ExprKind::MethodCall(meth, args_0, [args_1, ..], _) = &expr.kind; if (meth.ident.name == sym::index && match_trait_method(self.cx, expr, &paths::INDEX)) || (meth.ident.name == sym::index_mut && match_trait_method(self.cx, expr, &paths::INDEX_MUT)); if !self.check(args_1, args_0, expr); @@ -357,9 +356,12 @@ impl<'a, 'tcx> Visitor<'tcx> for VarVisitor<'a, 'tcx> { self.visit_expr(expr); } }, - ExprKind::MethodCall(_, args, _) => { + ExprKind::MethodCall(_, receiver, args, _) => { let def_id = self.cx.typeck_results().type_dependent_def_id(expr.hir_id).unwrap(); - for (ty, expr) in iter::zip(self.cx.tcx.fn_sig(def_id).inputs().skip_binder(), args) { + for (ty, expr) in iter::zip( + self.cx.tcx.fn_sig(def_id).inputs().skip_binder(), + std::iter::once(receiver).chain(args.iter()), + ) { self.prefer_mutable = false; if let ty::Ref(_, _, mutbl) = *ty.kind() { if mutbl == Mutability::Mut { @@ -371,7 +373,7 @@ impl<'a, 'tcx> Visitor<'tcx> for VarVisitor<'a, 'tcx> { }, ExprKind::Closure(&Closure { body, .. }) => { let body = self.cx.tcx.hir().body(body); - self.visit_expr(&body.value); + self.visit_expr(body.value); }, _ => walk_expr(self, expr), } diff --git a/src/tools/clippy/clippy_lints/src/loops/never_loop.rs b/src/tools/clippy/clippy_lints/src/loops/never_loop.rs index 32de20f65..116e589ca 100644 --- a/src/tools/clippy/clippy_lints/src/loops/never_loop.rs +++ b/src/tools/clippy/clippy_lints/src/loops/never_loop.rs @@ -120,8 +120,9 @@ fn never_loop_expr(expr: &Expr<'_>, main_loop_id: HirId) -> NeverLoopResult { | ExprKind::Repeat(e, _) | ExprKind::DropTemps(e) => never_loop_expr(e, main_loop_id), ExprKind::Let(let_expr) => never_loop_expr(let_expr.init, main_loop_id), - ExprKind::Array(es) | ExprKind::MethodCall(_, es, _) | ExprKind::Tup(es) => { - never_loop_expr_all(&mut es.iter(), main_loop_id) + ExprKind::Array(es) | ExprKind::Tup(es) => never_loop_expr_all(&mut es.iter(), main_loop_id), + ExprKind::MethodCall(_, receiver, es, _) => { + never_loop_expr_all(&mut std::iter::once(receiver).chain(es.iter()), main_loop_id) }, ExprKind::Struct(_, fields, base) => { let fields = never_loop_expr_all(&mut fields.iter().map(|f| f.expr), main_loop_id); @@ -178,9 +179,9 @@ fn never_loop_expr(expr: &Expr<'_>, main_loop_id: HirId) -> NeverLoopResult { InlineAsmOperand::In { expr, .. } | InlineAsmOperand::InOut { expr, .. } => { never_loop_expr(expr, main_loop_id) }, - InlineAsmOperand::Out { expr, .. } => never_loop_expr_all(&mut expr.iter(), main_loop_id), + InlineAsmOperand::Out { expr, .. } => never_loop_expr_all(&mut expr.iter().copied(), main_loop_id), InlineAsmOperand::SplitInOut { in_expr, out_expr, .. } => { - never_loop_expr_all(&mut once(in_expr).chain(out_expr.iter()), main_loop_id) + never_loop_expr_all(&mut once(*in_expr).chain(out_expr.iter().copied()), main_loop_id) }, InlineAsmOperand::Const { .. } | InlineAsmOperand::SymFn { .. } diff --git a/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs b/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs index 1439f1f4c..aeefe6e33 100644 --- a/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs +++ b/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs @@ -7,7 +7,7 @@ use if_chain::if_chain; use rustc_data_structures::fx::FxHashSet; use rustc_hir::def::{DefKind, Res}; use rustc_hir::intravisit::{walk_expr, Visitor}; -use rustc_hir::{BindingAnnotation, Block, Expr, ExprKind, HirId, Node, Pat, PatKind, Stmt, StmtKind}; +use rustc_hir::{BindingAnnotation, Block, Expr, ExprKind, HirId, Mutability, Node, Pat, PatKind, Stmt, StmtKind}; use rustc_lint::LateContext; use rustc_span::symbol::sym; use std::iter::Iterator; @@ -65,7 +65,7 @@ pub(super) fn check<'tcx>( if_chain! { if let Node::Pat(pat) = node; if let PatKind::Binding(bind_ann, ..) = pat.kind; - if !matches!(bind_ann, BindingAnnotation::RefMut | BindingAnnotation::Mutable); + if !matches!(bind_ann, BindingAnnotation(_, Mutability::Mut)); let parent_node = cx.tcx.hir().get_parent_node(hir_id); if let Some(Node::Local(parent_let_expr)) = cx.tcx.hir().find(parent_node); if let Some(init) = parent_let_expr.init; @@ -180,10 +180,9 @@ fn get_vec_push<'tcx>(cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) -> Option<(& if_chain! { // Extract method being called if let StmtKind::Semi(semi_stmt) = &stmt.kind; - if let ExprKind::MethodCall(path, args, _) = &semi_stmt.kind; + if let ExprKind::MethodCall(path, self_expr, args, _) = &semi_stmt.kind; // Figure out the parameters for the method call - if let Some(self_expr) = args.get(0); - if let Some(pushed_item) = args.get(1); + if let Some(pushed_item) = args.get(0); // Check that the method being called is push() on a Vec if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(self_expr), sym::Vec); if path.ident.name.as_str() == "push"; diff --git a/src/tools/clippy/clippy_lints/src/loops/single_element_loop.rs b/src/tools/clippy/clippy_lints/src/loops/single_element_loop.rs index a0bd7ad0a..f4b47808d 100644 --- a/src/tools/clippy/clippy_lints/src/loops/single_element_loop.rs +++ b/src/tools/clippy/clippy_lints/src/loops/single_element_loop.rs @@ -35,32 +35,29 @@ pub(super) fn check<'tcx>( ) => (arg, "&mut "), ExprKind::MethodCall( method, - [ - Expr { - kind: ExprKind::Array([arg]), - .. - }, - ], + Expr { + kind: ExprKind::Array([arg]), + .. + }, + [], _, ) if method.ident.name == rustc_span::sym::iter => (arg, "&"), ExprKind::MethodCall( method, - [ - Expr { - kind: ExprKind::Array([arg]), - .. - }, - ], + Expr { + kind: ExprKind::Array([arg]), + .. + }, + [], _, ) if method.ident.name.as_str() == "iter_mut" => (arg, "&mut "), ExprKind::MethodCall( method, - [ - Expr { - kind: ExprKind::Array([arg]), - .. - }, - ], + Expr { + kind: ExprKind::Array([arg]), + .. + }, + [], _, ) if method.ident.name == rustc_span::sym::into_iter => (arg, ""), // Only check for arrays edition 2021 or later, as this case will trigger a compiler error otherwise. diff --git a/src/tools/clippy/clippy_lints/src/loops/while_let_loop.rs b/src/tools/clippy/clippy_lints/src/loops/while_let_loop.rs index ca617859d..735d704a4 100644 --- a/src/tools/clippy/clippy_lints/src/loops/while_let_loop.rs +++ b/src/tools/clippy/clippy_lints/src/loops/while_let_loop.rs @@ -11,7 +11,14 @@ use rustc_lint::LateContext; pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, loop_block: &'tcx Block<'_>) { let (init, has_trailing_exprs) = match (loop_block.stmts, loop_block.expr) { ([stmt, stmts @ ..], expr) => { - if let StmtKind::Local(&Local { init: Some(e), els: None, .. }) | StmtKind::Semi(e) | StmtKind::Expr(e) = stmt.kind { + if let StmtKind::Local(&Local { + init: Some(e), + els: None, + .. + }) + | StmtKind::Semi(e) + | StmtKind::Expr(e) = stmt.kind + { (e, !stmts.is_empty() || expr.is_some()) } else { return; diff --git a/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs b/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs index e9e215e66..deb21894f 100644 --- a/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs +++ b/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs @@ -23,7 +23,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if let Res::Def(_, pat_did) = pat_path.res; if match_def_path(cx, pat_did, &paths::OPTION_SOME); // check for call to `Iterator::next` - if let ExprKind::MethodCall(method_name, [iter_expr], _) = let_expr.kind; + if let ExprKind::MethodCall(method_name, iter_expr, [], _) = let_expr.kind; if method_name.ident.name == sym::next; if is_trait_method(cx, let_expr, sym::Iterator); if let Some(iter_expr_struct) = try_parse_iter_expr(cx, iter_expr); @@ -356,7 +356,7 @@ fn needs_mutable_borrow(cx: &LateContext<'_>, iter_expr: &IterExpr, loop_expr: & after_loop: false, used_iter: false, }; - v.visit_expr(&cx.tcx.hir().body(cx.enclosing_body.unwrap()).value); + v.visit_expr(cx.tcx.hir().body(cx.enclosing_body.unwrap()).value); v.used_iter } } |