solar_sema/hir/
visit.rs

1use super::*;
2use std::ops::ControlFlow;
3
4solar_macros::declare_visitors! {
5/// HIR traversal.
6pub trait Visit<'hir> {
7    /// The value returned when breaking from the traversal.
8    ///
9    /// This can be [`Never`](solar_data_structures::Never) to indicate that the traversal
10    /// should never break.
11    type BreakValue;
12
13    /// Returns the HIR map.
14    fn hir(&self) -> &'hir Hir<'hir>;
15
16    fn visit_nested_source(&mut self, id: SourceId) -> ControlFlow<Self::BreakValue>{
17        visit_nested_items(self, self.hir().source(id).items)
18    }
19
20    fn visit_nested_item(&mut self, id: ItemId) -> ControlFlow<Self::BreakValue> {
21        match id {
22            ItemId::Contract(id) => self.visit_nested_contract(id),
23            ItemId::Function(id) => self.visit_nested_function(id),
24            ItemId::Struct(_id) => ControlFlow::Continue(()), // TODO
25            ItemId::Enum(_id) => ControlFlow::Continue(()), // TODO
26            ItemId::Udvt(_id) => ControlFlow::Continue(()), // TODO
27            ItemId::Error(_id) => ControlFlow::Continue(()), // TODO
28            ItemId::Event(_id) => ControlFlow::Continue(()), // TODO
29            ItemId::Variable(id) => self.visit_nested_var(id),
30        }
31    }
32
33    fn visit_item(&mut self, item: Item<'hir, 'hir>) -> ControlFlow<Self::BreakValue> {
34        match item {
35            Item::Contract(item) => self.visit_contract(item),
36            Item::Function(item) => self.visit_function(item),
37            Item::Struct(_item) => ControlFlow::Continue(()), // TODO
38            Item::Enum(_item) => ControlFlow::Continue(()), // TODO
39            Item::Udvt(_item) => ControlFlow::Continue(()), // TODO
40            Item::Error(_item) => ControlFlow::Continue(()), // TODO
41            Item::Event(_item) => ControlFlow::Continue(()), // TODO
42            Item::Variable(item) => self.visit_var(item),
43        }
44    }
45
46    fn visit_nested_contract(&mut self, id: ContractId) -> ControlFlow<Self::BreakValue> {
47        self.visit_contract(self.hir().contract(id))
48    }
49
50    fn visit_contract(&mut self, contract: &'hir Contract<'hir>) -> ControlFlow<Self::BreakValue> {
51        for base in contract.bases_args {
52            self.visit_modifier(base)?;
53        }
54        visit_nested_items(self, contract.items)
55    }
56
57    fn visit_nested_function(&mut self, id: FunctionId) -> ControlFlow<Self::BreakValue> {
58        self.visit_function(self.hir().function(id))
59    }
60
61    fn visit_function(&mut self, func: &'hir Function<'hir>) -> ControlFlow<Self::BreakValue> {
62        let Function { source: _, contract: _, span: _, name: _, kind: _, visibility: _, state_mutability: _, modifiers, marked_virtual: _, virtual_: _, override_: _, overrides: _, parameters, returns, body, body_span: _, gettee: _ } = func;
63        for &param in parameters.iter() {
64            self.visit_nested_var(param)?;
65        }
66        for modifier in modifiers.iter() {
67            self.visit_modifier(modifier)?;
68        }
69        for &ret in returns.iter() {
70            self.visit_nested_var(ret)?;
71        }
72        if let Some(body) = body {
73            for stmt in body.iter() {
74                self.visit_stmt(stmt)?;
75            }
76        }
77        ControlFlow::Continue(())
78    }
79
80    fn visit_modifier(&mut self, modifier: &'hir Modifier<'hir>) -> ControlFlow<Self::BreakValue> {
81        let Modifier { span: _, id: _, args } = modifier;
82        self.visit_call_args(args)
83    }
84
85    fn visit_nested_var(&mut self, id: VariableId) -> ControlFlow<Self::BreakValue> {
86        self.visit_var(self.hir().variable(id))
87    }
88
89    fn visit_var(&mut self, var: &'hir Variable<'hir>) -> ControlFlow<Self::BreakValue> {
90        self.visit_ty(&var.ty)?;
91        if let Some(expr) = var.initializer {
92            self.visit_expr(expr)?;
93        }
94        ControlFlow::Continue(())
95    }
96
97    fn visit_expr(&mut self, expr: &'hir Expr<'hir>) -> ControlFlow<Self::BreakValue> {
98        match expr.kind {
99            ExprKind::Call(expr, ref args, opts) => {
100                self.visit_expr(expr)?;
101                if let Some(opts) = opts {
102                    for opt in opts {
103                        self.visit_expr(&opt.value)?;
104                    }
105                }
106                self.visit_call_args(args)?;
107            }
108            ExprKind::Delete(expr)
109            | ExprKind::Member(expr, _)
110            | ExprKind::Payable(expr)
111            | ExprKind::Unary(_, expr) => self.visit_expr(expr)?,
112            ExprKind::Assign(lhs, _, rhs) | ExprKind::Binary(lhs, _, rhs) => {
113                self.visit_expr(lhs)?;
114                self.visit_expr(rhs)?;
115            }
116            ExprKind::Index(expr, index) => {
117                self.visit_expr(expr)?;
118                if let Some(index) = index {
119                    self.visit_expr(index)?;
120                }
121            }
122            ExprKind::Slice(expr, start, end) => {
123                self.visit_expr(expr)?;
124                if let Some(start) = start {
125                    self.visit_expr(start)?;
126                }
127                if let Some(end) = end {
128                    self.visit_expr(end)?;
129                }
130            }
131            ExprKind::Ternary(cond, true_, false_) => {
132                self.visit_expr(cond)?;
133                self.visit_expr(true_)?;
134                self.visit_expr(false_)?;
135            }
136            ExprKind::Array(exprs) => {
137                for expr in exprs {
138                    self.visit_expr(expr)?;
139                }
140            }
141            ExprKind::Tuple(exprs) => {
142                exprs.iter().copied().flatten().try_for_each(|expr| self.visit_expr(expr))?;
143            }
144            ExprKind::Ident(_) => {}
145            ExprKind::Lit(_) => {}
146            ExprKind::New(ref ty) | ExprKind::TypeCall(ref ty) | ExprKind::Type(ref ty) => {
147                self.visit_ty(ty)?;
148            }
149            ExprKind::Err(_guar) => {}
150        }
151        ControlFlow::Continue(())
152    }
153
154    fn visit_call_args(&mut self, args: &'hir CallArgs<'hir>) -> ControlFlow<Self::BreakValue> {
155        let CallArgs { span: _, kind } = args;
156        for expr in kind.exprs() {
157            self.visit_expr(expr)?;
158        }
159        ControlFlow::Continue(())
160    }
161
162    fn visit_stmt(&mut self, stmt: &'hir Stmt<'hir>) -> ControlFlow<Self::BreakValue> {
163        match stmt.kind {
164            StmtKind::DeclSingle(var) => self.visit_nested_var(var)?,
165            StmtKind::DeclMulti(vars, expr) => {
166                for &var in vars {
167                    if let Some(var) = var {
168                        self.visit_nested_var(var)?;
169                    }
170                }
171                self.visit_expr(expr)?;
172            }
173            StmtKind::Block(block) | StmtKind::UncheckedBlock(block) | StmtKind::Loop(block, _) => {
174                for stmt in block.stmts {
175                    self.visit_stmt(stmt)?;
176                }
177            }
178            StmtKind::Emit(expr) => self.visit_expr(expr)?,
179            StmtKind::Revert(expr) => self.visit_expr(expr)?,
180            StmtKind::Return(expr) => {
181                if let Some(expr) = expr {
182                    self.visit_expr(expr)?;
183                }
184            }
185            StmtKind::Break => {}
186            StmtKind::Continue => {}
187            StmtKind::If(cond, true_, false_) => {
188                self.visit_expr(cond)?;
189                self.visit_stmt(true_)?;
190                if let Some(false_) = false_ {
191                    self.visit_stmt(false_)?;
192                }
193            }
194            StmtKind::Try(try_) => {
195                self.visit_expr(&try_.expr)?;
196                for clause in try_.clauses {
197                    for &var in clause.args {
198                        self.visit_nested_var(var)?;
199                    }
200                    for stmt in clause.block.iter() {
201                        self.visit_stmt(stmt)?;
202                    }
203                }
204            }
205            StmtKind::Expr(expr) => self.visit_expr(expr)?,
206            StmtKind::Placeholder => {}
207            StmtKind::Err(_guar) => {}
208        }
209        ControlFlow::Continue(())
210    }
211
212    fn visit_ty(&mut self, ty: &'hir Type<'hir>) -> ControlFlow<Self::BreakValue> {
213        match ty.kind {
214            TypeKind::Elementary(_) => {}
215            TypeKind::Array(arr) => {
216                self.visit_ty(&arr.element)?;
217                if let Some(len) = arr.size {
218                    self.visit_expr(len)?;
219                }
220            }
221            TypeKind::Function(func) => {
222                for &param in func.parameters {
223                    self.visit_nested_var(param)?;
224                }
225                for &ret in func.returns {
226                    self.visit_nested_var(ret)?;
227                }
228            }
229            TypeKind::Mapping(map) => {
230                self.visit_ty(&map.key)?;
231                self.visit_ty(&map.value)?;
232            }
233            TypeKind::Custom(_) => {}
234            TypeKind::Err(_guar) => {}
235        }
236        ControlFlow::Continue(())
237    }
238}
239}
240
241fn visit_nested_items<'hir, V: Visit<'hir> + ?Sized>(
242    v: &mut V,
243    ids: &[ItemId],
244) -> ControlFlow<V::BreakValue> {
245    ids.iter().try_for_each(|&id| v.visit_nested_item(id))
246}