HIR visitor for DefCollector

So that we can work with inlined HIR from metadata.
This commit is contained in:
Nick Cameron 2016-04-14 18:04:55 +12:00
parent 0c37d4bb1d
commit 744be0b5aa
2 changed files with 175 additions and 14 deletions

View File

@ -10,20 +10,28 @@
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,
};
@ -39,8 +47,9 @@ impl DefCollector {
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,
};
@ -57,6 +66,11 @@ impl DefCollector {
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
}
@ -83,7 +97,7 @@ impl DefCollector {
}
}
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);
@ -226,3 +240,151 @@ impl<'ast> visit::Visitor<'ast> for DefCollector {
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));
}
}

View File

@ -843,14 +843,13 @@ pub fn map_decoded_item<'ast, F: FoldOps>(map: &Map<'ast>,
let ii = map.forest.inlined_items.alloc(ii);
let ii_parent_id = fld.new_id(DUMMY_NODE_ID);
// TODO need to save defs in metadata :-(
// let defs = mem::replace(&mut *map.definitions.borrow_mut(), Definitions::new());
// let mut def_collector = DefCollector::extend(ii_parent_id,
// parent_def_path.clone(),
// parent_def_id,
// defs);
// ii.visit(&mut def_collector);
// *map.definitions.borrow_mut() = def_collector.definitions;
let defs = mem::replace(&mut *map.definitions.borrow_mut(), Definitions::new());
let mut def_collector = DefCollector::extend(ii_parent_id,
parent_def_path.clone(),
parent_def_id,
defs);
def_collector.walk_item(ii, map.krate());
*map.definitions.borrow_mut() = def_collector.definitions;
let mut collector = NodeCollector::extend(map.krate(),
ii,