]>
Commit | Line | Data |
---|---|---|
a7813a04 XL |
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>, | |
3157f602 | 28 | definitions: &'ast mut Definitions, |
a7813a04 XL |
29 | parent_def: Option<DefIndex>, |
30 | } | |
31 | ||
32 | impl<'ast> DefCollector<'ast> { | |
3157f602 | 33 | pub fn root(definitions: &'ast mut Definitions) -> DefCollector<'ast> { |
a7813a04 XL |
34 | let mut collector = DefCollector { |
35 | hir_crate: None, | |
3157f602 | 36 | definitions: definitions, |
a7813a04 XL |
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, | |
3157f602 | 51 | definitions: &'ast mut Definitions) |
a7813a04 XL |
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 | ||
3157f602 | 101 | fn visit_ast_const_integer(&mut self, expr: &Expr) { |
a7813a04 XL |
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 | ||
3157f602 XL |
127 | impl<'ast> visit::Visitor for DefCollector<'ast> { |
128 | fn visit_item(&mut self, i: &Item) { | |
a7813a04 XL |
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::Trait(..) | | |
137 | ItemKind::ExternCrate(..) | ItemKind::ForeignMod(..) | ItemKind::Ty(..) => | |
5bcae85e SL |
138 | DefPathData::TypeNs(i.ident.name.as_str()), |
139 | ItemKind::Mod(..) => DefPathData::Module(i.ident.name.as_str()), | |
a7813a04 | 140 | ItemKind::Static(..) | ItemKind::Const(..) | ItemKind::Fn(..) => |
5bcae85e SL |
141 | DefPathData::ValueNs(i.ident.name.as_str()), |
142 | ItemKind::Mac(..) => DefPathData::MacroDef(i.ident.name.as_str()), | |
a7813a04 XL |
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(), | |
5bcae85e | 153 | DefPathData::EnumVariant(v.node.name.name.as_str())); |
a7813a04 XL |
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())); | |
5bcae85e | 158 | this.create_def(field.id, DefPathData::Field(name.as_str())); |
a7813a04 XL |
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, _) => { | |
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() { | |
5bcae85e SL |
175 | let name = field.ident.map(|ident| ident.name.as_str()) |
176 | .unwrap_or(token::intern(&index.to_string()).as_str()); | |
a7813a04 XL |
177 | this.create_def(field.id, DefPathData::Field(name)); |
178 | } | |
179 | } | |
180 | _ => {} | |
181 | } | |
182 | visit::walk_item(this, i); | |
183 | }); | |
184 | } | |
185 | ||
3157f602 | 186 | fn visit_foreign_item(&mut self, foreign_item: &ForeignItem) { |
5bcae85e SL |
187 | let def = self.create_def(foreign_item.id, |
188 | DefPathData::ValueNs(foreign_item.ident.name.as_str())); | |
a7813a04 XL |
189 | |
190 | self.with_parent(def, |this| { | |
191 | visit::walk_foreign_item(this, foreign_item); | |
192 | }); | |
193 | } | |
194 | ||
3157f602 | 195 | fn visit_generics(&mut self, generics: &Generics) { |
a7813a04 | 196 | for ty_param in generics.ty_params.iter() { |
5bcae85e | 197 | self.create_def(ty_param.id, DefPathData::TypeParam(ty_param.ident.name.as_str())); |
a7813a04 XL |
198 | } |
199 | ||
200 | visit::walk_generics(self, generics); | |
201 | } | |
202 | ||
3157f602 | 203 | fn visit_trait_item(&mut self, ti: &TraitItem) { |
a7813a04 XL |
204 | let def_data = match ti.node { |
205 | TraitItemKind::Method(..) | TraitItemKind::Const(..) => | |
5bcae85e SL |
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()), | |
a7813a04 XL |
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 | ||
3157f602 | 221 | fn visit_impl_item(&mut self, ii: &ImplItem) { |
a7813a04 XL |
222 | let def_data = match ii.node { |
223 | ImplItemKind::Method(..) | ImplItemKind::Const(..) => | |
5bcae85e SL |
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()), | |
a7813a04 XL |
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 | ||
3157f602 | 239 | fn visit_pat(&mut self, pat: &Pat) { |
a7813a04 XL |
240 | let parent_def = self.parent_def; |
241 | ||
242 | if let PatKind::Ident(_, id, _) = pat.node { | |
5bcae85e | 243 | let def = self.create_def(pat.id, DefPathData::Binding(id.node.name.as_str())); |
a7813a04 XL |
244 | self.parent_def = Some(def); |
245 | } | |
246 | ||
247 | visit::walk_pat(self, pat); | |
248 | self.parent_def = parent_def; | |
249 | } | |
250 | ||
3157f602 | 251 | fn visit_expr(&mut self, expr: &Expr) { |
a7813a04 XL |
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 | ||
3157f602 | 267 | fn visit_ty(&mut self, ty: &Ty) { |
a7813a04 XL |
268 | if let TyKind::FixedLengthVec(_, ref length) = ty.node { |
269 | self.visit_ast_const_integer(length); | |
270 | } | |
5bcae85e SL |
271 | if let TyKind::ImplTrait(..) = ty.node { |
272 | self.create_def(ty.id, DefPathData::ImplTrait); | |
273 | } | |
a7813a04 XL |
274 | visit::walk_ty(self, ty); |
275 | } | |
276 | ||
3157f602 | 277 | fn visit_lifetime_def(&mut self, def: &LifetimeDef) { |
5bcae85e | 278 | self.create_def(def.lifetime.id, DefPathData::LifetimeDef(def.lifetime.name.as_str())); |
a7813a04 XL |
279 | } |
280 | ||
3157f602 | 281 | fn visit_macro_def(&mut self, macro_def: &MacroDef) { |
5bcae85e | 282 | self.create_def(macro_def.id, DefPathData::MacroDef(macro_def.ident.name.as_str())); |
a7813a04 XL |
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(..) => | |
5bcae85e | 308 | DefPathData::TypeNs(i.name.as_str()), |
a7813a04 | 309 | hir::ItemStatic(..) | hir::ItemConst(..) | hir::ItemFn(..) => |
5bcae85e | 310 | DefPathData::ValueNs(i.name.as_str()), |
a7813a04 XL |
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(), | |
5bcae85e | 321 | DefPathData::EnumVariant(v.node.name.as_str())); |
a7813a04 XL |
322 | |
323 | this.with_parent(variant_def_index, |this| { | |
324 | for field in v.node.data.fields() { | |
325 | this.create_def(field.id, | |
5bcae85e | 326 | DefPathData::Field(field.name.as_str())); |
a7813a04 XL |
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() { | |
5bcae85e | 342 | this.create_def(field.id, DefPathData::Field(field.name.as_str())); |
a7813a04 XL |
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) { | |
5bcae85e SL |
352 | let def = self.create_def(foreign_item.id, |
353 | DefPathData::ValueNs(foreign_item.name.as_str())); | |
a7813a04 XL |
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() { | |
5bcae85e | 362 | self.create_def(ty_param.id, DefPathData::TypeParam(ty_param.name.as_str())); |
a7813a04 XL |
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(..) => | |
5bcae85e SL |
371 | DefPathData::ValueNs(ti.name.as_str()), |
372 | hir::TypeTraitItem(..) => DefPathData::TypeNs(ti.name.as_str()), | |
a7813a04 XL |
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(..) => | |
5bcae85e SL |
388 | DefPathData::ValueNs(ii.name.as_str()), |
389 | hir::ImplItemKind::Type(..) => DefPathData::TypeNs(ii.name.as_str()), | |
a7813a04 XL |
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 | ||
3157f602 | 405 | if let hir::PatKind::Binding(_, name, _) = pat.node { |
5bcae85e | 406 | let def = self.create_def(pat.id, DefPathData::Binding(name.node.as_str())); |
a7813a04 XL |
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 | } | |
5bcae85e SL |
434 | if let hir::TyImplTrait(..) = ty.node { |
435 | self.create_def(ty.id, DefPathData::ImplTrait); | |
436 | } | |
a7813a04 XL |
437 | intravisit::walk_ty(self, ty); |
438 | } | |
439 | ||
440 | fn visit_lifetime_def(&mut self, def: &'ast hir::LifetimeDef) { | |
5bcae85e | 441 | self.create_def(def.lifetime.id, DefPathData::LifetimeDef(def.lifetime.name.as_str())); |
a7813a04 XL |
442 | } |
443 | ||
444 | fn visit_macro_def(&mut self, macro_def: &'ast hir::MacroDef) { | |
5bcae85e | 445 | self.create_def(macro_def.id, DefPathData::MacroDef(macro_def.name.as_str())); |
a7813a04 XL |
446 | } |
447 | } |