1 use rustc_data_structures
::fx
::FxHashSet
;
2 use rustc_data_structures
::sync
::{par_iter, Lock, ParallelIterator}
;
4 use rustc_hir
::def_id
::{LocalDefId, CRATE_DEF_INDEX}
;
5 use rustc_hir
::intravisit
;
6 use rustc_hir
::itemlikevisit
::ItemLikeVisitor
;
7 use rustc_hir
::{HirId, ItemLocalId}
;
8 use rustc_middle
::hir
::map
::Map
;
9 use rustc_middle
::ty
::TyCtxt
;
11 pub fn check_crate(tcx
: TyCtxt
<'_
>) {
12 tcx
.dep_graph
.assert_ignored();
14 let errors
= Lock
::new(Vec
::new());
15 let hir_map
= tcx
.hir();
17 par_iter(&hir_map
.krate().modules
).for_each(|(module_id
, _
)| {
18 let local_def_id
= hir_map
.local_def_id(*module_id
);
19 hir_map
.visit_item_likes_in_module(
21 &mut OuterVisitor { hir_map, errors: &errors }
,
25 let errors
= errors
.into_inner();
27 if !errors
.is_empty() {
28 let message
= errors
.iter().fold(String
::new(), |s1
, s2
| s1
+ "\n" + s2
);
29 tcx
.sess
.delay_span_bug(rustc_span
::DUMMY_SP
, &message
);
33 struct HirIdValidator
<'a
, 'hir
> {
35 owner
: Option
<LocalDefId
>,
36 hir_ids_seen
: FxHashSet
<ItemLocalId
>,
37 errors
: &'a Lock
<Vec
<String
>>,
40 struct OuterVisitor
<'a
, 'hir
> {
42 errors
: &'a Lock
<Vec
<String
>>,
45 impl<'a
, 'hir
> OuterVisitor
<'a
, 'hir
> {
46 fn new_inner_visitor(&self, hir_map
: Map
<'hir
>) -> HirIdValidator
<'a
, 'hir
> {
50 hir_ids_seen
: Default
::default(),
56 impl<'a
, 'hir
> ItemLikeVisitor
<'hir
> for OuterVisitor
<'a
, 'hir
> {
57 fn visit_item(&mut self, i
: &'hir hir
::Item
<'hir
>) {
58 let mut inner_visitor
= self.new_inner_visitor(self.hir_map
);
59 inner_visitor
.check(i
.hir_id
, |this
| intravisit
::walk_item(this
, i
));
62 fn visit_trait_item(&mut self, i
: &'hir hir
::TraitItem
<'hir
>) {
63 let mut inner_visitor
= self.new_inner_visitor(self.hir_map
);
64 inner_visitor
.check(i
.hir_id
, |this
| intravisit
::walk_trait_item(this
, i
));
67 fn visit_impl_item(&mut self, i
: &'hir hir
::ImplItem
<'hir
>) {
68 let mut inner_visitor
= self.new_inner_visitor(self.hir_map
);
69 inner_visitor
.check(i
.hir_id
, |this
| intravisit
::walk_impl_item(this
, i
));
73 impl<'a
, 'hir
> HirIdValidator
<'a
, 'hir
> {
76 fn error(&self, f
: impl FnOnce() -> String
) {
77 self.errors
.lock().push(f());
80 fn check
<F
: FnOnce(&mut HirIdValidator
<'a
, 'hir
>)>(&mut self, hir_id
: HirId
, walk
: F
) {
81 assert
!(self.owner
.is_none());
82 let owner
= self.hir_map
.local_def_id(hir_id
);
83 self.owner
= Some(owner
);
86 if owner
.local_def_index
== CRATE_DEF_INDEX
{
90 // There's always at least one entry for the owning item itself
94 .map(|local_id
| local_id
.as_usize())
96 .expect("owning item has no entry");
98 if max
!= self.hir_ids_seen
.len() - 1 {
99 // Collect the missing ItemLocalIds
100 let missing
: Vec
<_
> = (0..=max
as u32)
101 .filter(|&i
| !self.hir_ids_seen
.contains(&ItemLocalId
::from_u32(i
)))
104 // Try to map those to something more useful
105 let mut missing_items
= Vec
::with_capacity(missing
.len());
107 for local_id
in missing
{
108 let hir_id
= HirId { owner, local_id: ItemLocalId::from_u32(local_id) }
;
110 trace
!("missing hir id {:#?}", hir_id
);
112 missing_items
.push(format
!(
113 "[local_id: {}, owner: {}]",
115 self.hir_map
.def_path(owner
).to_string_no_crate()
120 "ItemLocalIds not assigned densely in {}. \
121 Max ItemLocalId = {}, missing IDs = {:?}; seens IDs = {:?}",
122 self.hir_map
.def_path(owner
).to_string_no_crate(),
127 .map(|&local_id
| HirId { owner, local_id }
)
128 .map(|h
| format
!("({:?} {})", h
, self.hir_map
.node_to_string(h
)))
136 impl<'a
, 'hir
> intravisit
::Visitor
<'hir
> for HirIdValidator
<'a
, 'hir
> {
137 type Map
= Map
<'hir
>;
139 fn nested_visit_map(&mut self) -> intravisit
::NestedVisitorMap
<Self::Map
> {
140 intravisit
::NestedVisitorMap
::OnlyBodies(self.hir_map
)
143 fn visit_id(&mut self, hir_id
: HirId
) {
144 let owner
= self.owner
.expect("no owner");
146 if owner
!= hir_id
.owner
{
149 "HirIdValidator: The recorded owner of {} is {} instead of {}",
150 self.hir_map
.node_to_string(hir_id
),
151 self.hir_map
.def_path(hir_id
.owner
).to_string_no_crate(),
152 self.hir_map
.def_path(owner
).to_string_no_crate()
157 self.hir_ids_seen
.insert(hir_id
.local_id
);
160 fn visit_impl_item_ref(&mut self, _
: &'hir hir
::ImplItemRef
<'hir
>) {
161 // Explicitly do nothing here. ImplItemRefs contain hir::Visibility
162 // values that actually belong to an ImplItem instead of the ItemKind::Impl
163 // we are currently in. So for those it's correct that they have a