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