forge_fmt/
visit.rs

1//! Visitor helpers to traverse the [solang Solidity Parse Tree](solang_parser::pt).
2
3use crate::solang_ext::pt::*;
4
5/// A trait that is invoked while traversing the Solidity Parse Tree.
6/// Each method of the [Visitor] trait is a hook that can be potentially overridden.
7///
8/// Currently the main implementer of this trait is the [`Formatter`](crate::Formatter<'_>) struct.
9pub trait Visitor {
10    type Error: std::error::Error;
11
12    fn visit_source(&mut self, _loc: Loc) -> Result<(), Self::Error> {
13        Ok(())
14    }
15
16    fn visit_source_unit(&mut self, _source_unit: &mut SourceUnit) -> Result<(), Self::Error> {
17        Ok(())
18    }
19
20    fn visit_contract(&mut self, _contract: &mut ContractDefinition) -> Result<(), Self::Error> {
21        Ok(())
22    }
23
24    fn visit_annotation(&mut self, annotation: &mut Annotation) -> Result<(), Self::Error> {
25        self.visit_source(annotation.loc)
26    }
27
28    fn visit_pragma(
29        &mut self,
30        loc: Loc,
31        _ident: &mut Option<Identifier>,
32        _str: &mut Option<StringLiteral>,
33    ) -> Result<(), Self::Error> {
34        self.visit_source(loc)
35    }
36
37    fn visit_import_plain(
38        &mut self,
39        _loc: Loc,
40        _import: &mut ImportPath,
41    ) -> Result<(), Self::Error> {
42        Ok(())
43    }
44
45    fn visit_import_global(
46        &mut self,
47        _loc: Loc,
48        _global: &mut ImportPath,
49        _alias: &mut Identifier,
50    ) -> Result<(), Self::Error> {
51        Ok(())
52    }
53
54    fn visit_import_renames(
55        &mut self,
56        _loc: Loc,
57        _imports: &mut [(Identifier, Option<Identifier>)],
58        _from: &mut ImportPath,
59    ) -> Result<(), Self::Error> {
60        Ok(())
61    }
62
63    fn visit_enum(&mut self, _enum: &mut EnumDefinition) -> Result<(), Self::Error> {
64        Ok(())
65    }
66
67    fn visit_assembly(
68        &mut self,
69        loc: Loc,
70        _dialect: &mut Option<StringLiteral>,
71        _block: &mut YulBlock,
72        _flags: &mut Option<Vec<StringLiteral>>,
73    ) -> Result<(), Self::Error> {
74        self.visit_source(loc)
75    }
76
77    fn visit_block(
78        &mut self,
79        loc: Loc,
80        _unchecked: bool,
81        _statements: &mut Vec<Statement>,
82    ) -> Result<(), Self::Error> {
83        self.visit_source(loc)
84    }
85
86    fn visit_args(&mut self, loc: Loc, _args: &mut Vec<NamedArgument>) -> Result<(), Self::Error> {
87        self.visit_source(loc)
88    }
89
90    /// Don't write semicolon at the end because expressions can appear as both
91    /// part of other node and a statement in the function body
92    fn visit_expr(&mut self, loc: Loc, _expr: &mut Expression) -> Result<(), Self::Error> {
93        self.visit_source(loc)
94    }
95
96    fn visit_ident(&mut self, loc: Loc, _ident: &mut Identifier) -> Result<(), Self::Error> {
97        self.visit_source(loc)
98    }
99
100    fn visit_ident_path(&mut self, idents: &mut IdentifierPath) -> Result<(), Self::Error> {
101        self.visit_source(idents.loc)
102    }
103
104    fn visit_emit(&mut self, loc: Loc, _event: &mut Expression) -> Result<(), Self::Error> {
105        self.visit_source(loc)?;
106        self.visit_stray_semicolon()?;
107
108        Ok(())
109    }
110
111    fn visit_var_definition(&mut self, var: &mut VariableDefinition) -> Result<(), Self::Error> {
112        self.visit_source(var.loc)?;
113        self.visit_stray_semicolon()?;
114
115        Ok(())
116    }
117
118    fn visit_var_definition_stmt(
119        &mut self,
120        loc: Loc,
121        _declaration: &mut VariableDeclaration,
122        _expr: &mut Option<Expression>,
123    ) -> Result<(), Self::Error> {
124        self.visit_source(loc)?;
125        self.visit_stray_semicolon()
126    }
127
128    fn visit_var_declaration(&mut self, var: &mut VariableDeclaration) -> Result<(), Self::Error> {
129        self.visit_source(var.loc)
130    }
131
132    fn visit_return(
133        &mut self,
134        loc: Loc,
135        _expr: &mut Option<Expression>,
136    ) -> Result<(), Self::Error> {
137        self.visit_source(loc)?;
138        self.visit_stray_semicolon()?;
139
140        Ok(())
141    }
142
143    fn visit_revert(
144        &mut self,
145        loc: Loc,
146        _error: &mut Option<IdentifierPath>,
147        _args: &mut Vec<Expression>,
148    ) -> Result<(), Self::Error> {
149        self.visit_source(loc)?;
150        self.visit_stray_semicolon()?;
151
152        Ok(())
153    }
154
155    fn visit_revert_named_args(
156        &mut self,
157        loc: Loc,
158        _error: &mut Option<IdentifierPath>,
159        _args: &mut Vec<NamedArgument>,
160    ) -> Result<(), Self::Error> {
161        self.visit_source(loc)?;
162        self.visit_stray_semicolon()?;
163
164        Ok(())
165    }
166
167    fn visit_break(&mut self, loc: Loc, _semicolon: bool) -> Result<(), Self::Error> {
168        self.visit_source(loc)
169    }
170
171    fn visit_continue(&mut self, loc: Loc, _semicolon: bool) -> Result<(), Self::Error> {
172        self.visit_source(loc)
173    }
174
175    #[expect(clippy::type_complexity)]
176    fn visit_try(
177        &mut self,
178        loc: Loc,
179        _expr: &mut Expression,
180        _returns: &mut Option<(Vec<(Loc, Option<Parameter>)>, Box<Statement>)>,
181        _clauses: &mut Vec<CatchClause>,
182    ) -> Result<(), Self::Error> {
183        self.visit_source(loc)
184    }
185
186    fn visit_if(
187        &mut self,
188        loc: Loc,
189        _cond: &mut Expression,
190        _if_branch: &mut Box<Statement>,
191        _else_branch: &mut Option<Box<Statement>>,
192        _is_first_stmt: bool,
193    ) -> Result<(), Self::Error> {
194        self.visit_source(loc)
195    }
196
197    fn visit_do_while(
198        &mut self,
199        loc: Loc,
200        _body: &mut Statement,
201        _cond: &mut Expression,
202    ) -> Result<(), Self::Error> {
203        self.visit_source(loc)
204    }
205
206    fn visit_while(
207        &mut self,
208        loc: Loc,
209        _cond: &mut Expression,
210        _body: &mut Statement,
211    ) -> Result<(), Self::Error> {
212        self.visit_source(loc)
213    }
214
215    fn visit_for(
216        &mut self,
217        loc: Loc,
218        _init: &mut Option<Box<Statement>>,
219        _cond: &mut Option<Box<Expression>>,
220        _update: &mut Option<Box<Expression>>,
221        _body: &mut Option<Box<Statement>>,
222    ) -> Result<(), Self::Error> {
223        self.visit_source(loc)
224    }
225
226    fn visit_function(&mut self, func: &mut FunctionDefinition) -> Result<(), Self::Error> {
227        self.visit_source(func.loc())?;
228        if func.body.is_none() {
229            self.visit_stray_semicolon()?;
230        }
231
232        Ok(())
233    }
234
235    fn visit_function_attribute(
236        &mut self,
237        attribute: &mut FunctionAttribute,
238    ) -> Result<(), Self::Error> {
239        self.visit_source(attribute.loc())?;
240        Ok(())
241    }
242
243    fn visit_var_attribute(
244        &mut self,
245        attribute: &mut VariableAttribute,
246    ) -> Result<(), Self::Error> {
247        self.visit_source(attribute.loc())?;
248        Ok(())
249    }
250
251    fn visit_base(&mut self, base: &mut Base) -> Result<(), Self::Error> {
252        self.visit_source(base.loc)
253    }
254
255    fn visit_parameter(&mut self, parameter: &mut Parameter) -> Result<(), Self::Error> {
256        self.visit_source(parameter.loc)
257    }
258
259    fn visit_struct(&mut self, structure: &mut StructDefinition) -> Result<(), Self::Error> {
260        self.visit_source(structure.loc)?;
261
262        Ok(())
263    }
264
265    fn visit_event(&mut self, event: &mut EventDefinition) -> Result<(), Self::Error> {
266        self.visit_source(event.loc)?;
267        self.visit_stray_semicolon()?;
268
269        Ok(())
270    }
271
272    fn visit_event_parameter(&mut self, param: &mut EventParameter) -> Result<(), Self::Error> {
273        self.visit_source(param.loc)
274    }
275
276    fn visit_error(&mut self, error: &mut ErrorDefinition) -> Result<(), Self::Error> {
277        self.visit_source(error.loc)?;
278        self.visit_stray_semicolon()?;
279
280        Ok(())
281    }
282
283    fn visit_error_parameter(&mut self, param: &mut ErrorParameter) -> Result<(), Self::Error> {
284        self.visit_source(param.loc)
285    }
286
287    fn visit_type_definition(&mut self, def: &mut TypeDefinition) -> Result<(), Self::Error> {
288        self.visit_source(def.loc)
289    }
290
291    fn visit_stray_semicolon(&mut self) -> Result<(), Self::Error> {
292        Ok(())
293    }
294
295    fn visit_opening_paren(&mut self) -> Result<(), Self::Error> {
296        Ok(())
297    }
298
299    fn visit_closing_paren(&mut self) -> Result<(), Self::Error> {
300        Ok(())
301    }
302
303    fn visit_newline(&mut self) -> Result<(), Self::Error> {
304        Ok(())
305    }
306
307    fn visit_using(&mut self, using: &mut Using) -> Result<(), Self::Error> {
308        self.visit_source(using.loc)?;
309        self.visit_stray_semicolon()?;
310
311        Ok(())
312    }
313
314    fn visit_yul_block(
315        &mut self,
316        loc: Loc,
317        _stmts: &mut Vec<YulStatement>,
318        _attempt_single_line: bool,
319    ) -> Result<(), Self::Error> {
320        self.visit_source(loc)
321    }
322
323    fn visit_yul_expr(&mut self, expr: &mut YulExpression) -> Result<(), Self::Error> {
324        self.visit_source(expr.loc())
325    }
326
327    fn visit_yul_assignment<T>(
328        &mut self,
329        loc: Loc,
330        _exprs: &mut Vec<T>,
331        _expr: &mut Option<&mut YulExpression>,
332    ) -> Result<(), Self::Error>
333    where
334        T: Visitable + CodeLocation,
335    {
336        self.visit_source(loc)
337    }
338
339    fn visit_yul_for(&mut self, stmt: &mut YulFor) -> Result<(), Self::Error> {
340        self.visit_source(stmt.loc)
341    }
342
343    fn visit_yul_function_call(&mut self, stmt: &mut YulFunctionCall) -> Result<(), Self::Error> {
344        self.visit_source(stmt.loc)
345    }
346
347    fn visit_yul_fun_def(&mut self, stmt: &mut YulFunctionDefinition) -> Result<(), Self::Error> {
348        self.visit_source(stmt.loc)
349    }
350
351    fn visit_yul_if(
352        &mut self,
353        loc: Loc,
354        _expr: &mut YulExpression,
355        _block: &mut YulBlock,
356    ) -> Result<(), Self::Error> {
357        self.visit_source(loc)
358    }
359
360    fn visit_yul_leave(&mut self, loc: Loc) -> Result<(), Self::Error> {
361        self.visit_source(loc)
362    }
363
364    fn visit_yul_switch(&mut self, stmt: &mut YulSwitch) -> Result<(), Self::Error> {
365        self.visit_source(stmt.loc)
366    }
367
368    fn visit_yul_var_declaration(
369        &mut self,
370        loc: Loc,
371        _idents: &mut Vec<YulTypedIdentifier>,
372        _expr: &mut Option<YulExpression>,
373    ) -> Result<(), Self::Error> {
374        self.visit_source(loc)
375    }
376
377    fn visit_yul_typed_ident(&mut self, ident: &mut YulTypedIdentifier) -> Result<(), Self::Error> {
378        self.visit_source(ident.loc)
379    }
380
381    fn visit_parser_error(&mut self, loc: Loc) -> Result<(), Self::Error> {
382        self.visit_source(loc)
383    }
384}
385
386/// Visitable trait for [`solang_parser::pt`] types.
387///
388/// All [`solang_parser::pt`] types, such as [Statement], should implement the [Visitable] trait
389/// that accepts a trait [Visitor] implementation, which has various callback handles for Solidity
390/// Parse Tree nodes.
391///
392/// We want to take a `&mut self` to be able to implement some advanced features in the future such
393/// as modifying the Parse Tree before formatting it.
394pub trait Visitable {
395    fn visit<V>(&mut self, v: &mut V) -> Result<(), V::Error>
396    where
397        V: Visitor;
398}
399
400impl<T> Visitable for &mut T
401where
402    T: Visitable,
403{
404    fn visit<V>(&mut self, v: &mut V) -> Result<(), V::Error>
405    where
406        V: Visitor,
407    {
408        T::visit(self, v)
409    }
410}
411
412impl<T> Visitable for Option<T>
413where
414    T: Visitable,
415{
416    fn visit<V>(&mut self, v: &mut V) -> Result<(), V::Error>
417    where
418        V: Visitor,
419    {
420        if let Some(inner) = self.as_mut() {
421            inner.visit(v)
422        } else {
423            Ok(())
424        }
425    }
426}
427
428impl<T> Visitable for Box<T>
429where
430    T: Visitable,
431{
432    fn visit<V>(&mut self, v: &mut V) -> Result<(), V::Error>
433    where
434        V: Visitor,
435    {
436        T::visit(self, v)
437    }
438}
439
440impl<T> Visitable for Vec<T>
441where
442    T: Visitable,
443{
444    fn visit<V>(&mut self, v: &mut V) -> Result<(), V::Error>
445    where
446        V: Visitor,
447    {
448        for item in self.iter_mut() {
449            item.visit(v)?;
450        }
451        Ok(())
452    }
453}
454
455impl Visitable for SourceUnitPart {
456    fn visit<V>(&mut self, v: &mut V) -> Result<(), V::Error>
457    where
458        V: Visitor,
459    {
460        match self {
461            Self::ContractDefinition(contract) => v.visit_contract(contract),
462            Self::PragmaDirective(loc, ident, str) => v.visit_pragma(*loc, ident, str),
463            Self::ImportDirective(import) => import.visit(v),
464            Self::EnumDefinition(enumeration) => v.visit_enum(enumeration),
465            Self::StructDefinition(structure) => v.visit_struct(structure),
466            Self::EventDefinition(event) => v.visit_event(event),
467            Self::ErrorDefinition(error) => v.visit_error(error),
468            Self::FunctionDefinition(function) => v.visit_function(function),
469            Self::VariableDefinition(variable) => v.visit_var_definition(variable),
470            Self::TypeDefinition(def) => v.visit_type_definition(def),
471            Self::StraySemicolon(_) => v.visit_stray_semicolon(),
472            Self::Using(using) => v.visit_using(using),
473            Self::Annotation(annotation) => v.visit_annotation(annotation),
474        }
475    }
476}
477
478impl Visitable for Import {
479    fn visit<V>(&mut self, v: &mut V) -> Result<(), V::Error>
480    where
481        V: Visitor,
482    {
483        match self {
484            Self::Plain(import, loc) => v.visit_import_plain(*loc, import),
485            Self::GlobalSymbol(global, import_as, loc) => {
486                v.visit_import_global(*loc, global, import_as)
487            }
488            Self::Rename(from, imports, loc) => v.visit_import_renames(*loc, imports, from),
489        }
490    }
491}
492
493impl Visitable for ContractPart {
494    fn visit<V>(&mut self, v: &mut V) -> Result<(), V::Error>
495    where
496        V: Visitor,
497    {
498        match self {
499            Self::StructDefinition(structure) => v.visit_struct(structure),
500            Self::EventDefinition(event) => v.visit_event(event),
501            Self::ErrorDefinition(error) => v.visit_error(error),
502            Self::EnumDefinition(enumeration) => v.visit_enum(enumeration),
503            Self::VariableDefinition(variable) => v.visit_var_definition(variable),
504            Self::FunctionDefinition(function) => v.visit_function(function),
505            Self::TypeDefinition(def) => v.visit_type_definition(def),
506            Self::StraySemicolon(_) => v.visit_stray_semicolon(),
507            Self::Using(using) => v.visit_using(using),
508            Self::Annotation(annotation) => v.visit_annotation(annotation),
509        }
510    }
511}
512
513impl Visitable for Statement {
514    fn visit<V>(&mut self, v: &mut V) -> Result<(), V::Error>
515    where
516        V: Visitor,
517    {
518        match self {
519            Self::Block { loc, unchecked, statements } => {
520                v.visit_block(*loc, *unchecked, statements)
521            }
522            Self::Assembly { loc, dialect, block, flags } => {
523                v.visit_assembly(*loc, dialect, block, flags)
524            }
525            Self::Args(loc, args) => v.visit_args(*loc, args),
526            Self::If(loc, cond, if_branch, else_branch) => {
527                v.visit_if(*loc, cond, if_branch, else_branch, true)
528            }
529            Self::While(loc, cond, body) => v.visit_while(*loc, cond, body),
530            Self::Expression(loc, expr) => {
531                v.visit_expr(*loc, expr)?;
532                v.visit_stray_semicolon()
533            }
534            Self::VariableDefinition(loc, declaration, expr) => {
535                v.visit_var_definition_stmt(*loc, declaration, expr)
536            }
537            Self::For(loc, init, cond, update, body) => v.visit_for(*loc, init, cond, update, body),
538            Self::DoWhile(loc, body, cond) => v.visit_do_while(*loc, body, cond),
539            Self::Continue(loc) => v.visit_continue(*loc, true),
540            Self::Break(loc) => v.visit_break(*loc, true),
541            Self::Return(loc, expr) => v.visit_return(*loc, expr),
542            Self::Revert(loc, error, args) => v.visit_revert(*loc, error, args),
543            Self::RevertNamedArgs(loc, error, args) => v.visit_revert_named_args(*loc, error, args),
544            Self::Emit(loc, event) => v.visit_emit(*loc, event),
545            Self::Try(loc, expr, returns, clauses) => v.visit_try(*loc, expr, returns, clauses),
546            Self::Error(loc) => v.visit_parser_error(*loc),
547        }
548    }
549}
550
551impl Visitable for Loc {
552    fn visit<V>(&mut self, v: &mut V) -> Result<(), V::Error>
553    where
554        V: Visitor,
555    {
556        v.visit_source(*self)
557    }
558}
559
560impl Visitable for Expression {
561    fn visit<V>(&mut self, v: &mut V) -> Result<(), V::Error>
562    where
563        V: Visitor,
564    {
565        v.visit_expr(self.loc(), self)
566    }
567}
568
569impl Visitable for Identifier {
570    fn visit<V>(&mut self, v: &mut V) -> Result<(), V::Error>
571    where
572        V: Visitor,
573    {
574        v.visit_ident(self.loc, self)
575    }
576}
577
578impl Visitable for VariableDeclaration {
579    fn visit<V>(&mut self, v: &mut V) -> Result<(), V::Error>
580    where
581        V: Visitor,
582    {
583        v.visit_var_declaration(self)
584    }
585}
586
587impl Visitable for YulBlock {
588    fn visit<V>(&mut self, v: &mut V) -> Result<(), V::Error>
589    where
590        V: Visitor,
591    {
592        v.visit_yul_block(self.loc, self.statements.as_mut(), false)
593    }
594}
595
596impl Visitable for YulStatement {
597    fn visit<V>(&mut self, v: &mut V) -> Result<(), V::Error>
598    where
599        V: Visitor,
600    {
601        match self {
602            Self::Assign(loc, exprs, expr) => v.visit_yul_assignment(*loc, exprs, &mut Some(expr)),
603            Self::Block(block) => v.visit_yul_block(block.loc, block.statements.as_mut(), false),
604            Self::Break(loc) => v.visit_break(*loc, false),
605            Self::Continue(loc) => v.visit_continue(*loc, false),
606            Self::For(stmt) => v.visit_yul_for(stmt),
607            Self::FunctionCall(stmt) => v.visit_yul_function_call(stmt),
608            Self::FunctionDefinition(stmt) => v.visit_yul_fun_def(stmt),
609            Self::If(loc, expr, block) => v.visit_yul_if(*loc, expr, block),
610            Self::Leave(loc) => v.visit_yul_leave(*loc),
611            Self::Switch(stmt) => v.visit_yul_switch(stmt),
612            Self::VariableDeclaration(loc, idents, expr) => {
613                v.visit_yul_var_declaration(*loc, idents, expr)
614            }
615            Self::Error(loc) => v.visit_parser_error(*loc),
616        }
617    }
618}
619
620macro_rules! impl_visitable {
621    ($type:ty, $func:ident) => {
622        impl Visitable for $type {
623            fn visit<V>(&mut self, v: &mut V) -> Result<(), V::Error>
624            where
625                V: Visitor,
626            {
627                v.$func(self)
628            }
629        }
630    };
631}
632
633impl_visitable!(SourceUnit, visit_source_unit);
634impl_visitable!(FunctionAttribute, visit_function_attribute);
635impl_visitable!(VariableAttribute, visit_var_attribute);
636impl_visitable!(Parameter, visit_parameter);
637impl_visitable!(Base, visit_base);
638impl_visitable!(EventParameter, visit_event_parameter);
639impl_visitable!(ErrorParameter, visit_error_parameter);
640impl_visitable!(IdentifierPath, visit_ident_path);
641impl_visitable!(YulExpression, visit_yul_expr);
642impl_visitable!(YulTypedIdentifier, visit_yul_typed_ident);