Skip to content

Commit

Permalink
Improvement on divide before multiply detector
Browse files Browse the repository at this point in the history
  • Loading branch information
arlosiggio committed Aug 9, 2023
1 parent 2459305 commit 94d4e3c
Showing 1 changed file with 33 additions and 47 deletions.
80 changes: 33 additions & 47 deletions detectors/divide-before-multiply/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,68 +38,54 @@ dylint_linting::declare_late_lint! {
"Division should be performed after multiplication"
}

impl<'tcx> LateLintPass<'tcx> for DivideBeforeMultiply {
fn check_fn(
&mut self,
cx: &LateContext<'tcx>,
_: rustc_hir::intravisit::FnKind<'tcx>,
_: &'tcx rustc_hir::FnDecl<'tcx>,
body: &'tcx rustc_hir::Body<'tcx>,
_: Span,
_: rustc_hir::HirId,
) {
struct DivideBeforeMultiplyVisitor {
has_multiplication: bool,
is_precision_loss: bool,
is_precision_loss_span: Vec<Option<Span>>,
}
fn get_divisions_inside_expr<'tcx>(expr: &'tcx Expr<'_>) -> Vec<Span> {
struct DivisionsInsideExpr {
divisions: Vec<Span>,
}

impl<'tcx> Visitor<'tcx> for DivideBeforeMultiplyVisitor {
fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
if_chain! {
if let ExprKind::Binary(binop, _, _) = expr.kind;
if let BinOpKind::Mul = binop.node;
then {
self.has_multiplication = true;
walk_expr(self, expr);
}
impl<'tcx> Visitor<'tcx> for DivisionsInsideExpr {
fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
if_chain! {
if let ExprKind::Binary(op, _lexpr, _rexpr) = expr.kind;
if BinOpKind::Div == op.node;
then{
self.divisions.push(expr.span);
}

if_chain!(
if self.has_multiplication;
if let ExprKind::Binary(binop, _, _) = expr.kind;
if let BinOpKind::Div = binop.node;
then {
self.is_precision_loss = true;
self.is_precision_loss_span.push(Some(expr.span));
}
);

walk_expr(self, expr);
}
walk_expr(self, expr);
}
}

let mut visitor = DivisionsInsideExpr {
divisions: Vec::default(),
};

let mut visitor = DivideBeforeMultiplyVisitor {
has_multiplication: false,
is_precision_loss: false,
is_precision_loss_span: Vec::new(),
};
walk_expr(&mut visitor, expr);

walk_expr(&mut visitor, body.value);
return visitor.divisions;
}

if visitor.is_precision_loss {
visitor.is_precision_loss_span.iter().for_each(|span| {
if let Some(span) = span {
impl<'tcx> LateLintPass<'tcx> for DivideBeforeMultiply {
fn check_expr(
&mut self,
cx: &LateContext<'tcx>,
expr: &'tcx rustc_hir::Expr<'tcx>
) {
if_chain! {
if let ExprKind::Binary(op, _lexpr, _rexpr) = expr.kind;
if BinOpKind::Mul == op.node;
then{
for division in get_divisions_inside_expr(expr) {
span_lint_and_help(
cx,
DIVIDE_BEFORE_MULTIPLY,
*span,
division,
"Division before multiplication might result in a loss of precision",
None,
"Consider reversing the order of operations to reduce the loss of precision.",
);
}
});
}
}
}
}
Expand Down

0 comments on commit 94d4e3c

Please sign in to comment.