11use super :: MissingZeroCheck ;
22use crate :: {
33 linter:: { LateLintPass , LintContext } ,
4- sol:: { Severity , SolLint } ,
4+ sol:: {
5+ Severity , SolLint ,
6+ analysis:: primitives:: {
7+ address_call_receiver, branch_always_exits, is_address_type, is_require_or_assert,
8+ } ,
9+ } ,
510} ;
611use solar:: {
712 ast,
8- interface:: { data_structures:: Never , kw , sym } ,
9- sema:: hir:: { self , ElementaryType , ExprKind , ItemId , Res , StmtKind , TypeKind , Visit } ,
13+ interface:: data_structures:: Never ,
14+ sema:: hir:: { self , ExprKind , ItemId , Res , StmtKind , Visit } ,
1015} ;
1116use std:: {
1217 collections:: { HashMap , HashSet } ,
@@ -32,7 +37,7 @@ impl<'hir> LateLintPass<'hir> for MissingZeroCheck {
3237 }
3338
3439 let params: HashSet < hir:: VariableId > =
35- func. parameters . iter ( ) . copied ( ) . filter ( |id| is_address ( hir, * id) ) . collect ( ) ;
40+ func. parameters . iter ( ) . copied ( ) . filter ( |id| is_address_type ( hir, * id) ) . collect ( ) ;
3641
3742 if params. is_empty ( ) {
3843 return ;
@@ -70,10 +75,6 @@ fn is_entry_point(func: &hir::Function<'_>) -> bool {
7075 && matches ! ( func. visibility, ast:: Visibility :: Public | ast:: Visibility :: External )
7176}
7277
73- fn is_address ( hir : & hir:: Hir < ' _ > , id : hir:: VariableId ) -> bool {
74- matches ! ( hir. variable( id) . ty. kind, TypeKind :: Elementary ( ElementaryType :: Address ( _) ) )
75- }
76-
7778/// Tracks address-parameter taint, sinks reached, and guards observed in a function body.
7879struct Analyzer < ' hir > {
7980 hir : & ' hir hir:: Hir < ' hir > ,
@@ -248,7 +249,7 @@ impl<'hir> Visit<'hir> for Analyzer<'hir> {
248249 StmtKind :: DeclSingle ( var_id) => {
249250 let v = self . hir . variable ( var_id) ;
250251 if let Some ( init) = v. initializer
251- && is_address ( self . hir , var_id)
252+ && is_address_type ( self . hir , var_id)
252253 {
253254 let srcs = self . taint_sources ( init) ;
254255 if !srcs. is_empty ( ) {
@@ -299,7 +300,7 @@ impl<'hir> Visit<'hir> for Analyzer<'hir> {
299300 }
300301 // Taint propagation: assignment to an address local.
301302 if let Some ( local) = lhs_local_var ( self . hir , lhs)
302- && is_address ( self . hir , local)
303+ && is_address_type ( self . hir , local)
303304 {
304305 let srcs = self . taint_sources ( rhs) ;
305306 if !srcs. is_empty ( ) {
@@ -334,60 +335,14 @@ impl<'hir> Visit<'hir> for Analyzer<'hir> {
334335 }
335336}
336337
337- fn is_require_or_assert ( callee : & hir:: Expr < ' _ > ) -> bool {
338- if let ExprKind :: Ident ( reses) = & callee. kind {
339- return reses. iter ( ) . any ( |r| {
340- if let Res :: Builtin ( b) = r {
341- let n = b. name ( ) ;
342- n == sym:: require || n == sym:: assert
343- } else {
344- false
345- }
346- } ) ;
347- }
348- false
349- }
350-
351- /// If `callee` is `<receiver>.{call,delegatecall,transfer,send}` (with or without
352- /// call options), returns the `<receiver>` expression.
353- fn address_call_receiver < ' hir > ( callee : & ' hir hir:: Expr < ' hir > ) -> Option < & ' hir hir:: Expr < ' hir > > {
354- // `addr.call{value: x}(..)` lowers as `Call(Member(receiver, "call"), ..)` — peel an
355- // outer call layer so the inner Member is reachable.
356- let inner = match & callee. kind {
357- ExprKind :: Call ( inner, ..) => inner,
358- _ => callee,
359- } ;
360- let target = if matches ! ( inner. kind, ExprKind :: Member ( ..) ) { inner } else { callee } ;
361- if let ExprKind :: Member ( receiver, name) = & target. kind {
362- let n = name. name ;
363- if n == kw:: Call || n == kw:: Delegatecall || n == sym:: transfer || n == sym:: send {
364- return Some ( receiver) ;
365- }
366- }
367- None
368- }
369-
370- fn branch_always_exits ( stmt : & hir:: Stmt < ' _ > ) -> bool {
371- match & stmt. kind {
372- StmtKind :: Return ( _) | StmtKind :: Revert ( _) => true ,
373- StmtKind :: Block ( block) | StmtKind :: UncheckedBlock ( block) => {
374- block. stmts . last ( ) . is_some_and ( branch_always_exits)
375- }
376- StmtKind :: If ( _, t, Some ( e) ) => branch_always_exits ( t) && branch_always_exits ( e) ,
377- _ => false ,
378- }
379- }
380-
381338fn is_address_state_var_lhs ( hir : & hir:: Hir < ' _ > , lhs : & hir:: Expr < ' _ > ) -> bool {
382339 if let ExprKind :: Ident ( reses) = & lhs. kind {
383340 for res in * reses {
384- if let Res :: Item ( ItemId :: Variable ( vid) ) = res {
385- let v = hir. variable ( * vid) ;
386- if v. kind . is_state ( )
387- && matches ! ( v. ty. kind, TypeKind :: Elementary ( ElementaryType :: Address ( _) ) )
388- {
389- return true ;
390- }
341+ if let Res :: Item ( ItemId :: Variable ( vid) ) = res
342+ && hir. variable ( * vid) . kind . is_state ( )
343+ && is_address_type ( hir, * vid)
344+ {
345+ return true ;
391346 }
392347 }
393348 }
0 commit comments