2 use crate::dep_graph
::{DepGraph, DepKind, DepNodeIndex}
;
4 use crate::hir
::def_id
::{LOCAL_CRATE, CrateNum}
;
5 use crate::hir
::intravisit
::{Visitor, NestedVisitorMap}
;
6 use rustc_data_structures
::svh
::Svh
;
7 use crate::ich
::Fingerprint
;
8 use crate::middle
::cstore
::CrateStore
;
9 use crate::session
::CrateDisambiguator
;
10 use crate::session
::Session
;
11 use std
::iter
::repeat
;
12 use syntax
::ast
::{NodeId, CRATE_NODE_ID}
;
13 use syntax
::source_map
::SourceMap
;
16 use crate::ich
::StableHashingContext
;
17 use rustc_data_structures
::stable_hasher
::{HashStable, StableHasher, StableHasherResult}
;
19 /// A Visitor that walks over the HIR and collects Nodes into a HIR map
20 pub(super) struct NodeCollector
<'a
, 'hir
> {
25 source_map
: &'a SourceMap
,
28 map
: Vec
<Option
<Entry
<'hir
>>>,
29 /// The parent of this node
30 parent_node
: hir
::HirId
,
32 // These fields keep track of the currently relevant DepNodes during
33 // the visitor's traversal.
34 current_dep_node_owner
: DefIndex
,
35 current_signature_dep_index
: DepNodeIndex
,
36 current_full_dep_index
: DepNodeIndex
,
37 currently_in_body
: bool
,
39 dep_graph
: &'a DepGraph
,
40 definitions
: &'a definitions
::Definitions
,
41 hir_to_node_id
: &'a FxHashMap
<HirId
, NodeId
>,
43 hcx
: StableHashingContext
<'a
>,
45 // We are collecting DepNode::HirBody hashes here so we can compute the
46 // crate hash from then later on.
47 hir_body_nodes
: Vec
<(DefPathHash
, Fingerprint
)>,
50 fn input_dep_node_and_hash
<I
>(
52 hcx
: &mut StableHashingContext
<'_
>,
55 ) -> (DepNodeIndex
, Fingerprint
)
57 I
: for<'a
> HashStable
<StableHashingContext
<'a
>>,
59 let dep_node_index
= dep_graph
.input_task(dep_node
, &mut *hcx
, &input
).1;
61 let hash
= if dep_graph
.is_fully_enabled() {
62 dep_graph
.fingerprint_of(dep_node_index
)
64 let mut stable_hasher
= StableHasher
::new();
65 input
.hash_stable(hcx
, &mut stable_hasher
);
66 stable_hasher
.finish()
69 (dep_node_index
, hash
)
72 fn alloc_hir_dep_nodes
<I
>(
74 hcx
: &mut StableHashingContext
<'_
>,
75 def_path_hash
: DefPathHash
,
77 hir_body_nodes
: &mut Vec
<(DefPathHash
, Fingerprint
)>,
78 ) -> (DepNodeIndex
, DepNodeIndex
)
80 I
: for<'a
> HashStable
<StableHashingContext
<'a
>>,
82 let sig
= dep_graph
.input_task(
83 def_path_hash
.to_dep_node(DepKind
::Hir
),
85 HirItemLike { item_like: &item_like, hash_bodies: false }
,
87 let (full
, hash
) = input_dep_node_and_hash(
90 def_path_hash
.to_dep_node(DepKind
::HirBody
),
91 HirItemLike { item_like: &item_like, hash_bodies: true }
,
93 hir_body_nodes
.push((def_path_hash
, hash
));
97 impl<'a
, 'hir
> NodeCollector
<'a
, 'hir
> {
98 pub(super) fn root(sess
: &'a Session
,
100 dep_graph
: &'a DepGraph
,
101 definitions
: &'a definitions
::Definitions
,
102 hir_to_node_id
: &'a FxHashMap
<HirId
, NodeId
>,
103 mut hcx
: StableHashingContext
<'a
>)
104 -> NodeCollector
<'a
, 'hir
> {
105 let root_mod_def_path_hash
= definitions
.def_path_hash(CRATE_DEF_INDEX
);
107 let mut hir_body_nodes
= Vec
::new();
109 // Allocate DepNodes for the root module
110 let (root_mod_sig_dep_index
, root_mod_full_dep_index
) = {
113 // Crate attributes are not copied over to the root `Mod`, so hash
114 // them explicitly here.
117 // These fields are handled separately:
132 root_mod_def_path_hash
,
133 (module
, attrs
, span
),
139 dep_graph
.input_task(
140 DepNode
::new_no_params(DepKind
::AllLocalTraitImpls
),
146 let mut collector
= NodeCollector
{
148 source_map
: sess
.source_map(),
149 map
: repeat(None
).take(sess
.current_node_id_count()).collect(),
150 parent_node
: hir
::CRATE_HIR_ID
,
151 current_signature_dep_index
: root_mod_sig_dep_index
,
152 current_full_dep_index
: root_mod_full_dep_index
,
153 current_dep_node_owner
: CRATE_DEF_INDEX
,
154 currently_in_body
: false,
161 collector
.insert_entry(CRATE_NODE_ID
, Entry
{
162 parent
: CRATE_NODE_ID
,
163 parent_hir
: hir
::CRATE_HIR_ID
,
164 dep_node
: root_mod_sig_dep_index
,
171 pub(super) fn finalize_and_compute_crate_hash(mut self,
172 crate_disambiguator
: CrateDisambiguator
,
173 cstore
: &dyn CrateStore
,
174 commandline_args_hash
: u64)
175 -> (Vec
<Option
<Entry
<'hir
>>>, Svh
)
177 self.hir_body_nodes
.sort_unstable_by_key(|bn
| bn
.0);
179 let node_hashes
= self
182 .fold(Fingerprint
::ZERO
, |combined_fingerprint
, &(def_path_hash
, fingerprint
)| {
183 combined_fingerprint
.combine(def_path_hash
.0.combine(fingerprint
))
186 let mut upstream_crates
: Vec
<_
> = cstore
.crates_untracked().iter().map(|&cnum
| {
187 let name
= cstore
.crate_name_untracked(cnum
).as_str();
188 let disambiguator
= cstore
.crate_disambiguator_untracked(cnum
).to_fingerprint();
189 let hash
= cstore
.crate_hash_untracked(cnum
);
190 (name
, disambiguator
, hash
)
193 upstream_crates
.sort_unstable_by_key(|&(name
, dis
, _
)| (name
, dis
));
195 // We hash the final, remapped names of all local source files so we
196 // don't have to include the path prefix remapping commandline args.
197 // If we included the full mapping in the SVH, we could only have
198 // reproducible builds by compiling from the same directory. So we just
199 // hash the result of the mapping instead of the mapping itself.
200 let mut source_file_names
: Vec
<_
> = self
204 .filter(|source_file
| CrateNum
::from_u32(source_file
.crate_of_origin
) == LOCAL_CRATE
)
205 .map(|source_file
| source_file
.name_hash
)
208 source_file_names
.sort_unstable();
210 let crate_hash_input
= (
211 ((node_hashes
, upstream_crates
), source_file_names
),
212 (commandline_args_hash
, crate_disambiguator
.to_fingerprint())
215 let (_
, crate_hash
) = input_dep_node_and_hash(
218 DepNode
::new_no_params(DepKind
::Krate
),
222 let svh
= Svh
::new(crate_hash
.to_smaller_hash());
226 fn insert_entry(&mut self, id
: NodeId
, entry
: Entry
<'hir
>) {
227 debug
!("hir_map: {:?} => {:?}", id
, entry
);
228 self.map
[id
.as_usize()] = Some(entry
);
231 fn insert(&mut self, span
: Span
, hir_id
: HirId
, node
: Node
<'hir
>) {
233 parent
: self.hir_to_node_id
[&self.parent_node
],
234 parent_hir
: self.parent_node
,
235 dep_node
: if self.currently_in_body
{
236 self.current_full_dep_index
238 self.current_signature_dep_index
243 let node_id
= self.hir_to_node_id
[&hir_id
];
245 // Make sure that the DepNode of some node coincides with the HirId
246 // owner of that node.
247 if cfg
!(debug_assertions
) {
248 assert_eq
!(self.definitions
.node_to_hir_id(node_id
), hir_id
);
250 if hir_id
.owner
!= self.current_dep_node_owner
{
251 let node_str
= match self.definitions
.opt_def_index(node_id
) {
253 self.definitions
.def_path(def_index
).to_string_no_crate()
255 None
=> format
!("{:?}", node
)
258 let forgot_str
= if hir_id
== crate::hir
::DUMMY_HIR_ID
{
259 format
!("\nMaybe you forgot to lower the node id {:?}?", node_id
)
266 "inconsistent DepNode at `{:?}` for `{}`: \
267 current_dep_node_owner={} ({:?}), hir_id.owner={} ({:?}){}",
268 self.source_map
.span_to_string(span
),
271 .def_path(self.current_dep_node_owner
)
272 .to_string_no_crate(),
273 self.current_dep_node_owner
,
274 self.definitions
.def_path(hir_id
.owner
).to_string_no_crate(),
281 self.insert_entry(node_id
, entry
);
284 fn with_parent
<F
: FnOnce(&mut Self)>(
286 parent_node_id
: HirId
,
289 let parent_node
= self.parent_node
;
290 self.parent_node
= parent_node_id
;
292 self.parent_node
= parent_node
;
295 fn with_dep_node_owner
<T
: for<'b
> HashStable
<StableHashingContext
<'b
>>,
296 F
: FnOnce(&mut Self)>(&mut self,
297 dep_node_owner
: DefIndex
,
300 let prev_owner
= self.current_dep_node_owner
;
301 let prev_signature_dep_index
= self.current_signature_dep_index
;
302 let prev_full_dep_index
= self.current_full_dep_index
;
303 let prev_in_body
= self.currently_in_body
;
305 let def_path_hash
= self.definitions
.def_path_hash(dep_node_owner
);
307 let (signature_dep_index
, full_dep_index
) = alloc_hir_dep_nodes(
312 &mut self.hir_body_nodes
,
314 self.current_signature_dep_index
= signature_dep_index
;
315 self.current_full_dep_index
= full_dep_index
;
317 self.current_dep_node_owner
= dep_node_owner
;
318 self.currently_in_body
= false;
320 self.currently_in_body
= prev_in_body
;
321 self.current_dep_node_owner
= prev_owner
;
322 self.current_full_dep_index
= prev_full_dep_index
;
323 self.current_signature_dep_index
= prev_signature_dep_index
;
327 impl<'a
, 'hir
> Visitor
<'hir
> for NodeCollector
<'a
, 'hir
> {
328 /// Because we want to track parent items and so forth, enable
329 /// deep walking so that we walk nested items in the context of
330 /// their outer items.
332 fn nested_visit_map
<'this
>(&'this
mut self) -> NestedVisitorMap
<'this
, 'hir
> {
333 panic
!("visit_nested_xxx must be manually implemented in this visitor")
336 fn visit_nested_item(&mut self, item
: ItemId
) {
337 debug
!("visit_nested_item: {:?}", item
);
338 self.visit_item(self.krate
.item(item
.id
));
341 fn visit_nested_trait_item(&mut self, item_id
: TraitItemId
) {
342 self.visit_trait_item(self.krate
.trait_item(item_id
));
345 fn visit_nested_impl_item(&mut self, item_id
: ImplItemId
) {
346 self.visit_impl_item(self.krate
.impl_item(item_id
));
349 fn visit_nested_body(&mut self, id
: BodyId
) {
350 let prev_in_body
= self.currently_in_body
;
351 self.currently_in_body
= true;
352 self.visit_body(self.krate
.body(id
));
353 self.currently_in_body
= prev_in_body
;
356 fn visit_item(&mut self, i
: &'hir Item
) {
357 debug
!("visit_item: {:?}", i
);
358 debug_assert_eq
!(i
.hir_id
.owner
,
359 self.definitions
.opt_def_index(i
.id
).unwrap());
360 self.with_dep_node_owner(i
.hir_id
.owner
, i
, |this
| {
361 this
.insert(i
.span
, i
.hir_id
, Node
::Item(i
));
362 this
.with_parent(i
.hir_id
, |this
| {
363 if let ItemKind
::Struct(ref struct_def
, _
) = i
.node
{
364 // If this is a tuple-like struct, register the constructor.
365 if !struct_def
.is_struct() {
366 this
.insert(i
.span
, struct_def
.hir_id(), Node
::StructCtor(struct_def
));
369 intravisit
::walk_item(this
, i
);
374 fn visit_foreign_item(&mut self, foreign_item
: &'hir ForeignItem
) {
375 self.insert(foreign_item
.span
, foreign_item
.hir_id
, Node
::ForeignItem(foreign_item
));
377 self.with_parent(foreign_item
.hir_id
, |this
| {
378 intravisit
::walk_foreign_item(this
, foreign_item
);
382 fn visit_generic_param(&mut self, param
: &'hir GenericParam
) {
383 self.insert(param
.span
, param
.hir_id
, Node
::GenericParam(param
));
384 intravisit
::walk_generic_param(self, param
);
387 fn visit_trait_item(&mut self, ti
: &'hir TraitItem
) {
388 debug_assert_eq
!(ti
.hir_id
.owner
,
389 self.definitions
.opt_def_index(ti
.id
).unwrap());
390 self.with_dep_node_owner(ti
.hir_id
.owner
, ti
, |this
| {
391 this
.insert(ti
.span
, ti
.hir_id
, Node
::TraitItem(ti
));
393 this
.with_parent(ti
.hir_id
, |this
| {
394 intravisit
::walk_trait_item(this
, ti
);
399 fn visit_impl_item(&mut self, ii
: &'hir ImplItem
) {
400 debug_assert_eq
!(ii
.hir_id
.owner
,
401 self.definitions
.opt_def_index(ii
.id
).unwrap());
402 self.with_dep_node_owner(ii
.hir_id
.owner
, ii
, |this
| {
403 this
.insert(ii
.span
, ii
.hir_id
, Node
::ImplItem(ii
));
405 this
.with_parent(ii
.hir_id
, |this
| {
406 intravisit
::walk_impl_item(this
, ii
);
411 fn visit_pat(&mut self, pat
: &'hir Pat
) {
412 let node
= if let PatKind
::Binding(..) = pat
.node
{
417 self.insert(pat
.span
, pat
.hir_id
, node
);
419 self.with_parent(pat
.hir_id
, |this
| {
420 intravisit
::walk_pat(this
, pat
);
424 fn visit_anon_const(&mut self, constant
: &'hir AnonConst
) {
425 self.insert(DUMMY_SP
, constant
.hir_id
, Node
::AnonConst(constant
));
427 self.with_parent(constant
.hir_id
, |this
| {
428 intravisit
::walk_anon_const(this
, constant
);
432 fn visit_expr(&mut self, expr
: &'hir Expr
) {
433 self.insert(expr
.span
, expr
.hir_id
, Node
::Expr(expr
));
435 self.with_parent(expr
.hir_id
, |this
| {
436 intravisit
::walk_expr(this
, expr
);
440 fn visit_stmt(&mut self, stmt
: &'hir Stmt
) {
441 self.insert(stmt
.span
, stmt
.hir_id
, Node
::Stmt(stmt
));
443 self.with_parent(stmt
.hir_id
, |this
| {
444 intravisit
::walk_stmt(this
, stmt
);
448 fn visit_path_segment(&mut self, path_span
: Span
, path_segment
: &'hir PathSegment
) {
449 if let Some(hir_id
) = path_segment
.hir_id
{
450 self.insert(path_span
, hir_id
, Node
::PathSegment(path_segment
));
452 intravisit
::walk_path_segment(self, path_span
, path_segment
);
455 fn visit_ty(&mut self, ty
: &'hir Ty
) {
456 self.insert(ty
.span
, ty
.hir_id
, Node
::Ty(ty
));
458 self.with_parent(ty
.hir_id
, |this
| {
459 intravisit
::walk_ty(this
, ty
);
463 fn visit_trait_ref(&mut self, tr
: &'hir TraitRef
) {
464 self.insert(tr
.path
.span
, tr
.hir_ref_id
, Node
::TraitRef(tr
));
466 self.with_parent(tr
.hir_ref_id
, |this
| {
467 intravisit
::walk_trait_ref(this
, tr
);
471 fn visit_fn(&mut self, fk
: intravisit
::FnKind
<'hir
>, fd
: &'hir FnDecl
,
472 b
: BodyId
, s
: Span
, id
: HirId
) {
473 assert_eq
!(self.parent_node
, id
);
474 intravisit
::walk_fn(self, fk
, fd
, b
, s
, id
);
477 fn visit_block(&mut self, block
: &'hir Block
) {
478 self.insert(block
.span
, block
.hir_id
, Node
::Block(block
));
479 self.with_parent(block
.hir_id
, |this
| {
480 intravisit
::walk_block(this
, block
);
484 fn visit_local(&mut self, l
: &'hir Local
) {
485 self.insert(l
.span
, l
.hir_id
, Node
::Local(l
));
486 self.with_parent(l
.hir_id
, |this
| {
487 intravisit
::walk_local(this
, l
)
491 fn visit_lifetime(&mut self, lifetime
: &'hir Lifetime
) {
492 self.insert(lifetime
.span
, lifetime
.hir_id
, Node
::Lifetime(lifetime
));
495 fn visit_vis(&mut self, visibility
: &'hir Visibility
) {
496 match visibility
.node
{
497 VisibilityKind
::Public
|
498 VisibilityKind
::Crate(_
) |
499 VisibilityKind
::Inherited
=> {}
500 VisibilityKind
::Restricted { hir_id, .. }
=> {
501 self.insert(visibility
.span
, hir_id
, Node
::Visibility(visibility
));
502 self.with_parent(hir_id
, |this
| {
503 intravisit
::walk_vis(this
, visibility
);
509 fn visit_macro_def(&mut self, macro_def
: &'hir MacroDef
) {
510 let def_index
= self.definitions
.opt_def_index(macro_def
.id
).unwrap();
512 self.with_dep_node_owner(def_index
, macro_def
, |this
| {
513 this
.insert(macro_def
.span
, macro_def
.hir_id
, Node
::MacroDef(macro_def
));
517 fn visit_variant(&mut self, v
: &'hir Variant
, g
: &'hir Generics
, item_id
: HirId
) {
518 self.insert(v
.span
, v
.node
.data
.hir_id(), Node
::Variant(v
));
519 self.with_parent(v
.node
.data
.hir_id(), |this
| {
520 intravisit
::walk_variant(this
, v
, g
, item_id
);
524 fn visit_struct_field(&mut self, field
: &'hir StructField
) {
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.
542 self.visit_nested_trait_item(id
);
545 fn visit_impl_item_ref(&mut self, ii
: &'hir ImplItemRef
) {
546 // Do not visit the duplicate information in ImplItemRef. We want to
547 // map the actual nodes, not the duplicate ones in the *Ref.
557 self.visit_nested_impl_item(id
);
561 // This is a wrapper structure that allows determining if span values within
562 // the wrapped item should be hashed or not.
563 struct HirItemLike
<T
> {
568 impl<'a
, 'hir
, T
> HashStable
<StableHashingContext
<'hir
>> for HirItemLike
<T
>
569 where T
: HashStable
<StableHashingContext
<'hir
>>
571 fn hash_stable
<W
: StableHasherResult
>(&self,
572 hcx
: &mut StableHashingContext
<'hir
>,
573 hasher
: &mut StableHasher
<W
>) {
574 hcx
.while_hashing_hir_bodies(self.hash_bodies
, |hcx
| {
575 self.item_like
.hash_stable(hcx
, hasher
);