From: Niko Matsakis Date: Tue, 17 Nov 2015 22:32:12 +0000 (-0500) Subject: Refactor the HIR so that items are stored in a map in the `Crate`, X-Git-Url: https://git.lizzy.rs/?a=commitdiff_plain;h=767ee79c4c38e7909c7fefef1b33be4612112336;p=rust.git Refactor the HIR so that items are stored in a map in the `Crate`, rather being stored inline. Refactor (and rename) the visitor so that (by default) it only visits the interior content of an item not nested items. This is a [breaking-change] for anyone who uses the HIR visitor. Besides changing `visit::` to `intravisit::`, you need to refactor your visitor in one of two ways, depending on what it requires: 1. If you just want to visit all items (most common), you should call `krate.visit_all_items(&mut visitor)`. 2. If you need to visit nested items in the middle of the parent items, you should override `visit_nested_item` with something like: `self.visit_item(self.tcx.map.expect_item(item.id))`, presuming you have access to a tcx (or at least a HIR map). --- diff --git a/mk/crates.mk b/mk/crates.mk index 89a836eb7cb..d77d99a4a1a 100644 --- a/mk/crates.mk +++ b/mk/crates.mk @@ -96,7 +96,7 @@ DEPS_rustc_driver := arena flate getopts graphviz libc rustc rustc_back rustc_bo rustc_typeck rustc_mir rustc_resolve log syntax serialize rustc_llvm \ rustc_trans rustc_privacy rustc_lint rustc_front -DEPS_rustc_front := std syntax log serialize +DEPS_rustc_front := std syntax log serialize rustc_data_structures DEPS_rustc_lint := rustc log syntax DEPS_rustc_llvm := native:rustllvm libc std rustc_bitflags DEPS_rustc_mir := rustc rustc_front syntax diff --git a/src/librustc_front/fold.rs b/src/librustc_front/fold.rs index b963aba9c07..7ec4e1ba331 100644 --- a/src/librustc_front/fold.rs +++ b/src/librustc_front/fold.rs @@ -77,10 +77,14 @@ fn fold_foreign_item(&mut self, ni: P) -> P { noop_fold_foreign_item(ni, self) } - fn fold_item(&mut self, i: P) -> P { + fn fold_item(&mut self, i: Item) -> Item { noop_fold_item(i, self) } + fn fold_item_id(&mut self, i: ItemId) -> ItemId { + noop_fold_item_id(i, self) + } + fn fold_struct_field(&mut self, sf: StructField) -> StructField { noop_fold_struct_field(sf, self) } @@ -271,10 +275,16 @@ fn fold_where_predicate(&mut self, where_predicate: WherePredicate) -> WherePred noop_fold_where_predicate(where_predicate, self) } + /// called for the `id` on each declaration fn new_id(&mut self, i: NodeId) -> NodeId { i } + /// called for ids that are references (e.g., ItemDef) + fn map_id(&mut self, i: NodeId) -> NodeId { + i + } + fn new_span(&mut self, sp: Span) -> Span { sp } @@ -342,7 +352,7 @@ pub fn noop_fold_decl(d: P, fld: &mut T) -> P { span: fld.new_span(span), }, DeclItem(it) => Spanned { - node: DeclItem(fld.fold_item(it)), + node: DeclItem(fld.fold_item_id(it)), span: fld.new_span(span), }, } @@ -879,34 +889,40 @@ pub fn noop_fold_impl_item(i: P, folder: &mut T) -> P(Mod { inner, items }: Mod, folder: &mut T) -> Mod { +pub fn noop_fold_mod(Mod { inner, item_ids }: Mod, folder: &mut T) -> Mod { Mod { inner: folder.new_span(inner), - items: items.into_iter().map(|x| folder.fold_item(x)).collect(), + item_ids: item_ids.into_iter().map(|x| folder.fold_item_id(x)).collect(), } } -pub fn noop_fold_crate(Crate { module, attrs, config, span, exported_macros }: Crate, +pub fn noop_fold_crate(Crate { module, attrs, config, span, + exported_macros, items }: Crate, folder: &mut T) -> Crate { let config = folder.fold_meta_items(config); - let crate_mod = folder.fold_item(P(hir::Item { + let crate_mod = folder.fold_item(hir::Item { name: token::special_idents::invalid.name, attrs: attrs, id: DUMMY_NODE_ID, vis: hir::Public, span: span, node: hir::ItemMod(module), - })); + }); - let (module, attrs, span) = - crate_mod.and_then(|hir::Item { attrs, span, node, .. }| { + let (module, attrs, span) = match crate_mod { + hir::Item { attrs, span, node, .. } => { match node { hir::ItemMod(m) => (m, attrs, span), _ => panic!("fold converted a module to not a module"), } - }); + } + }; + + let items = items.into_iter() + .map(|(id, item)| (id, folder.fold_item(item))) + .collect(); Crate { module: module, @@ -914,31 +930,37 @@ pub fn noop_fold_crate(Crate { module, attrs, config, span, exported_ config: config, span: span, exported_macros: exported_macros, + items: items, } } -pub fn noop_fold_item(item: P, folder: &mut T) -> P { - item.map(|Item { id, name, attrs, node, vis, span }| { - let id = folder.new_id(id); - let node = folder.fold_item_underscore(node); - // FIXME: we should update the impl_pretty_name, but it uses pretty printing. - // let ident = match node { - // // The node may have changed, recompute the "pretty" impl name. - // ItemImpl(_, _, _, ref maybe_trait, ref ty, _) => { - // impl_pretty_name(maybe_trait, Some(&**ty)) - // } - // _ => ident - // }; - - Item { - id: id, - name: folder.fold_name(name), - attrs: fold_attrs(attrs, folder), - node: node, - vis: vis, - span: folder.new_span(span), - } - }) +pub fn noop_fold_item_id(i: ItemId, folder: &mut T) -> ItemId { + let id = folder.map_id(i.id); + ItemId { id: id } +} + +// fold one item into one item +pub fn noop_fold_item(item: Item, folder: &mut T) -> Item { + let Item { id, name, attrs, node, vis, span } = item; + let id = folder.new_id(id); + let node = folder.fold_item_underscore(node); + // FIXME: we should update the impl_pretty_name, but it uses pretty printing. + // let ident = match node { + // // The node may have changed, recompute the "pretty" impl name. + // ItemImpl(_, _, _, ref maybe_trait, ref ty, _) => { + // impl_pretty_name(maybe_trait, Some(&**ty)) + // } + // _ => ident + // }; + + Item { + id: id, + name: folder.fold_name(name), + attrs: fold_attrs(attrs, folder), + node: node, + vis: vis, + span: folder.new_span(span), + } } pub fn noop_fold_foreign_item(ni: P, folder: &mut T) -> P { diff --git a/src/librustc_front/hir.rs b/src/librustc_front/hir.rs index 1fa7c9d301c..4232254327c 100644 --- a/src/librustc_front/hir.rs +++ b/src/librustc_front/hir.rs @@ -35,6 +35,8 @@ pub use self::Visibility::*; pub use self::PathParameters::*; +use intravisit::Visitor; +use rustc_data_structures::fnv::FnvHashMap; use syntax::codemap::{self, Span, Spanned, DUMMY_SP, ExpnId}; use syntax::abi::Abi; use syntax::ast::{Name, Ident, NodeId, DUMMY_NODE_ID, TokenTree, AsmDialect}; @@ -320,13 +322,42 @@ pub struct WhereEqPredicate { pub ty: P, } -#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Debug)] pub struct Crate { pub module: Mod, pub attrs: Vec, pub config: CrateConfig, pub span: Span, pub exported_macros: Vec, + pub items: FnvHashMap, +} + +impl Crate { + pub fn item(&self, id: NodeId) -> &Item { + &self.items[&id] + } + + /// Visits all items in the crate in some determinstic (but + /// unspecified) order. If you just need to process every item, + /// but don't care about nesting, this method is the best choice. + /// + /// If you do care about nesting -- usually because your algorithm + /// follows lexical scoping rules -- then you want a different + /// approach. You should override `visit_nested_item` in your + /// visitor and then call `intravisit::walk_crate` instead. + pub fn visit_all_items<'hir, V:Visitor<'hir>>(&'hir self, visitor: &mut V) { + // In principle, we could just iterate over the hashmap, but + // in practice that makes the order of error reporting vary + // with small changes in the input etc etc, which makes the + // test base hard to maintain. So instead we sort by node-id + // so as to get reproducible results. + let mut pairs: Vec<_> = self.items.iter().collect(); + pairs.sort_by(|&(id1, _), &(id2, _)| id1.cmp(id2)); + + for (_, item) in pairs { + visitor.visit_item(item); + } + } } /// A macro definition, in this crate or imported from another. @@ -537,7 +568,7 @@ pub enum Decl_ { /// A local (let) binding: DeclLocal(P), /// An item binding: - DeclItem(P), + DeclItem(ItemId), } /// represents one arm of a 'match' @@ -992,7 +1023,7 @@ pub struct Mod { /// For `mod foo;`, the inner span ranges from the first token /// to the last token in the external file. pub inner: Span, - pub items: Vec>, + pub item_ids: Vec, } #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] @@ -1205,7 +1236,13 @@ pub fn is_unit(&self) -> bool { } } - +// The bodies for items are stored "out of line", in a separate +// hashmap in the `Crate`. Here we just record the node-id of the item +// so it can fetched later. +#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] +pub struct ItemId { + pub id: NodeId, +} // FIXME (#3300): Should allow items to be anonymous. Right now // we just use dummy names for anon items. diff --git a/src/librustc_front/intravisit.rs b/src/librustc_front/intravisit.rs new file mode 100644 index 00000000000..9c923ea32ef --- /dev/null +++ b/src/librustc_front/intravisit.rs @@ -0,0 +1,816 @@ +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! HIR walker. Each overridden visit method has full control over what +//! happens with its node, it can do its own traversal of the node's children, +//! call `visit::walk_*` to apply the default traversal algorithm, or prevent +//! deeper traversal by doing nothing. +//! +//! Note: it is an important invariant that the default visitor walks the body +//! of a function in "execution order" (more concretely, reverse post-order +//! with respect to the CFG implied by the AST), meaning that if AST node A may +//! execute before AST node B, then A is visited first. The borrow checker in +//! particular relies on this property. +//! +//! Note: walking an AST before macro expansion is probably a bad idea. For +//! instance, a walker looking for item names in a module will miss all of +//! those that are created by the expansion of a macro. + +use syntax::abi::Abi; +use syntax::ast::{Ident, NodeId, CRATE_NODE_ID, Name, Attribute}; +use syntax::codemap::Span; +use hir::*; + +#[derive(Copy, Clone, PartialEq, Eq)] +pub enum FnKind<'a> { + /// fn foo() or extern "Abi" fn foo() + ItemFn(Name, &'a Generics, Unsafety, Constness, Abi, Visibility), + + /// fn foo(&self) + Method(Name, &'a MethodSig, Option), + + /// |x, y| {} + Closure, +} + +/// Each method of the Visitor trait is a hook to be potentially +/// overridden. Each method's default implementation recursively visits +/// the substructure of the input via the corresponding `walk` method; +/// e.g. the `visit_mod` method by default calls `visit::walk_mod`. +/// +/// Note that this visitor does NOT visit nested items by default. If +/// you simply want to visit all items in the crate in some order, you +/// should call `Crate::visit_all_items`. Otherwise, see the comment +/// on `visit_nested_item` for details on how to visit nested items. +/// +/// If you want to ensure that your code handles every variant +/// explicitly, you need to override each method. (And you also need +/// to monitor future changes to `Visitor` in case a new method with a +/// new default implementation gets introduced.) +pub trait Visitor<'v> : Sized { + /////////////////////////////////////////////////////////////////////////// + // Nested items. + + /// Invoked when a nested item is encountered. By default, does + /// nothing. If you want a deep walk, you need to override to + /// fetch the item contents. But most of the time, it is easier + /// (and better) to invoke `Crate::visit_all_items`, which visits + /// all items in the crate in some order (but doesn't respect + /// nesting). + #[allow(unused_variables)] + fn visit_nested_item(&mut self, id: ItemId) { + } + + /// Visit the top-level item and (optionally) nested items. See + /// `visit_nested_item` for details. + fn visit_item(&mut self, i: &'v Item) { + walk_item(self, i) + } + + /////////////////////////////////////////////////////////////////////////// + + fn visit_name(&mut self, _span: Span, _name: Name) { + // Nothing to do. + } + fn visit_ident(&mut self, span: Span, ident: Ident) { + walk_ident(self, span, ident); + } + fn visit_mod(&mut self, m: &'v Mod, _s: Span, _n: NodeId) { + walk_mod(self, m) + } + fn visit_foreign_item(&mut self, i: &'v ForeignItem) { + walk_foreign_item(self, i) + } + fn visit_local(&mut self, l: &'v Local) { + walk_local(self, l) + } + fn visit_block(&mut self, b: &'v Block) { + walk_block(self, b) + } + fn visit_stmt(&mut self, s: &'v Stmt) { + walk_stmt(self, s) + } + fn visit_arm(&mut self, a: &'v Arm) { + walk_arm(self, a) + } + fn visit_pat(&mut self, p: &'v Pat) { + walk_pat(self, p) + } + fn visit_decl(&mut self, d: &'v Decl) { + walk_decl(self, d) + } + fn visit_expr(&mut self, ex: &'v Expr) { + walk_expr(self, ex) + } + fn visit_expr_post(&mut self, _ex: &'v Expr) { + } + fn visit_ty(&mut self, t: &'v Ty) { + walk_ty(self, t) + } + fn visit_generics(&mut self, g: &'v Generics) { + walk_generics(self, g) + } + fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v FnDecl, b: &'v Block, s: Span, _: NodeId) { + walk_fn(self, fk, fd, b, s) + } + fn visit_trait_item(&mut self, ti: &'v TraitItem) { + walk_trait_item(self, ti) + } + fn visit_impl_item(&mut self, ii: &'v ImplItem) { + walk_impl_item(self, ii) + } + fn visit_trait_ref(&mut self, t: &'v TraitRef) { + walk_trait_ref(self, t) + } + fn visit_ty_param_bound(&mut self, bounds: &'v TyParamBound) { + walk_ty_param_bound(self, bounds) + } + fn visit_poly_trait_ref(&mut self, t: &'v PolyTraitRef, m: &'v TraitBoundModifier) { + walk_poly_trait_ref(self, t, m) + } + fn visit_variant_data(&mut self, + s: &'v VariantData, + _: Name, + _: &'v Generics, + _: NodeId, + _: Span) { + walk_struct_def(self, s) + } + fn visit_struct_field(&mut self, s: &'v StructField) { + walk_struct_field(self, s) + } + fn visit_enum_def(&mut self, + enum_definition: &'v EnumDef, + generics: &'v Generics, + item_id: NodeId, + _: Span) { + walk_enum_def(self, enum_definition, generics, item_id) + } + fn visit_variant(&mut self, v: &'v Variant, g: &'v Generics, item_id: NodeId) { + walk_variant(self, v, g, item_id) + } + fn visit_lifetime(&mut self, lifetime: &'v Lifetime) { + walk_lifetime(self, lifetime) + } + fn visit_lifetime_def(&mut self, lifetime: &'v LifetimeDef) { + walk_lifetime_def(self, lifetime) + } + fn visit_explicit_self(&mut self, es: &'v ExplicitSelf) { + walk_explicit_self(self, es) + } + fn visit_path(&mut self, path: &'v Path, _id: NodeId) { + walk_path(self, path) + } + fn visit_path_list_item(&mut self, prefix: &'v Path, item: &'v PathListItem) { + walk_path_list_item(self, prefix, item) + } + fn visit_path_segment(&mut self, path_span: Span, path_segment: &'v PathSegment) { + walk_path_segment(self, path_span, path_segment) + } + fn visit_path_parameters(&mut self, path_span: Span, path_parameters: &'v PathParameters) { + walk_path_parameters(self, path_span, path_parameters) + } + fn visit_assoc_type_binding(&mut self, type_binding: &'v TypeBinding) { + walk_assoc_type_binding(self, type_binding) + } + fn visit_attribute(&mut self, _attr: &'v Attribute) { + } + fn visit_macro_def(&mut self, macro_def: &'v MacroDef) { + walk_macro_def(self, macro_def) + } +} + +pub fn walk_opt_name<'v, V: Visitor<'v>>(visitor: &mut V, span: Span, opt_name: Option) { + for name in opt_name { + visitor.visit_name(span, name); + } +} + +pub fn walk_opt_ident<'v, V: Visitor<'v>>(visitor: &mut V, span: Span, opt_ident: Option) { + for ident in opt_ident { + visitor.visit_ident(span, ident); + } +} + +pub fn walk_ident<'v, V: Visitor<'v>>(visitor: &mut V, span: Span, ident: Ident) { + visitor.visit_name(span, ident.name); +} + +/// Walks the contents of a crate. See also `Crate::visit_all_items`. +pub fn walk_crate<'v, V: Visitor<'v>>(visitor: &mut V, krate: &'v Crate) { + visitor.visit_mod(&krate.module, krate.span, CRATE_NODE_ID); + walk_list!(visitor, visit_attribute, &krate.attrs); + walk_list!(visitor, visit_macro_def, &krate.exported_macros); +} + +pub fn walk_macro_def<'v, V: Visitor<'v>>(visitor: &mut V, macro_def: &'v MacroDef) { + visitor.visit_name(macro_def.span, macro_def.name); + walk_opt_name(visitor, macro_def.span, macro_def.imported_from); + walk_list!(visitor, visit_attribute, ¯o_def.attrs); +} + +pub fn walk_mod<'v, V: Visitor<'v>>(visitor: &mut V, module: &'v Mod) { + for &item_id in &module.item_ids { + visitor.visit_nested_item(item_id); + } +} + +pub fn walk_local<'v, V: Visitor<'v>>(visitor: &mut V, local: &'v Local) { + visitor.visit_pat(&local.pat); + walk_list!(visitor, visit_ty, &local.ty); + walk_list!(visitor, visit_expr, &local.init); +} + +pub fn walk_lifetime<'v, V: Visitor<'v>>(visitor: &mut V, lifetime: &'v Lifetime) { + visitor.visit_name(lifetime.span, lifetime.name); +} + +pub fn walk_lifetime_def<'v, V: Visitor<'v>>(visitor: &mut V, lifetime_def: &'v LifetimeDef) { + visitor.visit_lifetime(&lifetime_def.lifetime); + walk_list!(visitor, visit_lifetime, &lifetime_def.bounds); +} + +pub fn walk_explicit_self<'v, V: Visitor<'v>>(visitor: &mut V, explicit_self: &'v ExplicitSelf) { + match explicit_self.node { + SelfStatic => {} + SelfValue(name) => { + visitor.visit_name(explicit_self.span, name) + } + SelfRegion(ref opt_lifetime, _, name) => { + visitor.visit_name(explicit_self.span, name); + walk_list!(visitor, visit_lifetime, opt_lifetime); + } + SelfExplicit(ref typ, name) => { + visitor.visit_name(explicit_self.span, name); + visitor.visit_ty(typ) + } + } +} + +pub fn walk_poly_trait_ref<'v, V>(visitor: &mut V, + trait_ref: &'v PolyTraitRef, + _modifier: &'v TraitBoundModifier) + where V: Visitor<'v> +{ + walk_list!(visitor, visit_lifetime_def, &trait_ref.bound_lifetimes); + visitor.visit_trait_ref(&trait_ref.trait_ref); +} + +pub fn walk_trait_ref<'v, V>(visitor: &mut V, trait_ref: &'v TraitRef) + where V: Visitor<'v> +{ + visitor.visit_path(&trait_ref.path, trait_ref.ref_id) +} + +pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) { + visitor.visit_name(item.span, item.name); + match item.node { + ItemExternCrate(opt_name) => { + walk_opt_name(visitor, item.span, opt_name) + } + ItemUse(ref vp) => { + match vp.node { + ViewPathSimple(name, ref path) => { + visitor.visit_name(vp.span, name); + visitor.visit_path(path, item.id); + } + ViewPathGlob(ref path) => { + visitor.visit_path(path, item.id); + } + ViewPathList(ref prefix, ref list) => { + if !list.is_empty() { + for item in list { + visitor.visit_path_list_item(prefix, item) + } + } else { + visitor.visit_path(prefix, item.id); + } + } + } + } + ItemStatic(ref typ, _, ref expr) | + ItemConst(ref typ, ref expr) => { + visitor.visit_ty(typ); + visitor.visit_expr(expr); + } + ItemFn(ref declaration, unsafety, constness, abi, ref generics, ref body) => { + visitor.visit_fn(FnKind::ItemFn(item.name, + generics, + unsafety, + constness, + abi, + item.vis), + declaration, + body, + item.span, + item.id) + } + ItemMod(ref module) => { + visitor.visit_mod(module, item.span, item.id) + } + ItemForeignMod(ref foreign_module) => { + walk_list!(visitor, visit_foreign_item, &foreign_module.items); + } + ItemTy(ref typ, ref type_parameters) => { + visitor.visit_ty(typ); + visitor.visit_generics(type_parameters) + } + ItemEnum(ref enum_definition, ref type_parameters) => { + visitor.visit_generics(type_parameters); + visitor.visit_enum_def(enum_definition, type_parameters, item.id, item.span) + } + ItemDefaultImpl(_, ref trait_ref) => { + visitor.visit_trait_ref(trait_ref) + } + ItemImpl(_, _, ref type_parameters, ref opt_trait_reference, ref typ, ref impl_items) => { + visitor.visit_generics(type_parameters); + walk_list!(visitor, visit_trait_ref, opt_trait_reference); + visitor.visit_ty(typ); + walk_list!(visitor, visit_impl_item, impl_items); + } + ItemStruct(ref struct_definition, ref generics) => { + visitor.visit_generics(generics); + visitor.visit_variant_data(struct_definition, item.name, generics, item.id, item.span); + } + ItemTrait(_, ref generics, ref bounds, ref methods) => { + visitor.visit_generics(generics); + walk_list!(visitor, visit_ty_param_bound, bounds); + walk_list!(visitor, visit_trait_item, methods); + } + } + walk_list!(visitor, visit_attribute, &item.attrs); +} + +pub fn walk_enum_def<'v, V: Visitor<'v>>(visitor: &mut V, + enum_definition: &'v EnumDef, + generics: &'v Generics, + item_id: NodeId) { + walk_list!(visitor, + visit_variant, + &enum_definition.variants, + generics, + item_id); +} + +pub fn walk_variant<'v, V: Visitor<'v>>(visitor: &mut V, + variant: &'v Variant, + generics: &'v Generics, + item_id: NodeId) { + visitor.visit_name(variant.span, variant.node.name); + visitor.visit_variant_data(&variant.node.data, + variant.node.name, + generics, + item_id, + variant.span); + walk_list!(visitor, visit_expr, &variant.node.disr_expr); + walk_list!(visitor, visit_attribute, &variant.node.attrs); +} + +pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty) { + match typ.node { + TyVec(ref ty) => { + visitor.visit_ty(ty) + } + TyPtr(ref mutable_type) => { + visitor.visit_ty(&mutable_type.ty) + } + TyRptr(ref opt_lifetime, ref mutable_type) => { + walk_list!(visitor, visit_lifetime, opt_lifetime); + visitor.visit_ty(&mutable_type.ty) + } + TyTup(ref tuple_element_types) => { + walk_list!(visitor, visit_ty, tuple_element_types); + } + TyBareFn(ref function_declaration) => { + walk_fn_decl(visitor, &function_declaration.decl); + walk_list!(visitor, visit_lifetime_def, &function_declaration.lifetimes); + } + TyPath(ref maybe_qself, ref path) => { + if let Some(ref qself) = *maybe_qself { + visitor.visit_ty(&qself.ty); + } + visitor.visit_path(path, typ.id); + } + TyObjectSum(ref ty, ref bounds) => { + visitor.visit_ty(ty); + walk_list!(visitor, visit_ty_param_bound, bounds); + } + TyFixedLengthVec(ref ty, ref expression) => { + visitor.visit_ty(ty); + visitor.visit_expr(expression) + } + TyPolyTraitRef(ref bounds) => { + walk_list!(visitor, visit_ty_param_bound, bounds); + } + TyTypeof(ref expression) => { + visitor.visit_expr(expression) + } + TyInfer => {} + } +} + +pub fn walk_path<'v, V: Visitor<'v>>(visitor: &mut V, path: &'v Path) { + for segment in &path.segments { + visitor.visit_path_segment(path.span, segment); + } +} + +pub fn walk_path_list_item<'v, V: Visitor<'v>>(visitor: &mut V, + prefix: &'v Path, + item: &'v PathListItem) { + for segment in &prefix.segments { + visitor.visit_path_segment(prefix.span, segment); + } + + walk_opt_name(visitor, item.span, item.node.name()); + walk_opt_name(visitor, item.span, item.node.rename()); +} + +pub fn walk_path_segment<'v, V: Visitor<'v>>(visitor: &mut V, + path_span: Span, + segment: &'v PathSegment) { + visitor.visit_ident(path_span, segment.identifier); + visitor.visit_path_parameters(path_span, &segment.parameters); +} + +pub fn walk_path_parameters<'v, V: Visitor<'v>>(visitor: &mut V, + _path_span: Span, + path_parameters: &'v PathParameters) { + match *path_parameters { + AngleBracketedParameters(ref data) => { + walk_list!(visitor, visit_ty, &data.types); + walk_list!(visitor, visit_lifetime, &data.lifetimes); + walk_list!(visitor, visit_assoc_type_binding, &data.bindings); + } + ParenthesizedParameters(ref data) => { + walk_list!(visitor, visit_ty, &data.inputs); + walk_list!(visitor, visit_ty, &data.output); + } + } +} + +pub fn walk_assoc_type_binding<'v, V: Visitor<'v>>(visitor: &mut V, + type_binding: &'v TypeBinding) { + visitor.visit_name(type_binding.span, type_binding.name); + visitor.visit_ty(&type_binding.ty); +} + +pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat) { + match pattern.node { + PatEnum(ref path, ref opt_children) => { + visitor.visit_path(path, pattern.id); + if let Some(ref children) = *opt_children { + walk_list!(visitor, visit_pat, children); + } + } + PatQPath(ref qself, ref path) => { + visitor.visit_ty(&qself.ty); + visitor.visit_path(path, pattern.id) + } + PatStruct(ref path, ref fields, _) => { + visitor.visit_path(path, pattern.id); + for field in fields { + visitor.visit_name(field.span, field.node.name); + visitor.visit_pat(&field.node.pat) + } + } + PatTup(ref tuple_elements) => { + walk_list!(visitor, visit_pat, tuple_elements); + } + PatBox(ref subpattern) | + PatRegion(ref subpattern, _) => { + visitor.visit_pat(subpattern) + } + PatIdent(_, ref pth1, ref optional_subpattern) => { + visitor.visit_ident(pth1.span, pth1.node); + walk_list!(visitor, visit_pat, optional_subpattern); + } + PatLit(ref expression) => visitor.visit_expr(expression), + PatRange(ref lower_bound, ref upper_bound) => { + visitor.visit_expr(lower_bound); + visitor.visit_expr(upper_bound) + } + PatWild => (), + PatVec(ref prepatterns, ref slice_pattern, ref postpatterns) => { + walk_list!(visitor, visit_pat, prepatterns); + walk_list!(visitor, visit_pat, slice_pattern); + walk_list!(visitor, visit_pat, postpatterns); + } + } +} + +pub fn walk_foreign_item<'v, V: Visitor<'v>>(visitor: &mut V, foreign_item: &'v ForeignItem) { + visitor.visit_name(foreign_item.span, foreign_item.name); + + match foreign_item.node { + ForeignItemFn(ref function_declaration, ref generics) => { + walk_fn_decl(visitor, function_declaration); + visitor.visit_generics(generics) + } + ForeignItemStatic(ref typ, _) => visitor.visit_ty(typ), + } + + walk_list!(visitor, visit_attribute, &foreign_item.attrs); +} + +pub fn walk_ty_param_bound<'v, V: Visitor<'v>>(visitor: &mut V, bound: &'v TyParamBound) { + match *bound { + TraitTyParamBound(ref typ, ref modifier) => { + visitor.visit_poly_trait_ref(typ, modifier); + } + RegionTyParamBound(ref lifetime) => { + visitor.visit_lifetime(lifetime); + } + } +} + +pub fn walk_generics<'v, V: Visitor<'v>>(visitor: &mut V, generics: &'v Generics) { + for param in &generics.ty_params { + visitor.visit_name(param.span, param.name); + walk_list!(visitor, visit_ty_param_bound, ¶m.bounds); + walk_list!(visitor, visit_ty, ¶m.default); + } + walk_list!(visitor, visit_lifetime_def, &generics.lifetimes); + for predicate in &generics.where_clause.predicates { + match predicate { + &WherePredicate::BoundPredicate(WhereBoundPredicate{ref bounded_ty, + ref bounds, + ref bound_lifetimes, + ..}) => { + visitor.visit_ty(bounded_ty); + walk_list!(visitor, visit_ty_param_bound, bounds); + walk_list!(visitor, visit_lifetime_def, bound_lifetimes); + } + &WherePredicate::RegionPredicate(WhereRegionPredicate{ref lifetime, + ref bounds, + ..}) => { + visitor.visit_lifetime(lifetime); + walk_list!(visitor, visit_lifetime, bounds); + } + &WherePredicate::EqPredicate(WhereEqPredicate{id, + ref path, + ref ty, + ..}) => { + visitor.visit_path(path, id); + visitor.visit_ty(ty); + } + } + } +} + +pub fn walk_fn_ret_ty<'v, V: Visitor<'v>>(visitor: &mut V, ret_ty: &'v FunctionRetTy) { + if let Return(ref output_ty) = *ret_ty { + visitor.visit_ty(output_ty) + } +} + +pub fn walk_fn_decl<'v, V: Visitor<'v>>(visitor: &mut V, function_declaration: &'v FnDecl) { + for argument in &function_declaration.inputs { + visitor.visit_pat(&argument.pat); + visitor.visit_ty(&argument.ty) + } + walk_fn_ret_ty(visitor, &function_declaration.output) +} + +pub fn walk_fn_decl_nopat<'v, V: Visitor<'v>>(visitor: &mut V, function_declaration: &'v FnDecl) { + for argument in &function_declaration.inputs { + visitor.visit_ty(&argument.ty) + } + walk_fn_ret_ty(visitor, &function_declaration.output) +} + +pub fn walk_fn_kind<'v, V: Visitor<'v>>(visitor: &mut V, function_kind: FnKind<'v>) { + match function_kind { + FnKind::ItemFn(_, generics, _, _, _, _) => { + visitor.visit_generics(generics); + } + FnKind::Method(_, sig, _) => { + visitor.visit_generics(&sig.generics); + visitor.visit_explicit_self(&sig.explicit_self); + } + FnKind::Closure => {} + } +} + +pub fn walk_fn<'v, V: Visitor<'v>>(visitor: &mut V, + function_kind: FnKind<'v>, + function_declaration: &'v FnDecl, + function_body: &'v Block, + _span: Span) { + walk_fn_decl(visitor, function_declaration); + walk_fn_kind(visitor, function_kind); + visitor.visit_block(function_body) +} + +pub fn walk_trait_item<'v, V: Visitor<'v>>(visitor: &mut V, trait_item: &'v TraitItem) { + visitor.visit_name(trait_item.span, trait_item.name); + walk_list!(visitor, visit_attribute, &trait_item.attrs); + match trait_item.node { + ConstTraitItem(ref ty, ref default) => { + visitor.visit_ty(ty); + walk_list!(visitor, visit_expr, default); + } + MethodTraitItem(ref sig, None) => { + visitor.visit_explicit_self(&sig.explicit_self); + visitor.visit_generics(&sig.generics); + walk_fn_decl(visitor, &sig.decl); + } + MethodTraitItem(ref sig, Some(ref body)) => { + visitor.visit_fn(FnKind::Method(trait_item.name, sig, None), + &sig.decl, + body, + trait_item.span, + trait_item.id); + } + TypeTraitItem(ref bounds, ref default) => { + walk_list!(visitor, visit_ty_param_bound, bounds); + walk_list!(visitor, visit_ty, default); + } + } +} + +pub fn walk_impl_item<'v, V: Visitor<'v>>(visitor: &mut V, impl_item: &'v ImplItem) { + visitor.visit_name(impl_item.span, impl_item.name); + walk_list!(visitor, visit_attribute, &impl_item.attrs); + match impl_item.node { + ImplItemKind::Const(ref ty, ref expr) => { + visitor.visit_ty(ty); + visitor.visit_expr(expr); + } + ImplItemKind::Method(ref sig, ref body) => { + visitor.visit_fn(FnKind::Method(impl_item.name, sig, Some(impl_item.vis)), + &sig.decl, + body, + impl_item.span, + impl_item.id); + } + ImplItemKind::Type(ref ty) => { + visitor.visit_ty(ty); + } + } +} + +pub fn walk_struct_def<'v, V: Visitor<'v>>(visitor: &mut V, struct_definition: &'v VariantData) { + walk_list!(visitor, visit_struct_field, struct_definition.fields()); +} + +pub fn walk_struct_field<'v, V: Visitor<'v>>(visitor: &mut V, struct_field: &'v StructField) { + walk_opt_name(visitor, struct_field.span, struct_field.node.name()); + visitor.visit_ty(&struct_field.node.ty); + walk_list!(visitor, visit_attribute, &struct_field.node.attrs); +} + +pub fn walk_block<'v, V: Visitor<'v>>(visitor: &mut V, block: &'v Block) { + walk_list!(visitor, visit_stmt, &block.stmts); + walk_list!(visitor, visit_expr, &block.expr); +} + +pub fn walk_stmt<'v, V: Visitor<'v>>(visitor: &mut V, statement: &'v Stmt) { + match statement.node { + StmtDecl(ref declaration, _) => visitor.visit_decl(declaration), + StmtExpr(ref expression, _) | StmtSemi(ref expression, _) => { + visitor.visit_expr(expression) + } + } +} + +pub fn walk_decl<'v, V: Visitor<'v>>(visitor: &mut V, declaration: &'v Decl) { + match declaration.node { + DeclLocal(ref local) => visitor.visit_local(local), + DeclItem(item) => visitor.visit_nested_item(item), + } +} + +pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) { + match expression.node { + ExprBox(ref subexpression) => { + visitor.visit_expr(subexpression) + } + ExprVec(ref subexpressions) => { + walk_list!(visitor, visit_expr, subexpressions); + } + ExprRepeat(ref element, ref count) => { + visitor.visit_expr(element); + visitor.visit_expr(count) + } + ExprStruct(ref path, ref fields, ref optional_base) => { + visitor.visit_path(path, expression.id); + for field in fields { + visitor.visit_name(field.name.span, field.name.node); + visitor.visit_expr(&field.expr) + } + walk_list!(visitor, visit_expr, optional_base); + } + ExprTup(ref subexpressions) => { + walk_list!(visitor, visit_expr, subexpressions); + } + ExprCall(ref callee_expression, ref arguments) => { + walk_list!(visitor, visit_expr, arguments); + visitor.visit_expr(callee_expression) + } + ExprMethodCall(ref name, ref types, ref arguments) => { + visitor.visit_name(name.span, name.node); + walk_list!(visitor, visit_expr, arguments); + walk_list!(visitor, visit_ty, types); + } + ExprBinary(_, ref left_expression, ref right_expression) => { + visitor.visit_expr(left_expression); + visitor.visit_expr(right_expression) + } + ExprAddrOf(_, ref subexpression) | ExprUnary(_, ref subexpression) => { + visitor.visit_expr(subexpression) + } + ExprLit(_) => {} + ExprCast(ref subexpression, ref typ) => { + visitor.visit_expr(subexpression); + visitor.visit_ty(typ) + } + ExprIf(ref head_expression, ref if_block, ref optional_else) => { + visitor.visit_expr(head_expression); + visitor.visit_block(if_block); + walk_list!(visitor, visit_expr, optional_else); + } + ExprWhile(ref subexpression, ref block, opt_ident) => { + visitor.visit_expr(subexpression); + visitor.visit_block(block); + walk_opt_ident(visitor, expression.span, opt_ident) + } + ExprLoop(ref block, opt_ident) => { + visitor.visit_block(block); + walk_opt_ident(visitor, expression.span, opt_ident) + } + ExprMatch(ref subexpression, ref arms, _) => { + visitor.visit_expr(subexpression); + walk_list!(visitor, visit_arm, arms); + } + ExprClosure(_, ref function_declaration, ref body) => { + visitor.visit_fn(FnKind::Closure, + function_declaration, + body, + expression.span, + expression.id) + } + ExprBlock(ref block) => visitor.visit_block(block), + ExprAssign(ref left_hand_expression, ref right_hand_expression) => { + visitor.visit_expr(right_hand_expression); + visitor.visit_expr(left_hand_expression) + } + ExprAssignOp(_, ref left_expression, ref right_expression) => { + visitor.visit_expr(right_expression); + visitor.visit_expr(left_expression) + } + ExprField(ref subexpression, ref name) => { + visitor.visit_expr(subexpression); + visitor.visit_name(name.span, name.node); + } + ExprTupField(ref subexpression, _) => { + visitor.visit_expr(subexpression); + } + ExprIndex(ref main_expression, ref index_expression) => { + visitor.visit_expr(main_expression); + visitor.visit_expr(index_expression) + } + ExprRange(ref start, ref end) => { + walk_list!(visitor, visit_expr, start); + walk_list!(visitor, visit_expr, end); + } + ExprPath(ref maybe_qself, ref path) => { + if let Some(ref qself) = *maybe_qself { + visitor.visit_ty(&qself.ty); + } + visitor.visit_path(path, expression.id) + } + ExprBreak(ref opt_sp_ident) | ExprAgain(ref opt_sp_ident) => { + for sp_ident in opt_sp_ident { + visitor.visit_ident(sp_ident.span, sp_ident.node); + } + } + ExprRet(ref optional_expression) => { + walk_list!(visitor, visit_expr, optional_expression); + } + ExprInlineAsm(ref ia) => { + for &(_, ref input) in &ia.inputs { + visitor.visit_expr(&input) + } + for &(_, ref output, _) in &ia.outputs { + visitor.visit_expr(&output) + } + } + } + + visitor.visit_expr_post(expression) +} + +pub fn walk_arm<'v, V: Visitor<'v>>(visitor: &mut V, arm: &'v Arm) { + walk_list!(visitor, visit_pat, &arm.pats); + walk_list!(visitor, visit_expr, &arm.guard); + visitor.visit_expr(&arm.body); + walk_list!(visitor, visit_attribute, &arm.attrs); +} diff --git a/src/librustc_front/lib.rs b/src/librustc_front/lib.rs index 022744cbc3a..d8c5eac1feb 100644 --- a/src/librustc_front/lib.rs +++ b/src/librustc_front/lib.rs @@ -45,13 +45,14 @@ #[macro_use] #[no_link] extern crate rustc_bitflags; +extern crate rustc_data_structures; extern crate serialize as rustc_serialize; // used by deriving pub mod hir; pub mod lowering; pub mod fold; -pub mod visit; +pub mod intravisit; pub mod util; pub mod print { diff --git a/src/librustc_front/lowering.rs b/src/librustc_front/lowering.rs index 250379d2d7e..ad081598c11 100644 --- a/src/librustc_front/lowering.rs +++ b/src/librustc_front/lowering.rs @@ -71,6 +71,8 @@ use syntax::owned_slice::OwnedSlice; use syntax::parse::token::{self, str_to_ident}; use syntax::std_inject; +use syntax::visit::{self, Visitor}; +use rustc_data_structures::fnv::FnvHashMap; use std::cell::{Cell, RefCell}; @@ -191,7 +193,7 @@ pub fn lower_decl(lctx: &LoweringContext, d: &Decl) -> P { span: d.span, }), DeclItem(ref it) => P(Spanned { - node: hir::DeclItem(lower_item(lctx, it)), + node: hir::DeclItem(lower_item_id(lctx, it)), span: d.span, }), } @@ -693,17 +695,36 @@ pub fn lower_impl_item(lctx: &LoweringContext, i: &ImplItem) -> P pub fn lower_mod(lctx: &LoweringContext, m: &Mod) -> hir::Mod { hir::Mod { inner: m.inner, - items: m.items.iter().map(|x| lower_item(lctx, x)).collect(), + item_ids: m.items.iter().map(|x| lower_item_id(lctx, x)).collect(), + } +} + +struct ItemLowerer<'lcx, 'interner: 'lcx> { + items: FnvHashMap, + lctx: &'lcx LoweringContext<'interner>, +} + +impl<'lcx, 'interner> Visitor<'lcx> for ItemLowerer<'lcx, 'interner> { + fn visit_item(&mut self, item: &'lcx Item) { + self.items.insert(item.id, lower_item(self.lctx, item)); + visit::walk_item(self, item); } } pub fn lower_crate(lctx: &LoweringContext, c: &Crate) -> hir::Crate { + let items = { + let mut item_lowerer = ItemLowerer { items: FnvHashMap(), lctx: lctx }; + visit::walk_crate(&mut item_lowerer, c); + item_lowerer.items + }; + hir::Crate { module: lower_mod(lctx, &c.module), attrs: c.attrs.clone(), config: c.config.clone(), span: c.span, exported_macros: c.exported_macros.iter().map(|m| lower_macro_def(lctx, m)).collect(), + items: items, } } @@ -721,13 +742,11 @@ pub fn lower_macro_def(_lctx: &LoweringContext, m: &MacroDef) -> hir::MacroDef { } } -// fold one item into possibly many items -pub fn lower_item(lctx: &LoweringContext, i: &Item) -> P { - P(lower_item_simple(lctx, i)) +pub fn lower_item_id(_lctx: &LoweringContext, i: &Item) -> hir::ItemId { + hir::ItemId { id: i.id } } -// fold one item into exactly one item -pub fn lower_item_simple(lctx: &LoweringContext, i: &Item) -> hir::Item { +pub fn lower_item(lctx: &LoweringContext, i: &Item) -> hir::Item { let node = lower_item_underscore(lctx, &i.node); hir::Item { diff --git a/src/librustc_front/print/pprust.rs b/src/librustc_front/print/pprust.rs index 09c814449a9..f29ef0e8217 100644 --- a/src/librustc_front/print/pprust.rs +++ b/src/librustc_front/print/pprust.rs @@ -25,7 +25,7 @@ use syntax::ptr::P; use hir; -use hir::{RegionTyParamBound, TraitTyParamBound, TraitBoundModifier}; +use hir::{Crate, RegionTyParamBound, TraitTyParamBound, TraitBoundModifier}; use std::io::{self, Write, Read}; @@ -54,6 +54,7 @@ impl PpAnn for NoAnn {} pub struct State<'a> { + krate: Option<&'a Crate>, pub s: pp::Printer<'a>, cm: Option<&'a CodeMap>, comments: Option>, @@ -85,13 +86,14 @@ fn literals(&self) -> &Option> { } } -pub fn rust_printer<'a>(writer: Box) -> State<'a> { +pub fn rust_printer<'a>(writer: Box, krate: Option<&'a Crate>) -> State<'a> { static NO_ANN: NoAnn = NoAnn; - rust_printer_annotated(writer, &NO_ANN) + rust_printer_annotated(writer, &NO_ANN, krate) } -pub fn rust_printer_annotated<'a>(writer: Box, ann: &'a PpAnn) -> State<'a> { +pub fn rust_printer_annotated<'a>(writer: Box, ann: &'a PpAnn, krate: Option<&'a Crate>) -> State<'a> { State { + krate: krate, s: pp::mk_printer(writer, default_columns), cm: None, comments: None, @@ -124,7 +126,7 @@ pub fn print_crate<'a>(cm: &'a CodeMap, ann: &'a PpAnn, is_expanded: bool) -> io::Result<()> { - let mut s = State::new_from_input(cm, span_diagnostic, filename, input, out, ann, is_expanded); + let mut s = State::new_from_input(cm, span_diagnostic, filename, input, out, ann, is_expanded, Some(krate)); // When printing the AST, we sometimes need to inject `#[no_std]` here. // Since you can't compile the HIR, it's not necessary. @@ -141,7 +143,8 @@ pub fn new_from_input(cm: &'a CodeMap, input: &mut Read, out: Box, ann: &'a PpAnn, - is_expanded: bool) + is_expanded: bool, + krate: Option<&'a Crate>) -> State<'a> { let (cmnts, lits) = comments::gather_comments_and_literals(span_diagnostic, filename, @@ -158,16 +161,19 @@ pub fn new_from_input(cm: &'a CodeMap, None } else { Some(lits) - }) + }, + krate) } pub fn new(cm: &'a CodeMap, out: Box, ann: &'a PpAnn, comments: Option>, - literals: Option>) + literals: Option>, + krate: Option<&'a Crate>) -> State<'a> { State { + krate: krate, s: pp::mk_printer(out, default_columns), cm: Some(cm), comments: comments.clone(), @@ -187,7 +193,7 @@ pub fn to_string(f: F) -> String { let mut wr = Vec::new(); { - let mut printer = rust_printer(Box::new(&mut wr)); + let mut printer = rust_printer(Box::new(&mut wr), None); f(&mut printer).unwrap(); eof(&mut printer.s).unwrap(); } @@ -451,8 +457,8 @@ pub fn commasep_exprs(&mut self, b: Breaks, exprs: &[P]) -> io::Resul pub fn print_mod(&mut self, _mod: &hir::Mod, attrs: &[ast::Attribute]) -> io::Result<()> { try!(self.print_inner_attributes(attrs)); - for item in &_mod.items { - try!(self.print_item(&**item)); + for item_id in &_mod.item_ids { + try!(self.print_item_id(item_id)); } Ok(()) } @@ -620,6 +626,16 @@ fn print_associated_type(&mut self, word(&mut self.s, ";") } + pub fn print_item_id(&mut self, item_id: &hir::ItemId) -> io::Result<()> { + if let Some(krate) = self.krate { + // skip nested items if krate context was not provided + let item = &krate.items[&item_id.id]; + self.print_item(item) + } else { + Ok(()) + } + } + /// Pretty-print an item pub fn print_item(&mut self, item: &hir::Item) -> io::Result<()> { try!(self.hardbreak_if_not_bol()); @@ -1566,7 +1582,9 @@ pub fn print_decl(&mut self, decl: &hir::Decl) -> io::Result<()> { } self.end() } - hir::DeclItem(ref item) => self.print_item(&**item), + hir::DeclItem(ref item) => { + self.print_item_id(item) + } } } diff --git a/src/librustc_front/util.rs b/src/librustc_front/util.rs index a2c52b274d5..97b25dafb6d 100644 --- a/src/librustc_front/util.rs +++ b/src/librustc_front/util.rs @@ -10,7 +10,7 @@ use hir; use hir::*; -use visit::{self, Visitor, FnKind}; +use intravisit::{self, Visitor, FnKind}; use syntax::ast_util; use syntax::ast::{Ident, Name, NodeId, DUMMY_NODE_ID}; use syntax::codemap::Span; @@ -145,12 +145,26 @@ pub fn unop_to_string(op: UnOp) -> &'static str { } pub struct IdVisitor<'a, O: 'a> { - pub operation: &'a mut O, - pub pass_through_items: bool, - pub visited_outermost: bool, + operation: &'a mut O, + + // In general, the id visitor visits the contents of an item, but + // not including nested trait/impl items, nor other nested items. + // The base visitor itself always skips nested items, but not + // trait/impl items. This means in particular that if you start by + // visiting a trait or an impl, you should not visit the + // trait/impl items respectively. This is handled by setting + // `skip_members` to true when `visit_item` is on the stack. This + // way, if the user begins by calling `visit_trait_item`, we will + // visit the trait item, but if they begin with `visit_item`, we + // won't visit the (nested) trait items. + skip_members: bool, } impl<'a, O: ast_util::IdVisitingOperation> IdVisitor<'a, O> { + pub fn new(operation: &'a mut O) -> IdVisitor<'a, O> { + IdVisitor { operation: operation, skip_members: false } + } + fn visit_generics_helper(&mut self, generics: &Generics) { for type_parameter in generics.ty_params.iter() { self.operation.visit_id(type_parameter.id) @@ -164,22 +178,17 @@ fn visit_generics_helper(&mut self, generics: &Generics) { impl<'a, 'v, O: ast_util::IdVisitingOperation> Visitor<'v> for IdVisitor<'a, O> { fn visit_mod(&mut self, module: &Mod, _: Span, node_id: NodeId) { self.operation.visit_id(node_id); - visit::walk_mod(self, module) + intravisit::walk_mod(self, module) } fn visit_foreign_item(&mut self, foreign_item: &ForeignItem) { self.operation.visit_id(foreign_item.id); - visit::walk_foreign_item(self, foreign_item) + intravisit::walk_foreign_item(self, foreign_item) } fn visit_item(&mut self, item: &Item) { - if !self.pass_through_items { - if self.visited_outermost { - return; - } else { - self.visited_outermost = true - } - } + assert!(!self.skip_members); + self.skip_members = true; self.operation.visit_id(item.id); match item.node { @@ -196,45 +205,44 @@ fn visit_item(&mut self, item: &Item) { } _ => {} } + intravisit::walk_item(self, item); - visit::walk_item(self, item); - - self.visited_outermost = false + self.skip_members = false; } fn visit_local(&mut self, local: &Local) { self.operation.visit_id(local.id); - visit::walk_local(self, local) + intravisit::walk_local(self, local) } fn visit_block(&mut self, block: &Block) { self.operation.visit_id(block.id); - visit::walk_block(self, block) + intravisit::walk_block(self, block) } fn visit_stmt(&mut self, statement: &Stmt) { self.operation.visit_id(stmt_id(statement)); - visit::walk_stmt(self, statement) + intravisit::walk_stmt(self, statement) } fn visit_pat(&mut self, pattern: &Pat) { self.operation.visit_id(pattern.id); - visit::walk_pat(self, pattern) + intravisit::walk_pat(self, pattern) } fn visit_expr(&mut self, expression: &Expr) { self.operation.visit_id(expression.id); - visit::walk_expr(self, expression) + intravisit::walk_expr(self, expression) } fn visit_ty(&mut self, typ: &Ty) { self.operation.visit_id(typ.id); - visit::walk_ty(self, typ) + intravisit::walk_ty(self, typ) } fn visit_generics(&mut self, generics: &Generics) { self.visit_generics_helper(generics); - visit::walk_generics(self, generics) + intravisit::walk_generics(self, generics) } fn visit_fn(&mut self, @@ -243,14 +251,6 @@ fn visit_fn(&mut self, block: &'v Block, span: Span, node_id: NodeId) { - if !self.pass_through_items { - match function_kind { - FnKind::Method(..) if self.visited_outermost => return, - FnKind::Method(..) => self.visited_outermost = true, - _ => {} - } - } - self.operation.visit_id(node_id); match function_kind { @@ -267,18 +267,12 @@ fn visit_fn(&mut self, self.operation.visit_id(argument.id) } - visit::walk_fn(self, function_kind, function_declaration, block, span); - - if !self.pass_through_items { - if let FnKind::Method(..) = function_kind { - self.visited_outermost = false; - } - } + intravisit::walk_fn(self, function_kind, function_declaration, block, span); } fn visit_struct_field(&mut self, struct_field: &StructField) { self.operation.visit_id(struct_field.node.id); - visit::walk_struct_field(self, struct_field) + intravisit::walk_struct_field(self, struct_field) } fn visit_variant_data(&mut self, @@ -288,17 +282,21 @@ fn visit_variant_data(&mut self, _: NodeId, _: Span) { self.operation.visit_id(struct_def.id()); - visit::walk_struct_def(self, struct_def); + intravisit::walk_struct_def(self, struct_def); } fn visit_trait_item(&mut self, ti: &hir::TraitItem) { - self.operation.visit_id(ti.id); - visit::walk_trait_item(self, ti); + if !self.skip_members { + self.operation.visit_id(ti.id); + intravisit::walk_trait_item(self, ti); + } } fn visit_impl_item(&mut self, ii: &hir::ImplItem) { - self.operation.visit_id(ii.id); - visit::walk_impl_item(self, ii); + if !self.skip_members { + self.operation.visit_id(ii.id); + intravisit::walk_impl_item(self, ii); + } } fn visit_lifetime(&mut self, lifetime: &Lifetime) { @@ -311,7 +309,7 @@ fn visit_lifetime_def(&mut self, def: &LifetimeDef) { fn visit_trait_ref(&mut self, trait_ref: &TraitRef) { self.operation.visit_id(trait_ref.ref_id); - visit::walk_trait_ref(self, trait_ref); + intravisit::walk_trait_ref(self, trait_ref); } } @@ -323,11 +321,7 @@ pub fn compute_id_range_for_fn_body(fk: FnKind, id: NodeId) -> ast_util::IdRange { let mut visitor = ast_util::IdRangeComputingVisitor { result: ast_util::IdRange::max() }; - let mut id_visitor = IdVisitor { - operation: &mut visitor, - pass_through_items: false, - visited_outermost: false, - }; + let mut id_visitor = IdVisitor::new(&mut visitor); id_visitor.visit_fn(fk, decl, body, sp, id); id_visitor.operation.result } diff --git a/src/librustc_front/visit.rs b/src/librustc_front/visit.rs deleted file mode 100644 index ec58f31b6de..00000000000 --- a/src/librustc_front/visit.rs +++ /dev/null @@ -1,790 +0,0 @@ -// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! HIR walker. Each overridden visit method has full control over what -//! happens with its node, it can do its own traversal of the node's children, -//! call `visit::walk_*` to apply the default traversal algorithm, or prevent -//! deeper traversal by doing nothing. -//! -//! Note: it is an important invariant that the default visitor walks the body -//! of a function in "execution order" (more concretely, reverse post-order -//! with respect to the CFG implied by the AST), meaning that if AST node A may -//! execute before AST node B, then A is visited first. The borrow checker in -//! particular relies on this property. -//! -//! Note: walking an AST before macro expansion is probably a bad idea. For -//! instance, a walker looking for item names in a module will miss all of -//! those that are created by the expansion of a macro. - -use syntax::abi::Abi; -use syntax::ast::{Ident, NodeId, CRATE_NODE_ID, Name, Attribute}; -use syntax::codemap::Span; -use hir::*; - -#[derive(Copy, Clone, PartialEq, Eq)] -pub enum FnKind<'a> { - /// fn foo() or extern "Abi" fn foo() - ItemFn(Name, &'a Generics, Unsafety, Constness, Abi, Visibility), - - /// fn foo(&self) - Method(Name, &'a MethodSig, Option), - - /// |x, y| {} - Closure, -} - -/// Each method of the Visitor trait is a hook to be potentially -/// overridden. Each method's default implementation recursively visits -/// the substructure of the input via the corresponding `walk` method; -/// e.g. the `visit_mod` method by default calls `visit::walk_mod`. -/// -/// If you want to ensure that your code handles every variant -/// explicitly, you need to override each method. (And you also need -/// to monitor future changes to `Visitor` in case a new method with a -/// new default implementation gets introduced.) -pub trait Visitor<'v> : Sized { - fn visit_name(&mut self, _span: Span, _name: Name) { - // Nothing to do. - } - fn visit_ident(&mut self, span: Span, ident: Ident) { - walk_ident(self, span, ident); - } - fn visit_mod(&mut self, m: &'v Mod, _s: Span, _n: NodeId) { - walk_mod(self, m) - } - fn visit_foreign_item(&mut self, i: &'v ForeignItem) { - walk_foreign_item(self, i) - } - fn visit_item(&mut self, i: &'v Item) { - walk_item(self, i) - } - fn visit_local(&mut self, l: &'v Local) { - walk_local(self, l) - } - fn visit_block(&mut self, b: &'v Block) { - walk_block(self, b) - } - fn visit_stmt(&mut self, s: &'v Stmt) { - walk_stmt(self, s) - } - fn visit_arm(&mut self, a: &'v Arm) { - walk_arm(self, a) - } - fn visit_pat(&mut self, p: &'v Pat) { - walk_pat(self, p) - } - fn visit_decl(&mut self, d: &'v Decl) { - walk_decl(self, d) - } - fn visit_expr(&mut self, ex: &'v Expr) { - walk_expr(self, ex) - } - fn visit_expr_post(&mut self, _ex: &'v Expr) { - } - fn visit_ty(&mut self, t: &'v Ty) { - walk_ty(self, t) - } - fn visit_generics(&mut self, g: &'v Generics) { - walk_generics(self, g) - } - fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v FnDecl, b: &'v Block, s: Span, _: NodeId) { - walk_fn(self, fk, fd, b, s) - } - fn visit_trait_item(&mut self, ti: &'v TraitItem) { - walk_trait_item(self, ti) - } - fn visit_impl_item(&mut self, ii: &'v ImplItem) { - walk_impl_item(self, ii) - } - fn visit_trait_ref(&mut self, t: &'v TraitRef) { - walk_trait_ref(self, t) - } - fn visit_ty_param_bound(&mut self, bounds: &'v TyParamBound) { - walk_ty_param_bound(self, bounds) - } - fn visit_poly_trait_ref(&mut self, t: &'v PolyTraitRef, m: &'v TraitBoundModifier) { - walk_poly_trait_ref(self, t, m) - } - fn visit_variant_data(&mut self, - s: &'v VariantData, - _: Name, - _: &'v Generics, - _: NodeId, - _: Span) { - walk_struct_def(self, s) - } - fn visit_struct_field(&mut self, s: &'v StructField) { - walk_struct_field(self, s) - } - fn visit_enum_def(&mut self, - enum_definition: &'v EnumDef, - generics: &'v Generics, - item_id: NodeId, - _: Span) { - walk_enum_def(self, enum_definition, generics, item_id) - } - fn visit_variant(&mut self, v: &'v Variant, g: &'v Generics, item_id: NodeId) { - walk_variant(self, v, g, item_id) - } - fn visit_lifetime(&mut self, lifetime: &'v Lifetime) { - walk_lifetime(self, lifetime) - } - fn visit_lifetime_def(&mut self, lifetime: &'v LifetimeDef) { - walk_lifetime_def(self, lifetime) - } - fn visit_explicit_self(&mut self, es: &'v ExplicitSelf) { - walk_explicit_self(self, es) - } - fn visit_path(&mut self, path: &'v Path, _id: NodeId) { - walk_path(self, path) - } - fn visit_path_list_item(&mut self, prefix: &'v Path, item: &'v PathListItem) { - walk_path_list_item(self, prefix, item) - } - fn visit_path_segment(&mut self, path_span: Span, path_segment: &'v PathSegment) { - walk_path_segment(self, path_span, path_segment) - } - fn visit_path_parameters(&mut self, path_span: Span, path_parameters: &'v PathParameters) { - walk_path_parameters(self, path_span, path_parameters) - } - fn visit_assoc_type_binding(&mut self, type_binding: &'v TypeBinding) { - walk_assoc_type_binding(self, type_binding) - } - fn visit_attribute(&mut self, _attr: &'v Attribute) { - } - fn visit_macro_def(&mut self, macro_def: &'v MacroDef) { - walk_macro_def(self, macro_def) - } -} - -pub fn walk_opt_name<'v, V: Visitor<'v>>(visitor: &mut V, span: Span, opt_name: Option) { - for name in opt_name { - visitor.visit_name(span, name); - } -} - -pub fn walk_opt_ident<'v, V: Visitor<'v>>(visitor: &mut V, span: Span, opt_ident: Option) { - for ident in opt_ident { - visitor.visit_ident(span, ident); - } -} - -pub fn walk_ident<'v, V: Visitor<'v>>(visitor: &mut V, span: Span, ident: Ident) { - visitor.visit_name(span, ident.name); -} - -pub fn walk_crate<'v, V: Visitor<'v>>(visitor: &mut V, krate: &'v Crate) { - visitor.visit_mod(&krate.module, krate.span, CRATE_NODE_ID); - walk_list!(visitor, visit_attribute, &krate.attrs); - walk_list!(visitor, visit_macro_def, &krate.exported_macros); -} - -pub fn walk_macro_def<'v, V: Visitor<'v>>(visitor: &mut V, macro_def: &'v MacroDef) { - visitor.visit_name(macro_def.span, macro_def.name); - walk_opt_name(visitor, macro_def.span, macro_def.imported_from); - walk_list!(visitor, visit_attribute, ¯o_def.attrs); -} - -pub fn walk_mod<'v, V: Visitor<'v>>(visitor: &mut V, module: &'v Mod) { - walk_list!(visitor, visit_item, &module.items); -} - -pub fn walk_local<'v, V: Visitor<'v>>(visitor: &mut V, local: &'v Local) { - visitor.visit_pat(&local.pat); - walk_list!(visitor, visit_ty, &local.ty); - walk_list!(visitor, visit_expr, &local.init); -} - -pub fn walk_lifetime<'v, V: Visitor<'v>>(visitor: &mut V, lifetime: &'v Lifetime) { - visitor.visit_name(lifetime.span, lifetime.name); -} - -pub fn walk_lifetime_def<'v, V: Visitor<'v>>(visitor: &mut V, lifetime_def: &'v LifetimeDef) { - visitor.visit_lifetime(&lifetime_def.lifetime); - walk_list!(visitor, visit_lifetime, &lifetime_def.bounds); -} - -pub fn walk_explicit_self<'v, V: Visitor<'v>>(visitor: &mut V, explicit_self: &'v ExplicitSelf) { - match explicit_self.node { - SelfStatic => {} - SelfValue(name) => { - visitor.visit_name(explicit_self.span, name) - } - SelfRegion(ref opt_lifetime, _, name) => { - visitor.visit_name(explicit_self.span, name); - walk_list!(visitor, visit_lifetime, opt_lifetime); - } - SelfExplicit(ref typ, name) => { - visitor.visit_name(explicit_self.span, name); - visitor.visit_ty(typ) - } - } -} - -pub fn walk_poly_trait_ref<'v, V>(visitor: &mut V, - trait_ref: &'v PolyTraitRef, - _modifier: &'v TraitBoundModifier) - where V: Visitor<'v> -{ - walk_list!(visitor, visit_lifetime_def, &trait_ref.bound_lifetimes); - visitor.visit_trait_ref(&trait_ref.trait_ref); -} - -pub fn walk_trait_ref<'v, V>(visitor: &mut V, trait_ref: &'v TraitRef) - where V: Visitor<'v> -{ - visitor.visit_path(&trait_ref.path, trait_ref.ref_id) -} - -pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) { - visitor.visit_name(item.span, item.name); - match item.node { - ItemExternCrate(opt_name) => { - walk_opt_name(visitor, item.span, opt_name) - } - ItemUse(ref vp) => { - match vp.node { - ViewPathSimple(name, ref path) => { - visitor.visit_name(vp.span, name); - visitor.visit_path(path, item.id); - } - ViewPathGlob(ref path) => { - visitor.visit_path(path, item.id); - } - ViewPathList(ref prefix, ref list) => { - if !list.is_empty() { - for item in list { - visitor.visit_path_list_item(prefix, item) - } - } else { - visitor.visit_path(prefix, item.id); - } - } - } - } - ItemStatic(ref typ, _, ref expr) | - ItemConst(ref typ, ref expr) => { - visitor.visit_ty(typ); - visitor.visit_expr(expr); - } - ItemFn(ref declaration, unsafety, constness, abi, ref generics, ref body) => { - visitor.visit_fn(FnKind::ItemFn(item.name, - generics, - unsafety, - constness, - abi, - item.vis), - declaration, - body, - item.span, - item.id) - } - ItemMod(ref module) => { - visitor.visit_mod(module, item.span, item.id) - } - ItemForeignMod(ref foreign_module) => { - walk_list!(visitor, visit_foreign_item, &foreign_module.items); - } - ItemTy(ref typ, ref type_parameters) => { - visitor.visit_ty(typ); - visitor.visit_generics(type_parameters) - } - ItemEnum(ref enum_definition, ref type_parameters) => { - visitor.visit_generics(type_parameters); - visitor.visit_enum_def(enum_definition, type_parameters, item.id, item.span) - } - ItemDefaultImpl(_, ref trait_ref) => { - visitor.visit_trait_ref(trait_ref) - } - ItemImpl(_, _, ref type_parameters, ref opt_trait_reference, ref typ, ref impl_items) => { - visitor.visit_generics(type_parameters); - walk_list!(visitor, visit_trait_ref, opt_trait_reference); - visitor.visit_ty(typ); - walk_list!(visitor, visit_impl_item, impl_items); - } - ItemStruct(ref struct_definition, ref generics) => { - visitor.visit_generics(generics); - visitor.visit_variant_data(struct_definition, item.name, generics, item.id, item.span); - } - ItemTrait(_, ref generics, ref bounds, ref methods) => { - visitor.visit_generics(generics); - walk_list!(visitor, visit_ty_param_bound, bounds); - walk_list!(visitor, visit_trait_item, methods); - } - } - walk_list!(visitor, visit_attribute, &item.attrs); -} - -pub fn walk_enum_def<'v, V: Visitor<'v>>(visitor: &mut V, - enum_definition: &'v EnumDef, - generics: &'v Generics, - item_id: NodeId) { - walk_list!(visitor, - visit_variant, - &enum_definition.variants, - generics, - item_id); -} - -pub fn walk_variant<'v, V: Visitor<'v>>(visitor: &mut V, - variant: &'v Variant, - generics: &'v Generics, - item_id: NodeId) { - visitor.visit_name(variant.span, variant.node.name); - visitor.visit_variant_data(&variant.node.data, - variant.node.name, - generics, - item_id, - variant.span); - walk_list!(visitor, visit_expr, &variant.node.disr_expr); - walk_list!(visitor, visit_attribute, &variant.node.attrs); -} - -pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty) { - match typ.node { - TyVec(ref ty) => { - visitor.visit_ty(ty) - } - TyPtr(ref mutable_type) => { - visitor.visit_ty(&mutable_type.ty) - } - TyRptr(ref opt_lifetime, ref mutable_type) => { - walk_list!(visitor, visit_lifetime, opt_lifetime); - visitor.visit_ty(&mutable_type.ty) - } - TyTup(ref tuple_element_types) => { - walk_list!(visitor, visit_ty, tuple_element_types); - } - TyBareFn(ref function_declaration) => { - walk_fn_decl(visitor, &function_declaration.decl); - walk_list!(visitor, visit_lifetime_def, &function_declaration.lifetimes); - } - TyPath(ref maybe_qself, ref path) => { - if let Some(ref qself) = *maybe_qself { - visitor.visit_ty(&qself.ty); - } - visitor.visit_path(path, typ.id); - } - TyObjectSum(ref ty, ref bounds) => { - visitor.visit_ty(ty); - walk_list!(visitor, visit_ty_param_bound, bounds); - } - TyFixedLengthVec(ref ty, ref expression) => { - visitor.visit_ty(ty); - visitor.visit_expr(expression) - } - TyPolyTraitRef(ref bounds) => { - walk_list!(visitor, visit_ty_param_bound, bounds); - } - TyTypeof(ref expression) => { - visitor.visit_expr(expression) - } - TyInfer => {} - } -} - -pub fn walk_path<'v, V: Visitor<'v>>(visitor: &mut V, path: &'v Path) { - for segment in &path.segments { - visitor.visit_path_segment(path.span, segment); - } -} - -pub fn walk_path_list_item<'v, V: Visitor<'v>>(visitor: &mut V, - prefix: &'v Path, - item: &'v PathListItem) { - for segment in &prefix.segments { - visitor.visit_path_segment(prefix.span, segment); - } - - walk_opt_name(visitor, item.span, item.node.name()); - walk_opt_name(visitor, item.span, item.node.rename()); -} - -pub fn walk_path_segment<'v, V: Visitor<'v>>(visitor: &mut V, - path_span: Span, - segment: &'v PathSegment) { - visitor.visit_ident(path_span, segment.identifier); - visitor.visit_path_parameters(path_span, &segment.parameters); -} - -pub fn walk_path_parameters<'v, V: Visitor<'v>>(visitor: &mut V, - _path_span: Span, - path_parameters: &'v PathParameters) { - match *path_parameters { - AngleBracketedParameters(ref data) => { - walk_list!(visitor, visit_ty, &data.types); - walk_list!(visitor, visit_lifetime, &data.lifetimes); - walk_list!(visitor, visit_assoc_type_binding, &data.bindings); - } - ParenthesizedParameters(ref data) => { - walk_list!(visitor, visit_ty, &data.inputs); - walk_list!(visitor, visit_ty, &data.output); - } - } -} - -pub fn walk_assoc_type_binding<'v, V: Visitor<'v>>(visitor: &mut V, - type_binding: &'v TypeBinding) { - visitor.visit_name(type_binding.span, type_binding.name); - visitor.visit_ty(&type_binding.ty); -} - -pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat) { - match pattern.node { - PatEnum(ref path, ref opt_children) => { - visitor.visit_path(path, pattern.id); - if let Some(ref children) = *opt_children { - walk_list!(visitor, visit_pat, children); - } - } - PatQPath(ref qself, ref path) => { - visitor.visit_ty(&qself.ty); - visitor.visit_path(path, pattern.id) - } - PatStruct(ref path, ref fields, _) => { - visitor.visit_path(path, pattern.id); - for field in fields { - visitor.visit_name(field.span, field.node.name); - visitor.visit_pat(&field.node.pat) - } - } - PatTup(ref tuple_elements) => { - walk_list!(visitor, visit_pat, tuple_elements); - } - PatBox(ref subpattern) | - PatRegion(ref subpattern, _) => { - visitor.visit_pat(subpattern) - } - PatIdent(_, ref pth1, ref optional_subpattern) => { - visitor.visit_ident(pth1.span, pth1.node); - walk_list!(visitor, visit_pat, optional_subpattern); - } - PatLit(ref expression) => visitor.visit_expr(expression), - PatRange(ref lower_bound, ref upper_bound) => { - visitor.visit_expr(lower_bound); - visitor.visit_expr(upper_bound) - } - PatWild => (), - PatVec(ref prepatterns, ref slice_pattern, ref postpatterns) => { - walk_list!(visitor, visit_pat, prepatterns); - walk_list!(visitor, visit_pat, slice_pattern); - walk_list!(visitor, visit_pat, postpatterns); - } - } -} - -pub fn walk_foreign_item<'v, V: Visitor<'v>>(visitor: &mut V, foreign_item: &'v ForeignItem) { - visitor.visit_name(foreign_item.span, foreign_item.name); - - match foreign_item.node { - ForeignItemFn(ref function_declaration, ref generics) => { - walk_fn_decl(visitor, function_declaration); - visitor.visit_generics(generics) - } - ForeignItemStatic(ref typ, _) => visitor.visit_ty(typ), - } - - walk_list!(visitor, visit_attribute, &foreign_item.attrs); -} - -pub fn walk_ty_param_bound<'v, V: Visitor<'v>>(visitor: &mut V, bound: &'v TyParamBound) { - match *bound { - TraitTyParamBound(ref typ, ref modifier) => { - visitor.visit_poly_trait_ref(typ, modifier); - } - RegionTyParamBound(ref lifetime) => { - visitor.visit_lifetime(lifetime); - } - } -} - -pub fn walk_generics<'v, V: Visitor<'v>>(visitor: &mut V, generics: &'v Generics) { - for param in &generics.ty_params { - visitor.visit_name(param.span, param.name); - walk_list!(visitor, visit_ty_param_bound, ¶m.bounds); - walk_list!(visitor, visit_ty, ¶m.default); - } - walk_list!(visitor, visit_lifetime_def, &generics.lifetimes); - for predicate in &generics.where_clause.predicates { - match predicate { - &WherePredicate::BoundPredicate(WhereBoundPredicate{ref bounded_ty, - ref bounds, - ref bound_lifetimes, - ..}) => { - visitor.visit_ty(bounded_ty); - walk_list!(visitor, visit_ty_param_bound, bounds); - walk_list!(visitor, visit_lifetime_def, bound_lifetimes); - } - &WherePredicate::RegionPredicate(WhereRegionPredicate{ref lifetime, - ref bounds, - ..}) => { - visitor.visit_lifetime(lifetime); - walk_list!(visitor, visit_lifetime, bounds); - } - &WherePredicate::EqPredicate(WhereEqPredicate{id, - ref path, - ref ty, - ..}) => { - visitor.visit_path(path, id); - visitor.visit_ty(ty); - } - } - } -} - -pub fn walk_fn_ret_ty<'v, V: Visitor<'v>>(visitor: &mut V, ret_ty: &'v FunctionRetTy) { - if let Return(ref output_ty) = *ret_ty { - visitor.visit_ty(output_ty) - } -} - -pub fn walk_fn_decl<'v, V: Visitor<'v>>(visitor: &mut V, function_declaration: &'v FnDecl) { - for argument in &function_declaration.inputs { - visitor.visit_pat(&argument.pat); - visitor.visit_ty(&argument.ty) - } - walk_fn_ret_ty(visitor, &function_declaration.output) -} - -pub fn walk_fn_decl_nopat<'v, V: Visitor<'v>>(visitor: &mut V, function_declaration: &'v FnDecl) { - for argument in &function_declaration.inputs { - visitor.visit_ty(&argument.ty) - } - walk_fn_ret_ty(visitor, &function_declaration.output) -} - -pub fn walk_fn_kind<'v, V: Visitor<'v>>(visitor: &mut V, function_kind: FnKind<'v>) { - match function_kind { - FnKind::ItemFn(_, generics, _, _, _, _) => { - visitor.visit_generics(generics); - } - FnKind::Method(_, sig, _) => { - visitor.visit_generics(&sig.generics); - visitor.visit_explicit_self(&sig.explicit_self); - } - FnKind::Closure => {} - } -} - -pub fn walk_fn<'v, V: Visitor<'v>>(visitor: &mut V, - function_kind: FnKind<'v>, - function_declaration: &'v FnDecl, - function_body: &'v Block, - _span: Span) { - walk_fn_decl(visitor, function_declaration); - walk_fn_kind(visitor, function_kind); - visitor.visit_block(function_body) -} - -pub fn walk_trait_item<'v, V: Visitor<'v>>(visitor: &mut V, trait_item: &'v TraitItem) { - visitor.visit_name(trait_item.span, trait_item.name); - walk_list!(visitor, visit_attribute, &trait_item.attrs); - match trait_item.node { - ConstTraitItem(ref ty, ref default) => { - visitor.visit_ty(ty); - walk_list!(visitor, visit_expr, default); - } - MethodTraitItem(ref sig, None) => { - visitor.visit_explicit_self(&sig.explicit_self); - visitor.visit_generics(&sig.generics); - walk_fn_decl(visitor, &sig.decl); - } - MethodTraitItem(ref sig, Some(ref body)) => { - visitor.visit_fn(FnKind::Method(trait_item.name, sig, None), - &sig.decl, - body, - trait_item.span, - trait_item.id); - } - TypeTraitItem(ref bounds, ref default) => { - walk_list!(visitor, visit_ty_param_bound, bounds); - walk_list!(visitor, visit_ty, default); - } - } -} - -pub fn walk_impl_item<'v, V: Visitor<'v>>(visitor: &mut V, impl_item: &'v ImplItem) { - visitor.visit_name(impl_item.span, impl_item.name); - walk_list!(visitor, visit_attribute, &impl_item.attrs); - match impl_item.node { - ImplItemKind::Const(ref ty, ref expr) => { - visitor.visit_ty(ty); - visitor.visit_expr(expr); - } - ImplItemKind::Method(ref sig, ref body) => { - visitor.visit_fn(FnKind::Method(impl_item.name, sig, Some(impl_item.vis)), - &sig.decl, - body, - impl_item.span, - impl_item.id); - } - ImplItemKind::Type(ref ty) => { - visitor.visit_ty(ty); - } - } -} - -pub fn walk_struct_def<'v, V: Visitor<'v>>(visitor: &mut V, struct_definition: &'v VariantData) { - walk_list!(visitor, visit_struct_field, struct_definition.fields()); -} - -pub fn walk_struct_field<'v, V: Visitor<'v>>(visitor: &mut V, struct_field: &'v StructField) { - walk_opt_name(visitor, struct_field.span, struct_field.node.name()); - visitor.visit_ty(&struct_field.node.ty); - walk_list!(visitor, visit_attribute, &struct_field.node.attrs); -} - -pub fn walk_block<'v, V: Visitor<'v>>(visitor: &mut V, block: &'v Block) { - walk_list!(visitor, visit_stmt, &block.stmts); - walk_list!(visitor, visit_expr, &block.expr); -} - -pub fn walk_stmt<'v, V: Visitor<'v>>(visitor: &mut V, statement: &'v Stmt) { - match statement.node { - StmtDecl(ref declaration, _) => visitor.visit_decl(declaration), - StmtExpr(ref expression, _) | StmtSemi(ref expression, _) => { - visitor.visit_expr(expression) - } - } -} - -pub fn walk_decl<'v, V: Visitor<'v>>(visitor: &mut V, declaration: &'v Decl) { - match declaration.node { - DeclLocal(ref local) => visitor.visit_local(local), - DeclItem(ref item) => visitor.visit_item(item), - } -} - -pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) { - match expression.node { - ExprBox(ref subexpression) => { - visitor.visit_expr(subexpression) - } - ExprVec(ref subexpressions) => { - walk_list!(visitor, visit_expr, subexpressions); - } - ExprRepeat(ref element, ref count) => { - visitor.visit_expr(element); - visitor.visit_expr(count) - } - ExprStruct(ref path, ref fields, ref optional_base) => { - visitor.visit_path(path, expression.id); - for field in fields { - visitor.visit_name(field.name.span, field.name.node); - visitor.visit_expr(&field.expr) - } - walk_list!(visitor, visit_expr, optional_base); - } - ExprTup(ref subexpressions) => { - walk_list!(visitor, visit_expr, subexpressions); - } - ExprCall(ref callee_expression, ref arguments) => { - walk_list!(visitor, visit_expr, arguments); - visitor.visit_expr(callee_expression) - } - ExprMethodCall(ref name, ref types, ref arguments) => { - visitor.visit_name(name.span, name.node); - walk_list!(visitor, visit_expr, arguments); - walk_list!(visitor, visit_ty, types); - } - ExprBinary(_, ref left_expression, ref right_expression) => { - visitor.visit_expr(left_expression); - visitor.visit_expr(right_expression) - } - ExprAddrOf(_, ref subexpression) | ExprUnary(_, ref subexpression) => { - visitor.visit_expr(subexpression) - } - ExprLit(_) => {} - ExprCast(ref subexpression, ref typ) => { - visitor.visit_expr(subexpression); - visitor.visit_ty(typ) - } - ExprIf(ref head_expression, ref if_block, ref optional_else) => { - visitor.visit_expr(head_expression); - visitor.visit_block(if_block); - walk_list!(visitor, visit_expr, optional_else); - } - ExprWhile(ref subexpression, ref block, opt_ident) => { - visitor.visit_expr(subexpression); - visitor.visit_block(block); - walk_opt_ident(visitor, expression.span, opt_ident) - } - ExprLoop(ref block, opt_ident) => { - visitor.visit_block(block); - walk_opt_ident(visitor, expression.span, opt_ident) - } - ExprMatch(ref subexpression, ref arms, _) => { - visitor.visit_expr(subexpression); - walk_list!(visitor, visit_arm, arms); - } - ExprClosure(_, ref function_declaration, ref body) => { - visitor.visit_fn(FnKind::Closure, - function_declaration, - body, - expression.span, - expression.id) - } - ExprBlock(ref block) => visitor.visit_block(block), - ExprAssign(ref left_hand_expression, ref right_hand_expression) => { - visitor.visit_expr(right_hand_expression); - visitor.visit_expr(left_hand_expression) - } - ExprAssignOp(_, ref left_expression, ref right_expression) => { - visitor.visit_expr(right_expression); - visitor.visit_expr(left_expression) - } - ExprField(ref subexpression, ref name) => { - visitor.visit_expr(subexpression); - visitor.visit_name(name.span, name.node); - } - ExprTupField(ref subexpression, _) => { - visitor.visit_expr(subexpression); - } - ExprIndex(ref main_expression, ref index_expression) => { - visitor.visit_expr(main_expression); - visitor.visit_expr(index_expression) - } - ExprRange(ref start, ref end) => { - walk_list!(visitor, visit_expr, start); - walk_list!(visitor, visit_expr, end); - } - ExprPath(ref maybe_qself, ref path) => { - if let Some(ref qself) = *maybe_qself { - visitor.visit_ty(&qself.ty); - } - visitor.visit_path(path, expression.id) - } - ExprBreak(ref opt_sp_ident) | ExprAgain(ref opt_sp_ident) => { - for sp_ident in opt_sp_ident { - visitor.visit_ident(sp_ident.span, sp_ident.node); - } - } - ExprRet(ref optional_expression) => { - walk_list!(visitor, visit_expr, optional_expression); - } - ExprInlineAsm(ref ia) => { - for &(_, ref input) in &ia.inputs { - visitor.visit_expr(&input) - } - for &(_, ref output, _) in &ia.outputs { - visitor.visit_expr(&output) - } - } - } - - visitor.visit_expr_post(expression) -} - -pub fn walk_arm<'v, V: Visitor<'v>>(visitor: &mut V, arm: &'v Arm) { - walk_list!(visitor, visit_pat, &arm.pats); - walk_list!(visitor, visit_expr, &arm.guard); - visitor.visit_expr(&arm.body); - walk_list!(visitor, visit_attribute, &arm.attrs); -}