]> git.lizzy.rs Git - rust.git/blob - src/librustc/hir/map/def_collector.rs
7486d954c480233fde7058411c821c964a26a25f
[rust.git] / src / librustc / hir / map / def_collector.rs
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.
4 //
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.
10
11 use hir::map::definitions::*;
12
13 use hir;
14 use hir::intravisit;
15 use hir::def_id::{CRATE_DEF_INDEX, DefId, DefIndex};
16
17 use middle::cstore::InlinedItem;
18
19 use syntax::ast::*;
20 use syntax::ext::hygiene::Mark;
21 use syntax::visit;
22 use syntax::symbol::{Symbol, keywords};
23
24 /// Creates def ids for nodes in the HIR.
25 pub struct DefCollector<'a> {
26     // If we are walking HIR (c.f., AST), we need to keep a reference to the
27     // crate.
28     hir_crate: Option<&'a hir::Crate>,
29     definitions: &'a mut Definitions,
30     parent_def: Option<DefIndex>,
31     pub visit_macro_invoc: Option<&'a mut FnMut(MacroInvocationData)>,
32 }
33
34 pub struct MacroInvocationData {
35     pub mark: Mark,
36     pub def_index: DefIndex,
37     pub const_integer: bool,
38 }
39
40 impl<'a> DefCollector<'a> {
41     pub fn new(definitions: &'a mut Definitions) -> Self {
42         DefCollector {
43             hir_crate: None,
44             definitions: definitions,
45             parent_def: None,
46             visit_macro_invoc: None,
47         }
48     }
49
50     pub fn extend(parent_node: NodeId,
51                   parent_def_path: DefPath,
52                   parent_def_id: DefId,
53                   definitions: &'a mut Definitions)
54                   -> Self {
55         let mut collector = DefCollector::new(definitions);
56
57         assert_eq!(parent_def_path.krate, parent_def_id.krate);
58         let root_path = Box::new(InlinedRootPath {
59             data: parent_def_path.data,
60             def_id: parent_def_id,
61         });
62
63         let def = collector.create_def(parent_node, DefPathData::InlinedRoot(root_path));
64         collector.parent_def = Some(def);
65
66         collector
67     }
68
69     pub fn collect_root(&mut self) {
70         let root = self.create_def_with_parent(None, CRATE_NODE_ID, DefPathData::CrateRoot);
71         assert_eq!(root, CRATE_DEF_INDEX);
72         self.parent_def = Some(root);
73
74         self.create_def_with_parent(Some(CRATE_DEF_INDEX), DUMMY_NODE_ID, DefPathData::Misc);
75     }
76
77     pub fn walk_item(&mut self, ii: &'a InlinedItem, krate: &'a hir::Crate) {
78         self.hir_crate = Some(krate);
79         ii.visit(self);
80     }
81
82     fn create_def(&mut self, node_id: NodeId, data: DefPathData) -> DefIndex {
83         let parent_def = self.parent_def;
84         debug!("create_def(node_id={:?}, data={:?}, parent_def={:?})", node_id, data, parent_def);
85         self.definitions.create_def_with_parent(parent_def, node_id, data)
86     }
87
88     fn create_def_with_parent(&mut self,
89                               parent: Option<DefIndex>,
90                               node_id: NodeId,
91                               data: DefPathData)
92                               -> DefIndex {
93         self.definitions.create_def_with_parent(parent, node_id, data)
94     }
95
96     pub fn with_parent<F: FnOnce(&mut Self)>(&mut self, parent_def: DefIndex, f: F) {
97         let parent = self.parent_def;
98         self.parent_def = Some(parent_def);
99         f(self);
100         self.parent_def = parent;
101     }
102
103     pub fn visit_ast_const_integer(&mut self, expr: &Expr) {
104         match expr.node {
105             // Find the node which will be used after lowering.
106             ExprKind::Paren(ref inner) => return self.visit_ast_const_integer(inner),
107             ExprKind::Mac(..) => return self.visit_macro_invoc(expr.id, true),
108             // FIXME(eddyb) Closures should have separate
109             // function definition IDs and expression IDs.
110             ExprKind::Closure(..) => return,
111             _ => {}
112         }
113
114         self.create_def(expr.id, DefPathData::Initializer);
115     }
116
117     fn visit_hir_const_integer(&mut self, expr: &hir::Expr) {
118         // FIXME(eddyb) Closures should have separate
119         // function definition IDs and expression IDs.
120         if let hir::ExprClosure(..) = expr.node {
121             return;
122         }
123
124         self.create_def(expr.id, DefPathData::Initializer);
125     }
126
127     fn visit_macro_invoc(&mut self, id: NodeId, const_integer: bool) {
128         if let Some(ref mut visit) = self.visit_macro_invoc {
129             visit(MacroInvocationData {
130                 mark: Mark::from_placeholder_id(id),
131                 const_integer: const_integer,
132                 def_index: self.parent_def.unwrap(),
133             })
134         }
135     }
136 }
137
138 impl<'a> visit::Visitor for DefCollector<'a> {
139     fn visit_item(&mut self, i: &Item) {
140         debug!("visit_item: {:?}", i);
141
142         // Pick the def data. This need not be unique, but the more
143         // information we encapsulate into
144         let def_data = match i.node {
145             ItemKind::DefaultImpl(..) | ItemKind::Impl(..) =>
146                 DefPathData::Impl,
147             ItemKind::Enum(..) | ItemKind::Struct(..) | ItemKind::Union(..) | ItemKind::Trait(..) |
148             ItemKind::ExternCrate(..) | ItemKind::ForeignMod(..) | ItemKind::Ty(..) =>
149                 DefPathData::TypeNs(i.ident.name.as_str()),
150             ItemKind::Mod(..) if i.ident == keywords::Invalid.ident() => {
151                 return visit::walk_item(self, i);
152             }
153             ItemKind::Mod(..) => DefPathData::Module(i.ident.name.as_str()),
154             ItemKind::Static(..) | ItemKind::Const(..) | ItemKind::Fn(..) =>
155                 DefPathData::ValueNs(i.ident.name.as_str()),
156             ItemKind::Mac(..) if i.id == DUMMY_NODE_ID => return, // Scope placeholder
157             ItemKind::Mac(..) => return self.visit_macro_invoc(i.id, false),
158             ItemKind::Use(..) => DefPathData::Misc,
159         };
160         let def = self.create_def(i.id, def_data);
161
162         self.with_parent(def, |this| {
163             match i.node {
164                 ItemKind::Enum(ref enum_definition, _) => {
165                     for v in &enum_definition.variants {
166                         let variant_def_index =
167                             this.create_def(v.node.data.id(),
168                                             DefPathData::EnumVariant(v.node.name.name.as_str()));
169                         this.with_parent(variant_def_index, |this| {
170                             for (index, field) in v.node.data.fields().iter().enumerate() {
171                                 let name = field.ident.map(|ident| ident.name)
172                                     .unwrap_or_else(|| Symbol::intern(&index.to_string()));
173                                 this.create_def(field.id, DefPathData::Field(name.as_str()));
174                             }
175
176                             if let Some(ref expr) = v.node.disr_expr {
177                                 this.visit_ast_const_integer(expr);
178                             }
179                         });
180                     }
181                 }
182                 ItemKind::Struct(ref struct_def, _) | ItemKind::Union(ref struct_def, _) => {
183                     // If this is a tuple-like struct, register the constructor.
184                     if !struct_def.is_struct() {
185                         this.create_def(struct_def.id(),
186                                         DefPathData::StructCtor);
187                     }
188
189                     for (index, field) in struct_def.fields().iter().enumerate() {
190                         let name = field.ident.map(|ident| ident.name.as_str())
191                             .unwrap_or(Symbol::intern(&index.to_string()).as_str());
192                         this.create_def(field.id, DefPathData::Field(name));
193                     }
194                 }
195                 _ => {}
196             }
197             visit::walk_item(this, i);
198         });
199     }
200
201     fn visit_foreign_item(&mut self, foreign_item: &ForeignItem) {
202         let def = self.create_def(foreign_item.id,
203                                   DefPathData::ValueNs(foreign_item.ident.name.as_str()));
204
205         self.with_parent(def, |this| {
206             visit::walk_foreign_item(this, foreign_item);
207         });
208     }
209
210     fn visit_generics(&mut self, generics: &Generics) {
211         for ty_param in generics.ty_params.iter() {
212             self.create_def(ty_param.id, DefPathData::TypeParam(ty_param.ident.name.as_str()));
213         }
214
215         visit::walk_generics(self, generics);
216     }
217
218     fn visit_trait_item(&mut self, ti: &TraitItem) {
219         let def_data = match ti.node {
220             TraitItemKind::Method(..) | TraitItemKind::Const(..) =>
221                 DefPathData::ValueNs(ti.ident.name.as_str()),
222             TraitItemKind::Type(..) => DefPathData::TypeNs(ti.ident.name.as_str()),
223             TraitItemKind::Macro(..) => return self.visit_macro_invoc(ti.id, false),
224         };
225
226         let def = self.create_def(ti.id, def_data);
227         self.with_parent(def, |this| {
228             if let TraitItemKind::Const(_, Some(ref expr)) = ti.node {
229                 this.create_def(expr.id, DefPathData::Initializer);
230             }
231
232             visit::walk_trait_item(this, ti);
233         });
234     }
235
236     fn visit_impl_item(&mut self, ii: &ImplItem) {
237         let def_data = match ii.node {
238             ImplItemKind::Method(..) | ImplItemKind::Const(..) =>
239                 DefPathData::ValueNs(ii.ident.name.as_str()),
240             ImplItemKind::Type(..) => DefPathData::TypeNs(ii.ident.name.as_str()),
241             ImplItemKind::Macro(..) => return self.visit_macro_invoc(ii.id, false),
242         };
243
244         let def = self.create_def(ii.id, def_data);
245         self.with_parent(def, |this| {
246             if let ImplItemKind::Const(_, ref expr) = ii.node {
247                 this.create_def(expr.id, DefPathData::Initializer);
248             }
249
250             visit::walk_impl_item(this, ii);
251         });
252     }
253
254     fn visit_pat(&mut self, pat: &Pat) {
255         let parent_def = self.parent_def;
256
257         match pat.node {
258             PatKind::Mac(..) => return self.visit_macro_invoc(pat.id, false),
259             PatKind::Ident(_, id, _) => {
260                 let def = self.create_def(pat.id, DefPathData::Binding(id.node.name.as_str()));
261                 self.parent_def = Some(def);
262             }
263             _ => {}
264         }
265
266         visit::walk_pat(self, pat);
267         self.parent_def = parent_def;
268     }
269
270     fn visit_expr(&mut self, expr: &Expr) {
271         let parent_def = self.parent_def;
272
273         match expr.node {
274             ExprKind::Mac(..) => return self.visit_macro_invoc(expr.id, false),
275             ExprKind::Repeat(_, ref count) => self.visit_ast_const_integer(count),
276             ExprKind::Closure(..) => {
277                 let def = self.create_def(expr.id, DefPathData::ClosureExpr);
278                 self.parent_def = Some(def);
279             }
280             _ => {}
281         }
282
283         visit::walk_expr(self, expr);
284         self.parent_def = parent_def;
285     }
286
287     fn visit_ty(&mut self, ty: &Ty) {
288         match ty.node {
289             TyKind::Mac(..) => return self.visit_macro_invoc(ty.id, false),
290             TyKind::Array(_, ref length) => self.visit_ast_const_integer(length),
291             TyKind::ImplTrait(..) => {
292                 self.create_def(ty.id, DefPathData::ImplTrait);
293             }
294             _ => {}
295         }
296         visit::walk_ty(self, ty);
297     }
298
299     fn visit_lifetime_def(&mut self, def: &LifetimeDef) {
300         self.create_def(def.lifetime.id, DefPathData::LifetimeDef(def.lifetime.name.as_str()));
301     }
302
303     fn visit_macro_def(&mut self, macro_def: &MacroDef) {
304         self.create_def(macro_def.id, DefPathData::MacroDef(macro_def.ident.name.as_str()));
305     }
306
307     fn visit_stmt(&mut self, stmt: &Stmt) {
308         match stmt.node {
309             StmtKind::Mac(..) => self.visit_macro_invoc(stmt.id, false),
310             _ => visit::walk_stmt(self, stmt),
311         }
312     }
313 }
314
315 // We walk the HIR rather than the AST when reading items from metadata.
316 impl<'ast> intravisit::Visitor<'ast> for DefCollector<'ast> {
317     fn visit_item(&mut self, i: &'ast hir::Item) {
318         debug!("visit_item: {:?}", i);
319
320         // Pick the def data. This need not be unique, but the more
321         // information we encapsulate into
322         let def_data = match i.node {
323             hir::ItemDefaultImpl(..) | hir::ItemImpl(..) =>
324                 DefPathData::Impl,
325             hir::ItemEnum(..) | hir::ItemStruct(..) | hir::ItemUnion(..) |
326             hir::ItemTrait(..) | hir::ItemExternCrate(..) | hir::ItemMod(..) |
327             hir::ItemForeignMod(..) | hir::ItemTy(..) =>
328                 DefPathData::TypeNs(i.name.as_str()),
329             hir::ItemStatic(..) | hir::ItemConst(..) | hir::ItemFn(..) =>
330                 DefPathData::ValueNs(i.name.as_str()),
331             hir::ItemUse(..) => DefPathData::Misc,
332         };
333         let def = self.create_def(i.id, def_data);
334
335         self.with_parent(def, |this| {
336             match i.node {
337                 hir::ItemEnum(ref enum_definition, _) => {
338                     for v in &enum_definition.variants {
339                         let variant_def_index =
340                             this.create_def(v.node.data.id(),
341                                             DefPathData::EnumVariant(v.node.name.as_str()));
342
343                         this.with_parent(variant_def_index, |this| {
344                             for field in v.node.data.fields() {
345                                 this.create_def(field.id,
346                                                 DefPathData::Field(field.name.as_str()));
347                             }
348                             if let Some(ref expr) = v.node.disr_expr {
349                                 this.visit_hir_const_integer(expr);
350                             }
351                         });
352                     }
353                 }
354                 hir::ItemStruct(ref struct_def, _) |
355                 hir::ItemUnion(ref struct_def, _) => {
356                     // If this is a tuple-like struct, register the constructor.
357                     if !struct_def.is_struct() {
358                         this.create_def(struct_def.id(),
359                                         DefPathData::StructCtor);
360                     }
361
362                     for field in struct_def.fields() {
363                         this.create_def(field.id, DefPathData::Field(field.name.as_str()));
364                     }
365                 }
366                 _ => {}
367             }
368             intravisit::walk_item(this, i);
369         });
370     }
371
372     fn visit_foreign_item(&mut self, foreign_item: &'ast hir::ForeignItem) {
373         let def = self.create_def(foreign_item.id,
374                                   DefPathData::ValueNs(foreign_item.name.as_str()));
375
376         self.with_parent(def, |this| {
377             intravisit::walk_foreign_item(this, foreign_item);
378         });
379     }
380
381     fn visit_generics(&mut self, generics: &'ast hir::Generics) {
382         for ty_param in generics.ty_params.iter() {
383             self.create_def(ty_param.id, DefPathData::TypeParam(ty_param.name.as_str()));
384         }
385
386         intravisit::walk_generics(self, generics);
387     }
388
389     fn visit_trait_item(&mut self, ti: &'ast hir::TraitItem) {
390         let def_data = match ti.node {
391             hir::MethodTraitItem(..) | hir::ConstTraitItem(..) =>
392                 DefPathData::ValueNs(ti.name.as_str()),
393             hir::TypeTraitItem(..) => DefPathData::TypeNs(ti.name.as_str()),
394         };
395
396         let def = self.create_def(ti.id, def_data);
397         self.with_parent(def, |this| {
398             if let hir::ConstTraitItem(_, Some(ref expr)) = ti.node {
399                 this.create_def(expr.id, DefPathData::Initializer);
400             }
401
402             intravisit::walk_trait_item(this, ti);
403         });
404     }
405
406     fn visit_impl_item(&mut self, ii: &'ast hir::ImplItem) {
407         let def_data = match ii.node {
408             hir::ImplItemKind::Method(..) | hir::ImplItemKind::Const(..) =>
409                 DefPathData::ValueNs(ii.name.as_str()),
410             hir::ImplItemKind::Type(..) => DefPathData::TypeNs(ii.name.as_str()),
411         };
412
413         let def = self.create_def(ii.id, def_data);
414         self.with_parent(def, |this| {
415             if let hir::ImplItemKind::Const(_, ref expr) = ii.node {
416                 this.create_def(expr.id, DefPathData::Initializer);
417             }
418
419             intravisit::walk_impl_item(this, ii);
420         });
421     }
422
423     fn visit_pat(&mut self, pat: &'ast hir::Pat) {
424         let parent_def = self.parent_def;
425
426         if let hir::PatKind::Binding(_, name, _) = pat.node {
427             let def = self.create_def(pat.id, DefPathData::Binding(name.node.as_str()));
428             self.parent_def = Some(def);
429         }
430
431         intravisit::walk_pat(self, pat);
432         self.parent_def = parent_def;
433     }
434
435     fn visit_expr(&mut self, expr: &'ast hir::Expr) {
436         let parent_def = self.parent_def;
437
438         if let hir::ExprRepeat(_, ref count) = expr.node {
439             self.visit_hir_const_integer(count);
440         }
441
442         if let hir::ExprClosure(..) = expr.node {
443             let def = self.create_def(expr.id, DefPathData::ClosureExpr);
444             self.parent_def = Some(def);
445         }
446
447         intravisit::walk_expr(self, expr);
448         self.parent_def = parent_def;
449     }
450
451     fn visit_ty(&mut self, ty: &'ast hir::Ty) {
452         if let hir::TyArray(_, ref length) = ty.node {
453             self.visit_hir_const_integer(length);
454         }
455         if let hir::TyImplTrait(..) = ty.node {
456             self.create_def(ty.id, DefPathData::ImplTrait);
457         }
458         intravisit::walk_ty(self, ty);
459     }
460
461     fn visit_lifetime_def(&mut self, def: &'ast hir::LifetimeDef) {
462         self.create_def(def.lifetime.id, DefPathData::LifetimeDef(def.lifetime.name.as_str()));
463     }
464
465     fn visit_macro_def(&mut self, macro_def: &'ast hir::MacroDef) {
466         self.create_def(macro_def.id, DefPathData::MacroDef(macro_def.name.as_str()));
467     }
468 }