forge_lint/sol/med/
incorrect_strict_equality.rs1use super::IncorrectStrictEquality;
2use crate::{
3 linter::{LateLintPass, LintContext},
4 sol::{Severity, SolLint, analysis::referenced_item},
5};
6use solar::{
7 ast::BinOpKind,
8 sema::{
9 Gcx,
10 builtins::Builtin,
11 hir::{Expr, ExprKind, ItemId},
12 },
13};
14use std::ops::ControlFlow;
15
16declare_forge_lint!(
17 INCORRECT_STRICT_EQUALITY,
18 Severity::Med,
19 "incorrect-strict-equality",
20 "dangerous strict equality check on an externally-influenced value"
21);
22
23impl<'gcx> LateLintPass<'gcx> for IncorrectStrictEquality {
24 fn check_expr(&mut self, ctx: &LintContext, gcx: Gcx<'gcx>, expr: &'gcx Expr<'gcx>) {
25 if let ExprKind::Binary(lhs, op, rhs) = &expr.kind
26 && matches!(op.kind, BinOpKind::Eq | BinOpKind::Ne)
27 && [lhs, rhs].into_iter().any(|side| {
28 side.visit(&mut |e| {
29 if is_externally_influenced(gcx, e) {
30 ControlFlow::Break(())
31 } else {
32 ControlFlow::Continue(())
33 }
34 })
35 .is_break()
36 })
37 {
38 ctx.emit(&INCORRECT_STRICT_EQUALITY, expr.span);
39 }
40 }
41}
42
43fn is_externally_influenced<'gcx>(gcx: Gcx<'gcx>, expr: &Expr<'gcx>) -> bool {
49 match &expr.peel_parens().kind {
50 ExprKind::Member(..) => gcx.resolved_builtin(expr) == Some(Builtin::AddressBalance),
51 ExprKind::Call(callee, ..) => {
52 matches!(&callee.peel_parens().kind, ExprKind::Member(base, m)
53 if m.as_str() == "balanceOf"
54 && !matches!(referenced_item(gcx, base), Some(ItemId::Contract(cid))
55 if gcx.hir.contract(cid).kind.is_library()))
56 }
57 _ => false,
58 }
59}