forge_lint/sol/high/
incorrect_shift.rs1use super::IncorrectShift;
2use crate::{
3 linter::{EarlyLintPass, LintContext},
4 sol::{Severity, SolLint},
5};
6use solar::{
7 ast::{Stmt, StmtKind, yul},
8 interface::kw,
9};
10
11declare_forge_lint!(
12 INCORRECT_SHIFT,
13 Severity::High,
14 "incorrect-shift",
15 "the order of args in a shift operation is incorrect"
16);
17
18impl<'ast> EarlyLintPass<'ast> for IncorrectShift {
19 fn check_stmt(&mut self, ctx: &LintContext, stmt: &'ast Stmt<'ast>) {
20 if let StmtKind::Assembly(assembly) = &stmt.kind {
21 check_yul_block(ctx, &assembly.block);
22 }
23 }
24}
25
26fn check_yul_block(ctx: &LintContext, block: &yul::Block<'_>) {
27 for stmt in block.stmts.iter() {
28 check_yul_stmt(ctx, stmt);
29 }
30}
31
32fn check_yul_stmt(ctx: &LintContext, stmt: &yul::Stmt<'_>) {
33 match &stmt.kind {
34 yul::StmtKind::Block(block) => check_yul_block(ctx, block),
35 yul::StmtKind::AssignSingle(_, expr)
36 | yul::StmtKind::AssignMulti(_, expr)
37 | yul::StmtKind::Expr(expr) => check_yul_expr(ctx, expr),
38 yul::StmtKind::If(cond, block) => {
39 check_yul_expr(ctx, cond);
40 check_yul_block(ctx, block);
41 }
42 yul::StmtKind::For(for_stmt) => {
43 check_yul_block(ctx, &for_stmt.init);
44 check_yul_expr(ctx, &for_stmt.cond);
45 check_yul_block(ctx, &for_stmt.step);
46 check_yul_block(ctx, &for_stmt.body);
47 }
48 yul::StmtKind::Switch(switch) => {
49 check_yul_expr(ctx, &switch.selector);
50 for case in switch.cases.iter() {
51 check_yul_block(ctx, &case.body);
52 }
53 }
54 yul::StmtKind::FunctionDef(func) => check_yul_block(ctx, &func.body),
55 yul::StmtKind::VarDecl(_, Some(init)) => check_yul_expr(ctx, init),
56 yul::StmtKind::Leave
57 | yul::StmtKind::Break
58 | yul::StmtKind::Continue
59 | yul::StmtKind::VarDecl(_, None) => {}
60 }
61}
62
63fn check_yul_expr(ctx: &LintContext, expr: &yul::Expr<'_>) {
64 let yul::ExprKind::Call(call) = &expr.kind else { return };
65
66 if matches!(call.name.name, kw::Shl | kw::Shr | kw::Sar)
67 && let [left, right] = call.arguments.as_ref()
68 && !matches!(left.kind, yul::ExprKind::Lit(_))
69 && matches!(right.kind, yul::ExprKind::Lit(_))
70 {
71 ctx.emit(&INCORRECT_SHIFT, expr.span);
72 }
73
74 for arg in call.arguments.iter() {
75 check_yul_expr(ctx, arg);
76 }
77}