1 use crate::arena
::Arena
;
2 use crate::hir
::map
::{Entry, HirOwnerData, Map}
;
3 use crate::hir
::{Owner, OwnerNodes, ParentedNode}
;
4 use crate::ich
::StableHashingContext
;
5 use crate::middle
::cstore
::CrateStore
;
6 use rustc_data_structures
::fingerprint
::Fingerprint
;
7 use rustc_data_structures
::fx
::FxHashMap
;
8 use rustc_data_structures
::stable_hasher
::{HashStable, StableHasher}
;
9 use rustc_data_structures
::svh
::Svh
;
11 use rustc_hir
::def_id
::CRATE_DEF_INDEX
;
12 use rustc_hir
::def_id
::{LocalDefId, LOCAL_CRATE}
;
13 use rustc_hir
::definitions
::{self, DefPathHash}
;
14 use rustc_hir
::intravisit
::{self, NestedVisitorMap, Visitor}
;
16 use rustc_index
::vec
::{Idx, IndexVec}
;
17 use rustc_session
::{CrateDisambiguator, Session}
;
18 use rustc_span
::source_map
::SourceMap
;
19 use rustc_span
::{Span, Symbol, DUMMY_SP}
;
21 use std
::iter
::repeat
;
23 /// A visitor that walks over the HIR and collects `Node`s into a HIR map.
24 pub(super) struct NodeCollector
<'a
, 'hir
> {
25 arena
: &'hir Arena
<'hir
>,
28 krate
: &'hir Crate
<'hir
>,
31 source_map
: &'a SourceMap
,
33 map
: IndexVec
<LocalDefId
, HirOwnerData
<'hir
>>,
35 /// The parent of this node
36 parent_node
: hir
::HirId
,
38 current_dep_node_owner
: LocalDefId
,
40 definitions
: &'a definitions
::Definitions
,
42 hcx
: StableHashingContext
<'a
>,
44 // We are collecting HIR hashes here so we can compute the
45 // crate hash from them later on.
46 hir_body_nodes
: Vec
<(DefPathHash
, Fingerprint
)>,
49 fn insert_vec_map
<K
: Idx
, V
: Clone
>(map
: &mut IndexVec
<K
, Option
<V
>>, k
: K
, v
: V
) {
53 map
.extend(repeat(None
).take(i
- len
+ 1));
59 hcx
: &mut StableHashingContext
<'_
>,
60 input
: impl for<'a
> HashStable
<StableHashingContext
<'a
>>,
62 let mut stable_hasher
= StableHasher
::new();
63 input
.hash_stable(hcx
, &mut stable_hasher
);
64 stable_hasher
.finish()
68 hcx
: &mut StableHashingContext
<'_
>,
69 def_path_hash
: DefPathHash
,
70 item_like
: impl for<'a
> HashStable
<StableHashingContext
<'a
>>,
71 hir_body_nodes
: &mut Vec
<(DefPathHash
, Fingerprint
)>,
73 let hash
= hash(hcx
, HirItemLike { item_like: &item_like }
);
74 hir_body_nodes
.push((def_path_hash
, hash
));
78 fn upstream_crates(cstore
: &dyn CrateStore
) -> Vec
<(Symbol
, Fingerprint
, Svh
)> {
79 let mut upstream_crates
: Vec
<_
> = cstore
83 let name
= cstore
.crate_name_untracked(cnum
);
84 let disambiguator
= cstore
.crate_disambiguator_untracked(cnum
).to_fingerprint();
85 let hash
= cstore
.crate_hash_untracked(cnum
);
86 (name
, disambiguator
, hash
)
89 upstream_crates
.sort_unstable_by_key(|&(name
, dis
, _
)| (name
.as_str(), dis
));
93 impl<'a
, 'hir
> NodeCollector
<'a
, 'hir
> {
96 arena
: &'hir Arena
<'hir
>,
97 krate
: &'hir Crate
<'hir
>,
98 definitions
: &'a definitions
::Definitions
,
99 mut hcx
: StableHashingContext
<'a
>,
100 ) -> NodeCollector
<'a
, 'hir
> {
101 let root_mod_def_path_hash
=
102 definitions
.def_path_hash(LocalDefId { local_def_index: CRATE_DEF_INDEX }
);
104 let mut hir_body_nodes
= Vec
::new();
109 // These fields are handled separately:
111 non_exported_macro_attrs
: _
,
123 hash_body(&mut hcx
, root_mod_def_path_hash
, item
, &mut hir_body_nodes
)
126 let mut collector
= NodeCollector
{
129 source_map
: sess
.source_map(),
130 parent_node
: hir
::CRATE_HIR_ID
,
131 current_dep_node_owner
: LocalDefId { local_def_index: CRATE_DEF_INDEX }
,
135 map
: (0..definitions
.def_index_count())
136 .map(|_
| HirOwnerData { signature: None, with_bodies: None }
)
139 collector
.insert_entry(
141 Entry { parent: hir::CRATE_HIR_ID, node: Node::Crate(&krate.item) }
,
148 pub(super) fn finalize_and_compute_crate_hash(
150 crate_disambiguator
: CrateDisambiguator
,
151 cstore
: &dyn CrateStore
,
152 commandline_args_hash
: u64,
153 ) -> (IndexVec
<LocalDefId
, HirOwnerData
<'hir
>>, Svh
) {
154 // Insert bodies into the map
155 for (id
, body
) in self.krate
.bodies
.iter() {
156 let bodies
= &mut self.map
[id
.hir_id
.owner
].with_bodies
.as_mut().unwrap().bodies
;
157 assert
!(bodies
.insert(id
.hir_id
.local_id
, body
).is_none());
160 self.hir_body_nodes
.sort_unstable_by_key(|bn
| bn
.0);
162 let node_hashes
= self.hir_body_nodes
.iter().fold(
164 |combined_fingerprint
, &(def_path_hash
, fingerprint
)| {
165 combined_fingerprint
.combine(def_path_hash
.0.combine(fingerprint
))
169 let upstream_crates
= upstream_crates(cstore
);
171 // We hash the final, remapped names of all local source files so we
172 // don't have to include the path prefix remapping commandline args.
173 // If we included the full mapping in the SVH, we could only have
174 // reproducible builds by compiling from the same directory. So we just
175 // hash the result of the mapping instead of the mapping itself.
176 let mut source_file_names
: Vec
<_
> = self
180 .filter(|source_file
| source_file
.cnum
== LOCAL_CRATE
)
181 .map(|source_file
| source_file
.name_hash
)
184 source_file_names
.sort_unstable();
186 let crate_hash_input
= (
187 ((node_hashes
, upstream_crates
), source_file_names
),
188 (commandline_args_hash
, crate_disambiguator
.to_fingerprint()),
191 let mut stable_hasher
= StableHasher
::new();
192 crate_hash_input
.hash_stable(&mut self.hcx
, &mut stable_hasher
);
193 let crate_hash
: Fingerprint
= stable_hasher
.finish();
195 let svh
= Svh
::new(crate_hash
.to_smaller_hash());
199 fn insert_entry(&mut self, id
: HirId
, entry
: Entry
<'hir
>, hash
: Fingerprint
) {
200 let i
= id
.local_id
.as_u32() as usize;
202 let arena
= self.arena
;
204 let data
= &mut self.map
[id
.owner
];
206 if data
.with_bodies
.is_none() {
207 data
.with_bodies
= Some(arena
.alloc(OwnerNodes
{
209 nodes
: IndexVec
::new(),
210 bodies
: FxHashMap
::default(),
214 let nodes
= data
.with_bodies
.as_mut().unwrap();
217 // Overwrite the dummy hash with the real HIR owner hash.
220 // FIXME: feature(impl_trait_in_bindings) broken and trigger this assert
221 //assert!(data.signature.is_none());
224 Some(self.arena
.alloc(Owner { parent: entry.parent, node: entry.node }
));
226 assert_eq
!(entry
.parent
.owner
, id
.owner
);
230 ParentedNode { parent: entry.parent.local_id, node: entry.node }
,
235 fn insert(&mut self, span
: Span
, hir_id
: HirId
, node
: Node
<'hir
>) {
236 self.insert_with_hash(span
, hir_id
, node
, Fingerprint
::ZERO
)
239 fn insert_with_hash(&mut self, span
: Span
, hir_id
: HirId
, node
: Node
<'hir
>, hash
: Fingerprint
) {
240 let entry
= Entry { parent: self.parent_node, node }
;
242 // Make sure that the DepNode of some node coincides with the HirId
243 // owner of that node.
244 if cfg
!(debug_assertions
) {
245 if hir_id
.owner
!= self.current_dep_node_owner
{
246 let node_str
= match self.definitions
.opt_hir_id_to_local_def_id(hir_id
) {
247 Some(def_id
) => self.definitions
.def_path(def_id
).to_string_no_crate_verbose(),
248 None
=> format
!("{:?}", node
),
253 "inconsistent DepNode at `{:?}` for `{}`: \
254 current_dep_node_owner={} ({:?}), hir_id.owner={} ({:?})",
255 self.source_map
.span_to_string(span
),
258 .def_path(self.current_dep_node_owner
)
259 .to_string_no_crate_verbose(),
260 self.current_dep_node_owner
,
261 self.definitions
.def_path(hir_id
.owner
).to_string_no_crate_verbose(),
267 self.insert_entry(hir_id
, entry
, hash
);
270 fn with_parent
<F
: FnOnce(&mut Self)>(&mut self, parent_node_id
: HirId
, f
: F
) {
271 let parent_node
= self.parent_node
;
272 self.parent_node
= parent_node_id
;
274 self.parent_node
= parent_node
;
277 fn with_dep_node_owner
<
278 T
: for<'b
> HashStable
<StableHashingContext
<'b
>>,
279 F
: FnOnce(&mut Self, Fingerprint
),
282 dep_node_owner
: LocalDefId
,
286 let prev_owner
= self.current_dep_node_owner
;
288 let def_path_hash
= self.definitions
.def_path_hash(dep_node_owner
);
290 let hash
= hash_body(&mut self.hcx
, def_path_hash
, item_like
, &mut self.hir_body_nodes
);
292 self.current_dep_node_owner
= dep_node_owner
;
294 self.current_dep_node_owner
= prev_owner
;
298 impl<'a
, 'hir
> Visitor
<'hir
> for NodeCollector
<'a
, 'hir
> {
299 type Map
= Map
<'hir
>;
301 /// Because we want to track parent items and so forth, enable
302 /// deep walking so that we walk nested items in the context of
303 /// their outer items.
305 fn nested_visit_map(&mut self) -> NestedVisitorMap
<Self::Map
> {
306 panic
!("`visit_nested_xxx` must be manually implemented in this visitor");
309 fn visit_nested_item(&mut self, item
: ItemId
) {
310 debug
!("visit_nested_item: {:?}", item
);
311 self.visit_item(self.krate
.item(item
.id
));
314 fn visit_nested_trait_item(&mut self, item_id
: TraitItemId
) {
315 self.visit_trait_item(self.krate
.trait_item(item_id
));
318 fn visit_nested_impl_item(&mut self, item_id
: ImplItemId
) {
319 self.visit_impl_item(self.krate
.impl_item(item_id
));
322 fn visit_nested_body(&mut self, id
: BodyId
) {
323 self.visit_body(self.krate
.body(id
));
326 fn visit_param(&mut self, param
: &'hir Param
<'hir
>) {
327 let node
= Node
::Param(param
);
328 self.insert(param
.pat
.span
, param
.hir_id
, node
);
329 self.with_parent(param
.hir_id
, |this
| {
330 intravisit
::walk_param(this
, param
);
334 fn visit_item(&mut self, i
: &'hir Item
<'hir
>) {
335 debug
!("visit_item: {:?}", i
);
338 self.definitions
.opt_hir_id_to_local_def_id(i
.hir_id
).unwrap()
340 self.with_dep_node_owner(i
.hir_id
.owner
, i
, |this
, hash
| {
341 this
.insert_with_hash(i
.span
, i
.hir_id
, Node
::Item(i
), hash
);
342 this
.with_parent(i
.hir_id
, |this
| {
343 if let ItemKind
::Struct(ref struct_def
, _
) = i
.kind
{
344 // If this is a tuple or unit-like struct, register the constructor.
345 if let Some(ctor_hir_id
) = struct_def
.ctor_hir_id() {
346 this
.insert(i
.span
, ctor_hir_id
, Node
::Ctor(struct_def
));
349 intravisit
::walk_item(this
, i
);
354 fn visit_foreign_item(&mut self, foreign_item
: &'hir ForeignItem
<'hir
>) {
355 self.insert(foreign_item
.span
, foreign_item
.hir_id
, Node
::ForeignItem(foreign_item
));
357 self.with_parent(foreign_item
.hir_id
, |this
| {
358 intravisit
::walk_foreign_item(this
, foreign_item
);
362 fn visit_generic_param(&mut self, param
: &'hir GenericParam
<'hir
>) {
363 self.insert(param
.span
, param
.hir_id
, Node
::GenericParam(param
));
364 intravisit
::walk_generic_param(self, param
);
367 fn visit_trait_item(&mut self, ti
: &'hir TraitItem
<'hir
>) {
370 self.definitions
.opt_hir_id_to_local_def_id(ti
.hir_id
).unwrap()
372 self.with_dep_node_owner(ti
.hir_id
.owner
, ti
, |this
, hash
| {
373 this
.insert_with_hash(ti
.span
, ti
.hir_id
, Node
::TraitItem(ti
), hash
);
375 this
.with_parent(ti
.hir_id
, |this
| {
376 intravisit
::walk_trait_item(this
, ti
);
381 fn visit_impl_item(&mut self, ii
: &'hir ImplItem
<'hir
>) {
384 self.definitions
.opt_hir_id_to_local_def_id(ii
.hir_id
).unwrap()
386 self.with_dep_node_owner(ii
.hir_id
.owner
, ii
, |this
, hash
| {
387 this
.insert_with_hash(ii
.span
, ii
.hir_id
, Node
::ImplItem(ii
), hash
);
389 this
.with_parent(ii
.hir_id
, |this
| {
390 intravisit
::walk_impl_item(this
, ii
);
395 fn visit_pat(&mut self, pat
: &'hir Pat
<'hir
>) {
397 if let PatKind
::Binding(..) = pat
.kind { Node::Binding(pat) }
else { Node::Pat(pat) }
;
398 self.insert(pat
.span
, pat
.hir_id
, node
);
400 self.with_parent(pat
.hir_id
, |this
| {
401 intravisit
::walk_pat(this
, pat
);
405 fn visit_arm(&mut self, arm
: &'hir Arm
<'hir
>) {
406 let node
= Node
::Arm(arm
);
408 self.insert(arm
.span
, arm
.hir_id
, node
);
410 self.with_parent(arm
.hir_id
, |this
| {
411 intravisit
::walk_arm(this
, arm
);
415 fn visit_anon_const(&mut self, constant
: &'hir AnonConst
) {
416 self.insert(DUMMY_SP
, constant
.hir_id
, Node
::AnonConst(constant
));
418 self.with_parent(constant
.hir_id
, |this
| {
419 intravisit
::walk_anon_const(this
, constant
);
423 fn visit_expr(&mut self, expr
: &'hir Expr
<'hir
>) {
424 self.insert(expr
.span
, expr
.hir_id
, Node
::Expr(expr
));
426 self.with_parent(expr
.hir_id
, |this
| {
427 intravisit
::walk_expr(this
, expr
);
431 fn visit_stmt(&mut self, stmt
: &'hir Stmt
<'hir
>) {
432 self.insert(stmt
.span
, stmt
.hir_id
, Node
::Stmt(stmt
));
434 self.with_parent(stmt
.hir_id
, |this
| {
435 intravisit
::walk_stmt(this
, stmt
);
439 fn visit_path_segment(&mut self, path_span
: Span
, path_segment
: &'hir PathSegment
<'hir
>) {
440 if let Some(hir_id
) = path_segment
.hir_id
{
441 self.insert(path_span
, hir_id
, Node
::PathSegment(path_segment
));
443 intravisit
::walk_path_segment(self, path_span
, path_segment
);
446 fn visit_ty(&mut self, ty
: &'hir Ty
<'hir
>) {
447 self.insert(ty
.span
, ty
.hir_id
, Node
::Ty(ty
));
449 self.with_parent(ty
.hir_id
, |this
| {
450 intravisit
::walk_ty(this
, ty
);
454 fn visit_trait_ref(&mut self, tr
: &'hir TraitRef
<'hir
>) {
455 self.insert(tr
.path
.span
, tr
.hir_ref_id
, Node
::TraitRef(tr
));
457 self.with_parent(tr
.hir_ref_id
, |this
| {
458 intravisit
::walk_trait_ref(this
, tr
);
464 fk
: intravisit
::FnKind
<'hir
>,
465 fd
: &'hir FnDecl
<'hir
>,
470 assert_eq
!(self.parent_node
, id
);
471 intravisit
::walk_fn(self, fk
, fd
, b
, s
, id
);
474 fn visit_block(&mut self, block
: &'hir Block
<'hir
>) {
475 self.insert(block
.span
, block
.hir_id
, Node
::Block(block
));
476 self.with_parent(block
.hir_id
, |this
| {
477 intravisit
::walk_block(this
, block
);
481 fn visit_local(&mut self, l
: &'hir Local
<'hir
>) {
482 self.insert(l
.span
, l
.hir_id
, Node
::Local(l
));
483 self.with_parent(l
.hir_id
, |this
| intravisit
::walk_local(this
, l
))
486 fn visit_lifetime(&mut self, lifetime
: &'hir Lifetime
) {
487 self.insert(lifetime
.span
, lifetime
.hir_id
, Node
::Lifetime(lifetime
));
490 fn visit_vis(&mut self, visibility
: &'hir Visibility
<'hir
>) {
491 match visibility
.node
{
492 VisibilityKind
::Public
| VisibilityKind
::Crate(_
) | VisibilityKind
::Inherited
=> {}
493 VisibilityKind
::Restricted { hir_id, .. }
=> {
494 self.insert(visibility
.span
, hir_id
, Node
::Visibility(visibility
));
495 self.with_parent(hir_id
, |this
| {
496 intravisit
::walk_vis(this
, visibility
);
502 fn visit_macro_def(&mut self, macro_def
: &'hir MacroDef
<'hir
>) {
503 self.with_dep_node_owner(macro_def
.hir_id
.owner
, macro_def
, |this
, hash
| {
504 this
.insert_with_hash(
507 Node
::MacroDef(macro_def
),
513 fn visit_variant(&mut self, v
: &'hir Variant
<'hir
>, g
: &'hir Generics
<'hir
>, item_id
: HirId
) {
514 self.insert(v
.span
, v
.id
, Node
::Variant(v
));
515 self.with_parent(v
.id
, |this
| {
516 // Register the constructor of this variant.
517 if let Some(ctor_hir_id
) = v
.data
.ctor_hir_id() {
518 this
.insert(v
.span
, ctor_hir_id
, Node
::Ctor(&v
.data
));
520 intravisit
::walk_variant(this
, v
, g
, item_id
);
524 fn visit_struct_field(&mut self, field
: &'hir StructField
<'hir
>) {
525 self.insert(field
.span
, field
.hir_id
, Node
::Field(field
));
526 self.with_parent(field
.hir_id
, |this
| {
527 intravisit
::walk_struct_field(this
, field
);
531 fn visit_trait_item_ref(&mut self, ii
: &'hir TraitItemRef
) {
532 // Do not visit the duplicate information in TraitItemRef. We want to
533 // map the actual nodes, not the duplicate ones in the *Ref.
534 let TraitItemRef { id, ident: _, kind: _, span: _, defaultness: _ }
= *ii
;
536 self.visit_nested_trait_item(id
);
539 fn visit_impl_item_ref(&mut self, ii
: &'hir ImplItemRef
<'hir
>) {
540 // Do not visit the duplicate information in ImplItemRef. We want to
541 // map the actual nodes, not the duplicate ones in the *Ref.
542 let ImplItemRef { id, ident: _, kind: _, span: _, vis: _, defaultness: _ }
= *ii
;
544 self.visit_nested_impl_item(id
);
548 struct HirItemLike
<T
> {
552 impl<'hir
, T
> HashStable
<StableHashingContext
<'hir
>> for HirItemLike
<T
>
554 T
: HashStable
<StableHashingContext
<'hir
>>,
556 fn hash_stable(&self, hcx
: &mut StableHashingContext
<'hir
>, hasher
: &mut StableHasher
) {
557 hcx
.while_hashing_hir_bodies(true, |hcx
| {
558 self.item_like
.hash_stable(hcx
, hasher
);