David Tolnay | 5533772 | 2016-09-11 12:58:56 -0700 | [diff] [blame] | 1 | // 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 | |
| 18 | use 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.) |
| 29 | pub trait Visitor: Sized { |
| 30 | fn visit_ident(&mut self, _ident: &Ident) {} |
David Tolnay | c4fbf40 | 2016-09-24 09:31:47 -0700 | [diff] [blame] | 31 | fn visit_macro_input(&mut self, macro_input: &MacroInput) { |
| 32 | walk_macro_input(self, macro_input) |
David Tolnay | 5533772 | 2016-09-11 12:58:56 -0700 | [diff] [blame] | 33 | } |
| 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 | } |
| 75 | } |
| 76 | |
| 77 | #[macro_export] |
| 78 | macro_rules! walk_list { |
| 79 | ($visitor: expr, $method: ident, $list: expr) => { |
| 80 | for elem in $list { |
| 81 | $visitor.$method(elem) |
| 82 | } |
| 83 | }; |
| 84 | ($visitor: expr, $method: ident, $list: expr, $($extra_args: expr),*) => { |
| 85 | for elem in $list { |
| 86 | $visitor.$method(elem, $($extra_args,)*) |
| 87 | } |
| 88 | } |
| 89 | } |
| 90 | |
| 91 | pub fn walk_opt_ident<V: Visitor>(visitor: &mut V, opt_ident: &Option<Ident>) { |
| 92 | if let Some(ref ident) = *opt_ident { |
| 93 | visitor.visit_ident(ident); |
| 94 | } |
| 95 | } |
| 96 | |
| 97 | pub fn walk_lifetime_def<V: Visitor>(visitor: &mut V, lifetime_def: &LifetimeDef) { |
| 98 | visitor.visit_lifetime(&lifetime_def.lifetime); |
| 99 | walk_list!(visitor, visit_lifetime, &lifetime_def.bounds); |
| 100 | } |
| 101 | |
| 102 | pub fn walk_poly_trait_ref<V>(visitor: &mut V, trait_ref: &PolyTraitRef, _: &TraitBoundModifier) |
David Tolnay | daaf774 | 2016-10-03 11:11:43 -0700 | [diff] [blame] | 103 | where V: Visitor |
David Tolnay | 5533772 | 2016-09-11 12:58:56 -0700 | [diff] [blame] | 104 | { |
| 105 | walk_list!(visitor, visit_lifetime_def, &trait_ref.bound_lifetimes); |
| 106 | visitor.visit_path(&trait_ref.trait_ref); |
| 107 | } |
| 108 | |
David Tolnay | c4fbf40 | 2016-09-24 09:31:47 -0700 | [diff] [blame] | 109 | pub fn walk_macro_input<V: Visitor>(visitor: &mut V, macro_input: &MacroInput) { |
| 110 | visitor.visit_ident(¯o_input.ident); |
| 111 | visitor.visit_generics(¯o_input.generics); |
| 112 | match macro_input.body { |
David Tolnay | 5533772 | 2016-09-11 12:58:56 -0700 | [diff] [blame] | 113 | Body::Enum(ref variants) => { |
David Tolnay | c4fbf40 | 2016-09-24 09:31:47 -0700 | [diff] [blame] | 114 | walk_list!(visitor, visit_variant, variants, ¯o_input.generics); |
David Tolnay | 5533772 | 2016-09-11 12:58:56 -0700 | [diff] [blame] | 115 | } |
| 116 | Body::Struct(ref variant_data) => { |
David Tolnay | daaf774 | 2016-10-03 11:11:43 -0700 | [diff] [blame] | 117 | visitor.visit_variant_data(variant_data, ¯o_input.ident, ¯o_input.generics); |
David Tolnay | 5533772 | 2016-09-11 12:58:56 -0700 | [diff] [blame] | 118 | } |
| 119 | } |
David Tolnay | c4fbf40 | 2016-09-24 09:31:47 -0700 | [diff] [blame] | 120 | walk_list!(visitor, visit_attribute, ¯o_input.attrs); |
David Tolnay | 5533772 | 2016-09-11 12:58:56 -0700 | [diff] [blame] | 121 | } |
| 122 | |
| 123 | pub fn walk_variant<V>(visitor: &mut V, variant: &Variant, generics: &Generics) |
David Tolnay | daaf774 | 2016-10-03 11:11:43 -0700 | [diff] [blame] | 124 | where V: Visitor |
David Tolnay | 5533772 | 2016-09-11 12:58:56 -0700 | [diff] [blame] | 125 | { |
| 126 | visitor.visit_ident(&variant.ident); |
| 127 | visitor.visit_variant_data(&variant.data, &variant.ident, generics); |
| 128 | walk_list!(visitor, visit_attribute, &variant.attrs); |
| 129 | } |
| 130 | |
| 131 | pub fn walk_ty<V: Visitor>(visitor: &mut V, ty: &Ty) { |
| 132 | match *ty { |
David Tolnay | daaf774 | 2016-10-03 11:11:43 -0700 | [diff] [blame] | 133 | Ty::Vec(ref inner) | |
| 134 | Ty::Paren(ref inner) => visitor.visit_ty(inner), |
| 135 | Ty::Ptr(ref mutable_type) => visitor.visit_ty(&mutable_type.ty), |
David Tolnay | 5533772 | 2016-09-11 12:58:56 -0700 | [diff] [blame] | 136 | Ty::Rptr(ref opt_lifetime, ref mutable_type) => { |
| 137 | walk_list!(visitor, visit_lifetime, opt_lifetime); |
| 138 | visitor.visit_ty(&mutable_type.ty) |
| 139 | } |
David Tolnay | daaf774 | 2016-10-03 11:11:43 -0700 | [diff] [blame] | 140 | Ty::Never => {} |
David Tolnay | 5533772 | 2016-09-11 12:58:56 -0700 | [diff] [blame] | 141 | Ty::Tup(ref tuple_element_types) => { |
| 142 | walk_list!(visitor, visit_ty, tuple_element_types); |
| 143 | } |
David Tolnay | 1391b52 | 2016-10-03 21:05:45 -0700 | [diff] [blame^] | 144 | Ty::BareFn(ref bare_fn) => { |
| 145 | walk_list!(visitor, visit_lifetime_def, &bare_fn.lifetimes); |
| 146 | for argument in &bare_fn.inputs { |
| 147 | walk_opt_ident(visitor, &argument.name); |
| 148 | visitor.visit_ty(&argument.ty) |
| 149 | } |
| 150 | visitor.visit_fn_ret_ty(&bare_fn.output) |
David Tolnay | 5533772 | 2016-09-11 12:58:56 -0700 | [diff] [blame] | 151 | } |
| 152 | Ty::Path(ref maybe_qself, ref path) => { |
| 153 | if let Some(ref qself) = *maybe_qself { |
| 154 | visitor.visit_ty(&qself.ty); |
| 155 | } |
| 156 | visitor.visit_path(path); |
| 157 | } |
| 158 | Ty::ObjectSum(ref inner, ref bounds) => { |
| 159 | visitor.visit_ty(inner); |
| 160 | walk_list!(visitor, visit_ty_param_bound, bounds); |
| 161 | } |
| 162 | Ty::FixedLengthVec(ref inner, _len) => { |
| 163 | visitor.visit_ty(inner); |
| 164 | } |
| 165 | Ty::PolyTraitRef(ref bounds) => { |
| 166 | walk_list!(visitor, visit_ty_param_bound, bounds); |
| 167 | } |
| 168 | Ty::ImplTrait(ref bounds) => { |
| 169 | walk_list!(visitor, visit_ty_param_bound, bounds); |
| 170 | } |
| 171 | Ty::Infer => {} |
| 172 | } |
| 173 | } |
| 174 | |
| 175 | pub fn walk_path<V: Visitor>(visitor: &mut V, path: &Path) { |
| 176 | for segment in &path.segments { |
| 177 | visitor.visit_path_segment(segment); |
| 178 | } |
| 179 | } |
| 180 | |
| 181 | pub fn walk_path_segment<V: Visitor>(visitor: &mut V, segment: &PathSegment) { |
| 182 | visitor.visit_ident(&segment.ident); |
| 183 | visitor.visit_path_parameters(&segment.parameters); |
| 184 | } |
| 185 | |
| 186 | pub fn walk_path_parameters<V>(visitor: &mut V, path_parameters: &PathParameters) |
David Tolnay | daaf774 | 2016-10-03 11:11:43 -0700 | [diff] [blame] | 187 | where V: Visitor |
David Tolnay | 5533772 | 2016-09-11 12:58:56 -0700 | [diff] [blame] | 188 | { |
| 189 | match *path_parameters { |
| 190 | PathParameters::AngleBracketed(ref data) => { |
| 191 | walk_list!(visitor, visit_ty, &data.types); |
| 192 | walk_list!(visitor, visit_lifetime, &data.lifetimes); |
| 193 | walk_list!(visitor, visit_assoc_type_binding, &data.bindings); |
| 194 | } |
| 195 | PathParameters::Parenthesized(ref data) => { |
| 196 | walk_list!(visitor, visit_ty, &data.inputs); |
| 197 | walk_list!(visitor, visit_ty, &data.output); |
| 198 | } |
| 199 | } |
| 200 | } |
| 201 | |
| 202 | pub fn walk_assoc_type_binding<V: Visitor>(visitor: &mut V, type_binding: &TypeBinding) { |
| 203 | visitor.visit_ident(&type_binding.ident); |
| 204 | visitor.visit_ty(&type_binding.ty); |
| 205 | } |
| 206 | |
| 207 | pub fn walk_ty_param_bound<V: Visitor>(visitor: &mut V, bound: &TyParamBound) { |
| 208 | match *bound { |
| 209 | TyParamBound::Trait(ref ty, ref modifier) => { |
| 210 | visitor.visit_poly_trait_ref(ty, modifier); |
| 211 | } |
| 212 | TyParamBound::Region(ref lifetime) => { |
| 213 | visitor.visit_lifetime(lifetime); |
| 214 | } |
| 215 | } |
| 216 | } |
| 217 | |
| 218 | pub fn walk_generics<V: Visitor>(visitor: &mut V, generics: &Generics) { |
| 219 | for param in &generics.ty_params { |
| 220 | visitor.visit_ident(¶m.ident); |
| 221 | walk_list!(visitor, visit_ty_param_bound, ¶m.bounds); |
| 222 | walk_list!(visitor, visit_ty, ¶m.default); |
| 223 | } |
| 224 | walk_list!(visitor, visit_lifetime_def, &generics.lifetimes); |
| 225 | for predicate in &generics.where_clause.predicates { |
| 226 | match *predicate { |
David Tolnay | daaf774 | 2016-10-03 11:11:43 -0700 | [diff] [blame] | 227 | WherePredicate::BoundPredicate(WhereBoundPredicate { ref bounded_ty, |
| 228 | ref bounds, |
| 229 | ref bound_lifetimes, |
| 230 | .. }) => { |
David Tolnay | 5533772 | 2016-09-11 12:58:56 -0700 | [diff] [blame] | 231 | visitor.visit_ty(bounded_ty); |
| 232 | walk_list!(visitor, visit_ty_param_bound, bounds); |
| 233 | walk_list!(visitor, visit_lifetime_def, bound_lifetimes); |
| 234 | } |
David Tolnay | daaf774 | 2016-10-03 11:11:43 -0700 | [diff] [blame] | 235 | WherePredicate::RegionPredicate(WhereRegionPredicate { ref lifetime, |
| 236 | ref bounds, |
| 237 | .. }) => { |
David Tolnay | 5533772 | 2016-09-11 12:58:56 -0700 | [diff] [blame] | 238 | visitor.visit_lifetime(lifetime); |
| 239 | walk_list!(visitor, visit_lifetime, bounds); |
| 240 | } |
| 241 | } |
| 242 | } |
| 243 | } |
| 244 | |
| 245 | pub fn walk_fn_ret_ty<V: Visitor>(visitor: &mut V, ret_ty: &FunctionRetTy) { |
| 246 | if let FunctionRetTy::Ty(ref output_ty) = *ret_ty { |
| 247 | visitor.visit_ty(output_ty) |
| 248 | } |
| 249 | } |
| 250 | |
David Tolnay | 5533772 | 2016-09-11 12:58:56 -0700 | [diff] [blame] | 251 | pub fn walk_variant_data<V: Visitor>(visitor: &mut V, data: &VariantData) { |
| 252 | walk_list!(visitor, visit_field, data.fields()); |
| 253 | } |
| 254 | |
| 255 | pub fn walk_field<V: Visitor>(visitor: &mut V, field: &Field) { |
| 256 | walk_opt_ident(visitor, &field.ident); |
| 257 | visitor.visit_ty(&field.ty); |
| 258 | walk_list!(visitor, visit_attribute, &field.attrs); |
| 259 | } |