about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--clippy_lints/src/casts/cast_sign_loss.rs30
1 files changed, 18 insertions, 12 deletions
diff --git a/clippy_lints/src/casts/cast_sign_loss.rs b/clippy_lints/src/casts/cast_sign_loss.rs
index db7121928fe..20a7cbd4a1b 100644
--- a/clippy_lints/src/casts/cast_sign_loss.rs
+++ b/clippy_lints/src/casts/cast_sign_loss.rs
@@ -1,5 +1,8 @@
+use std::ops::ControlFlow;
+
 use clippy_utils::consts::{constant, Constant};
 use clippy_utils::diagnostics::span_lint;
+use clippy_utils::visitors::{for_each_expr, Descend};
 use clippy_utils::{method_chain_args, sext};
 use rustc_hir::{BinOpKind, Expr, ExprKind};
 use rustc_lint::LateContext;
@@ -216,34 +219,37 @@ fn expr_muldiv_sign(cx: &LateContext<'_>, expr: &Expr<'_>) -> Sign {
 ///
 /// Expressions using other operators are preserved, so we can try to evaluate them later.
 fn exprs_with_muldiv_binop_peeled<'e>(expr: &'e Expr<'_>) -> Vec<&'e Expr<'e>> {
-    #[inline]
-    fn collect_operands<'e>(expr: &'e Expr<'e>, operands: &mut Vec<&'e Expr<'e>>) {
-        match expr.kind {
-            ExprKind::Binary(op, lhs, rhs) => {
+    let mut res = vec![];
+
+    for_each_expr(expr, |sub_expr| {
+        match sub_expr.kind {
+            ExprKind::Binary(op, lhs, _rhs) => {
                 if matches!(op.node, BinOpKind::Mul | BinOpKind::Div) {
                     // For binary operators which both contribute to the sign of the result,
                     // collect all their operands, recursively. This ignores overflow.
-                    collect_operands(lhs, operands);
-                    collect_operands(rhs, operands);
+                    ControlFlow::Continue(Descend::Yes)
                 } else if matches!(op.node, BinOpKind::Rem) {
                     // For binary operators where the left hand side determines the sign of the result,
                     // only collect that side, recursively. Overflow panics, so this always holds.
                     //
                     // > Given remainder = dividend % divisor, the remainder will have the same sign as the dividend
                     // https://doc.rust-lang.org/reference/expressions/operator-expr.html#arithmetic-and-logical-binary-operators
-                    collect_operands(lhs, operands);
+                    res.push(lhs);
+                    ControlFlow::Break(())
                 } else {
                     // The sign of the result of other binary operators depends on the values of the operands,
                     // so try to evaluate the expression.
-                    operands.push(expr);
+                    res.push(expr);
+                    ControlFlow::Continue(Descend::No)
                 }
             },
             // For other expressions, including unary operators and constants, try to evaluate the expression.
-            _ => operands.push(expr),
+            _ => {
+                res.push(expr);
+                ControlFlow::Continue(Descend::No)
+            },
         }
-    }
+    });
 
-    let mut res = vec![];
-    collect_operands(expr, &mut res);
     res
 }