1 use rustc_data_structures
::fx
::FxHashMap
;
2 use rustc_data_structures
::sorted_map
::SortedMap
;
4 use rustc_hir
::def_id
::LocalDefId
;
5 use rustc_hir
::definitions
;
6 use rustc_hir
::intravisit
::{self, Visitor}
;
8 use rustc_index
::vec
::{Idx, IndexVec}
;
9 use rustc_middle
::span_bug
;
10 use rustc_session
::Session
;
11 use rustc_span
::source_map
::SourceMap
;
12 use rustc_span
::{Span, DUMMY_SP}
;
16 /// A visitor that walks over the HIR and collects `Node`s into a HIR map.
17 pub(super) struct NodeCollector
<'a
, 'hir
> {
19 source_map
: &'a SourceMap
,
20 bodies
: &'a SortedMap
<ItemLocalId
, &'hir Body
<'hir
>>,
23 nodes
: IndexVec
<ItemLocalId
, Option
<ParentedNode
<'hir
>>>,
24 parenting
: FxHashMap
<LocalDefId
, ItemLocalId
>,
26 /// The parent of this node
27 parent_node
: hir
::ItemLocalId
,
31 definitions
: &'a definitions
::Definitions
,
34 #[tracing::instrument(level = "debug", skip(sess, definitions, bodies))]
35 pub(super) fn index_hir
<'hir
>(
37 definitions
: &definitions
::Definitions
,
38 item
: hir
::OwnerNode
<'hir
>,
39 bodies
: &SortedMap
<ItemLocalId
, &'hir Body
<'hir
>>,
40 ) -> (IndexVec
<ItemLocalId
, Option
<ParentedNode
<'hir
>>>, FxHashMap
<LocalDefId
, ItemLocalId
>) {
41 let mut nodes
= IndexVec
::new();
42 // This node's parent should never be accessed: the owner's parent is computed by the
43 // hir_owner_parent query. Make it invalid (= ItemLocalId::MAX) to force an ICE whenever it is
45 nodes
.push(Some(ParentedNode { parent: ItemLocalId::INVALID, node: item.into() }
));
46 let mut collector
= NodeCollector
{
47 source_map
: sess
.source_map(),
50 parent_node
: ItemLocalId
::new(0),
53 parenting
: FxHashMap
::default(),
57 OwnerNode
::Crate(citem
) => {
58 collector
.visit_mod(&citem
, citem
.spans
.inner_span
, hir
::CRATE_HIR_ID
)
60 OwnerNode
::Item(item
) => collector
.visit_item(item
),
61 OwnerNode
::TraitItem(item
) => collector
.visit_trait_item(item
),
62 OwnerNode
::ImplItem(item
) => collector
.visit_impl_item(item
),
63 OwnerNode
::ForeignItem(item
) => collector
.visit_foreign_item(item
),
66 (collector
.nodes
, collector
.parenting
)
69 impl<'a
, 'hir
> NodeCollector
<'a
, 'hir
> {
70 #[tracing::instrument(level = "debug", skip(self))]
71 fn insert(&mut self, span
: Span
, hir_id
: HirId
, node
: Node
<'hir
>) {
72 debug_assert_eq
!(self.owner
, hir_id
.owner
);
73 debug_assert_ne
!(hir_id
.local_id
.as_u32(), 0);
75 // Make sure that the DepNode of some node coincides with the HirId
76 // owner of that node.
77 if cfg
!(debug_assertions
) {
78 if hir_id
.owner
!= self.owner
{
81 "inconsistent DepNode at `{:?}` for `{:?}`: \
82 current_dep_node_owner={} ({:?}), hir_id.owner={} ({:?})",
83 self.source_map
.span_to_diagnostic_string(span
),
85 self.definitions
.def_path(self.owner
).to_string_no_crate_verbose(),
87 self.definitions
.def_path(hir_id
.owner
).to_string_no_crate_verbose(),
93 self.nodes
.insert(hir_id
.local_id
, ParentedNode { parent: self.parent_node, node: node }
);
96 fn with_parent
<F
: FnOnce(&mut Self)>(&mut self, parent_node_id
: HirId
, f
: F
) {
97 debug_assert_eq
!(parent_node_id
.owner
, self.owner
);
98 let parent_node
= self.parent_node
;
99 self.parent_node
= parent_node_id
.local_id
;
101 self.parent_node
= parent_node
;
104 fn insert_nested(&mut self, item
: LocalDefId
) {
105 self.parenting
.insert(item
, self.parent_node
);
109 impl<'a
, 'hir
> Visitor
<'hir
> for NodeCollector
<'a
, 'hir
> {
110 /// Because we want to track parent items and so forth, enable
111 /// deep walking so that we walk nested items in the context of
112 /// their outer items.
114 fn visit_nested_item(&mut self, item
: ItemId
) {
115 debug
!("visit_nested_item: {:?}", item
);
116 self.insert_nested(item
.def_id
);
119 fn visit_nested_trait_item(&mut self, item_id
: TraitItemId
) {
120 self.insert_nested(item_id
.def_id
);
123 fn visit_nested_impl_item(&mut self, item_id
: ImplItemId
) {
124 self.insert_nested(item_id
.def_id
);
127 fn visit_nested_foreign_item(&mut self, foreign_id
: ForeignItemId
) {
128 self.insert_nested(foreign_id
.def_id
);
131 fn visit_nested_body(&mut self, id
: BodyId
) {
132 debug_assert_eq
!(id
.hir_id
.owner
, self.owner
);
133 let body
= self.bodies
[&id
.hir_id
.local_id
];
134 self.visit_body(body
);
137 fn visit_param(&mut self, param
: &'hir Param
<'hir
>) {
138 let node
= Node
::Param(param
);
139 self.insert(param
.pat
.span
, param
.hir_id
, node
);
140 self.with_parent(param
.hir_id
, |this
| {
141 intravisit
::walk_param(this
, param
);
145 #[tracing::instrument(level = "debug", skip(self))]
146 fn visit_item(&mut self, i
: &'hir Item
<'hir
>) {
147 debug_assert_eq
!(i
.def_id
, self.owner
);
148 self.with_parent(i
.hir_id(), |this
| {
149 if let ItemKind
::Struct(ref struct_def
, _
) = i
.kind
{
150 // If this is a tuple or unit-like struct, register the constructor.
151 if let Some(ctor_hir_id
) = struct_def
.ctor_hir_id() {
152 this
.insert(i
.span
, ctor_hir_id
, Node
::Ctor(struct_def
));
155 intravisit
::walk_item(this
, i
);
159 #[tracing::instrument(level = "debug", skip(self))]
160 fn visit_foreign_item(&mut self, fi
: &'hir ForeignItem
<'hir
>) {
161 debug_assert_eq
!(fi
.def_id
, self.owner
);
162 self.with_parent(fi
.hir_id(), |this
| {
163 intravisit
::walk_foreign_item(this
, fi
);
167 fn visit_generic_param(&mut self, param
: &'hir GenericParam
<'hir
>) {
168 self.insert(param
.span
, param
.hir_id
, Node
::GenericParam(param
));
169 intravisit
::walk_generic_param(self, param
);
172 fn visit_const_param_default(&mut self, param
: HirId
, ct
: &'hir AnonConst
) {
173 self.with_parent(param
, |this
| {
174 intravisit
::walk_const_param_default(this
, ct
);
178 #[tracing::instrument(level = "debug", skip(self))]
179 fn visit_trait_item(&mut self, ti
: &'hir TraitItem
<'hir
>) {
180 debug_assert_eq
!(ti
.def_id
, self.owner
);
181 self.with_parent(ti
.hir_id(), |this
| {
182 intravisit
::walk_trait_item(this
, ti
);
186 #[tracing::instrument(level = "debug", skip(self))]
187 fn visit_impl_item(&mut self, ii
: &'hir ImplItem
<'hir
>) {
188 debug_assert_eq
!(ii
.def_id
, self.owner
);
189 self.with_parent(ii
.hir_id(), |this
| {
190 intravisit
::walk_impl_item(this
, ii
);
194 fn visit_pat(&mut self, pat
: &'hir Pat
<'hir
>) {
196 if let PatKind
::Binding(..) = pat
.kind { Node::Binding(pat) }
else { Node::Pat(pat) }
;
197 self.insert(pat
.span
, pat
.hir_id
, node
);
199 self.with_parent(pat
.hir_id
, |this
| {
200 intravisit
::walk_pat(this
, pat
);
204 fn visit_arm(&mut self, arm
: &'hir Arm
<'hir
>) {
205 let node
= Node
::Arm(arm
);
207 self.insert(arm
.span
, arm
.hir_id
, node
);
209 self.with_parent(arm
.hir_id
, |this
| {
210 intravisit
::walk_arm(this
, arm
);
214 fn visit_anon_const(&mut self, constant
: &'hir AnonConst
) {
215 self.insert(DUMMY_SP
, constant
.hir_id
, Node
::AnonConst(constant
));
217 self.with_parent(constant
.hir_id
, |this
| {
218 intravisit
::walk_anon_const(this
, constant
);
222 fn visit_expr(&mut self, expr
: &'hir Expr
<'hir
>) {
223 self.insert(expr
.span
, expr
.hir_id
, Node
::Expr(expr
));
225 self.with_parent(expr
.hir_id
, |this
| {
226 intravisit
::walk_expr(this
, expr
);
230 fn visit_stmt(&mut self, stmt
: &'hir Stmt
<'hir
>) {
231 self.insert(stmt
.span
, stmt
.hir_id
, Node
::Stmt(stmt
));
233 self.with_parent(stmt
.hir_id
, |this
| {
234 intravisit
::walk_stmt(this
, stmt
);
238 fn visit_path_segment(&mut self, path_span
: Span
, path_segment
: &'hir PathSegment
<'hir
>) {
239 if let Some(hir_id
) = path_segment
.hir_id
{
240 self.insert(path_span
, hir_id
, Node
::PathSegment(path_segment
));
242 intravisit
::walk_path_segment(self, path_span
, path_segment
);
245 fn visit_ty(&mut self, ty
: &'hir Ty
<'hir
>) {
246 self.insert(ty
.span
, ty
.hir_id
, Node
::Ty(ty
));
248 self.with_parent(ty
.hir_id
, |this
| {
249 intravisit
::walk_ty(this
, ty
);
253 fn visit_infer(&mut self, inf
: &'hir InferArg
) {
254 self.insert(inf
.span
, inf
.hir_id
, Node
::Infer(inf
));
256 self.with_parent(inf
.hir_id
, |this
| {
257 intravisit
::walk_inf(this
, inf
);
261 fn visit_trait_ref(&mut self, tr
: &'hir TraitRef
<'hir
>) {
262 self.insert(tr
.path
.span
, tr
.hir_ref_id
, Node
::TraitRef(tr
));
264 self.with_parent(tr
.hir_ref_id
, |this
| {
265 intravisit
::walk_trait_ref(this
, tr
);
271 fk
: intravisit
::FnKind
<'hir
>,
272 fd
: &'hir FnDecl
<'hir
>,
277 assert_eq
!(self.owner
, id
.owner
);
278 assert_eq
!(self.parent_node
, id
.local_id
);
279 intravisit
::walk_fn(self, fk
, fd
, b
, s
, id
);
282 fn visit_block(&mut self, block
: &'hir Block
<'hir
>) {
283 self.insert(block
.span
, block
.hir_id
, Node
::Block(block
));
284 self.with_parent(block
.hir_id
, |this
| {
285 intravisit
::walk_block(this
, block
);
289 fn visit_local(&mut self, l
: &'hir Local
<'hir
>) {
290 self.insert(l
.span
, l
.hir_id
, Node
::Local(l
));
291 self.with_parent(l
.hir_id
, |this
| {
292 intravisit
::walk_local(this
, l
);
296 fn visit_lifetime(&mut self, lifetime
: &'hir Lifetime
) {
297 self.insert(lifetime
.span
, lifetime
.hir_id
, Node
::Lifetime(lifetime
));
300 fn visit_variant(&mut self, v
: &'hir Variant
<'hir
>, g
: &'hir Generics
<'hir
>, item_id
: HirId
) {
301 self.insert(v
.span
, v
.id
, Node
::Variant(v
));
302 self.with_parent(v
.id
, |this
| {
303 // Register the constructor of this variant.
304 if let Some(ctor_hir_id
) = v
.data
.ctor_hir_id() {
305 this
.insert(v
.span
, ctor_hir_id
, Node
::Ctor(&v
.data
));
307 intravisit
::walk_variant(this
, v
, g
, item_id
);
311 fn visit_field_def(&mut self, field
: &'hir FieldDef
<'hir
>) {
312 self.insert(field
.span
, field
.hir_id
, Node
::Field(field
));
313 self.with_parent(field
.hir_id
, |this
| {
314 intravisit
::walk_field_def(this
, field
);
318 fn visit_assoc_type_binding(&mut self, type_binding
: &'hir TypeBinding
<'hir
>) {
319 self.insert(type_binding
.span
, type_binding
.hir_id
, Node
::TypeBinding(type_binding
));
320 self.with_parent(type_binding
.hir_id
, |this
| {
321 intravisit
::walk_assoc_type_binding(this
, type_binding
)
325 fn visit_trait_item_ref(&mut self, ii
: &'hir TraitItemRef
) {
326 // Do not visit the duplicate information in TraitItemRef. We want to
327 // map the actual nodes, not the duplicate ones in the *Ref.
328 let TraitItemRef { id, ident: _, kind: _, span: _, defaultness: _ }
= *ii
;
330 self.visit_nested_trait_item(id
);
333 fn visit_impl_item_ref(&mut self, ii
: &'hir ImplItemRef
) {
334 // Do not visit the duplicate information in ImplItemRef. We want to
335 // map the actual nodes, not the duplicate ones in the *Ref.
336 let ImplItemRef { id, ident: _, kind: _, span: _, defaultness: _, trait_item_def_id: _ }
=
339 self.visit_nested_impl_item(id
);
342 fn visit_foreign_item_ref(&mut self, fi
: &'hir ForeignItemRef
) {
343 // Do not visit the duplicate information in ForeignItemRef. We want to
344 // map the actual nodes, not the duplicate ones in the *Ref.
345 let ForeignItemRef { id, ident: _, span: _ }
= *fi
;
347 self.visit_nested_foreign_item(id
);