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