use super::*;
+use hir;
+use hir::intravisit;
use hir::def_id::{CRATE_DEF_INDEX, DefId, DefIndex};
+use middle::cstore::InlinedItem;
+
use syntax::ast::*;
use syntax::visit;
/// Creates def ids for nodes in the HIR.
-pub struct DefCollector {
+pub struct DefCollector<'ast> {
+ // If we are walking HIR (c.f., AST), we need to keep a reference to the
+ // crate.
+ hir_crate: Option<&'ast hir::Crate>,
pub definitions: Definitions,
- pub parent_def: Option<DefIndex>,
+ parent_def: Option<DefIndex>,
}
-impl DefCollector {
- pub fn root() -> DefCollector {
+impl<'ast> DefCollector<'ast> {
+ pub fn root() -> DefCollector<'ast> {
let mut collector = DefCollector {
+ hir_crate: None,
definitions: Definitions::new(),
parent_def: None,
};
parent_def_path: DefPath,
parent_def_id: DefId,
definitions: Definitions)
- -> DefCollector {
+ -> DefCollector<'ast> {
let mut collector = DefCollector {
+ hir_crate: None,
parent_def: None,
definitions: definitions,
};
collector
}
+ pub fn walk_item(&mut self, ii: &'ast InlinedItem, krate: &'ast hir::Crate) {
+ self.hir_crate = Some(krate);
+ ii.visit(self);
+ }
+
fn parent_def(&self) -> Option<DefIndex> {
self.parent_def
}
}
}
-impl<'ast> visit::Visitor<'ast> for DefCollector {
+impl<'ast> visit::Visitor<'ast> for DefCollector<'ast> {
fn visit_item(&mut self, i: &'ast Item) {
debug!("visit_item: {:?}", i);
self.create_def(macro_def.id, DefPathData::MacroDef(macro_def.ident.name));
}
}
+
+// We walk the HIR rather than the AST when reading items from metadata.
+impl<'ast> intravisit::Visitor<'ast> for DefCollector<'ast> {
+ /// Because we want to track parent items and so forth, enable
+ /// deep walking so that we walk nested items in the context of
+ /// their outer items.
+ fn visit_nested_item(&mut self, item_id: hir::ItemId) {
+ debug!("visit_nested_item: {:?}", item_id);
+ let item = self.hir_crate.unwrap().item(item_id.id);
+ self.visit_item(item)
+ }
+
+ fn visit_item(&mut self, i: &'ast hir::Item) {
+ debug!("visit_item: {:?}", i);
+
+ // Pick the def data. This need not be unique, but the more
+ // information we encapsulate into
+ let def_data = match i.node {
+ hir::ItemDefaultImpl(..) | hir::ItemImpl(..) =>
+ DefPathData::Impl,
+ hir::ItemEnum(..) | hir::ItemStruct(..) | hir::ItemTrait(..) |
+ hir::ItemExternCrate(..) | hir::ItemMod(..) | hir::ItemForeignMod(..) |
+ hir::ItemTy(..) =>
+ DefPathData::TypeNs(i.name),
+ hir::ItemStatic(..) | hir::ItemConst(..) | hir::ItemFn(..) =>
+ DefPathData::ValueNs(i.name),
+ hir::ItemUse(..) => DefPathData::Misc,
+ };
+ let def = self.create_def(i.id, def_data);
+
+ self.with_parent(def, |this| {
+ match i.node {
+ hir::ItemEnum(ref enum_definition, _) => {
+ for v in &enum_definition.variants {
+ let variant_def_index =
+ this.create_def(v.node.data.id(),
+ DefPathData::EnumVariant(v.node.name));
+
+ for field in v.node.data.fields() {
+ this.create_def_with_parent(Some(variant_def_index),
+ field.id,
+ DefPathData::Field(field.name));
+ }
+ }
+ }
+ hir::ItemStruct(ref struct_def, _) => {
+ // If this is a tuple-like struct, register the constructor.
+ if !struct_def.is_struct() {
+ this.create_def(struct_def.id(),
+ DefPathData::StructCtor);
+ }
+
+ for field in struct_def.fields() {
+ this.create_def(field.id, DefPathData::Field(field.name));
+ }
+ }
+ _ => {}
+ }
+ intravisit::walk_item(this, i);
+ });
+ }
+
+ fn visit_foreign_item(&mut self, foreign_item: &'ast hir::ForeignItem) {
+ let def = self.create_def(foreign_item.id, DefPathData::ValueNs(foreign_item.name));
+
+ self.with_parent(def, |this| {
+ intravisit::walk_foreign_item(this, foreign_item);
+ });
+ }
+
+ fn visit_generics(&mut self, generics: &'ast hir::Generics) {
+ for ty_param in generics.ty_params.iter() {
+ self.create_def(ty_param.id, DefPathData::TypeParam(ty_param.name));
+ }
+
+ intravisit::walk_generics(self, generics);
+ }
+
+ fn visit_trait_item(&mut self, ti: &'ast hir::TraitItem) {
+ let def_data = match ti.node {
+ hir::MethodTraitItem(..) | hir::ConstTraitItem(..) =>
+ DefPathData::ValueNs(ti.name),
+ hir::TypeTraitItem(..) => DefPathData::TypeNs(ti.name),
+ };
+
+ let def = self.create_def(ti.id, def_data);
+ self.with_parent(def, |this| {
+ if let hir::ConstTraitItem(_, Some(ref expr)) = ti.node {
+ this.create_def(expr.id, DefPathData::Initializer);
+ }
+
+ intravisit::walk_trait_item(this, ti);
+ });
+ }
+
+ fn visit_impl_item(&mut self, ii: &'ast hir::ImplItem) {
+ let def_data = match ii.node {
+ hir::ImplItemKind::Method(..) | hir::ImplItemKind::Const(..) =>
+ DefPathData::ValueNs(ii.name),
+ hir::ImplItemKind::Type(..) => DefPathData::TypeNs(ii.name),
+ };
+
+ let def = self.create_def(ii.id, def_data);
+ self.with_parent(def, |this| {
+ if let hir::ImplItemKind::Const(_, ref expr) = ii.node {
+ this.create_def(expr.id, DefPathData::Initializer);
+ }
+
+ intravisit::walk_impl_item(this, ii);
+ });
+ }
+
+ fn visit_pat(&mut self, pat: &'ast hir::Pat) {
+ let maybe_binding = match pat.node {
+ hir::PatKind::Ident(_, id, _) => Some(id.node),
+ _ => None
+ };
+
+ let parent_def = self.parent_def;
+ if let Some(id) = maybe_binding {
+ let def = self.create_def(pat.id, DefPathData::Binding(id.name));
+ self.parent_def = Some(def);
+ }
+
+ intravisit::walk_pat(self, pat);
+ self.parent_def = parent_def;
+ }
+
+ fn visit_expr(&mut self, expr: &'ast hir::Expr) {
+ let parent_def = self.parent_def;
+
+ if let hir::ExprClosure(..) = expr.node {
+ let def = self.create_def(expr.id, DefPathData::ClosureExpr);
+ self.parent_def = Some(def);
+ }
+
+ intravisit::walk_expr(self, expr);
+ self.parent_def = parent_def;
+ }
+
+ fn visit_lifetime_def(&mut self, def: &'ast hir::LifetimeDef) {
+ self.create_def(def.lifetime.id, DefPathData::LifetimeDef(def.lifetime.name));
+ }
+
+ fn visit_macro_def(&mut self, macro_def: &'ast hir::MacroDef) {
+ self.create_def(macro_def.id, DefPathData::MacroDef(macro_def.name));
+ }
+}
\ No newline at end of file