hooks_derive_core/
tlpc.rs

1pub struct ExprCallPath<'a> {
2    pub func_path: &'a mut syn::ExprPath,
3    pub paren_token: &'a mut syn::token::Paren,
4    pub args: &'a mut syn::punctuated::Punctuated<syn::Expr, syn::Token![,]>,
5}
6
7/// Mutate Top-Level-Path-Calls
8pub fn tlpc(expr: &mut syn::Expr, mutate_func_path: &mut impl FnMut(ExprCallPath)) {
9    match expr {
10        syn::Expr::Array(array) => {
11            for elem in array.elems.iter_mut() {
12                tlpc(elem, mutate_func_path);
13            }
14        }
15        syn::Expr::Assign(a) => tlpc(&mut a.right, mutate_func_path),
16        syn::Expr::AssignOp(a) => tlpc(&mut a.right, mutate_func_path),
17        syn::Expr::Async(_) => {
18            // `async {}` is untouched
19        }
20        syn::Expr::Await(_) => {
21            // `fut.await` is untouched
22            // because hook closure is not async and
23            // there cannot be any await exprs in top level.
24        }
25        syn::Expr::Binary(b) => {
26            tlpc(&mut b.left, mutate_func_path);
27            tlpc(&mut b.right, mutate_func_path);
28        }
29        syn::Expr::Block(_) => {
30            // `{}` is untouched because it is not top level
31        }
32        syn::Expr::Box(b) => tlpc(&mut b.expr, mutate_func_path),
33        syn::Expr::Break(_) => {
34            // `break` is untouched
35            // because there cannot be any break in top level.
36        }
37        syn::Expr::Call(c) => {
38            for arg in c.args.iter_mut() {
39                tlpc(arg, mutate_func_path);
40            }
41
42            if let syn::Expr::Path(func_path) = &mut *c.func {
43                mutate_func_path(ExprCallPath {
44                    func_path,
45                    paren_token: &mut c.paren_token,
46                    args: &mut c.args,
47                });
48            } else {
49                tlpc(&mut c.func, mutate_func_path);
50            }
51        }
52        syn::Expr::Cast(c) => tlpc(&mut c.expr, mutate_func_path),
53        syn::Expr::Closure(_) => {
54            // `|| {}` is untouched
55            // because exprs in the body are not top level
56        }
57        syn::Expr::Continue(_) => {
58            // `continue` is untouched
59            // with the same reason as `break`
60        }
61        syn::Expr::Field(f) => tlpc(&mut f.base, mutate_func_path),
62        syn::Expr::ForLoop(f) => tlpc(&mut f.expr, mutate_func_path),
63        syn::Expr::Group(g) => tlpc(&mut g.expr, mutate_func_path),
64        syn::Expr::If(i) => tlpc(&mut i.cond, mutate_func_path),
65        syn::Expr::Index(i) => {
66            tlpc(&mut i.expr, mutate_func_path);
67            tlpc(&mut i.index, mutate_func_path);
68        }
69        syn::Expr::Let(l) => tlpc(&mut l.expr, mutate_func_path),
70        syn::Expr::Lit(_) => {
71            // literals are untouched
72            // because there is no function call
73        }
74        syn::Expr::Loop(_) => {
75            // `loop {}` is untouched
76            // because there are no exprs in top level
77        }
78        syn::Expr::Macro(_) => {
79            // macros are untouched
80        }
81        syn::Expr::Match(m) => tlpc(&mut m.expr, mutate_func_path),
82        syn::Expr::MethodCall(m) => {
83            for arg in m.args.iter_mut() {
84                tlpc(arg, mutate_func_path);
85            }
86            tlpc(&mut m.receiver, mutate_func_path);
87        }
88        syn::Expr::Paren(p) => tlpc(&mut p.expr, mutate_func_path),
89        syn::Expr::Path(_) => {
90            // `std::mem::replace` is untouched
91            // because there is no function call
92        }
93        syn::Expr::Range(r) => {
94            if let Some(e) = &mut r.from {
95                tlpc(e, mutate_func_path);
96            }
97            if let Some(e) = &mut r.to {
98                tlpc(e, mutate_func_path);
99            }
100        }
101        syn::Expr::Reference(r) => {
102            tlpc(&mut r.expr, mutate_func_path);
103        }
104        syn::Expr::Repeat(_) => {
105            // `[expr; N]` is untouched
106            // because the expr is not considered top level
107        }
108        syn::Expr::Return(r) => {
109            if let Some(e) = &mut r.expr {
110                tlpc(e, mutate_func_path);
111            }
112        }
113        syn::Expr::Struct(s) => {
114            for field in s.fields.iter_mut() {
115                tlpc(&mut field.expr, mutate_func_path);
116            }
117            if let Some(e) = &mut s.rest {
118                tlpc(e, mutate_func_path);
119            }
120        }
121        syn::Expr::Try(t) => tlpc(&mut t.expr, mutate_func_path),
122        syn::Expr::TryBlock(_) => {
123            // `try {}` is untouched
124            // because there are no exprs in top level
125        }
126        syn::Expr::Tuple(t) => {
127            for elem in t.elems.iter_mut() {
128                tlpc(elem, mutate_func_path);
129            }
130        }
131        syn::Expr::Type(t) => tlpc(&mut t.expr, mutate_func_path),
132        syn::Expr::Unary(u) => tlpc(&mut u.expr, mutate_func_path),
133        syn::Expr::Unsafe(_) => {
134            // `unsafe {}` is untouched
135            // because there are no exprs in top level
136        }
137        syn::Expr::Verbatim(_) => {
138            // untouched because not interpreted by Syn
139        }
140        syn::Expr::While(w) => tlpc(&mut w.cond, mutate_func_path),
141        syn::Expr::Yield(_) => {
142            // `yield` is untouched
143            // with the same reason as `break`
144        }
145        _ => {
146            // unknown exprs are untouched
147            // Adding new variants or changing behavior of current variants
148            // would be a BREAKING CHANGE
149        }
150    }
151}