Use the visitor pattern instead of recusive functions
This commit is contained in:
parent
4ab2ed33a0
commit
740441fd98
@ -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
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user