solar_ast/
visit.rs

1//! Constant and mutable AST visitor trait definitions.
2
3use crate::ast::*;
4use solar_interface::{Ident, Span, Spanned};
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 var in vars.iter #_mut().flatten() {
308                        self.visit_variable_definition #_mut(var)?;
309                    }
310                    self.visit_expr #_mut(expr)?;
311                }
312                StmtKind::Block(block) => {
313                    self.visit_block #_mut(block)?;
314                }
315                StmtKind::Break => {}
316                StmtKind::Continue => {}
317                StmtKind::DoWhile(stmt, expr) => {
318                    self.visit_stmt #_mut(stmt)?;
319                    self.visit_expr #_mut(expr)?;
320                }
321                StmtKind::Emit(path, args) => {
322                    self.visit_path #_mut(path)?;
323                    self.visit_call_args #_mut(args)?;
324                }
325                StmtKind::Expr(expr) => {
326                    self.visit_expr #_mut(expr)?;
327                }
328                StmtKind::For { init, cond, next, body } => {
329                    if let Some(init) = init {
330                        self.visit_stmt #_mut(init)?;
331                    }
332                    if let Some(cond) = cond {
333                        self.visit_expr #_mut(cond)?;
334                    }
335                    if let Some(next) = next {
336                        self.visit_expr #_mut(next)?;
337                    }
338                    self.visit_stmt #_mut(body)?;
339                }
340                StmtKind::If(cond, then, else_) => {
341                    self.visit_expr #_mut(cond)?;
342                    self.visit_stmt #_mut(then)?;
343                    if let Some(else_) = else_ {
344                        self.visit_stmt #_mut(else_)?;
345                    }
346                }
347                StmtKind::Return(expr) => {
348                    if let Some(expr) = expr {
349                        self.visit_expr #_mut(expr)?;
350                    }
351                }
352                StmtKind::Revert(path, args) => {
353                    self.visit_path #_mut(path)?;
354                    self.visit_call_args #_mut(args)?;
355                }
356                StmtKind::Try(try_) => {
357                    self.visit_stmt_try #_mut(try_)?;
358                }
359                StmtKind::UncheckedBlock(block) => {
360                    self.visit_block #_mut(block)?;
361                }
362                StmtKind::While(cond, stmt) => {
363                    self.visit_expr #_mut(cond)?;
364                    self.visit_stmt #_mut(stmt)?;
365                }
366                StmtKind::Placeholder => {}
367            }
368            ControlFlow::Continue(())
369        }
370
371        fn visit_stmt_assembly(&mut self, assembly: &'ast #mut StmtAssembly<'ast>) -> ControlFlow<Self::BreakValue> {
372            let StmtAssembly { dialect: _, flags: _, block } = assembly;
373            self.visit_yul_block #_mut(block)?;
374            ControlFlow::Continue(())
375        }
376
377        fn visit_stmt_try(&mut self, try_: &'ast #mut StmtTry<'ast>) -> ControlFlow<Self::BreakValue> {
378            let StmtTry { expr, clauses } = try_;
379            self.visit_expr #_mut(expr)?;
380            for catch in clauses.iter #_mut() {
381                self.visit_try_catch_clause #_mut(catch)?;
382            }
383            ControlFlow::Continue(())
384        }
385
386        fn visit_try_catch_clause(&mut self, catch: &'ast #mut TryCatchClause<'ast>) -> ControlFlow<Self::BreakValue> {
387            let TryCatchClause { span, name, args, block } = catch;
388            self.visit_span #_mut(span)?;
389            if let Some(name) = name {
390                self.visit_ident #_mut(name)?;
391            }
392            self.visit_parameter_list #_mut(args)?;
393            self.visit_block #_mut(block)?;
394            ControlFlow::Continue(())
395        }
396
397        fn visit_block(&mut self, block: &'ast #mut Block<'ast>) -> ControlFlow<Self::BreakValue> {
398            let Block { span, stmts } = block;
399            self.visit_span #_mut(span)?;
400            for stmt in stmts.iter #_mut() {
401                self.visit_stmt #_mut(stmt)?;
402            }
403            ControlFlow::Continue(())
404        }
405
406        fn visit_expr(&mut self, expr: &'ast #mut Expr<'ast>) -> ControlFlow<Self::BreakValue> {
407            let Expr { span, kind } = expr;
408            self.visit_span #_mut(span)?;
409            match kind {
410                ExprKind::Array(exprs) => {
411                    for expr in exprs.iter #_mut() {
412                        self.visit_expr #_mut(expr)?;
413                    }
414                }
415                ExprKind::Assign(lhs, _op, rhs) => {
416                    self.visit_expr #_mut(lhs)?;
417                    self.visit_expr #_mut(rhs)?;
418                }
419                ExprKind::Binary(lhs, _op, rhs) => {
420                    self.visit_expr #_mut(lhs)?;
421                    self.visit_expr #_mut(rhs)?;
422                }
423                ExprKind::Call(lhs, args) => {
424                    self.visit_expr #_mut(lhs)?;
425                    self.visit_call_args #_mut(args)?;
426                }
427                ExprKind::CallOptions(lhs, args) => {
428                    self.visit_expr #_mut(lhs)?;
429                    self.visit_named_args #_mut(args)?;
430                }
431                ExprKind::Delete(expr) => {
432                    self.visit_expr #_mut(expr)?;
433                }
434                ExprKind::Ident(ident) => {
435                    self.visit_ident #_mut(ident)?;
436                }
437                ExprKind::Index(lhs, kind) => {
438                    self.visit_expr #_mut(lhs)?;
439                    match kind {
440                        IndexKind::Index(expr) => {
441                            if let Some(expr) = expr {
442                                self.visit_expr #_mut(expr)?;
443                            }
444                        }
445                        IndexKind::Range(start, end) => {
446                            if let Some(start) = start {
447                                self.visit_expr #_mut(start)?;
448                            }
449                            if let Some(end) = end {
450                                self.visit_expr #_mut(end)?;
451                            }
452                        }
453                    }
454                }
455                ExprKind::Lit(lit, _sub) => {
456                    self.visit_lit #_mut(lit)?;
457                }
458                ExprKind::Member(expr, member) => {
459                    self.visit_expr #_mut(expr)?;
460                    self.visit_ident #_mut(member)?;
461                }
462                ExprKind::New(ty) => {
463                    self.visit_ty #_mut(ty)?;
464                }
465                ExprKind::Payable(args) => {
466                    self.visit_call_args #_mut(args)?;
467                }
468                ExprKind::Ternary(cond, true_, false_) => {
469                    self.visit_expr #_mut(cond)?;
470                    self.visit_expr #_mut(true_)?;
471                    self.visit_expr #_mut(false_)?;
472                }
473                ExprKind::Tuple(exprs) => {
474                    for expr in exprs.iter #_mut().flatten() {
475                        self.visit_expr #_mut(expr)?;
476                    }
477                }
478                ExprKind::TypeCall(ty) => {
479                    self.visit_ty #_mut(ty)?;
480                }
481                ExprKind::Type(ty) => {
482                    self.visit_ty #_mut(ty)?;
483                }
484                ExprKind::Unary(_op, expr) => {
485                    self.visit_expr #_mut(expr)?;
486                }
487            }
488            ControlFlow::Continue(())
489        }
490
491        fn visit_parameter_list(&mut self, list: &'ast #mut ParameterList<'ast>) -> ControlFlow<Self::BreakValue> {
492            let ParameterList { span, vars } = list;
493            for param in vars.iter #_mut() {
494                self.visit_variable_definition #_mut(param)?;
495            }
496            self.visit_span #_mut(span)?;
497            ControlFlow::Continue(())
498        }
499
500        fn visit_lit(&mut self, lit: &'ast #mut Lit<'_>) -> ControlFlow<Self::BreakValue> {
501            let Lit { span, symbol: _, kind: _ } = lit;
502            self.visit_span #_mut(span)?;
503            ControlFlow::Continue(())
504        }
505
506        fn visit_yul_stmt(&mut self, stmt: &'ast #mut yul::Stmt<'ast>) -> ControlFlow<Self::BreakValue> {
507            let yul::Stmt { docs, span, kind } = stmt;
508            self.visit_doc_comments #_mut(docs)?;
509            self.visit_span #_mut(span)?;
510            match kind {
511                yul::StmtKind::Block(block) => {
512                    self.visit_yul_block #_mut(block)?;
513                }
514                yul::StmtKind::AssignSingle(path, expr) => {
515                    self.visit_path #_mut(path)?;
516                    self.visit_yul_expr #_mut(expr)?;
517                }
518                yul::StmtKind::AssignMulti(paths, call) => {
519                    for path in paths.iter #_mut() {
520                        self.visit_path #_mut(path)?;
521                    }
522                    self.visit_yul_expr_call #_mut(call)?;
523                }
524                yul::StmtKind::Expr(call) => {
525                    self.visit_yul_expr_call #_mut(call)?;
526                }
527                yul::StmtKind::If(expr, block) => {
528                    self.visit_yul_expr #_mut(expr)?;
529                    self.visit_yul_block #_mut(block)?;
530                }
531                yul::StmtKind::For { init, cond, step, body } => {
532                    self.visit_yul_block #_mut(init)?;
533                    self.visit_yul_expr #_mut(cond)?;
534                    self.visit_yul_block #_mut(step)?;
535                    self.visit_yul_block #_mut(body)?;
536                }
537                yul::StmtKind::Switch(switch) => {
538                    self.visit_yul_stmt_switch #_mut(switch)?;
539                }
540                yul::StmtKind::Leave => {}
541                yul::StmtKind::Break => {}
542                yul::StmtKind::Continue => {}
543                yul::StmtKind::FunctionDef(function) => {
544                    self.visit_yul_function #_mut(function)?;
545                }
546                yul::StmtKind::VarDecl(idents, expr) => {
547                    for ident in idents.iter #_mut() {
548                        self.visit_ident #_mut(ident)?;
549                    }
550                    if let Some(expr) = expr {
551                        self.visit_yul_expr #_mut(expr)?;
552                    }
553                }
554            }
555            ControlFlow::Continue(())
556        }
557
558        fn visit_yul_block(&mut self, block: &'ast #mut yul::Block<'ast>) -> ControlFlow<Self::BreakValue> {
559            let yul::Block { span, stmts } = block;
560            self.visit_span #_mut(span)?;
561            for stmt in stmts.iter #_mut() {
562                self.visit_yul_stmt #_mut(stmt)?;
563            }
564            ControlFlow::Continue(())
565        }
566
567        fn visit_yul_stmt_switch(&mut self, switch: &'ast #mut yul::StmtSwitch<'ast>) -> ControlFlow<Self::BreakValue> {
568            let yul::StmtSwitch { selector, cases } = switch;
569            self.visit_yul_expr #_mut(selector)?;
570            for case in cases.iter #_mut() {
571                self.visit_yul_stmt_case #_mut(case)?;
572            }
573            ControlFlow::Continue(())
574        }
575
576        fn visit_yul_stmt_case(&mut self, case: &'ast #mut yul::StmtSwitchCase<'ast>) -> ControlFlow<Self::BreakValue> {
577            let yul::StmtSwitchCase { span, constant, body } = case;
578            self.visit_span #_mut(span)?;
579            if let Some(constant) = constant {
580                self.visit_lit #_mut(constant)?;
581            }
582            self.visit_yul_block #_mut(body)?;
583            ControlFlow::Continue(())
584        }
585
586        fn visit_yul_function(&mut self, function: &'ast #mut yul::Function<'ast>) -> ControlFlow<Self::BreakValue> {
587            let yul::Function { name, parameters, returns, body } = function;
588            self.visit_ident #_mut(name)?;
589            for ident in parameters.iter #_mut() {
590                self.visit_ident #_mut(ident)?;
591            }
592            for ident in returns.iter #_mut() {
593                self.visit_ident #_mut(ident)?;
594            }
595            self.visit_yul_block #_mut(body)?;
596            ControlFlow::Continue(())
597        }
598
599        fn visit_yul_expr(&mut self, expr: &'ast #mut yul::Expr<'ast>) -> ControlFlow<Self::BreakValue> {
600            let yul::Expr { span, kind } = expr;
601            self.visit_span #_mut(span)?;
602            match kind {
603                yul::ExprKind::Path(path) => {
604                    self.visit_path #_mut(path)?;
605                }
606                yul::ExprKind::Call(call) => {
607                    self.visit_yul_expr_call #_mut(call)?;
608                }
609                yul::ExprKind::Lit(lit) => {
610                    self.visit_lit #_mut(lit)?;
611                }
612            }
613            ControlFlow::Continue(())
614        }
615
616        fn visit_yul_expr_call(&mut self, call: &'ast #mut yul::ExprCall<'ast>) -> ControlFlow<Self::BreakValue> {
617            let yul::ExprCall { name, arguments } = call;
618            self.visit_ident #_mut(name)?;
619            for arg in arguments.iter #_mut() {
620                self.visit_yul_expr #_mut(arg)?;
621            }
622            ControlFlow::Continue(())
623        }
624
625        fn visit_doc_comments(&mut self, doc_comments: &'ast #mut DocComments<'ast>) -> ControlFlow<Self::BreakValue> {
626            for doc_comment in doc_comments.iter #_mut() {
627                self.visit_doc_comment #_mut(doc_comment)?;
628            }
629            ControlFlow::Continue(())
630        }
631
632        fn visit_doc_comment(&mut self, doc_comment: &'ast #mut DocComment) -> ControlFlow<Self::BreakValue> {
633            let DocComment { kind: _, span, symbol: _ } = doc_comment;
634            self.visit_span #_mut(span)?;
635            ControlFlow::Continue(())
636        }
637
638        fn visit_path(&mut self, path: &'ast #mut PathSlice) -> ControlFlow<Self::BreakValue> {
639            for ident in path.segments #_mut() {
640                self.visit_ident #_mut(ident)?;
641            }
642            ControlFlow::Continue(())
643        }
644
645        fn visit_ident(&mut self, ident: &'ast #mut Ident) -> ControlFlow<Self::BreakValue> {
646            let Ident { name: _, span } = ident;
647            self.visit_span #_mut(span)?;
648            ControlFlow::Continue(())
649        }
650
651        fn visit_span(&mut self, span: &'ast #mut Span) -> ControlFlow<Self::BreakValue> {
652            // Nothing to do.
653            let _ = span;
654            ControlFlow::Continue(())
655        }
656    }
657}