]> git.lizzy.rs Git - rust.git/blob - src/librustc/hir/map/def_collector.rs
c0f38061a0d6dac2681a1a6fb47a68db53986594
[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 super::*;
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::visit;
21 use syntax::parse::token::{self, keywords};
22
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
26     // crate.
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)>,
31 }
32
33 pub struct MacroInvocationData {
34     pub id: NodeId,
35     pub def_index: DefIndex,
36     pub const_integer: bool,
37 }
38
39 impl<'a> DefCollector<'a> {
40     pub fn new(definitions: &'a mut Definitions) -> Self {
41         DefCollector {
42             hir_crate: None,
43             definitions: definitions,
44             parent_def: None,
45             visit_macro_invoc: None,
46         }
47     }
48
49     pub fn extend(parent_node: NodeId,
50                   parent_def_path: DefPath,
51                   parent_def_id: DefId,
52                   definitions: &'a mut Definitions)
53                   -> Self {
54         let mut collector = DefCollector::new(definitions);
55
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,
60         });
61
62         let def = collector.create_def(parent_node, DefPathData::InlinedRoot(root_path));
63         collector.parent_def = Some(def);
64
65         collector
66     }
67
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);
72
73         self.create_def_with_parent(Some(CRATE_DEF_INDEX), DUMMY_NODE_ID, DefPathData::Misc);
74     }
75
76     pub fn walk_item(&mut self, ii: &'a InlinedItem, krate: &'a hir::Crate) {
77         self.hir_crate = Some(krate);
78         ii.visit(self);
79     }
80
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)
85     }
86
87     fn create_def_with_parent(&mut self,
88                               parent: Option<DefIndex>,
89                               node_id: NodeId,
90                               data: DefPathData)
91                               -> DefIndex {
92         self.definitions.create_def_with_parent(parent, node_id, data)
93     }
94
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);
98         f(self);
99         self.parent_def = parent;
100     }
101
102     pub fn visit_ast_const_integer(&mut self, expr: &Expr) {
103         match expr.node {
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,
110             _ => {}
111         }
112
113         self.create_def(expr.id, DefPathData::Initializer);
114     }
115
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 {
120             return;
121         }
122
123         self.create_def(expr.id, DefPathData::Initializer);
124     }
125
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 {
129                 id: id,
130                 const_integer: const_integer,
131                 def_index: self.parent_def.unwrap(),
132             })
133         }
134     }
135 }
136
137 impl<'a> visit::Visitor for DefCollector<'a> {
138     fn visit_item(&mut self, i: &Item) {
139         debug!("visit_item: {:?}", i);
140
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(..) =>
145                 DefPathData::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);
151             }
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,
158         };
159         let def = self.create_def(i.id, def_data);
160
161         self.with_parent(def, |this| {
162             match i.node {
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()));
173                             }
174
175                             if let Some(ref expr) = v.node.disr_expr {
176                                 this.visit_ast_const_integer(expr);
177                             }
178                         });
179                     }
180                 }
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);
186                     }
187
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));
192                     }
193                 }
194                 _ => {}
195             }
196             visit::walk_item(this, i);
197         });
198     }
199
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()));
203
204         self.with_parent(def, |this| {
205             visit::walk_foreign_item(this, foreign_item);
206         });
207     }
208
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()));
212         }
213
214         visit::walk_generics(self, generics);
215     }
216
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),
223         };
224
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);
229             }
230
231             visit::walk_trait_item(this, ti);
232         });
233     }
234
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),
241         };
242
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);
247             }
248
249             visit::walk_impl_item(this, ii);
250         });
251     }
252
253     fn visit_pat(&mut self, pat: &Pat) {
254         let parent_def = self.parent_def;
255
256         match pat.node {
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);
261             }
262             _ => {}
263         }
264
265         visit::walk_pat(self, pat);
266         self.parent_def = parent_def;
267     }
268
269     fn visit_expr(&mut self, expr: &Expr) {
270         let parent_def = self.parent_def;
271
272         match expr.node {
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);
278             }
279             _ => {}
280         }
281
282         visit::walk_expr(self, expr);
283         self.parent_def = parent_def;
284     }
285
286     fn visit_ty(&mut self, ty: &Ty) {
287         match ty.node {
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);
292             }
293             _ => {}
294         }
295         visit::walk_ty(self, ty);
296     }
297
298     fn visit_lifetime_def(&mut self, def: &LifetimeDef) {
299         self.create_def(def.lifetime.id, DefPathData::LifetimeDef(def.lifetime.name.as_str()));
300     }
301
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()));
304     }
305
306     fn visit_stmt(&mut self, stmt: &Stmt) {
307         match stmt.node {
308             StmtKind::Mac(..) => self.visit_macro_invoc(stmt.id, false),
309             _ => visit::walk_stmt(self, stmt),
310         }
311     }
312 }
313
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);
318
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(..) =>
323                 DefPathData::Impl,
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,
331         };
332         let def = self.create_def(i.id, def_data);
333
334         self.with_parent(def, |this| {
335             match i.node {
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()));
341
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()));
346                             }
347                             if let Some(ref expr) = v.node.disr_expr {
348                                 this.visit_hir_const_integer(expr);
349                             }
350                         });
351                     }
352                 }
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);
359                     }
360
361                     for field in struct_def.fields() {
362                         this.create_def(field.id, DefPathData::Field(field.name.as_str()));
363                     }
364                 }
365                 _ => {}
366             }
367             intravisit::walk_item(this, i);
368         });
369     }
370
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()));
374
375         self.with_parent(def, |this| {
376             intravisit::walk_foreign_item(this, foreign_item);
377         });
378     }
379
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()));
383         }
384
385         intravisit::walk_generics(self, generics);
386     }
387
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()),
393         };
394
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);
399             }
400
401             intravisit::walk_trait_item(this, ti);
402         });
403     }
404
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()),
410         };
411
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);
416             }
417
418             intravisit::walk_impl_item(this, ii);
419         });
420     }
421
422     fn visit_pat(&mut self, pat: &'ast hir::Pat) {
423         let parent_def = self.parent_def;
424
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);
428         }
429
430         intravisit::walk_pat(self, pat);
431         self.parent_def = parent_def;
432     }
433
434     fn visit_expr(&mut self, expr: &'ast hir::Expr) {
435         let parent_def = self.parent_def;
436
437         if let hir::ExprRepeat(_, ref count) = expr.node {
438             self.visit_hir_const_integer(count);
439         }
440
441         if let hir::ExprClosure(..) = expr.node {
442             let def = self.create_def(expr.id, DefPathData::ClosureExpr);
443             self.parent_def = Some(def);
444         }
445
446         intravisit::walk_expr(self, expr);
447         self.parent_def = parent_def;
448     }
449
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);
453         }
454         if let hir::TyImplTrait(..) = ty.node {
455             self.create_def(ty.id, DefPathData::ImplTrait);
456         }
457         intravisit::walk_ty(self, ty);
458     }
459
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()));
462     }
463
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()));
466     }
467 }