1use super::*;
2use std::ops::ControlFlow;
3
4solar_macros::declare_visitors! {
5pub trait Visit<'hir> {
7 type BreakValue;
12
13 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(()), ItemId::Enum(_id) => ControlFlow::Continue(()), ItemId::Udvt(_id) => ControlFlow::Continue(()), ItemId::Error(_id) => ControlFlow::Continue(()), ItemId::Event(_id) => ControlFlow::Continue(()), 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(()), Item::Enum(_item) => ControlFlow::Continue(()), Item::Udvt(_item) => ControlFlow::Continue(()), Item::Error(_item) => ControlFlow::Continue(()), Item::Event(_item) => ControlFlow::Continue(()), 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 ¶m 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 ¶m 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}