1 use rustc_data_structures
::fx
::FxHashSet
;
2 use rustc_data_structures
::sync
::Lock
;
4 use rustc_hir
::def_id
::{LocalDefId, CRATE_DEF_ID}
;
5 use rustc_hir
::intravisit
;
6 use rustc_hir
::{HirId, ItemLocalId}
;
7 use rustc_middle
::hir
::map
::Map
;
8 use rustc_middle
::hir
::nested_filter
;
9 use rustc_middle
::ty
::TyCtxt
;
11 pub fn check_crate(tcx
: TyCtxt
<'_
>) {
12 tcx
.dep_graph
.assert_ignored();
14 if tcx
.sess
.opts
.debugging_opts
.hir_stats
{
15 crate::hir_stats
::print_hir_stats(tcx
);
18 let errors
= Lock
::new(Vec
::new());
19 let hir_map
= tcx
.hir();
21 hir_map
.par_for_each_module(|module_id
| {
22 let mut v
= HirIdValidator
{
25 hir_ids_seen
: Default
::default(),
29 tcx
.hir().deep_visit_item_likes_in_module(module_id
, &mut v
);
32 let errors
= errors
.into_inner();
34 if !errors
.is_empty() {
35 let message
= errors
.iter().fold(String
::new(), |s1
, s2
| s1
+ "\n" + s2
);
36 tcx
.sess
.delay_span_bug(rustc_span
::DUMMY_SP
, &message
);
40 struct HirIdValidator
<'a
, 'hir
> {
42 owner
: Option
<LocalDefId
>,
43 hir_ids_seen
: FxHashSet
<ItemLocalId
>,
44 errors
: &'a Lock
<Vec
<String
>>,
47 impl<'a
, 'hir
> HirIdValidator
<'a
, 'hir
> {
48 fn new_visitor(&self, hir_map
: Map
<'hir
>) -> HirIdValidator
<'a
, 'hir
> {
52 hir_ids_seen
: Default
::default(),
59 fn error(&self, f
: impl FnOnce() -> String
) {
60 self.errors
.lock().push(f());
63 fn check
<F
: FnOnce(&mut HirIdValidator
<'a
, 'hir
>)>(&mut self, owner
: LocalDefId
, walk
: F
) {
64 assert
!(self.owner
.is_none());
65 self.owner
= Some(owner
);
68 if owner
== CRATE_DEF_ID
{
72 // There's always at least one entry for the owning item itself
76 .map(|local_id
| local_id
.as_usize())
78 .expect("owning item has no entry");
80 if max
!= self.hir_ids_seen
.len() - 1 {
81 // Collect the missing ItemLocalIds
82 let missing
: Vec
<_
> = (0..=max
as u32)
83 .filter(|&i
| !self.hir_ids_seen
.contains(&ItemLocalId
::from_u32(i
)))
86 // Try to map those to something more useful
87 let mut missing_items
= Vec
::with_capacity(missing
.len());
89 for local_id
in missing
{
90 let hir_id
= HirId { owner, local_id: ItemLocalId::from_u32(local_id) }
;
92 trace
!("missing hir id {:#?}", hir_id
);
94 missing_items
.push(format
!(
95 "[local_id: {}, owner: {}]",
97 self.hir_map
.def_path(owner
).to_string_no_crate_verbose()
102 "ItemLocalIds not assigned densely in {}. \
103 Max ItemLocalId = {}, missing IDs = {:?}; seens IDs = {:?}",
104 self.hir_map
.def_path(owner
).to_string_no_crate_verbose(),
109 .map(|&local_id
| HirId { owner, local_id }
)
110 .map(|h
| format
!("({:?} {})", h
, self.hir_map
.node_to_string(h
)))
118 impl<'a
, 'hir
> intravisit
::Visitor
<'hir
> for HirIdValidator
<'a
, 'hir
> {
119 type NestedFilter
= nested_filter
::OnlyBodies
;
121 fn nested_visit_map(&mut self) -> Self::Map
{
125 fn visit_item(&mut self, i
: &'hir hir
::Item
<'hir
>) {
126 let mut inner_visitor
= self.new_visitor(self.hir_map
);
127 inner_visitor
.check(i
.def_id
, |this
| intravisit
::walk_item(this
, i
));
130 fn visit_id(&mut self, hir_id
: HirId
) {
131 let owner
= self.owner
.expect("no owner");
133 if owner
!= hir_id
.owner
{
136 "HirIdValidator: The recorded owner of {} is {} instead of {}",
137 self.hir_map
.node_to_string(hir_id
),
138 self.hir_map
.def_path(hir_id
.owner
).to_string_no_crate_verbose(),
139 self.hir_map
.def_path(owner
).to_string_no_crate_verbose()
144 self.hir_ids_seen
.insert(hir_id
.local_id
);
147 fn visit_foreign_item(&mut self, i
: &'hir hir
::ForeignItem
<'hir
>) {
148 let mut inner_visitor
= self.new_visitor(self.hir_map
);
149 inner_visitor
.check(i
.def_id
, |this
| intravisit
::walk_foreign_item(this
, i
));
152 fn visit_trait_item(&mut self, i
: &'hir hir
::TraitItem
<'hir
>) {
153 let mut inner_visitor
= self.new_visitor(self.hir_map
);
154 inner_visitor
.check(i
.def_id
, |this
| intravisit
::walk_trait_item(this
, i
));
157 fn visit_impl_item(&mut self, i
: &'hir hir
::ImplItem
<'hir
>) {
158 let mut inner_visitor
= self.new_visitor(self.hir_map
);
159 inner_visitor
.check(i
.def_id
, |this
| intravisit
::walk_impl_item(this
, i
));