forge_lint/sol/analysis/
primitives.rs1use solar::{
4 ast::LitKind,
5 interface::{Symbol, kw, sym},
6 sema::hir::{self, ElementaryType, Expr, ExprKind, Res, Stmt, StmtKind, TypeKind, VariableId},
7};
8
9fn is_builtin(expr: &Expr<'_>, name: Symbol) -> bool {
11 matches!(&expr.peel_parens().kind, ExprKind::Ident(reses)
12 if reses.iter().any(|r| matches!(r, Res::Builtin(b) if b.name() == name)))
13}
14
15pub fn is_address_type(hir: &hir::Hir<'_>, vid: VariableId) -> bool {
17 matches!(hir.variable(vid).ty.kind, TypeKind::Elementary(ElementaryType::Address(_)))
18}
19
20pub fn is_require_or_assert(callee: &Expr<'_>) -> bool {
22 matches!(&callee.kind, ExprKind::Ident(reses)
23 if reses.iter().any(|r| matches!(r,
24 Res::Builtin(b) if b.name() == sym::require || b.name() == sym::assert)))
25}
26
27pub fn address_call_receiver<'a>(callee: &'a Expr<'a>) -> Option<&'a Expr<'a>> {
30 let inner = match &callee.kind {
32 ExprKind::Call(inner, ..) => inner,
33 _ => callee,
34 };
35 let target = if matches!(inner.kind, ExprKind::Member(..)) { inner } else { callee };
36 if let ExprKind::Member(receiver, name) = &target.kind {
37 let n = name.name;
38 if n == kw::Call || n == kw::Delegatecall || n == sym::transfer || n == sym::send {
39 return Some(receiver);
40 }
41 }
42 None
43}
44
45pub fn branch_always_exits(stmt: &Stmt<'_>) -> bool {
50 match &stmt.kind {
51 StmtKind::Return(_) | StmtKind::Revert(_) => true,
52 StmtKind::Expr(expr) => is_exit_call(expr),
53 StmtKind::Block(b) | StmtKind::UncheckedBlock(b) => b.stmts.iter().any(branch_always_exits),
54 StmtKind::If(_, t, Some(e)) => branch_always_exits(t) && branch_always_exits(e),
55 _ => false,
56 }
57}
58
59fn is_exit_call(expr: &Expr<'_>) -> bool {
60 let ExprKind::Call(callee, args, _) = &expr.kind else { return false };
61 if is_builtin(callee, kw::Revert) {
62 return true;
63 }
64 if is_require_or_assert(callee)
65 && let Some(first) = args.exprs().next()
66 && matches!(
67 &first.peel_parens().kind,
68 ExprKind::Lit(lit) if matches!(lit.kind, LitKind::Bool(false))
69 )
70 {
71 return true;
72 }
73 false
74}