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}