]> git.lizzy.rs Git - rust.git/blob - src/librustc/hir/map/def_collector.rs
c44942a162685693ba03fc909065c959476f23a3
[rust.git] / src / librustc / hir / map / def_collector.rs
1 use crate::hir::map::definitions::*;
2 use crate::hir::def_id::DefIndex;
3
4 use syntax::ast::*;
5 use syntax::ext::hygiene::ExpnId;
6 use syntax::visit;
7 use syntax::symbol::{kw, sym};
8 use syntax::parse::token::{self, Token};
9 use syntax_pos::Span;
10
11 /// Creates `DefId`s for nodes in the AST.
12 pub struct DefCollector<'a> {
13     definitions: &'a mut Definitions,
14     parent_def: DefIndex,
15     expansion: ExpnId,
16 }
17
18 impl<'a> DefCollector<'a> {
19     pub fn new(definitions: &'a mut Definitions, expansion: ExpnId) -> Self {
20         let parent_def = definitions.invocation_parent(expansion);
21         DefCollector { definitions, parent_def, expansion }
22     }
23
24     fn create_def(&mut self,
25                   node_id: NodeId,
26                   data: DefPathData,
27                   span: Span)
28                   -> DefIndex {
29         let parent_def = self.parent_def;
30         debug!("create_def(node_id={:?}, data={:?}, parent_def={:?})", node_id, data, parent_def);
31         self.definitions.create_def_with_parent(parent_def, node_id, data, self.expansion, span)
32     }
33
34     pub fn with_parent<F: FnOnce(&mut Self)>(&mut self, parent_def: DefIndex, f: F) {
35         let orig_parent_def = std::mem::replace(&mut self.parent_def, parent_def);
36         f(self);
37         self.parent_def = orig_parent_def;
38     }
39
40     fn visit_async_fn(
41         &mut self,
42         id: NodeId,
43         name: Name,
44         span: Span,
45         header: &FnHeader,
46         generics: &'a Generics,
47         decl: &'a FnDecl,
48         body: &'a Block,
49     ) {
50         let (closure_id, return_impl_trait_id) = match header.asyncness.node {
51             IsAsync::Async {
52                 closure_id,
53                 return_impl_trait_id,
54             } => (closure_id, return_impl_trait_id),
55             _ => unreachable!(),
56         };
57
58         // For async functions, we need to create their inner defs inside of a
59         // closure to match their desugared representation.
60         let fn_def_data = DefPathData::ValueNs(name.as_interned_str());
61         let fn_def = self.create_def(id, fn_def_data, span);
62         return self.with_parent(fn_def, |this| {
63             this.create_def(return_impl_trait_id, DefPathData::ImplTrait, span);
64
65             visit::walk_generics(this, generics);
66             visit::walk_fn_decl(this, decl);
67
68             let closure_def = this.create_def(
69                 closure_id, DefPathData::ClosureExpr, span,
70             );
71             this.with_parent(closure_def, |this| {
72                 visit::walk_block(this, body);
73             })
74         })
75     }
76
77     fn visit_macro_invoc(&mut self, id: NodeId) {
78         self.definitions.set_invocation_parent(id.placeholder_to_expn_id(), self.parent_def);
79     }
80 }
81
82 impl<'a> visit::Visitor<'a> for DefCollector<'a> {
83     fn visit_item(&mut self, i: &'a Item) {
84         debug!("visit_item: {:?}", i);
85
86         // Pick the def data. This need not be unique, but the more
87         // information we encapsulate into, the better
88         let def_data = match i.node {
89             ItemKind::Impl(..) => DefPathData::Impl,
90             ItemKind::Mod(..) if i.ident.name == kw::Invalid => {
91                 return visit::walk_item(self, i);
92             }
93             ItemKind::Mod(..) | ItemKind::Trait(..) | ItemKind::TraitAlias(..) |
94             ItemKind::Enum(..) | ItemKind::Struct(..) | ItemKind::Union(..) |
95             ItemKind::OpaqueTy(..) | ItemKind::ExternCrate(..) | ItemKind::ForeignMod(..) |
96             ItemKind::Ty(..) => DefPathData::TypeNs(i.ident.as_interned_str()),
97             ItemKind::Fn(
98                 ref decl,
99                 ref header,
100                 ref generics,
101                 ref body,
102             ) if header.asyncness.node.is_async() => {
103                 return self.visit_async_fn(
104                     i.id,
105                     i.ident.name,
106                     i.span,
107                     header,
108                     generics,
109                     decl,
110                     body,
111                 )
112             }
113             ItemKind::Static(..) | ItemKind::Const(..) | ItemKind::Fn(..) =>
114                 DefPathData::ValueNs(i.ident.as_interned_str()),
115             ItemKind::MacroDef(..) => DefPathData::MacroNs(i.ident.as_interned_str()),
116             ItemKind::Mac(..) => return self.visit_macro_invoc(i.id),
117             ItemKind::GlobalAsm(..) => DefPathData::Misc,
118             ItemKind::Use(..) => {
119                 return visit::walk_item(self, i);
120             }
121         };
122         let def = self.create_def(i.id, def_data, i.span);
123
124         self.with_parent(def, |this| {
125             match i.node {
126                 ItemKind::Struct(ref struct_def, _) | ItemKind::Union(ref struct_def, _) => {
127                     // If this is a unit or tuple-like struct, register the constructor.
128                     if let Some(ctor_hir_id) = struct_def.ctor_id() {
129                         this.create_def(ctor_hir_id, DefPathData::Ctor, i.span);
130                     }
131                 }
132                 _ => {}
133             }
134             visit::walk_item(this, i);
135         });
136     }
137
138     fn visit_use_tree(&mut self, use_tree: &'a UseTree, id: NodeId, _nested: bool) {
139         self.create_def(id, DefPathData::Misc, use_tree.span);
140         visit::walk_use_tree(self, use_tree, id);
141     }
142
143     fn visit_foreign_item(&mut self, foreign_item: &'a ForeignItem) {
144         if let ForeignItemKind::Macro(_) = foreign_item.node {
145             return self.visit_macro_invoc(foreign_item.id);
146         }
147
148         let def = self.create_def(foreign_item.id,
149                                   DefPathData::ValueNs(foreign_item.ident.as_interned_str()),
150                                   foreign_item.span);
151
152         self.with_parent(def, |this| {
153             visit::walk_foreign_item(this, foreign_item);
154         });
155     }
156
157     fn visit_variant(&mut self, v: &'a Variant, g: &'a Generics, item_id: NodeId) {
158         let def = self.create_def(v.node.id,
159                                   DefPathData::TypeNs(v.node.ident.as_interned_str()),
160                                   v.span);
161         self.with_parent(def, |this| {
162             if let Some(ctor_hir_id) = v.node.data.ctor_id() {
163                 this.create_def(ctor_hir_id, DefPathData::Ctor, v.span);
164             }
165             visit::walk_variant(this, v, g, item_id)
166         });
167     }
168
169     fn visit_variant_data(&mut self, data: &'a VariantData, _: Ident,
170                           _: &'a Generics, _: NodeId, _: Span) {
171         for (index, field) in data.fields().iter().enumerate() {
172             let name = field.ident.map(|ident| ident.name)
173                 .unwrap_or_else(|| sym::integer(index));
174             let def = self.create_def(field.id,
175                                       DefPathData::ValueNs(name.as_interned_str()),
176                                       field.span);
177             self.with_parent(def, |this| this.visit_struct_field(field));
178         }
179     }
180
181     fn visit_generic_param(&mut self, param: &'a GenericParam) {
182         let name = param.ident.as_interned_str();
183         let def_path_data = match param.kind {
184             GenericParamKind::Lifetime { .. } => DefPathData::LifetimeNs(name),
185             GenericParamKind::Type { .. } => DefPathData::TypeNs(name),
186             GenericParamKind::Const { .. } => DefPathData::ValueNs(name),
187         };
188         self.create_def(param.id, def_path_data, param.ident.span);
189
190         visit::walk_generic_param(self, param);
191     }
192
193     fn visit_trait_item(&mut self, ti: &'a TraitItem) {
194         let def_data = match ti.node {
195             TraitItemKind::Method(..) | TraitItemKind::Const(..) =>
196                 DefPathData::ValueNs(ti.ident.as_interned_str()),
197             TraitItemKind::Type(..) => {
198                 DefPathData::TypeNs(ti.ident.as_interned_str())
199             },
200             TraitItemKind::Macro(..) => return self.visit_macro_invoc(ti.id),
201         };
202
203         let def = self.create_def(ti.id, def_data, ti.span);
204         self.with_parent(def, |this| visit::walk_trait_item(this, ti));
205     }
206
207     fn visit_impl_item(&mut self, ii: &'a ImplItem) {
208         let def_data = match ii.node {
209             ImplItemKind::Method(MethodSig {
210                 ref header,
211                 ref decl,
212             }, ref body) if header.asyncness.node.is_async() => {
213                 return self.visit_async_fn(
214                     ii.id,
215                     ii.ident.name,
216                     ii.span,
217                     header,
218                     &ii.generics,
219                     decl,
220                     body,
221                 )
222             }
223             ImplItemKind::Method(..) | ImplItemKind::Const(..) =>
224                 DefPathData::ValueNs(ii.ident.as_interned_str()),
225             ImplItemKind::Type(..) |
226             ImplItemKind::OpaqueTy(..) => {
227                 DefPathData::TypeNs(ii.ident.as_interned_str())
228             },
229             ImplItemKind::Macro(..) => return self.visit_macro_invoc(ii.id),
230         };
231
232         let def = self.create_def(ii.id, def_data, ii.span);
233         self.with_parent(def, |this| visit::walk_impl_item(this, ii));
234     }
235
236     fn visit_pat(&mut self, pat: &'a Pat) {
237         match pat.node {
238             PatKind::Mac(..) => return self.visit_macro_invoc(pat.id),
239             _ => visit::walk_pat(self, pat),
240         }
241     }
242
243     fn visit_anon_const(&mut self, constant: &'a AnonConst) {
244         let def = self.create_def(constant.id,
245                                   DefPathData::AnonConst,
246                                   constant.value.span);
247         self.with_parent(def, |this| visit::walk_anon_const(this, constant));
248     }
249
250     fn visit_expr(&mut self, expr: &'a Expr) {
251         let parent_def = match expr.node {
252             ExprKind::Mac(..) => return self.visit_macro_invoc(expr.id),
253             ExprKind::Closure(_, asyncness, ..) => {
254                 // Async closures desugar to closures inside of closures, so
255                 // we must create two defs.
256                 let closure_def = self.create_def(expr.id, DefPathData::ClosureExpr, expr.span);
257                 match asyncness {
258                     IsAsync::Async { closure_id, .. } =>
259                         self.create_def(closure_id, DefPathData::ClosureExpr, expr.span),
260                     IsAsync::NotAsync => closure_def,
261                 }
262             }
263             ExprKind::Async(_, async_id, _) =>
264                 self.create_def(async_id, DefPathData::ClosureExpr, expr.span),
265             _ => self.parent_def,
266         };
267
268         self.with_parent(parent_def, |this| visit::walk_expr(this, expr));
269     }
270
271     fn visit_ty(&mut self, ty: &'a Ty) {
272         match ty.node {
273             TyKind::Mac(..) => return self.visit_macro_invoc(ty.id),
274             TyKind::ImplTrait(node_id, _) => {
275                 self.create_def(node_id, DefPathData::ImplTrait, ty.span);
276             }
277             _ => {}
278         }
279         visit::walk_ty(self, ty);
280     }
281
282     fn visit_stmt(&mut self, stmt: &'a Stmt) {
283         match stmt.node {
284             StmtKind::Mac(..) => self.visit_macro_invoc(stmt.id),
285             _ => visit::walk_stmt(self, stmt),
286         }
287     }
288
289     fn visit_token(&mut self, t: Token) {
290         if let token::Interpolated(nt) = t.kind {
291             if let token::NtExpr(ref expr) = *nt {
292                 if let ExprKind::Mac(..) = expr.node {
293                     self.visit_macro_invoc(expr.id);
294                 }
295             }
296         }
297     }
298 }