forge_lint/sol/med/
div_mul.rs

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