about summary refs log tree commit diff
path: root/clippy_lints/src/loops
diff options
context:
space:
mode:
authorPhilipp Krones <hello@philkrones.com>2024-10-18 13:44:06 +0200
committerPhilipp Krones <hello@philkrones.com>2024-10-18 13:44:06 +0200
commitfea5e77da1dedea3a64711cb1b75c141e72ba248 (patch)
tree56cd01b028792c518439c83fa9db698b8350f184 /clippy_lints/src/loops
parentc512a221c23f3f7b98a38ab5fd81784b318d1663 (diff)
Merge commit 'a109190d7060236e655fc75533373fa274ec5343' into clippy-subtree-update
Diffstat (limited to 'clippy_lints/src/loops')
-rw-r--r--clippy_lints/src/loops/infinite_loop.rs19
-rw-r--r--clippy_lints/src/loops/manual_while_let_some.rs11
-rw-r--r--clippy_lints/src/loops/same_item_push.rs6
3 files changed, 25 insertions, 11 deletions
diff --git a/clippy_lints/src/loops/infinite_loop.rs b/clippy_lints/src/loops/infinite_loop.rs
index 858e3be5093..e25c03db534 100644
--- a/clippy_lints/src/loops/infinite_loop.rs
+++ b/clippy_lints/src/loops/infinite_loop.rs
@@ -42,6 +42,7 @@ pub(super) fn check<'tcx>(
     let mut loop_visitor = LoopVisitor {
         cx,
         label,
+        inner_labels: label.into_iter().collect(),
         is_finite: false,
         loop_depth: 0,
     };
@@ -93,6 +94,7 @@ fn get_parent_fn_ret_ty<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>) -> Option
 struct LoopVisitor<'hir, 'tcx> {
     cx: &'hir LateContext<'tcx>,
     label: Option<Label>,
+    inner_labels: Vec<Label>,
     loop_depth: usize,
     is_finite: bool,
 }
@@ -108,11 +110,24 @@ impl<'hir> Visitor<'hir> for LoopVisitor<'hir, '_> {
                     self.is_finite = true;
                 }
             },
+            ExprKind::Continue(hir::Destination { label, .. }) => {
+                // Check whether we are leaving this loop by continuing into an outer loop
+                // whose label we did not encounter.
+                if label.is_some_and(|label| !self.inner_labels.contains(&label)) {
+                    self.is_finite = true;
+                }
+            },
             ExprKind::Ret(..) => self.is_finite = true,
-            ExprKind::Loop(..) => {
+            ExprKind::Loop(_, label, _, _) => {
+                if let Some(label) = label {
+                    self.inner_labels.push(*label);
+                }
                 self.loop_depth += 1;
                 walk_expr(self, ex);
-                self.loop_depth = self.loop_depth.saturating_sub(1);
+                self.loop_depth -= 1;
+                if label.is_some() {
+                    self.inner_labels.pop();
+                }
             },
             _ => {
                 // Calls to a function that never return
diff --git a/clippy_lints/src/loops/manual_while_let_some.rs b/clippy_lints/src/loops/manual_while_let_some.rs
index 7476a87267f..4473a3343c7 100644
--- a/clippy_lints/src/loops/manual_while_let_some.rs
+++ b/clippy_lints/src/loops/manual_while_let_some.rs
@@ -47,8 +47,9 @@ fn report_lint(cx: &LateContext<'_>, pop_span: Span, pop_stmt_kind: PopStmt<'_>,
     );
 }
 
-fn match_method_call(cx: &LateContext<'_>, expr: &Expr<'_>, method: Symbol) -> bool {
-    if let ExprKind::MethodCall(..) = expr.kind
+fn match_method_call<const ARGS_COUNT: usize>(cx: &LateContext<'_>, expr: &Expr<'_>, method: Symbol) -> bool {
+    if let ExprKind::MethodCall(_, _, args, _) = expr.kind
+        && args.len() == ARGS_COUNT
         && let Some(id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
     {
         cx.tcx.is_diagnostic_item(method, id)
@@ -58,9 +59,9 @@ fn match_method_call(cx: &LateContext<'_>, expr: &Expr<'_>, method: Symbol) -> b
 }
 
 fn is_vec_pop_unwrap(cx: &LateContext<'_>, expr: &Expr<'_>, is_empty_recv: &Expr<'_>) -> bool {
-    if (match_method_call(cx, expr, sym::option_unwrap) || match_method_call(cx, expr, sym::option_expect))
+    if (match_method_call::<0>(cx, expr, sym::option_unwrap) || match_method_call::<1>(cx, expr, sym::option_expect))
         && let ExprKind::MethodCall(_, unwrap_recv, ..) = expr.kind
-        && match_method_call(cx, unwrap_recv, sym::vec_pop)
+        && match_method_call::<0>(cx, unwrap_recv, sym::vec_pop)
         && let ExprKind::MethodCall(_, pop_recv, ..) = unwrap_recv.kind
     {
         // make sure they're the same `Vec`
@@ -96,7 +97,7 @@ fn check_call_arguments(cx: &LateContext<'_>, stmt: &Stmt<'_>, is_empty_recv: &E
 pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, full_cond: &'tcx Expr<'_>, body: &'tcx Expr<'_>, loop_span: Span) {
     if let ExprKind::Unary(UnOp::Not, cond) = full_cond.kind
         && let ExprKind::MethodCall(_, is_empty_recv, _, _) = cond.kind
-        && match_method_call(cx, cond, sym::vec_is_empty)
+        && match_method_call::<0>(cx, cond, sym::vec_is_empty)
         && let ExprKind::Block(body, _) = body.kind
         && let Some(stmt) = body.stmts.first()
     {
diff --git a/clippy_lints/src/loops/same_item_push.rs b/clippy_lints/src/loops/same_item_push.rs
index f8659897ffe..d255fea3af2 100644
--- a/clippy_lints/src/loops/same_item_push.rs
+++ b/clippy_lints/src/loops/same_item_push.rs
@@ -172,10 +172,8 @@ fn get_vec_push<'tcx>(
     stmt: &'tcx Stmt<'_>,
 ) -> Option<(&'tcx Expr<'tcx>, &'tcx Expr<'tcx>, SyntaxContext)> {
     if let StmtKind::Semi(semi_stmt) = &stmt.kind
-            // Extract method being called
-            && let ExprKind::MethodCall(path, self_expr, args, _) = &semi_stmt.kind
-            // Figure out the parameters for the method call
-            && let Some(pushed_item) = args.first()
+            // Extract method being called and figure out the parameters for the method call
+            && let ExprKind::MethodCall(path, self_expr, [pushed_item], _) = &semi_stmt.kind
             // Check that the method being called is push() on a Vec
             && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(self_expr), sym::Vec)
             && path.ident.name.as_str() == "push"