1 // Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
15 use hir::def_id::{CRATE_DEF_INDEX, DefId, DefIndex};
17 use middle::cstore::InlinedItem;
21 use syntax::parse::token::{self, keywords};
23 /// Creates def ids for nodes in the HIR.
24 pub struct DefCollector<'a> {
25 // If we are walking HIR (c.f., AST), we need to keep a reference to the
27 hir_crate: Option<&'a hir::Crate>,
28 definitions: &'a mut Definitions,
29 parent_def: Option<DefIndex>,
30 pub visit_macro_invoc: Option<&'a mut FnMut(MacroInvocationData)>,
33 pub struct MacroInvocationData {
35 pub def_index: DefIndex,
36 pub const_integer: bool,
39 impl<'a> DefCollector<'a> {
40 pub fn new(definitions: &'a mut Definitions) -> Self {
43 definitions: definitions,
45 visit_macro_invoc: None,
49 pub fn extend(parent_node: NodeId,
50 parent_def_path: DefPath,
52 definitions: &'a mut Definitions)
54 let mut collector = DefCollector::new(definitions);
56 assert_eq!(parent_def_path.krate, parent_def_id.krate);
57 let root_path = Box::new(InlinedRootPath {
58 data: parent_def_path.data,
59 def_id: parent_def_id,
62 let def = collector.create_def(parent_node, DefPathData::InlinedRoot(root_path));
63 collector.parent_def = Some(def);
68 pub fn collect_root(&mut self) {
69 let root = self.create_def_with_parent(None, CRATE_NODE_ID, DefPathData::CrateRoot);
70 assert_eq!(root, CRATE_DEF_INDEX);
71 self.parent_def = Some(root);
73 self.create_def_with_parent(Some(CRATE_DEF_INDEX), DUMMY_NODE_ID, DefPathData::Misc);
76 pub fn walk_item(&mut self, ii: &'a InlinedItem, krate: &'a hir::Crate) {
77 self.hir_crate = Some(krate);
81 fn create_def(&mut self, node_id: NodeId, data: DefPathData) -> DefIndex {
82 let parent_def = self.parent_def;
83 debug!("create_def(node_id={:?}, data={:?}, parent_def={:?})", node_id, data, parent_def);
84 self.definitions.create_def_with_parent(parent_def, node_id, data)
87 fn create_def_with_parent(&mut self,
88 parent: Option<DefIndex>,
92 self.definitions.create_def_with_parent(parent, node_id, data)
95 pub fn with_parent<F: FnOnce(&mut Self)>(&mut self, parent_def: DefIndex, f: F) {
96 let parent = self.parent_def;
97 self.parent_def = Some(parent_def);
99 self.parent_def = parent;
102 pub fn visit_ast_const_integer(&mut self, expr: &Expr) {
104 // Find the node which will be used after lowering.
105 ExprKind::Paren(ref inner) => return self.visit_ast_const_integer(inner),
106 ExprKind::Mac(..) => return self.visit_macro_invoc(expr.id, true),
107 // FIXME(eddyb) Closures should have separate
108 // function definition IDs and expression IDs.
109 ExprKind::Closure(..) => return,
113 self.create_def(expr.id, DefPathData::Initializer);
116 fn visit_hir_const_integer(&mut self, expr: &hir::Expr) {
117 // FIXME(eddyb) Closures should have separate
118 // function definition IDs and expression IDs.
119 if let hir::ExprClosure(..) = expr.node {
123 self.create_def(expr.id, DefPathData::Initializer);
126 fn visit_macro_invoc(&mut self, id: NodeId, const_integer: bool) {
127 if let Some(ref mut visit) = self.visit_macro_invoc {
128 visit(MacroInvocationData {
130 const_integer: const_integer,
131 def_index: self.parent_def.unwrap(),
137 impl<'a> visit::Visitor for DefCollector<'a> {
138 fn visit_item(&mut self, i: &Item) {
139 debug!("visit_item: {:?}", i);
141 // Pick the def data. This need not be unique, but the more
142 // information we encapsulate into
143 let def_data = match i.node {
144 ItemKind::DefaultImpl(..) | ItemKind::Impl(..) =>
146 ItemKind::Enum(..) | ItemKind::Struct(..) | ItemKind::Union(..) | ItemKind::Trait(..) |
147 ItemKind::ExternCrate(..) | ItemKind::ForeignMod(..) | ItemKind::Ty(..) =>
148 DefPathData::TypeNs(i.ident.name.as_str()),
149 ItemKind::Mod(..) if i.ident == keywords::Invalid.ident() => {
150 return visit::walk_item(self, i);
152 ItemKind::Mod(..) => DefPathData::Module(i.ident.name.as_str()),
153 ItemKind::Static(..) | ItemKind::Const(..) | ItemKind::Fn(..) =>
154 DefPathData::ValueNs(i.ident.name.as_str()),
155 ItemKind::Mac(..) if i.id == DUMMY_NODE_ID => return, // Scope placeholder
156 ItemKind::Mac(..) => return self.visit_macro_invoc(i.id, false),
157 ItemKind::Use(..) => DefPathData::Misc,
159 let def = self.create_def(i.id, def_data);
161 self.with_parent(def, |this| {
163 ItemKind::Enum(ref enum_definition, _) => {
164 for v in &enum_definition.variants {
165 let variant_def_index =
166 this.create_def(v.node.data.id(),
167 DefPathData::EnumVariant(v.node.name.name.as_str()));
168 this.with_parent(variant_def_index, |this| {
169 for (index, field) in v.node.data.fields().iter().enumerate() {
170 let name = field.ident.map(|ident| ident.name)
171 .unwrap_or_else(|| token::intern(&index.to_string()));
172 this.create_def(field.id, DefPathData::Field(name.as_str()));
175 if let Some(ref expr) = v.node.disr_expr {
176 this.visit_ast_const_integer(expr);
181 ItemKind::Struct(ref struct_def, _) | ItemKind::Union(ref struct_def, _) => {
182 // If this is a tuple-like struct, register the constructor.
183 if !struct_def.is_struct() {
184 this.create_def(struct_def.id(),
185 DefPathData::StructCtor);
188 for (index, field) in struct_def.fields().iter().enumerate() {
189 let name = field.ident.map(|ident| ident.name.as_str())
190 .unwrap_or(token::intern(&index.to_string()).as_str());
191 this.create_def(field.id, DefPathData::Field(name));
196 visit::walk_item(this, i);
200 fn visit_foreign_item(&mut self, foreign_item: &ForeignItem) {
201 let def = self.create_def(foreign_item.id,
202 DefPathData::ValueNs(foreign_item.ident.name.as_str()));
204 self.with_parent(def, |this| {
205 visit::walk_foreign_item(this, foreign_item);
209 fn visit_generics(&mut self, generics: &Generics) {
210 for ty_param in generics.ty_params.iter() {
211 self.create_def(ty_param.id, DefPathData::TypeParam(ty_param.ident.name.as_str()));
214 visit::walk_generics(self, generics);
217 fn visit_trait_item(&mut self, ti: &TraitItem) {
218 let def_data = match ti.node {
219 TraitItemKind::Method(..) | TraitItemKind::Const(..) =>
220 DefPathData::ValueNs(ti.ident.name.as_str()),
221 TraitItemKind::Type(..) => DefPathData::TypeNs(ti.ident.name.as_str()),
222 TraitItemKind::Macro(..) => return self.visit_macro_invoc(ti.id, false),
225 let def = self.create_def(ti.id, def_data);
226 self.with_parent(def, |this| {
227 if let TraitItemKind::Const(_, Some(ref expr)) = ti.node {
228 this.create_def(expr.id, DefPathData::Initializer);
231 visit::walk_trait_item(this, ti);
235 fn visit_impl_item(&mut self, ii: &ImplItem) {
236 let def_data = match ii.node {
237 ImplItemKind::Method(..) | ImplItemKind::Const(..) =>
238 DefPathData::ValueNs(ii.ident.name.as_str()),
239 ImplItemKind::Type(..) => DefPathData::TypeNs(ii.ident.name.as_str()),
240 ImplItemKind::Macro(..) => return self.visit_macro_invoc(ii.id, false),
243 let def = self.create_def(ii.id, def_data);
244 self.with_parent(def, |this| {
245 if let ImplItemKind::Const(_, ref expr) = ii.node {
246 this.create_def(expr.id, DefPathData::Initializer);
249 visit::walk_impl_item(this, ii);
253 fn visit_pat(&mut self, pat: &Pat) {
254 let parent_def = self.parent_def;
257 PatKind::Mac(..) => return self.visit_macro_invoc(pat.id, false),
258 PatKind::Ident(_, id, _) => {
259 let def = self.create_def(pat.id, DefPathData::Binding(id.node.name.as_str()));
260 self.parent_def = Some(def);
265 visit::walk_pat(self, pat);
266 self.parent_def = parent_def;
269 fn visit_expr(&mut self, expr: &Expr) {
270 let parent_def = self.parent_def;
273 ExprKind::Mac(..) => return self.visit_macro_invoc(expr.id, false),
274 ExprKind::Repeat(_, ref count) => self.visit_ast_const_integer(count),
275 ExprKind::Closure(..) => {
276 let def = self.create_def(expr.id, DefPathData::ClosureExpr);
277 self.parent_def = Some(def);
282 visit::walk_expr(self, expr);
283 self.parent_def = parent_def;
286 fn visit_ty(&mut self, ty: &Ty) {
288 TyKind::Mac(..) => return self.visit_macro_invoc(ty.id, false),
289 TyKind::FixedLengthVec(_, ref length) => self.visit_ast_const_integer(length),
290 TyKind::ImplTrait(..) => {
291 self.create_def(ty.id, DefPathData::ImplTrait);
295 visit::walk_ty(self, ty);
298 fn visit_lifetime_def(&mut self, def: &LifetimeDef) {
299 self.create_def(def.lifetime.id, DefPathData::LifetimeDef(def.lifetime.name.as_str()));
302 fn visit_macro_def(&mut self, macro_def: &MacroDef) {
303 self.create_def(macro_def.id, DefPathData::MacroDef(macro_def.ident.name.as_str()));
306 fn visit_stmt(&mut self, stmt: &Stmt) {
308 StmtKind::Mac(..) => self.visit_macro_invoc(stmt.id, false),
309 _ => visit::walk_stmt(self, stmt),
314 // We walk the HIR rather than the AST when reading items from metadata.
315 impl<'ast> intravisit::Visitor<'ast> for DefCollector<'ast> {
316 fn visit_item(&mut self, i: &'ast hir::Item) {
317 debug!("visit_item: {:?}", i);
319 // Pick the def data. This need not be unique, but the more
320 // information we encapsulate into
321 let def_data = match i.node {
322 hir::ItemDefaultImpl(..) | hir::ItemImpl(..) =>
324 hir::ItemEnum(..) | hir::ItemStruct(..) | hir::ItemUnion(..) |
325 hir::ItemTrait(..) | hir::ItemExternCrate(..) | hir::ItemMod(..) |
326 hir::ItemForeignMod(..) | hir::ItemTy(..) =>
327 DefPathData::TypeNs(i.name.as_str()),
328 hir::ItemStatic(..) | hir::ItemConst(..) | hir::ItemFn(..) =>
329 DefPathData::ValueNs(i.name.as_str()),
330 hir::ItemUse(..) => DefPathData::Misc,
332 let def = self.create_def(i.id, def_data);
334 self.with_parent(def, |this| {
336 hir::ItemEnum(ref enum_definition, _) => {
337 for v in &enum_definition.variants {
338 let variant_def_index =
339 this.create_def(v.node.data.id(),
340 DefPathData::EnumVariant(v.node.name.as_str()));
342 this.with_parent(variant_def_index, |this| {
343 for field in v.node.data.fields() {
344 this.create_def(field.id,
345 DefPathData::Field(field.name.as_str()));
347 if let Some(ref expr) = v.node.disr_expr {
348 this.visit_hir_const_integer(expr);
353 hir::ItemStruct(ref struct_def, _) |
354 hir::ItemUnion(ref struct_def, _) => {
355 // If this is a tuple-like struct, register the constructor.
356 if !struct_def.is_struct() {
357 this.create_def(struct_def.id(),
358 DefPathData::StructCtor);
361 for field in struct_def.fields() {
362 this.create_def(field.id, DefPathData::Field(field.name.as_str()));
367 intravisit::walk_item(this, i);
371 fn visit_foreign_item(&mut self, foreign_item: &'ast hir::ForeignItem) {
372 let def = self.create_def(foreign_item.id,
373 DefPathData::ValueNs(foreign_item.name.as_str()));
375 self.with_parent(def, |this| {
376 intravisit::walk_foreign_item(this, foreign_item);
380 fn visit_generics(&mut self, generics: &'ast hir::Generics) {
381 for ty_param in generics.ty_params.iter() {
382 self.create_def(ty_param.id, DefPathData::TypeParam(ty_param.name.as_str()));
385 intravisit::walk_generics(self, generics);
388 fn visit_trait_item(&mut self, ti: &'ast hir::TraitItem) {
389 let def_data = match ti.node {
390 hir::MethodTraitItem(..) | hir::ConstTraitItem(..) =>
391 DefPathData::ValueNs(ti.name.as_str()),
392 hir::TypeTraitItem(..) => DefPathData::TypeNs(ti.name.as_str()),
395 let def = self.create_def(ti.id, def_data);
396 self.with_parent(def, |this| {
397 if let hir::ConstTraitItem(_, Some(ref expr)) = ti.node {
398 this.create_def(expr.id, DefPathData::Initializer);
401 intravisit::walk_trait_item(this, ti);
405 fn visit_impl_item(&mut self, ii: &'ast hir::ImplItem) {
406 let def_data = match ii.node {
407 hir::ImplItemKind::Method(..) | hir::ImplItemKind::Const(..) =>
408 DefPathData::ValueNs(ii.name.as_str()),
409 hir::ImplItemKind::Type(..) => DefPathData::TypeNs(ii.name.as_str()),
412 let def = self.create_def(ii.id, def_data);
413 self.with_parent(def, |this| {
414 if let hir::ImplItemKind::Const(_, ref expr) = ii.node {
415 this.create_def(expr.id, DefPathData::Initializer);
418 intravisit::walk_impl_item(this, ii);
422 fn visit_pat(&mut self, pat: &'ast hir::Pat) {
423 let parent_def = self.parent_def;
425 if let hir::PatKind::Binding(_, name, _) = pat.node {
426 let def = self.create_def(pat.id, DefPathData::Binding(name.node.as_str()));
427 self.parent_def = Some(def);
430 intravisit::walk_pat(self, pat);
431 self.parent_def = parent_def;
434 fn visit_expr(&mut self, expr: &'ast hir::Expr) {
435 let parent_def = self.parent_def;
437 if let hir::ExprRepeat(_, ref count) = expr.node {
438 self.visit_hir_const_integer(count);
441 if let hir::ExprClosure(..) = expr.node {
442 let def = self.create_def(expr.id, DefPathData::ClosureExpr);
443 self.parent_def = Some(def);
446 intravisit::walk_expr(self, expr);
447 self.parent_def = parent_def;
450 fn visit_ty(&mut self, ty: &'ast hir::Ty) {
451 if let hir::TyFixedLengthVec(_, ref length) = ty.node {
452 self.visit_hir_const_integer(length);
454 if let hir::TyImplTrait(..) = ty.node {
455 self.create_def(ty.id, DefPathData::ImplTrait);
457 intravisit::walk_ty(self, ty);
460 fn visit_lifetime_def(&mut self, def: &'ast hir::LifetimeDef) {
461 self.create_def(def.lifetime.id, DefPathData::LifetimeDef(def.lifetime.name.as_str()));
464 fn visit_macro_def(&mut self, macro_def: &'ast hir::MacroDef) {
465 self.create_def(macro_def.id, DefPathData::MacroDef(macro_def.name.as_str()));