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