forge_lint/sol/med/
div_mul.rs

1use super::DivideBeforeMultiply;
2use crate::{
3    linter::{EarlyLintPass, LintContext},
4    sol::{Severity, SolLint},
5};
6use solar_ast::{BinOp, BinOpKind, Expr, ExprKind};
7
8declare_forge_lint!(
9    DIVIDE_BEFORE_MULTIPLY,
10    Severity::Med,
11    "divide-before-multiply",
12    "multiplication should occur before division to avoid loss of precision"
13);
14
15impl<'ast> EarlyLintPass<'ast> for DivideBeforeMultiply {
16    fn check_expr(&mut self, ctx: &LintContext<'_>, expr: &'ast Expr<'ast>) {
17        if let ExprKind::Binary(left_expr, BinOp { kind: BinOpKind::Mul, .. }, _) = &expr.kind
18            && contains_division(left_expr)
19        {
20            ctx.emit(&DIVIDE_BEFORE_MULTIPLY, expr.span);
21        }
22    }
23}
24
25fn contains_division<'ast>(expr: &'ast Expr<'ast>) -> bool {
26    match &expr.kind {
27        ExprKind::Binary(_, BinOp { kind: BinOpKind::Div, .. }, _) => true,
28        ExprKind::Tuple(inner_exprs) => inner_exprs.iter().any(|opt_expr| {
29            if let Some(inner_expr) = opt_expr { contains_division(inner_expr) } else { false }
30        }),
31        _ => false,
32    }
33}