solar_ast/
visit.rs

1//! Constant and mutable AST visitor trait definitions.
2
3use crate::ast::*;
4use solar_interface::{Ident, Span, Spanned, SpannedOption};
5use solar_macros::declare_visitors;
6use std::ops::ControlFlow;
7
8declare_visitors! {
9    /// AST traversal.
10    pub trait Visit VisitMut <'ast> {
11        /// The value returned when breaking from the traversal.
12        ///
13        /// This can be [`Never`](solar_data_structures::Never) to indicate that the traversal
14        /// should never break.
15        type BreakValue;
16
17        fn visit_source_unit(&mut self, source_unit: &'ast #mut SourceUnit<'ast>) -> ControlFlow<Self::BreakValue> {
18            let SourceUnit { items } = source_unit;
19            for item in items.iter #_mut() {
20                self.visit_item #_mut(item)?;
21            }
22            ControlFlow::Continue(())
23        }
24
25        fn visit_item(&mut self, item: &'ast #mut Item<'ast>) -> ControlFlow<Self::BreakValue> {
26            let Item { docs, span, kind } = item;
27            self.visit_span #_mut(span)?;
28            self.visit_doc_comments #_mut(docs)?;
29            match kind {
30                ItemKind::Pragma(item) => self.visit_pragma_directive #_mut(item)?,
31                ItemKind::Import(item) => self.visit_import_directive #_mut(item)?,
32                ItemKind::Using(item) => self.visit_using_directive #_mut(item)?,
33                ItemKind::Contract(item) => self.visit_item_contract #_mut(item)?,
34                ItemKind::Function(item) => self.visit_item_function #_mut(item)?,
35                ItemKind::Variable(item) => self.visit_variable_definition #_mut(item)?,
36                ItemKind::Struct(item) => self.visit_item_struct #_mut(item)?,
37                ItemKind::Enum(item) => self.visit_item_enum #_mut(item)?,
38                ItemKind::Udvt(item) => self.visit_item_udvt #_mut(item)?,
39                ItemKind::Error(item) => self.visit_item_error #_mut(item)?,
40                ItemKind::Event(item) => self.visit_item_event #_mut(item)?,
41            }
42            ControlFlow::Continue(())
43        }
44
45        fn visit_pragma_directive(&mut self, pragma: &'ast #mut PragmaDirective<'ast>) -> ControlFlow<Self::BreakValue> {
46            // noop by default.
47            let PragmaDirective { tokens: _ } = pragma;
48            ControlFlow::Continue(())
49        }
50
51        fn visit_import_directive(&mut self, import: &'ast #mut ImportDirective<'ast>) -> ControlFlow<Self::BreakValue> {
52            let ImportDirective { path, items } = import;
53            let _ = path; // TODO: ?
54            match items {
55                ImportItems::Plain(alias) => {
56                    if let Some(alias) = alias {
57                        self.visit_ident #_mut(alias)?;
58                    }
59                }
60                ImportItems::Aliases(paths) => {
61                    for (import, alias) in paths.iter #_mut() {
62                        self.visit_ident #_mut(import)?;
63                        if let Some(alias) = alias {
64                            self.visit_ident #_mut(alias)?;
65                        }
66                    }
67                }
68                ImportItems::Glob(alias) => {
69                    self.visit_ident #_mut(alias)?;
70                }
71            }
72            ControlFlow::Continue(())
73        }
74
75        fn visit_using_directive(&mut self, using: &'ast #mut UsingDirective<'ast>) -> ControlFlow<Self::BreakValue> {
76            let UsingDirective { list, ty, global: _ } = using;
77            match list {
78                UsingList::Single(path) => {
79                    self.visit_path #_mut(path)?;
80                }
81                UsingList::Multiple(paths) => {
82                    for (path, _) in paths.iter #_mut() {
83                        self.visit_path #_mut(path)?;
84                    }
85                }
86            }
87            if let Some(ty) = ty {
88                self.visit_ty #_mut(ty)?;
89            }
90            ControlFlow::Continue(())
91        }
92
93        fn visit_item_contract(&mut self, contract: &'ast #mut ItemContract<'ast>) -> ControlFlow<Self::BreakValue> {
94            let ItemContract { kind: _, name, layout, bases, body } = contract;
95            self.visit_ident #_mut(name)?;
96            if let Some(StorageLayoutSpecifier { span, slot }) = layout {
97                self.visit_span #_mut(span)?;
98                self.visit_expr #_mut(slot)?;
99            }
100            for base in bases.iter #_mut() {
101                self.visit_modifier #_mut(base)?;
102            }
103            for item in body.iter #_mut() {
104                self.visit_item #_mut(item)?;
105            }
106            ControlFlow::Continue(())
107        }
108
109        fn visit_item_function(&mut self, function: &'ast #mut ItemFunction<'ast>) -> ControlFlow<Self::BreakValue> {
110            let ItemFunction { kind: _, header, body, body_span } = function;
111            self.visit_function_header #_mut(header)?;
112            if let Some(body) = body {
113                self.visit_block #_mut(body)?;
114            }
115            self.visit_span #_mut(body_span)?;
116            ControlFlow::Continue(())
117        }
118
119        fn visit_item_struct(&mut self, strukt: &'ast #mut ItemStruct<'ast>) -> ControlFlow<Self::BreakValue> {
120            let ItemStruct { name, fields } = strukt;
121            self.visit_ident #_mut(name)?;
122            for field in fields.iter #_mut() {
123                self.visit_variable_definition #_mut(field)?;
124            }
125            ControlFlow::Continue(())
126        }
127
128        fn visit_item_enum(&mut self, enum_: &'ast #mut ItemEnum<'ast>) -> ControlFlow<Self::BreakValue> {
129            let ItemEnum { name, variants } = enum_;
130            self.visit_ident #_mut(name)?;
131            for variant in variants.iter #_mut() {
132                self.visit_ident #_mut(variant)?;
133            }
134            ControlFlow::Continue(())
135        }
136
137        fn visit_item_udvt(&mut self, udvt: &'ast #mut ItemUdvt<'ast>) -> ControlFlow<Self::BreakValue> {
138            let ItemUdvt { name, ty } = udvt;
139            self.visit_ident #_mut(name)?;
140            self.visit_ty #_mut(ty)?;
141            ControlFlow::Continue(())
142        }
143
144        fn visit_item_error(&mut self, error: &'ast #mut ItemError<'ast>) -> ControlFlow<Self::BreakValue> {
145            let ItemError { name, parameters } = error;
146            self.visit_ident #_mut(name)?;
147            self.visit_parameter_list #_mut(parameters)?;
148            ControlFlow::Continue(())
149        }
150
151        fn visit_item_event(&mut self, event: &'ast #mut ItemEvent<'ast>) -> ControlFlow<Self::BreakValue> {
152            let ItemEvent { name, parameters, anonymous: _ } = event;
153            self.visit_ident #_mut(name)?;
154            self.visit_parameter_list #_mut(parameters)?;
155            ControlFlow::Continue(())
156        }
157
158        fn visit_variable_definition(&mut self, var: &'ast #mut VariableDefinition<'ast>) -> ControlFlow<Self::BreakValue> {
159            let VariableDefinition {
160                span,
161                ty,
162                visibility: _,
163                mutability: _,
164                data_location: _,
165                override_: _,
166                indexed: _,
167                name,
168                initializer,
169            } = var;
170            self.visit_span #_mut(span)?;
171            self.visit_ty #_mut(ty)?;
172            if let Some(name) = name {
173                self.visit_ident #_mut(name)?;
174            }
175            if let Some(initializer) = initializer {
176                self.visit_expr #_mut(initializer)?;
177            }
178            ControlFlow::Continue(())
179        }
180
181        fn visit_ty(&mut self, ty: &'ast #mut Type<'ast>) -> ControlFlow<Self::BreakValue> {
182            let Type { span, kind } = ty;
183            self.visit_span #_mut(span)?;
184            match kind {
185                TypeKind::Elementary(_) => {}
186                TypeKind::Array(array) => {
187                    let TypeArray { element, size } = &#mut **array;
188                    self.visit_ty #_mut(element)?;
189                    if let Some(size) = size {
190                        self.visit_expr #_mut(size)?;
191                    }
192                }
193                TypeKind::Function(function) => {
194                    let TypeFunction { parameters, visibility: _, state_mutability: _, returns } = &#mut **function;
195                    self.visit_parameter_list #_mut(parameters)?;
196                    if let Some(returns) = returns {
197                        self.visit_parameter_list #_mut(returns)?;
198                    }
199                }
200                TypeKind::Mapping(mapping) => {
201                    let TypeMapping { key, key_name, value, value_name } = &#mut **mapping;
202                    self.visit_ty #_mut(key)?;
203                    if let Some(key_name) = key_name {
204                        self.visit_ident #_mut(key_name)?;
205                    }
206                    self.visit_ty #_mut(value)?;
207                    if let Some(value_name) = value_name {
208                        self.visit_ident #_mut(value_name)?;
209                    }
210                }
211                TypeKind::Custom(path) => {
212                    self.visit_path #_mut(path)?;
213                }
214            }
215            ControlFlow::Continue(())
216        }
217
218        fn visit_function_header(&mut self, header: &'ast #mut FunctionHeader<'ast>) -> ControlFlow<Self::BreakValue> {
219            let FunctionHeader {
220                span,
221                name,
222                parameters,
223                visibility,
224                state_mutability,
225                modifiers,
226                virtual_: _,
227                override_,
228                returns,
229            } = header;
230            self.visit_span #_mut(span)?;
231            if let Some(name) = name {
232                self.visit_ident #_mut(name)?;
233            }
234            self.visit_parameter_list #_mut(parameters)?;
235            if let Some(vis) = visibility {
236                let Spanned { span: vis_span, .. } = vis;
237                self.visit_span #_mut(vis_span)?;
238            }
239            if let Some(state_mut) = state_mutability {
240                let Spanned { span: state_mut_span, .. } = state_mut;
241                self.visit_span #_mut(state_mut_span)?;
242            }
243            for modifier in modifiers.iter #_mut() {
244                self.visit_modifier #_mut(modifier)?;
245            }
246            if let Some(returns) = returns {
247                self.visit_parameter_list #_mut(returns)?;
248            }
249            if let Some(override_) = override_ {
250                self.visit_override #_mut(override_)?;
251            }
252            ControlFlow::Continue(())
253        }
254
255        fn visit_modifier(&mut self, modifier: &'ast #mut Modifier<'ast>) -> ControlFlow<Self::BreakValue> {
256            let Modifier { name, arguments } = modifier;
257            self.visit_path #_mut(name)?;
258            self.visit_call_args #_mut(arguments)?;
259            ControlFlow::Continue(())
260        }
261
262        fn visit_override(&mut self, override_: &'ast #mut Override<'ast>) -> ControlFlow<Self::BreakValue> {
263            let Override { span, paths } = override_;
264            self.visit_span #_mut(span)?;
265            for path in paths.iter #_mut() {
266                self.visit_path #_mut(path)?;
267            }
268            ControlFlow::Continue(())
269        }
270
271        fn visit_call_args(&mut self, args: &'ast #mut CallArgs<'ast>) -> ControlFlow<Self::BreakValue> {
272            let CallArgs { span, kind } = args;
273            self.visit_span #_mut(span)?;
274            match kind {
275                CallArgsKind::Named(named) => {
276                    self.visit_named_args #_mut(named)?;
277                }
278                CallArgsKind::Unnamed(unnamed) => {
279                    for arg in unnamed.iter #_mut() {
280                        self.visit_expr #_mut(arg)?;
281                    }
282                }
283            }
284            ControlFlow::Continue(())
285        }
286
287        fn visit_named_args(&mut self, args: &'ast #mut NamedArgList<'ast>) -> ControlFlow<Self::BreakValue> {
288            for NamedArg { name, value } in args.iter #_mut() {
289                self.visit_ident #_mut(name)?;
290                self.visit_expr #_mut(value)?;
291            }
292            ControlFlow::Continue(())
293        }
294
295        fn visit_stmt(&mut self, stmt: &'ast #mut Stmt<'ast>) -> ControlFlow<Self::BreakValue> {
296            let Stmt { docs, span, kind } = stmt;
297            self.visit_doc_comments #_mut(docs)?;
298            self.visit_span #_mut(span)?;
299            match kind {
300                StmtKind::Assembly(assembly) => {
301                    self.visit_stmt_assembly #_mut(assembly)?;
302                }
303                StmtKind::DeclSingle(var) => {
304                    self.visit_variable_definition #_mut(var)?;
305                }
306                StmtKind::DeclMulti(vars, expr) => {
307                    for spanned_var in vars.iter #_mut() {
308                        match spanned_var {
309                            SpannedOption::Some(var) => self.visit_variable_definition #_mut(var)?,
310                            SpannedOption::None(span) => self.visit_span #_mut(span)?,
311                        }
312                    }
313                    self.visit_expr #_mut(expr)?;
314                }
315                StmtKind::Block(block) => {
316                    self.visit_block #_mut(block)?;
317                }
318                StmtKind::Break => {}
319                StmtKind::Continue => {}
320                StmtKind::DoWhile(stmt, expr) => {
321                    self.visit_stmt #_mut(stmt)?;
322                    self.visit_expr #_mut(expr)?;
323                }
324                StmtKind::Emit(path, args) => {
325                    self.visit_path #_mut(path)?;
326                    self.visit_call_args #_mut(args)?;
327                }
328                StmtKind::Expr(expr) => {
329                    self.visit_expr #_mut(expr)?;
330                }
331                StmtKind::For { init, cond, next, body } => {
332                    if let Some(init) = init {
333                        self.visit_stmt #_mut(init)?;
334                    }
335                    if let Some(cond) = cond {
336                        self.visit_expr #_mut(cond)?;
337                    }
338                    if let Some(next) = next {
339                        self.visit_expr #_mut(next)?;
340                    }
341                    self.visit_stmt #_mut(body)?;
342                }
343                StmtKind::If(cond, then, else_) => {
344                    self.visit_expr #_mut(cond)?;
345                    self.visit_stmt #_mut(then)?;
346                    if let Some(else_) = else_ {
347                        self.visit_stmt #_mut(else_)?;
348                    }
349                }
350                StmtKind::Return(expr) => {
351                    if let Some(expr) = expr {
352                        self.visit_expr #_mut(expr)?;
353                    }
354                }
355                StmtKind::Revert(path, args) => {
356                    self.visit_path #_mut(path)?;
357                    self.visit_call_args #_mut(args)?;
358                }
359                StmtKind::Try(try_) => {
360                    self.visit_stmt_try #_mut(try_)?;
361                }
362                StmtKind::UncheckedBlock(block) => {
363                    self.visit_block #_mut(block)?;
364                }
365                StmtKind::While(cond, stmt) => {
366                    self.visit_expr #_mut(cond)?;
367                    self.visit_stmt #_mut(stmt)?;
368                }
369                StmtKind::Placeholder => {}
370            }
371            ControlFlow::Continue(())
372        }
373
374        fn visit_stmt_assembly(&mut self, assembly: &'ast #mut StmtAssembly<'ast>) -> ControlFlow<Self::BreakValue> {
375            let StmtAssembly { dialect: _, flags: _, block } = assembly;
376            self.visit_yul_block #_mut(block)?;
377            ControlFlow::Continue(())
378        }
379
380        fn visit_stmt_try(&mut self, try_: &'ast #mut StmtTry<'ast>) -> ControlFlow<Self::BreakValue> {
381            let StmtTry { expr, clauses } = try_;
382            self.visit_expr #_mut(expr)?;
383            for catch in clauses.iter #_mut() {
384                self.visit_try_catch_clause #_mut(catch)?;
385            }
386            ControlFlow::Continue(())
387        }
388
389        fn visit_try_catch_clause(&mut self, catch: &'ast #mut TryCatchClause<'ast>) -> ControlFlow<Self::BreakValue> {
390            let TryCatchClause { span, name, args, block } = catch;
391            self.visit_span #_mut(span)?;
392            if let Some(name) = name {
393                self.visit_ident #_mut(name)?;
394            }
395            self.visit_parameter_list #_mut(args)?;
396            self.visit_block #_mut(block)?;
397            ControlFlow::Continue(())
398        }
399
400        fn visit_block(&mut self, block: &'ast #mut Block<'ast>) -> ControlFlow<Self::BreakValue> {
401            let Block { span, stmts } = block;
402            self.visit_span #_mut(span)?;
403            for stmt in stmts.iter #_mut() {
404                self.visit_stmt #_mut(stmt)?;
405            }
406            ControlFlow::Continue(())
407        }
408
409        fn visit_expr(&mut self, expr: &'ast #mut Expr<'ast>) -> ControlFlow<Self::BreakValue> {
410            let Expr { span, kind } = expr;
411            self.visit_span #_mut(span)?;
412            match kind {
413                ExprKind::Array(exprs) => {
414                    for expr in exprs.iter #_mut() {
415                        self.visit_expr #_mut(expr)?;
416                    }
417                }
418                ExprKind::Assign(lhs, _op, rhs) => {
419                    self.visit_expr #_mut(lhs)?;
420                    self.visit_expr #_mut(rhs)?;
421                }
422                ExprKind::Binary(lhs, _op, rhs) => {
423                    self.visit_expr #_mut(lhs)?;
424                    self.visit_expr #_mut(rhs)?;
425                }
426                ExprKind::Call(lhs, args) => {
427                    self.visit_expr #_mut(lhs)?;
428                    self.visit_call_args #_mut(args)?;
429                }
430                ExprKind::CallOptions(lhs, args) => {
431                    self.visit_expr #_mut(lhs)?;
432                    self.visit_named_args #_mut(args)?;
433                }
434                ExprKind::Delete(expr) => {
435                    self.visit_expr #_mut(expr)?;
436                }
437                ExprKind::Ident(ident) => {
438                    self.visit_ident #_mut(ident)?;
439                }
440                ExprKind::Index(lhs, kind) => {
441                    self.visit_expr #_mut(lhs)?;
442                    match kind {
443                        IndexKind::Index(expr) => {
444                            if let Some(expr) = expr {
445                                self.visit_expr #_mut(expr)?;
446                            }
447                        }
448                        IndexKind::Range(start, end) => {
449                            if let Some(start) = start {
450                                self.visit_expr #_mut(start)?;
451                            }
452                            if let Some(end) = end {
453                                self.visit_expr #_mut(end)?;
454                            }
455                        }
456                    }
457                }
458                ExprKind::Lit(lit, _sub) => {
459                    self.visit_lit #_mut(lit)?;
460                }
461                ExprKind::Member(expr, member) => {
462                    self.visit_expr #_mut(expr)?;
463                    self.visit_ident #_mut(member)?;
464                }
465                ExprKind::New(ty) => {
466                    self.visit_ty #_mut(ty)?;
467                }
468                ExprKind::Payable(args) => {
469                    self.visit_call_args #_mut(args)?;
470                }
471                ExprKind::Ternary(cond, true_, false_) => {
472                    self.visit_expr #_mut(cond)?;
473                    self.visit_expr #_mut(true_)?;
474                    self.visit_expr #_mut(false_)?;
475                }
476                ExprKind::Tuple(exprs) => {
477                    for spanned_expr in exprs.iter #_mut() {
478                        match spanned_expr {
479                            SpannedOption::Some(expr) => self.visit_expr #_mut(expr)?,
480                            SpannedOption::None(span) => self.visit_span #_mut(span)?,
481                        }
482                    }
483                }
484                ExprKind::TypeCall(ty) => {
485                    self.visit_ty #_mut(ty)?;
486                }
487                ExprKind::Type(ty) => {
488                    self.visit_ty #_mut(ty)?;
489                }
490                ExprKind::Unary(_op, expr) => {
491                    self.visit_expr #_mut(expr)?;
492                }
493            }
494            ControlFlow::Continue(())
495        }
496
497        fn visit_parameter_list(&mut self, list: &'ast #mut ParameterList<'ast>) -> ControlFlow<Self::BreakValue> {
498            let ParameterList { span, vars } = list;
499            for param in vars.iter #_mut() {
500                self.visit_variable_definition #_mut(param)?;
501            }
502            self.visit_span #_mut(span)?;
503            ControlFlow::Continue(())
504        }
505
506        fn visit_lit(&mut self, lit: &'ast #mut Lit<'_>) -> ControlFlow<Self::BreakValue> {
507            let Lit { span, symbol: _, kind: _ } = lit;
508            self.visit_span #_mut(span)?;
509            ControlFlow::Continue(())
510        }
511
512        fn visit_yul_stmt(&mut self, stmt: &'ast #mut yul::Stmt<'ast>) -> ControlFlow<Self::BreakValue> {
513            let yul::Stmt { docs, span, kind } = stmt;
514            self.visit_doc_comments #_mut(docs)?;
515            self.visit_span #_mut(span)?;
516            match kind {
517                yul::StmtKind::Block(block) => {
518                    self.visit_yul_block #_mut(block)?;
519                }
520                yul::StmtKind::AssignSingle(path, expr) => {
521                    self.visit_path #_mut(path)?;
522                    self.visit_yul_expr #_mut(expr)?;
523                }
524                yul::StmtKind::AssignMulti(paths, expr) => {
525                    for path in paths.iter #_mut() {
526                        self.visit_path #_mut(path)?;
527                    }
528                    self.visit_yul_expr #_mut(expr)?;
529                }
530                yul::StmtKind::Expr(expr) => {
531                    self.visit_yul_expr #_mut(expr)?;
532                }
533                yul::StmtKind::If(expr, block) => {
534                    self.visit_yul_expr #_mut(expr)?;
535                    self.visit_yul_block #_mut(block)?;
536                }
537                yul::StmtKind::For(yul::StmtFor { init, cond, step, body }) => {
538                    self.visit_yul_block #_mut(init)?;
539                    self.visit_yul_expr #_mut(cond)?;
540                    self.visit_yul_block #_mut(step)?;
541                    self.visit_yul_block #_mut(body)?;
542                }
543                yul::StmtKind::Switch(switch) => {
544                    self.visit_yul_stmt_switch #_mut(switch)?;
545                }
546                yul::StmtKind::Leave => {}
547                yul::StmtKind::Break => {}
548                yul::StmtKind::Continue => {}
549                yul::StmtKind::FunctionDef(function) => {
550                    self.visit_yul_function #_mut(function)?;
551                }
552                yul::StmtKind::VarDecl(idents, expr) => {
553                    for ident in idents.iter #_mut() {
554                        self.visit_ident #_mut(ident)?;
555                    }
556                    if let Some(expr) = expr {
557                        self.visit_yul_expr #_mut(expr)?;
558                    }
559                }
560            }
561            ControlFlow::Continue(())
562        }
563
564        fn visit_yul_block(&mut self, block: &'ast #mut yul::Block<'ast>) -> ControlFlow<Self::BreakValue> {
565            let yul::Block { span, stmts } = block;
566            self.visit_span #_mut(span)?;
567            for stmt in stmts.iter #_mut() {
568                self.visit_yul_stmt #_mut(stmt)?;
569            }
570            ControlFlow::Continue(())
571        }
572
573        fn visit_yul_stmt_switch(&mut self, switch: &'ast #mut yul::StmtSwitch<'ast>) -> ControlFlow<Self::BreakValue> {
574            let yul::StmtSwitch { selector, cases } = switch;
575            self.visit_yul_expr #_mut(selector)?;
576            for case in cases.iter #_mut() {
577                self.visit_yul_stmt_case #_mut(case)?;
578            }
579            ControlFlow::Continue(())
580        }
581
582        fn visit_yul_stmt_case(&mut self, case: &'ast #mut yul::StmtSwitchCase<'ast>) -> ControlFlow<Self::BreakValue> {
583            let yul::StmtSwitchCase { span, constant, body } = case;
584            self.visit_span #_mut(span)?;
585            if let Some(constant) = constant {
586                self.visit_lit #_mut(constant)?;
587            }
588            self.visit_yul_block #_mut(body)?;
589            ControlFlow::Continue(())
590        }
591
592        fn visit_yul_function(&mut self, function: &'ast #mut yul::Function<'ast>) -> ControlFlow<Self::BreakValue> {
593            let yul::Function { name, parameters, returns, body } = function;
594            self.visit_ident #_mut(name)?;
595            for ident in parameters.iter #_mut() {
596                self.visit_ident #_mut(ident)?;
597            }
598            for ident in returns.iter #_mut() {
599                self.visit_ident #_mut(ident)?;
600            }
601            self.visit_yul_block #_mut(body)?;
602            ControlFlow::Continue(())
603        }
604
605        fn visit_yul_expr(&mut self, expr: &'ast #mut yul::Expr<'ast>) -> ControlFlow<Self::BreakValue> {
606            let yul::Expr { span, kind } = expr;
607            self.visit_span #_mut(span)?;
608            match kind {
609                yul::ExprKind::Path(path) => {
610                    self.visit_path #_mut(path)?;
611                }
612                yul::ExprKind::Call(call) => {
613                    self.visit_yul_expr_call #_mut(call)?;
614                }
615                yul::ExprKind::Lit(lit) => {
616                    self.visit_lit #_mut(lit)?;
617                }
618            }
619            ControlFlow::Continue(())
620        }
621
622        fn visit_yul_expr_call(&mut self, call: &'ast #mut yul::ExprCall<'ast>) -> ControlFlow<Self::BreakValue> {
623            let yul::ExprCall { name, arguments } = call;
624            self.visit_ident #_mut(name)?;
625            for arg in arguments.iter #_mut() {
626                self.visit_yul_expr #_mut(arg)?;
627            }
628            ControlFlow::Continue(())
629        }
630
631        fn visit_doc_comments(&mut self, doc_comments: &'ast #mut DocComments<'ast>) -> ControlFlow<Self::BreakValue> {
632            for doc_comment in doc_comments.iter #_mut() {
633                self.visit_doc_comment #_mut(doc_comment)?;
634            }
635            ControlFlow::Continue(())
636        }
637
638        fn visit_doc_comment(&mut self, doc_comment: &'ast #mut DocComment) -> ControlFlow<Self::BreakValue> {
639            let DocComment { kind: _, span, symbol: _ } = doc_comment;
640            self.visit_span #_mut(span)?;
641            ControlFlow::Continue(())
642        }
643
644        fn visit_path(&mut self, path: &'ast #mut PathSlice) -> ControlFlow<Self::BreakValue> {
645            for ident in path.segments #_mut() {
646                self.visit_ident #_mut(ident)?;
647            }
648            ControlFlow::Continue(())
649        }
650
651        fn visit_ident(&mut self, ident: &'ast #mut Ident) -> ControlFlow<Self::BreakValue> {
652            let Ident { name: _, span } = ident;
653            self.visit_span #_mut(span)?;
654            ControlFlow::Continue(())
655        }
656
657        fn visit_span(&mut self, span: &'ast #mut Span) -> ControlFlow<Self::BreakValue> {
658            // Nothing to do.
659            let _ = span;
660            ControlFlow::Continue(())
661        }
662    }
663}