2 use rustc_ast
::token
::{self, Token}
;
3 use rustc_ast
::visit
::{self, FnKind}
;
4 use rustc_ast
::walk_list
;
6 use rustc_ast_lowering
::ResolverAstLowering
;
7 use rustc_expand
::expand
::AstFragment
;
8 use rustc_hir
::def_id
::LocalDefId
;
9 use rustc_hir
::definitions
::*;
10 use rustc_span
::hygiene
::ExpnId
;
11 use rustc_span
::symbol
::{kw, sym}
;
15 crate fn collect_definitions(
16 resolver
: &mut Resolver
<'_
>,
17 fragment
: &AstFragment
,
20 let parent_def
= resolver
.invocation_parents
[&expansion
];
21 fragment
.visit_with(&mut DefCollector { resolver, parent_def, expansion }
);
24 /// Creates `DefId`s for nodes in the AST.
25 struct DefCollector
<'a
, 'b
> {
26 resolver
: &'a
mut Resolver
<'b
>,
27 parent_def
: LocalDefId
,
31 impl<'a
, 'b
> DefCollector
<'a
, 'b
> {
32 fn create_def(&mut self, node_id
: NodeId
, data
: DefPathData
, span
: Span
) -> LocalDefId
{
33 let parent_def
= self.parent_def
;
34 debug
!("create_def(node_id={:?}, data={:?}, parent_def={:?})", node_id
, data
, parent_def
);
35 self.resolver
.create_def(parent_def
, node_id
, data
, self.expansion
, span
)
38 fn with_parent
<F
: FnOnce(&mut Self)>(&mut self, parent_def
: LocalDefId
, f
: F
) {
39 let orig_parent_def
= std
::mem
::replace(&mut self.parent_def
, parent_def
);
41 self.parent_def
= orig_parent_def
;
44 fn collect_field(&mut self, field
: &'a StructField
, index
: Option
<usize>) {
45 let index
= |this
: &Self| {
46 index
.unwrap_or_else(|| {
47 let node_id
= NodeId
::placeholder_from_expn_id(this
.expansion
);
48 this
.resolver
.placeholder_field_indices
[&node_id
]
52 if field
.is_placeholder
{
53 let old_index
= self.resolver
.placeholder_field_indices
.insert(field
.id
, index(self));
54 assert
!(old_index
.is_none(), "placeholder field index is reset for a node ID");
55 self.visit_macro_invoc(field
.id
);
57 let name
= field
.ident
.map_or_else(|| sym
::integer(index(self)), |ident
| ident
.name
);
58 let def
= self.create_def(field
.id
, DefPathData
::ValueNs(name
), field
.span
);
59 self.with_parent(def
, |this
| visit
::walk_struct_field(this
, field
));
63 fn visit_macro_invoc(&mut self, id
: NodeId
) {
65 self.resolver
.invocation_parents
.insert(id
.placeholder_to_expn_id(), self.parent_def
);
66 assert
!(old_parent
.is_none(), "parent `LocalDefId` is reset for an invocation");
70 impl<'a
, 'b
> visit
::Visitor
<'a
> for DefCollector
<'a
, 'b
> {
71 fn visit_item(&mut self, i
: &'a Item
) {
72 debug
!("visit_item: {:?}", i
);
74 // Pick the def data. This need not be unique, but the more
75 // information we encapsulate into, the better
76 let def_data
= match &i
.kind
{
77 ItemKind
::Impl { .. }
=> DefPathData
::Impl
,
78 ItemKind
::Mod(..) if i
.ident
.name
== kw
::Invalid
=> {
79 return visit
::walk_item(self, i
);
83 | ItemKind
::TraitAlias(..)
85 | ItemKind
::Struct(..)
87 | ItemKind
::ExternCrate(..)
88 | ItemKind
::ForeignMod(..)
89 | ItemKind
::TyAlias(..) => DefPathData
::TypeNs(i
.ident
.name
),
90 ItemKind
::Static(..) | ItemKind
::Const(..) | ItemKind
::Fn(..) => {
91 DefPathData
::ValueNs(i
.ident
.name
)
93 ItemKind
::MacroDef(..) => DefPathData
::MacroNs(i
.ident
.name
),
94 ItemKind
::MacCall(..) => return self.visit_macro_invoc(i
.id
),
95 ItemKind
::GlobalAsm(..) => DefPathData
::Misc
,
96 ItemKind
::Use(..) => {
97 return visit
::walk_item(self, i
);
100 let def
= self.create_def(i
.id
, def_data
, i
.span
);
102 self.with_parent(def
, |this
| {
104 ItemKind
::Struct(ref struct_def
, _
) | ItemKind
::Union(ref struct_def
, _
) => {
105 // If this is a unit or tuple-like struct, register the constructor.
106 if let Some(ctor_hir_id
) = struct_def
.ctor_id() {
107 this
.create_def(ctor_hir_id
, DefPathData
::Ctor
, i
.span
);
112 visit
::walk_item(this
, i
);
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
);
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
));
132 visit
::walk_fn(self, fn_kind
, span
);
135 fn visit_use_tree(&mut self, use_tree
: &'a UseTree
, id
: NodeId
, _nested
: bool
) {
136 self.create_def(id
, DefPathData
::Misc
, use_tree
.span
);
137 visit
::walk_use_tree(self, use_tree
, id
);
140 fn visit_foreign_item(&mut self, foreign_item
: &'a ForeignItem
) {
141 if let ForeignItemKind
::MacCall(_
) = foreign_item
.kind
{
142 return self.visit_macro_invoc(foreign_item
.id
);
145 let def
= self.create_def(
147 DefPathData
::ValueNs(foreign_item
.ident
.name
),
151 self.with_parent(def
, |this
| {
152 visit
::walk_foreign_item(this
, foreign_item
);
156 fn visit_variant(&mut self, v
: &'a Variant
) {
157 if v
.is_placeholder
{
158 return self.visit_macro_invoc(v
.id
);
160 let def
= self.create_def(v
.id
, DefPathData
::TypeNs(v
.ident
.name
), v
.span
);
161 self.with_parent(def
, |this
| {
162 if let Some(ctor_hir_id
) = v
.data
.ctor_id() {
163 this
.create_def(ctor_hir_id
, DefPathData
::Ctor
, v
.span
);
165 visit
::walk_variant(this
, v
)
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.
173 for (index
, field
) in data
.fields().iter().enumerate() {
174 self.collect_field(field
, Some(index
));
178 fn visit_generic_param(&mut self, param
: &'a GenericParam
) {
179 if param
.is_placeholder
{
180 self.visit_macro_invoc(param
.id
);
183 let name
= param
.ident
.name
;
184 let def_path_data
= match param
.kind
{
185 GenericParamKind
::Lifetime { .. }
=> DefPathData
::LifetimeNs(name
),
186 GenericParamKind
::Type { .. }
=> DefPathData
::TypeNs(name
),
187 GenericParamKind
::Const { .. }
=> DefPathData
::ValueNs(name
),
189 self.create_def(param
.id
, def_path_data
, param
.ident
.span
);
191 visit
::walk_generic_param(self, param
);
194 fn visit_assoc_item(&mut self, i
: &'a AssocItem
, ctxt
: visit
::AssocCtxt
) {
195 let def_data
= match &i
.kind
{
196 AssocItemKind
::Fn(..) | AssocItemKind
::Const(..) => DefPathData
::ValueNs(i
.ident
.name
),
197 AssocItemKind
::TyAlias(..) => DefPathData
::TypeNs(i
.ident
.name
),
198 AssocItemKind
::MacCall(..) => return self.visit_macro_invoc(i
.id
),
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
));
205 fn visit_pat(&mut self, pat
: &'a Pat
) {
207 PatKind
::MacCall(..) => self.visit_macro_invoc(pat
.id
),
208 _
=> visit
::walk_pat(self, pat
),
212 fn visit_anon_const(&mut self, constant
: &'a AnonConst
) {
213 let def
= self.create_def(constant
.id
, DefPathData
::AnonConst
, constant
.value
.span
);
214 self.with_parent(def
, |this
| visit
::walk_anon_const(this
, constant
));
217 fn visit_expr(&mut self, expr
: &'a Expr
) {
218 let parent_def
= match expr
.kind
{
219 ExprKind
::MacCall(..) => return self.visit_macro_invoc(expr
.id
),
220 ExprKind
::Closure(_
, asyncness
, ..) => {
221 // Async closures desugar to closures inside of closures, so
222 // we must create two defs.
223 let closure_def
= self.create_def(expr
.id
, DefPathData
::ClosureExpr
, expr
.span
);
225 Async
::Yes { closure_id, .. }
=> {
226 self.create_def(closure_id
, DefPathData
::ClosureExpr
, expr
.span
)
228 Async
::No
=> closure_def
,
231 ExprKind
::Async(_
, async_id
, _
) => {
232 self.create_def(async_id
, DefPathData
::ClosureExpr
, expr
.span
)
234 _
=> self.parent_def
,
237 self.with_parent(parent_def
, |this
| visit
::walk_expr(this
, expr
));
240 fn visit_ty(&mut self, ty
: &'a Ty
) {
242 TyKind
::MacCall(..) => return self.visit_macro_invoc(ty
.id
),
243 TyKind
::ImplTrait(node_id
, _
) => {
244 self.create_def(node_id
, DefPathData
::ImplTrait
, ty
.span
);
248 visit
::walk_ty(self, ty
);
251 fn visit_stmt(&mut self, stmt
: &'a Stmt
) {
253 StmtKind
::MacCall(..) => self.visit_macro_invoc(stmt
.id
),
254 _
=> visit
::walk_stmt(self, stmt
),
258 fn visit_token(&mut self, t
: Token
) {
259 if let token
::Interpolated(nt
) = t
.kind
{
260 if let token
::NtExpr(ref expr
) = *nt
{
261 if let ExprKind
::MacCall(..) = expr
.kind
{
262 self.visit_macro_invoc(expr
.id
);
268 fn visit_arm(&mut self, arm
: &'a Arm
) {
269 if arm
.is_placeholder { self.visit_macro_invoc(arm.id) }
else { visit::walk_arm(self, arm) }
272 fn visit_field(&mut self, f
: &'a Field
) {
273 if f
.is_placeholder { self.visit_macro_invoc(f.id) }
else { visit::walk_field(self, f) }
276 fn visit_field_pattern(&mut self, fp
: &'a FieldPat
) {
277 if fp
.is_placeholder
{
278 self.visit_macro_invoc(fp
.id
)
280 visit
::walk_field_pattern(self, fp
)
284 fn visit_param(&mut self, p
: &'a Param
) {
285 if p
.is_placeholder { self.visit_macro_invoc(p.id) }
else { visit::walk_param(self, p) }
288 // This method is called only when we are visiting an individual field
289 // after expanding an attribute on it.
290 fn visit_struct_field(&mut self, field
: &'a StructField
) {
291 self.collect_field(field
, None
);