]>
Commit | Line | Data |
---|---|---|
f035d41b | 1 | use crate::Resolver; |
ba9703b0 XL |
2 | use rustc_ast::visit::{self, FnKind}; |
3 | use rustc_ast::walk_list; | |
3dfed10e | 4 | use rustc_ast::*; |
f035d41b | 5 | use rustc_ast_lowering::ResolverAstLowering; |
dfeec247 | 6 | use rustc_expand::expand::AstFragment; |
ba9703b0 XL |
7 | use rustc_hir::def_id::LocalDefId; |
8 | use rustc_hir::definitions::*; | |
dfeec247 XL |
9 | use rustc_span::hygiene::ExpnId; |
10 | use rustc_span::symbol::{kw, sym}; | |
11 | use rustc_span::Span; | |
3dfed10e | 12 | use tracing::debug; |
a7813a04 | 13 | |
60c5eb7d | 14 | crate fn collect_definitions( |
f035d41b | 15 | resolver: &mut Resolver<'_>, |
60c5eb7d XL |
16 | fragment: &AstFragment, |
17 | expansion: ExpnId, | |
18 | ) { | |
f035d41b XL |
19 | let parent_def = resolver.invocation_parents[&expansion]; |
20 | fragment.visit_with(&mut DefCollector { resolver, parent_def, expansion }); | |
60c5eb7d XL |
21 | } |
22 | ||
9fa01778 | 23 | /// Creates `DefId`s for nodes in the AST. |
f035d41b XL |
24 | struct DefCollector<'a, 'b> { |
25 | resolver: &'a mut Resolver<'b>, | |
ba9703b0 | 26 | parent_def: LocalDefId, |
416331ca | 27 | expansion: ExpnId, |
c30ab7b3 SL |
28 | } |
29 | ||
f035d41b | 30 | impl<'a, 'b> DefCollector<'a, 'b> { |
ba9703b0 | 31 | fn create_def(&mut self, node_id: NodeId, data: DefPathData, span: Span) -> LocalDefId { |
416331ca | 32 | let parent_def = self.parent_def; |
a7813a04 | 33 | debug!("create_def(node_id={:?}, data={:?}, parent_def={:?})", node_id, data, parent_def); |
f035d41b | 34 | self.resolver.create_def(parent_def, node_id, data, self.expansion, span) |
a7813a04 XL |
35 | } |
36 | ||
ba9703b0 | 37 | fn with_parent<F: FnOnce(&mut Self)>(&mut self, parent_def: LocalDefId, f: F) { |
416331ca | 38 | let orig_parent_def = std::mem::replace(&mut self.parent_def, parent_def); |
a7813a04 | 39 | f(self); |
416331ca | 40 | self.parent_def = orig_parent_def; |
a7813a04 XL |
41 | } |
42 | ||
e1599b0c | 43 | fn collect_field(&mut self, field: &'a StructField, index: Option<usize>) { |
dfeec247 XL |
44 | let index = |this: &Self| { |
45 | index.unwrap_or_else(|| { | |
46 | let node_id = NodeId::placeholder_from_expn_id(this.expansion); | |
f035d41b | 47 | this.resolver.placeholder_field_indices[&node_id] |
dfeec247 XL |
48 | }) |
49 | }; | |
e74abb32 | 50 | |
e1599b0c | 51 | if field.is_placeholder { |
f035d41b XL |
52 | let old_index = self.resolver.placeholder_field_indices.insert(field.id, index(self)); |
53 | assert!(old_index.is_none(), "placeholder field index is reset for a node ID"); | |
e1599b0c XL |
54 | self.visit_macro_invoc(field.id); |
55 | } else { | |
e74abb32 | 56 | let name = field.ident.map_or_else(|| sym::integer(index(self)), |ident| ident.name); |
e1599b0c XL |
57 | let def = self.create_def(field.id, DefPathData::ValueNs(name), field.span); |
58 | self.with_parent(def, |this| visit::walk_struct_field(this, field)); | |
59 | } | |
60 | } | |
61 | ||
e74abb32 | 62 | fn visit_macro_invoc(&mut self, id: NodeId) { |
f035d41b XL |
63 | let old_parent = |
64 | self.resolver.invocation_parents.insert(id.placeholder_to_expn_id(), self.parent_def); | |
65 | assert!(old_parent.is_none(), "parent `LocalDefId` is reset for an invocation"); | |
c30ab7b3 | 66 | } |
a7813a04 XL |
67 | } |
68 | ||
f035d41b | 69 | impl<'a, 'b> visit::Visitor<'a> for DefCollector<'a, 'b> { |
476ff2be | 70 | fn visit_item(&mut self, i: &'a Item) { |
a7813a04 XL |
71 | debug!("visit_item: {:?}", i); |
72 | ||
73 | // Pick the def data. This need not be unique, but the more | |
94b46f34 | 74 | // information we encapsulate into, the better |
60c5eb7d | 75 | let def_data = match &i.kind { |
dfeec247 | 76 | ItemKind::Impl { .. } => DefPathData::Impl, |
dc9dc135 | 77 | ItemKind::Mod(..) if i.ident.name == kw::Invalid => { |
29967ef6 | 78 | // Fake crate root item from expand. |
c30ab7b3 SL |
79 | return visit::walk_item(self, i); |
80 | } | |
dfeec247 XL |
81 | ItemKind::Mod(..) |
82 | | ItemKind::Trait(..) | |
83 | | ItemKind::TraitAlias(..) | |
84 | | ItemKind::Enum(..) | |
85 | | ItemKind::Struct(..) | |
86 | | ItemKind::Union(..) | |
87 | | ItemKind::ExternCrate(..) | |
88 | | ItemKind::ForeignMod(..) | |
89 | | ItemKind::TyAlias(..) => DefPathData::TypeNs(i.ident.name), | |
dfeec247 XL |
90 | ItemKind::Static(..) | ItemKind::Const(..) | ItemKind::Fn(..) => { |
91 | DefPathData::ValueNs(i.ident.name) | |
8faf50e0 | 92 | } |
e74abb32 | 93 | ItemKind::MacroDef(..) => DefPathData::MacroNs(i.ident.name), |
ba9703b0 | 94 | ItemKind::MacCall(..) => return self.visit_macro_invoc(i.id), |
cc61c64b | 95 | ItemKind::GlobalAsm(..) => DefPathData::Misc, |
ff7c6d11 XL |
96 | ItemKind::Use(..) => { |
97 | return visit::walk_item(self, i); | |
476ff2be | 98 | } |
a7813a04 | 99 | }; |
48663c56 | 100 | let def = self.create_def(i.id, def_data, i.span); |
a7813a04 XL |
101 | |
102 | self.with_parent(def, |this| { | |
e74abb32 | 103 | match i.kind { |
9e0c209e | 104 | ItemKind::Struct(ref struct_def, _) | ItemKind::Union(ref struct_def, _) => { |
532ac7d7 XL |
105 | // If this is a unit or tuple-like struct, register the constructor. |
106 | if let Some(ctor_hir_id) = struct_def.ctor_id() { | |
48663c56 | 107 | this.create_def(ctor_hir_id, DefPathData::Ctor, i.span); |
a7813a04 | 108 | } |
a7813a04 XL |
109 | } |
110 | _ => {} | |
111 | } | |
112 | visit::walk_item(this, i); | |
113 | }); | |
114 | } | |
115 | ||
ba9703b0 XL |
116 | fn visit_fn(&mut self, fn_kind: FnKind<'a>, span: Span, _: NodeId) { |
117 | if let FnKind::Fn(_, _, sig, _, body) = fn_kind { | |
118 | if let Async::Yes { closure_id, return_impl_trait_id, .. } = sig.header.asyncness { | |
119 | self.create_def(return_impl_trait_id, DefPathData::ImplTrait, span); | |
120 | ||
121 | // For async functions, we need to create their inner defs inside of a | |
122 | // closure to match their desugared representation. Besides that, | |
123 | // we must mirror everything that `visit::walk_fn` below does. | |
124 | self.visit_fn_header(&sig.header); | |
125 | visit::walk_fn_decl(self, &sig.decl); | |
126 | let closure_def = self.create_def(closure_id, DefPathData::ClosureExpr, span); | |
127 | self.with_parent(closure_def, |this| walk_list!(this, visit_block, body)); | |
128 | return; | |
129 | } | |
130 | } | |
131 | ||
132 | visit::walk_fn(self, fn_kind, span); | |
133 | } | |
134 | ||
ff7c6d11 | 135 | fn visit_use_tree(&mut self, use_tree: &'a UseTree, id: NodeId, _nested: bool) { |
48663c56 | 136 | self.create_def(id, DefPathData::Misc, use_tree.span); |
ff7c6d11 XL |
137 | visit::walk_use_tree(self, use_tree, id); |
138 | } | |
139 | ||
476ff2be | 140 | fn visit_foreign_item(&mut self, foreign_item: &'a ForeignItem) { |
ba9703b0 | 141 | if let ForeignItemKind::MacCall(_) = foreign_item.kind { |
94b46f34 | 142 | return self.visit_macro_invoc(foreign_item.id); |
83c7162d XL |
143 | } |
144 | ||
dfeec247 XL |
145 | let def = self.create_def( |
146 | foreign_item.id, | |
147 | DefPathData::ValueNs(foreign_item.ident.name), | |
148 | foreign_item.span, | |
149 | ); | |
a7813a04 XL |
150 | |
151 | self.with_parent(def, |this| { | |
152 | visit::walk_foreign_item(this, foreign_item); | |
153 | }); | |
154 | } | |
155 | ||
e1599b0c XL |
156 | fn visit_variant(&mut self, v: &'a Variant) { |
157 | if v.is_placeholder { | |
158 | return self.visit_macro_invoc(v.id); | |
159 | } | |
dfeec247 | 160 | let def = self.create_def(v.id, DefPathData::TypeNs(v.ident.name), v.span); |
532ac7d7 | 161 | self.with_parent(def, |this| { |
e1599b0c | 162 | if let Some(ctor_hir_id) = v.data.ctor_id() { |
48663c56 | 163 | this.create_def(ctor_hir_id, DefPathData::Ctor, v.span); |
532ac7d7 | 164 | } |
e1599b0c | 165 | visit::walk_variant(this, v) |
532ac7d7 | 166 | }); |
94b46f34 XL |
167 | } |
168 | ||
e1599b0c XL |
169 | fn visit_variant_data(&mut self, data: &'a VariantData) { |
170 | // The assumption here is that non-`cfg` macro expansion cannot change field indices. | |
171 | // It currently holds because only inert attributes are accepted on fields, | |
172 | // and every such attribute expands into a single field after it's resolved. | |
94b46f34 | 173 | for (index, field) in data.fields().iter().enumerate() { |
e1599b0c | 174 | self.collect_field(field, Some(index)); |
94b46f34 XL |
175 | } |
176 | } | |
177 | ||
ff7c6d11 | 178 | fn visit_generic_param(&mut self, param: &'a GenericParam) { |
e1599b0c XL |
179 | if param.is_placeholder { |
180 | self.visit_macro_invoc(param.id); | |
181 | return; | |
182 | } | |
e74abb32 | 183 | let name = param.ident.name; |
8faf50e0 | 184 | let def_path_data = match param.kind { |
48663c56 XL |
185 | GenericParamKind::Lifetime { .. } => DefPathData::LifetimeNs(name), |
186 | GenericParamKind::Type { .. } => DefPathData::TypeNs(name), | |
187 | GenericParamKind::Const { .. } => DefPathData::ValueNs(name), | |
8faf50e0 | 188 | }; |
48663c56 | 189 | self.create_def(param.id, def_path_data, param.ident.span); |
a7813a04 | 190 | |
ff7c6d11 | 191 | visit::walk_generic_param(self, param); |
a7813a04 XL |
192 | } |
193 | ||
74b04a01 XL |
194 | fn visit_assoc_item(&mut self, i: &'a AssocItem, ctxt: visit::AssocCtxt) { |
195 | let def_data = match &i.kind { | |
74b04a01 XL |
196 | AssocItemKind::Fn(..) | AssocItemKind::Const(..) => DefPathData::ValueNs(i.ident.name), |
197 | AssocItemKind::TyAlias(..) => DefPathData::TypeNs(i.ident.name), | |
ba9703b0 | 198 | AssocItemKind::MacCall(..) => return self.visit_macro_invoc(i.id), |
a7813a04 XL |
199 | }; |
200 | ||
74b04a01 XL |
201 | let def = self.create_def(i.id, def_data, i.span); |
202 | self.with_parent(def, |this| visit::walk_assoc_item(this, i, ctxt)); | |
a7813a04 XL |
203 | } |
204 | ||
476ff2be | 205 | fn visit_pat(&mut self, pat: &'a Pat) { |
e74abb32 | 206 | match pat.kind { |
ba9703b0 | 207 | PatKind::MacCall(..) => self.visit_macro_invoc(pat.id), |
ea8adc8c | 208 | _ => visit::walk_pat(self, pat), |
a7813a04 | 209 | } |
a7813a04 XL |
210 | } |
211 | ||
94b46f34 | 212 | fn visit_anon_const(&mut self, constant: &'a AnonConst) { |
dfeec247 | 213 | let def = self.create_def(constant.id, DefPathData::AnonConst, constant.value.span); |
94b46f34 XL |
214 | self.with_parent(def, |this| visit::walk_anon_const(this, constant)); |
215 | } | |
216 | ||
476ff2be | 217 | fn visit_expr(&mut self, expr: &'a Expr) { |
e74abb32 | 218 | let parent_def = match expr.kind { |
ba9703b0 | 219 | ExprKind::MacCall(..) => return self.visit_macro_invoc(expr.id), |
dc9dc135 | 220 | ExprKind::Closure(_, asyncness, ..) => { |
8faf50e0 XL |
221 | // Async closures desugar to closures inside of closures, so |
222 | // we must create two defs. | |
416331ca XL |
223 | let closure_def = self.create_def(expr.id, DefPathData::ClosureExpr, expr.span); |
224 | match asyncness { | |
74b04a01 | 225 | Async::Yes { closure_id, .. } => { |
dfeec247 XL |
226 | self.create_def(closure_id, DefPathData::ClosureExpr, expr.span) |
227 | } | |
74b04a01 | 228 | Async::No => closure_def, |
8faf50e0 XL |
229 | } |
230 | } | |
dfeec247 XL |
231 | ExprKind::Async(_, async_id, _) => { |
232 | self.create_def(async_id, DefPathData::ClosureExpr, expr.span) | |
233 | } | |
416331ca | 234 | _ => self.parent_def, |
8faf50e0 | 235 | }; |
a7813a04 | 236 | |
416331ca | 237 | self.with_parent(parent_def, |this| visit::walk_expr(this, expr)); |
a7813a04 XL |
238 | } |
239 | ||
476ff2be | 240 | fn visit_ty(&mut self, ty: &'a Ty) { |
e74abb32 | 241 | match ty.kind { |
29967ef6 | 242 | TyKind::MacCall(..) => self.visit_macro_invoc(ty.id), |
8faf50e0 | 243 | TyKind::ImplTrait(node_id, _) => { |
29967ef6 XL |
244 | let parent_def = self.create_def(node_id, DefPathData::ImplTrait, ty.span); |
245 | self.with_parent(parent_def, |this| visit::walk_ty(this, ty)); | |
8faf50e0 | 246 | } |
29967ef6 | 247 | _ => visit::walk_ty(self, ty), |
5bcae85e | 248 | } |
a7813a04 XL |
249 | } |
250 | ||
476ff2be | 251 | fn visit_stmt(&mut self, stmt: &'a Stmt) { |
e74abb32 | 252 | match stmt.kind { |
ba9703b0 | 253 | StmtKind::MacCall(..) => self.visit_macro_invoc(stmt.id), |
c30ab7b3 SL |
254 | _ => visit::walk_stmt(self, stmt), |
255 | } | |
256 | } | |
abe05a73 | 257 | |
e1599b0c | 258 | fn visit_arm(&mut self, arm: &'a Arm) { |
dfeec247 | 259 | if arm.is_placeholder { self.visit_macro_invoc(arm.id) } else { visit::walk_arm(self, arm) } |
e1599b0c XL |
260 | } |
261 | ||
262 | fn visit_field(&mut self, f: &'a Field) { | |
dfeec247 | 263 | if f.is_placeholder { self.visit_macro_invoc(f.id) } else { visit::walk_field(self, f) } |
e1599b0c XL |
264 | } |
265 | ||
266 | fn visit_field_pattern(&mut self, fp: &'a FieldPat) { | |
267 | if fp.is_placeholder { | |
268 | self.visit_macro_invoc(fp.id) | |
269 | } else { | |
270 | visit::walk_field_pattern(self, fp) | |
271 | } | |
272 | } | |
273 | ||
274 | fn visit_param(&mut self, p: &'a Param) { | |
dfeec247 | 275 | if p.is_placeholder { self.visit_macro_invoc(p.id) } else { visit::walk_param(self, p) } |
e1599b0c XL |
276 | } |
277 | ||
278 | // This method is called only when we are visiting an individual field | |
279 | // after expanding an attribute on it. | |
280 | fn visit_struct_field(&mut self, field: &'a StructField) { | |
281 | self.collect_field(field, None); | |
282 | } | |
a7813a04 | 283 | } |