2 use rustc_ast
::visit
::{self, FnKind}
;
3 use rustc_ast
::walk_list
;
5 use rustc_ast_lowering
::ResolverAstLowering
;
6 use rustc_expand
::expand
::AstFragment
;
7 use rustc_hir
::def_id
::LocalDefId
;
8 use rustc_hir
::definitions
::*;
9 use rustc_span
::hygiene
::ExpnId
;
10 use rustc_span
::symbol
::{kw, sym}
;
14 crate fn collect_definitions(
15 resolver
: &mut Resolver
<'_
>,
16 fragment
: &AstFragment
,
19 let parent_def
= resolver
.invocation_parents
[&expansion
];
20 fragment
.visit_with(&mut DefCollector { resolver, parent_def, expansion }
);
23 /// Creates `DefId`s for nodes in the AST.
24 struct DefCollector
<'a
, 'b
> {
25 resolver
: &'a
mut Resolver
<'b
>,
26 parent_def
: LocalDefId
,
30 impl<'a
, 'b
> DefCollector
<'a
, 'b
> {
31 fn create_def(&mut self, node_id
: NodeId
, data
: DefPathData
, span
: Span
) -> LocalDefId
{
32 let parent_def
= self.parent_def
;
33 debug
!("create_def(node_id={:?}, data={:?}, parent_def={:?})", node_id
, data
, parent_def
);
34 self.resolver
.create_def(parent_def
, node_id
, data
, self.expansion
, span
)
37 fn with_parent
<F
: FnOnce(&mut Self)>(&mut self, parent_def
: LocalDefId
, f
: F
) {
38 let orig_parent_def
= std
::mem
::replace(&mut self.parent_def
, parent_def
);
40 self.parent_def
= orig_parent_def
;
43 fn collect_field(&mut self, field
: &'a StructField
, index
: Option
<usize>) {
44 let index
= |this
: &Self| {
45 index
.unwrap_or_else(|| {
46 let node_id
= NodeId
::placeholder_from_expn_id(this
.expansion
);
47 this
.resolver
.placeholder_field_indices
[&node_id
]
51 if field
.is_placeholder
{
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");
54 self.visit_macro_invoc(field
.id
);
56 let name
= field
.ident
.map_or_else(|| sym
::integer(index(self)), |ident
| ident
.name
);
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
));
62 fn visit_macro_invoc(&mut self, id
: NodeId
) {
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");
69 impl<'a
, 'b
> visit
::Visitor
<'a
> for DefCollector
<'a
, 'b
> {
70 fn visit_item(&mut self, i
: &'a Item
) {
71 debug
!("visit_item: {:?}", i
);
73 // Pick the def data. This need not be unique, but the more
74 // information we encapsulate into, the better
75 let def_data
= match &i
.kind
{
76 ItemKind
::Impl { .. }
=> DefPathData
::Impl
,
77 ItemKind
::Mod(..) if i
.ident
.name
== kw
::Empty
=> {
78 // Fake crate root item from expand.
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(..) => {
95 visit
::walk_item(self, i
);
96 return self.visit_macro_invoc(i
.id
);
98 ItemKind
::GlobalAsm(..) => DefPathData
::Misc
,
99 ItemKind
::Use(..) => {
100 return visit
::walk_item(self, i
);
103 let def
= self.create_def(i
.id
, def_data
, i
.span
);
105 self.with_parent(def
, |this
| {
107 ItemKind
::Struct(ref struct_def
, _
) | ItemKind
::Union(ref struct_def
, _
) => {
108 // If this is a unit or tuple-like struct, register the constructor.
109 if let Some(ctor_hir_id
) = struct_def
.ctor_id() {
110 this
.create_def(ctor_hir_id
, DefPathData
::Ctor
, i
.span
);
115 visit
::walk_item(this
, i
);
119 fn visit_fn(&mut self, fn_kind
: FnKind
<'a
>, span
: Span
, _
: NodeId
) {
120 if let FnKind
::Fn(_
, _
, sig
, _
, body
) = fn_kind
{
121 if let Async
::Yes { closure_id, return_impl_trait_id, .. }
= sig
.header
.asyncness
{
122 self.create_def(return_impl_trait_id
, DefPathData
::ImplTrait
, span
);
124 // For async functions, we need to create their inner defs inside of a
125 // closure to match their desugared representation. Besides that,
126 // we must mirror everything that `visit::walk_fn` below does.
127 self.visit_fn_header(&sig
.header
);
128 visit
::walk_fn_decl(self, &sig
.decl
);
129 let closure_def
= self.create_def(closure_id
, DefPathData
::ClosureExpr
, span
);
130 self.with_parent(closure_def
, |this
| walk_list
!(this
, visit_block
, body
));
135 visit
::walk_fn(self, fn_kind
, span
);
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
);
143 fn visit_foreign_item(&mut self, foreign_item
: &'a ForeignItem
) {
144 if let ForeignItemKind
::MacCall(_
) = foreign_item
.kind
{
145 return self.visit_macro_invoc(foreign_item
.id
);
148 let def
= self.create_def(
150 DefPathData
::ValueNs(foreign_item
.ident
.name
),
154 self.with_parent(def
, |this
| {
155 visit
::walk_foreign_item(this
, foreign_item
);
159 fn visit_variant(&mut self, v
: &'a Variant
) {
160 if v
.is_placeholder
{
161 return self.visit_macro_invoc(v
.id
);
163 let def
= self.create_def(v
.id
, DefPathData
::TypeNs(v
.ident
.name
), v
.span
);
164 self.with_parent(def
, |this
| {
165 if let Some(ctor_hir_id
) = v
.data
.ctor_id() {
166 this
.create_def(ctor_hir_id
, DefPathData
::Ctor
, v
.span
);
168 visit
::walk_variant(this
, v
)
172 fn visit_variant_data(&mut self, data
: &'a VariantData
) {
173 // The assumption here is that non-`cfg` macro expansion cannot change field indices.
174 // It currently holds because only inert attributes are accepted on fields,
175 // and every such attribute expands into a single field after it's resolved.
176 for (index
, field
) in data
.fields().iter().enumerate() {
177 self.collect_field(field
, Some(index
));
181 fn visit_generic_param(&mut self, param
: &'a GenericParam
) {
182 if param
.is_placeholder
{
183 self.visit_macro_invoc(param
.id
);
186 let name
= param
.ident
.name
;
187 let def_path_data
= match param
.kind
{
188 GenericParamKind
::Lifetime { .. }
=> DefPathData
::LifetimeNs(name
),
189 GenericParamKind
::Type { .. }
=> DefPathData
::TypeNs(name
),
190 GenericParamKind
::Const { .. }
=> DefPathData
::ValueNs(name
),
192 self.create_def(param
.id
, def_path_data
, param
.ident
.span
);
194 visit
::walk_generic_param(self, param
);
197 fn visit_assoc_item(&mut self, i
: &'a AssocItem
, ctxt
: visit
::AssocCtxt
) {
198 let def_data
= match &i
.kind
{
199 AssocItemKind
::Fn(..) | AssocItemKind
::Const(..) => DefPathData
::ValueNs(i
.ident
.name
),
200 AssocItemKind
::TyAlias(..) => DefPathData
::TypeNs(i
.ident
.name
),
201 AssocItemKind
::MacCall(..) => return self.visit_macro_invoc(i
.id
),
204 let def
= self.create_def(i
.id
, def_data
, i
.span
);
205 self.with_parent(def
, |this
| visit
::walk_assoc_item(this
, i
, ctxt
));
208 fn visit_pat(&mut self, pat
: &'a Pat
) {
210 PatKind
::MacCall(..) => self.visit_macro_invoc(pat
.id
),
211 _
=> visit
::walk_pat(self, pat
),
215 fn visit_anon_const(&mut self, constant
: &'a AnonConst
) {
216 let def
= self.create_def(constant
.id
, DefPathData
::AnonConst
, constant
.value
.span
);
217 self.with_parent(def
, |this
| visit
::walk_anon_const(this
, constant
));
220 fn visit_expr(&mut self, expr
: &'a Expr
) {
221 let parent_def
= match expr
.kind
{
222 ExprKind
::MacCall(..) => return self.visit_macro_invoc(expr
.id
),
223 ExprKind
::Closure(_
, asyncness
, ..) => {
224 // Async closures desugar to closures inside of closures, so
225 // we must create two defs.
226 let closure_def
= self.create_def(expr
.id
, DefPathData
::ClosureExpr
, expr
.span
);
228 Async
::Yes { closure_id, .. }
=> {
229 self.create_def(closure_id
, DefPathData
::ClosureExpr
, expr
.span
)
231 Async
::No
=> closure_def
,
234 ExprKind
::Async(_
, async_id
, _
) => {
235 self.create_def(async_id
, DefPathData
::ClosureExpr
, expr
.span
)
237 _
=> self.parent_def
,
240 self.with_parent(parent_def
, |this
| visit
::walk_expr(this
, expr
));
243 fn visit_ty(&mut self, ty
: &'a Ty
) {
245 TyKind
::MacCall(..) => self.visit_macro_invoc(ty
.id
),
246 TyKind
::ImplTrait(node_id
, _
) => {
247 let parent_def
= self.create_def(node_id
, DefPathData
::ImplTrait
, ty
.span
);
248 self.with_parent(parent_def
, |this
| visit
::walk_ty(this
, ty
));
250 _
=> visit
::walk_ty(self, ty
),
254 fn visit_stmt(&mut self, stmt
: &'a Stmt
) {
256 StmtKind
::MacCall(..) => self.visit_macro_invoc(stmt
.id
),
257 _
=> visit
::walk_stmt(self, stmt
),
261 fn visit_arm(&mut self, arm
: &'a Arm
) {
262 if arm
.is_placeholder { self.visit_macro_invoc(arm.id) }
else { visit::walk_arm(self, arm) }
265 fn visit_field(&mut self, f
: &'a Field
) {
266 if f
.is_placeholder { self.visit_macro_invoc(f.id) }
else { visit::walk_field(self, f) }
269 fn visit_field_pattern(&mut self, fp
: &'a FieldPat
) {
270 if fp
.is_placeholder
{
271 self.visit_macro_invoc(fp
.id
)
273 visit
::walk_field_pattern(self, fp
)
277 fn visit_param(&mut self, p
: &'a Param
) {
278 if p
.is_placeholder { self.visit_macro_invoc(p.id) }
else { visit::walk_param(self, p) }
281 // This method is called only when we are visiting an individual field
282 // after expanding an attribute on it.
283 fn visit_struct_field(&mut self, field
: &'a StructField
) {
284 self.collect_field(field
, None
);