blob: 6ae2824becfe4e993c0ba68050d634605b5a4eca [file] [log] [blame]
David Tolnay55337722016-09-11 12:58:56 -07001// Adapted from libsyntax.
2
3//! AST walker. Each overridden visit method has full control over what
4//! happens with its node, it can do its own traversal of the node's children,
5//! call `visit::walk_*` to apply the default traversal algorithm, or prevent
6//! deeper traversal by doing nothing.
7//!
8//! Note: it is an important invariant that the default visitor walks the body
9//! of a function in "execution order" (more concretely, reverse post-order
10//! with respect to the CFG implied by the AST), meaning that if AST node A may
11//! execute before AST node B, then A is visited first. The borrow checker in
12//! particular relies on this property.
13//!
14//! Note: walking an AST before macro expansion is probably a bad idea. For
15//! instance, a walker looking for item names in a module will miss all of
16//! those that are created by the expansion of a macro.
17
18use super::*;
19
20/// Each method of the Visitor trait is a hook to be potentially
21/// overridden. Each method's default implementation recursively visits
22/// the substructure of the input via the corresponding `walk` method;
23/// e.g. the `visit_mod` method by default calls `visit::walk_mod`.
24///
25/// If you want to ensure that your code handles every variant
26/// explicitly, you need to override each method. (And you also need
27/// to monitor future changes to `Visitor` in case a new method with a
28/// new default implementation gets introduced.)
29pub trait Visitor: Sized {
30 fn visit_ident(&mut self, _ident: &Ident) {}
David Tolnayc4fbf402016-09-24 09:31:47 -070031 fn visit_macro_input(&mut self, macro_input: &MacroInput) {
32 walk_macro_input(self, macro_input)
David Tolnay55337722016-09-11 12:58:56 -070033 }
34 fn visit_ty(&mut self, ty: &Ty) {
35 walk_ty(self, ty)
36 }
37 fn visit_generics(&mut self, generics: &Generics) {
38 walk_generics(self, generics)
39 }
40 fn visit_ty_param_bound(&mut self, bound: &TyParamBound) {
41 walk_ty_param_bound(self, bound)
42 }
43 fn visit_poly_trait_ref(&mut self, trait_ref: &PolyTraitRef, modifier: &TraitBoundModifier) {
44 walk_poly_trait_ref(self, trait_ref, modifier)
45 }
46 fn visit_variant_data(&mut self, data: &VariantData, _ident: &Ident, _generics: &Generics) {
47 walk_variant_data(self, data)
48 }
49 fn visit_field(&mut self, field: &Field) {
50 walk_field(self, field)
51 }
52 fn visit_variant(&mut self, variant: &Variant, generics: &Generics) {
53 walk_variant(self, variant, generics)
54 }
55 fn visit_lifetime(&mut self, _lifetime: &Lifetime) {}
56 fn visit_lifetime_def(&mut self, lifetime: &LifetimeDef) {
57 walk_lifetime_def(self, lifetime)
58 }
59 fn visit_path(&mut self, path: &Path) {
60 walk_path(self, path)
61 }
62 fn visit_path_segment(&mut self, path_segment: &PathSegment) {
63 walk_path_segment(self, path_segment)
64 }
65 fn visit_path_parameters(&mut self, path_parameters: &PathParameters) {
66 walk_path_parameters(self, path_parameters)
67 }
68 fn visit_assoc_type_binding(&mut self, type_binding: &TypeBinding) {
69 walk_assoc_type_binding(self, type_binding)
70 }
71 fn visit_attribute(&mut self, _attr: &Attribute) {}
72 fn visit_fn_ret_ty(&mut self, ret_ty: &FunctionRetTy) {
73 walk_fn_ret_ty(self, ret_ty)
74 }
David Tolnay68eb4c32016-10-07 23:30:32 -070075 fn visit_const_expr(&mut self, expr: &ConstExpr) {
76 walk_const_expr(self, expr)
David Tolnay429168f2016-10-05 23:41:04 -070077 }
David Tolnay68eb4c32016-10-07 23:30:32 -070078 fn visit_lit(&mut self, _lit: &Lit) {}
David Tolnay55337722016-09-11 12:58:56 -070079}
80
81#[macro_export]
82macro_rules! walk_list {
83 ($visitor: expr, $method: ident, $list: expr) => {
84 for elem in $list {
85 $visitor.$method(elem)
86 }
87 };
88 ($visitor: expr, $method: ident, $list: expr, $($extra_args: expr),*) => {
89 for elem in $list {
90 $visitor.$method(elem, $($extra_args,)*)
91 }
92 }
93}
94
95pub fn walk_opt_ident<V: Visitor>(visitor: &mut V, opt_ident: &Option<Ident>) {
96 if let Some(ref ident) = *opt_ident {
97 visitor.visit_ident(ident);
98 }
99}
100
101pub fn walk_lifetime_def<V: Visitor>(visitor: &mut V, lifetime_def: &LifetimeDef) {
102 visitor.visit_lifetime(&lifetime_def.lifetime);
103 walk_list!(visitor, visit_lifetime, &lifetime_def.bounds);
104}
105
106pub fn walk_poly_trait_ref<V>(visitor: &mut V, trait_ref: &PolyTraitRef, _: &TraitBoundModifier)
David Tolnaydaaf7742016-10-03 11:11:43 -0700107 where V: Visitor
David Tolnay55337722016-09-11 12:58:56 -0700108{
109 walk_list!(visitor, visit_lifetime_def, &trait_ref.bound_lifetimes);
110 visitor.visit_path(&trait_ref.trait_ref);
111}
112
David Tolnayc4fbf402016-09-24 09:31:47 -0700113pub fn walk_macro_input<V: Visitor>(visitor: &mut V, macro_input: &MacroInput) {
114 visitor.visit_ident(&macro_input.ident);
115 visitor.visit_generics(&macro_input.generics);
116 match macro_input.body {
David Tolnay55337722016-09-11 12:58:56 -0700117 Body::Enum(ref variants) => {
David Tolnayc4fbf402016-09-24 09:31:47 -0700118 walk_list!(visitor, visit_variant, variants, &macro_input.generics);
David Tolnay55337722016-09-11 12:58:56 -0700119 }
120 Body::Struct(ref variant_data) => {
David Tolnaydaaf7742016-10-03 11:11:43 -0700121 visitor.visit_variant_data(variant_data, &macro_input.ident, &macro_input.generics);
David Tolnay55337722016-09-11 12:58:56 -0700122 }
123 }
David Tolnayc4fbf402016-09-24 09:31:47 -0700124 walk_list!(visitor, visit_attribute, &macro_input.attrs);
David Tolnay55337722016-09-11 12:58:56 -0700125}
126
127pub fn walk_variant<V>(visitor: &mut V, variant: &Variant, generics: &Generics)
David Tolnaydaaf7742016-10-03 11:11:43 -0700128 where V: Visitor
David Tolnay55337722016-09-11 12:58:56 -0700129{
130 visitor.visit_ident(&variant.ident);
131 visitor.visit_variant_data(&variant.data, &variant.ident, generics);
132 walk_list!(visitor, visit_attribute, &variant.attrs);
133}
134
135pub fn walk_ty<V: Visitor>(visitor: &mut V, ty: &Ty) {
136 match *ty {
David Tolnay429168f2016-10-05 23:41:04 -0700137 Ty::Slice(ref inner) |
David Tolnaydaaf7742016-10-03 11:11:43 -0700138 Ty::Paren(ref inner) => visitor.visit_ty(inner),
139 Ty::Ptr(ref mutable_type) => visitor.visit_ty(&mutable_type.ty),
David Tolnay55337722016-09-11 12:58:56 -0700140 Ty::Rptr(ref opt_lifetime, ref mutable_type) => {
141 walk_list!(visitor, visit_lifetime, opt_lifetime);
142 visitor.visit_ty(&mutable_type.ty)
143 }
David Tolnay58f6f672016-10-19 08:44:25 -0700144 Ty::Never | Ty::Infer => {}
David Tolnay55337722016-09-11 12:58:56 -0700145 Ty::Tup(ref tuple_element_types) => {
146 walk_list!(visitor, visit_ty, tuple_element_types);
147 }
David Tolnay1391b522016-10-03 21:05:45 -0700148 Ty::BareFn(ref bare_fn) => {
149 walk_list!(visitor, visit_lifetime_def, &bare_fn.lifetimes);
150 for argument in &bare_fn.inputs {
151 walk_opt_ident(visitor, &argument.name);
152 visitor.visit_ty(&argument.ty)
153 }
154 visitor.visit_fn_ret_ty(&bare_fn.output)
David Tolnay55337722016-09-11 12:58:56 -0700155 }
156 Ty::Path(ref maybe_qself, ref path) => {
157 if let Some(ref qself) = *maybe_qself {
158 visitor.visit_ty(&qself.ty);
159 }
160 visitor.visit_path(path);
161 }
162 Ty::ObjectSum(ref inner, ref bounds) => {
163 visitor.visit_ty(inner);
164 walk_list!(visitor, visit_ty_param_bound, bounds);
165 }
David Tolnay429168f2016-10-05 23:41:04 -0700166 Ty::Array(ref inner, ref len) => {
David Tolnay55337722016-09-11 12:58:56 -0700167 visitor.visit_ty(inner);
David Tolnay68eb4c32016-10-07 23:30:32 -0700168 visitor.visit_const_expr(len);
David Tolnay55337722016-09-11 12:58:56 -0700169 }
David Tolnay58f6f672016-10-19 08:44:25 -0700170 Ty::PolyTraitRef(ref bounds) |
David Tolnay55337722016-09-11 12:58:56 -0700171 Ty::ImplTrait(ref bounds) => {
172 walk_list!(visitor, visit_ty_param_bound, bounds);
173 }
David Tolnay55337722016-09-11 12:58:56 -0700174 }
175}
176
177pub fn walk_path<V: Visitor>(visitor: &mut V, path: &Path) {
178 for segment in &path.segments {
179 visitor.visit_path_segment(segment);
180 }
181}
182
183pub fn walk_path_segment<V: Visitor>(visitor: &mut V, segment: &PathSegment) {
184 visitor.visit_ident(&segment.ident);
185 visitor.visit_path_parameters(&segment.parameters);
186}
187
188pub fn walk_path_parameters<V>(visitor: &mut V, path_parameters: &PathParameters)
David Tolnaydaaf7742016-10-03 11:11:43 -0700189 where V: Visitor
David Tolnay55337722016-09-11 12:58:56 -0700190{
191 match *path_parameters {
192 PathParameters::AngleBracketed(ref data) => {
193 walk_list!(visitor, visit_ty, &data.types);
194 walk_list!(visitor, visit_lifetime, &data.lifetimes);
195 walk_list!(visitor, visit_assoc_type_binding, &data.bindings);
196 }
197 PathParameters::Parenthesized(ref data) => {
198 walk_list!(visitor, visit_ty, &data.inputs);
199 walk_list!(visitor, visit_ty, &data.output);
200 }
201 }
202}
203
204pub fn walk_assoc_type_binding<V: Visitor>(visitor: &mut V, type_binding: &TypeBinding) {
205 visitor.visit_ident(&type_binding.ident);
206 visitor.visit_ty(&type_binding.ty);
207}
208
209pub fn walk_ty_param_bound<V: Visitor>(visitor: &mut V, bound: &TyParamBound) {
210 match *bound {
211 TyParamBound::Trait(ref ty, ref modifier) => {
212 visitor.visit_poly_trait_ref(ty, modifier);
213 }
214 TyParamBound::Region(ref lifetime) => {
215 visitor.visit_lifetime(lifetime);
216 }
217 }
218}
219
220pub fn walk_generics<V: Visitor>(visitor: &mut V, generics: &Generics) {
221 for param in &generics.ty_params {
222 visitor.visit_ident(&param.ident);
223 walk_list!(visitor, visit_ty_param_bound, &param.bounds);
224 walk_list!(visitor, visit_ty, &param.default);
225 }
226 walk_list!(visitor, visit_lifetime_def, &generics.lifetimes);
227 for predicate in &generics.where_clause.predicates {
228 match *predicate {
David Tolnaydaaf7742016-10-03 11:11:43 -0700229 WherePredicate::BoundPredicate(WhereBoundPredicate { ref bounded_ty,
230 ref bounds,
231 ref bound_lifetimes,
232 .. }) => {
David Tolnay55337722016-09-11 12:58:56 -0700233 visitor.visit_ty(bounded_ty);
234 walk_list!(visitor, visit_ty_param_bound, bounds);
235 walk_list!(visitor, visit_lifetime_def, bound_lifetimes);
236 }
David Tolnaydaaf7742016-10-03 11:11:43 -0700237 WherePredicate::RegionPredicate(WhereRegionPredicate { ref lifetime,
238 ref bounds,
239 .. }) => {
David Tolnay55337722016-09-11 12:58:56 -0700240 visitor.visit_lifetime(lifetime);
241 walk_list!(visitor, visit_lifetime, bounds);
242 }
243 }
244 }
245}
246
247pub fn walk_fn_ret_ty<V: Visitor>(visitor: &mut V, ret_ty: &FunctionRetTy) {
248 if let FunctionRetTy::Ty(ref output_ty) = *ret_ty {
249 visitor.visit_ty(output_ty)
250 }
251}
252
David Tolnay55337722016-09-11 12:58:56 -0700253pub fn walk_variant_data<V: Visitor>(visitor: &mut V, data: &VariantData) {
254 walk_list!(visitor, visit_field, data.fields());
255}
256
257pub fn walk_field<V: Visitor>(visitor: &mut V, field: &Field) {
258 walk_opt_ident(visitor, &field.ident);
259 visitor.visit_ty(&field.ty);
260 walk_list!(visitor, visit_attribute, &field.attrs);
261}
David Tolnay429168f2016-10-05 23:41:04 -0700262
David Tolnay68eb4c32016-10-07 23:30:32 -0700263pub fn walk_const_expr<V: Visitor>(visitor: &mut V, len: &ConstExpr) {
David Tolnay429168f2016-10-05 23:41:04 -0700264 match *len {
David Tolnay68eb4c32016-10-07 23:30:32 -0700265 ConstExpr::Call(ref function, ref args) => {
David Tolnay58f6f672016-10-19 08:44:25 -0700266 visitor.visit_const_expr(function);
David Tolnay68eb4c32016-10-07 23:30:32 -0700267 walk_list!(visitor, visit_const_expr, args);
268 }
269 ConstExpr::Binary(_op, ref left, ref right) => {
270 visitor.visit_const_expr(left);
271 visitor.visit_const_expr(right);
272 }
273 ConstExpr::Unary(_op, ref v) => {
274 visitor.visit_const_expr(v);
275 }
276 ConstExpr::Lit(ref lit) => {
277 visitor.visit_lit(lit);
278 }
279 ConstExpr::Cast(ref expr, ref ty) => {
280 visitor.visit_const_expr(expr);
281 visitor.visit_ty(ty);
282 }
283 ConstExpr::Path(ref path) => {
David Tolnay429168f2016-10-05 23:41:04 -0700284 visitor.visit_path(path);
285 }
286 }
287}