]> git.lizzy.rs Git - rust.git/commitdiff
fix logic in IncrementVisitor
authorEric Wu <eric.dianhao.wu@gmail.com>
Fri, 16 Dec 2022 15:22:29 +0000 (10:22 -0500)
committerEric Wu <eric.dianhao.wu@gmail.com>
Fri, 16 Dec 2022 15:54:12 +0000 (10:54 -0500)
There used to be a logical bug where IncrementVisitor would
completely stop checking an expression/block after seeing a continue
statement. This led to issue #10058 where a variable incremented
(or otherwise modified) after any continue statement would still be
considered incremented only once.

The solution is to continue scanning the expression after seeing a
`continue` statement, but increment self.depth so that the Visitor
thinks that the rest of the loop is within a conditional.

clippy_lints/src/loops/utils.rs
tests/ui/explicit_counter_loop.rs

index b6f4cf7bbb37f149eccda55bbc0ef40b2f08def9..28ee24309cc467e57c6f374f8b0d86a314134d57 100644 (file)
@@ -25,7 +25,6 @@ pub(super) struct IncrementVisitor<'a, 'tcx> {
     cx: &'a LateContext<'tcx>,                  // context reference
     states: HirIdMap<IncrementVisitorVarState>, // incremented variables
     depth: u32,                                 // depth of conditional expressions
-    done: bool,
 }
 
 impl<'a, 'tcx> IncrementVisitor<'a, 'tcx> {
@@ -34,7 +33,6 @@ pub(super) fn new(cx: &'a LateContext<'tcx>) -> Self {
             cx,
             states: HirIdMap::default(),
             depth: 0,
-            done: false,
         }
     }
 
@@ -51,10 +49,6 @@ pub(super) fn into_results(self) -> impl Iterator<Item = HirId> {
 
 impl<'a, 'tcx> Visitor<'tcx> for IncrementVisitor<'a, 'tcx> {
     fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
-        if self.done {
-            return;
-        }
-
         // If node is a variable
         if let Some(def_id) = path_to_local(expr) {
             if let Some(parent) = get_parent_expr(self.cx, expr) {
@@ -95,7 +89,9 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
             walk_expr(self, expr);
             self.depth -= 1;
         } else if let ExprKind::Continue(_) = expr.kind {
-            self.done = true;
+            // If we see a `continue` block, then we increment depth so that the IncrementVisitor
+            // state will be set to DontWarn if we see the variable being modified anywhere afterwards.
+            self.depth += 1;
         } else {
             walk_expr(self, expr);
         }
index 6eddc01e2c471215af0fa4584f5083e5a1eec796..46565a97f005979b3bc03a5a4555d41a8c2ac0cc 100644 (file)
@@ -189,3 +189,33 @@ pub fn test() {
         }
     }
 }
+
+mod issue_10058 {
+    pub fn test() {
+        // should not lint since we are increasing counter potentially more than once in the loop
+        let values = [0, 1, 0, 1, 1, 1, 0, 1, 0, 1];
+        let mut counter = 0;
+        for value in values {
+            counter += 1;
+
+            if value == 0 {
+                continue;
+            }
+
+            counter += 1;
+        }
+    }
+
+    pub fn test2() {
+        // should not lint since we are increasing counter potentially more than once in the loop
+        let values = [0, 1, 0, 1, 1, 1, 0, 1, 0, 1];
+        let mut counter = 0;
+        for value in values {
+            counter += 1;
+
+            if value != 0 {
+                counter += 1;
+            }
+        }
+    }
+}