forge/brutalizer/
visitor.rs1use std::ops::ControlFlow;
2
3use solar::ast::{CallArgsKind, Expr, ExprKind, ItemFunction, SourceUnit, Type, visit::Visit};
4
5use super::{
6 assembly::assembly_transforms,
7 transform::{Transform, span_text},
8 value::{brutalize_cast, brutalize_payable_address, deterministic_mask},
9};
10
11struct BrutalizerVisitor<'src> {
12 transforms: Vec<Transform>,
13 source: &'src str,
14}
15
16impl<'src> BrutalizerVisitor<'src> {
17 const fn new(source: &'src str) -> Self {
18 Self { transforms: Vec::new(), source }
19 }
20}
21
22impl<'ast, 'src> Visit<'ast> for BrutalizerVisitor<'src> {
23 type BreakValue = ();
24
25 fn visit_expr(&mut self, expr: &'ast Expr<'ast>) -> ControlFlow<Self::BreakValue> {
26 if let Some((ty, arg_text)) = cast_call(self.source, expr) {
27 let mask = deterministic_mask(expr.span);
28 if let Some(replacement) = brutalize_cast(ty, arg_text, &mask) {
29 self.transforms.push(Transform::Replace { span: expr.span, replacement });
30 return ControlFlow::Continue(());
31 }
32 }
33 if let Some(arg_text) = payable_call(self.source, expr) {
34 let mask = deterministic_mask(expr.span);
35 let replacement = brutalize_payable_address(arg_text, &mask);
36 self.transforms.push(Transform::Replace { span: expr.span, replacement });
37 return ControlFlow::Continue(());
38 }
39
40 self.walk_expr(expr)
41 }
42
43 fn visit_item_function(
44 &mut self,
45 func: &'ast ItemFunction<'ast>,
46 ) -> ControlFlow<Self::BreakValue> {
47 self.transforms.extend(assembly_transforms(func));
48 self.walk_item_function(func)
49 }
50}
51
52fn payable_call<'src>(source: &'src str, expr: &Expr<'_>) -> Option<&'src str> {
53 let ExprKind::Payable(call_args) = &expr.kind else { return None };
54 let CallArgsKind::Unnamed(args_exprs) = &call_args.kind else { return None };
55 let arg_text = span_text(source, args_exprs.first()?.span)?;
56 (!arg_text.is_empty()).then_some(arg_text)
57}
58
59fn cast_call<'ast, 'src>(
60 source: &'src str,
61 expr: &'ast Expr<'ast>,
62) -> Option<(&'ast Type<'ast>, &'src str)> {
63 let ExprKind::Call(callee, call_args) = &expr.kind else { return None };
64 let ExprKind::Type(ty) = &callee.kind else { return None };
65 let CallArgsKind::Unnamed(args_exprs) = &call_args.kind else { return None };
66 let arg_text = span_text(source, args_exprs.first()?.span)?;
67 (!arg_text.is_empty()).then_some((ty, arg_text))
68}
69
70pub(super) fn collect_transforms<'ast>(
71 source: &str,
72 ast: &'ast SourceUnit<'ast>,
73) -> Vec<Transform> {
74 let mut visitor = BrutalizerVisitor::new(source);
75 let _ = visitor.visit_source_unit(ast);
76 visitor.transforms
77}