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
, _
)| {
19 .visit_item_likes_in_module(module_id
, &mut OuterVisitor { hir_map, errors: &errors }
);
22 let errors
= errors
.into_inner();
24 if !errors
.is_empty() {
25 let message
= errors
.iter().fold(String
::new(), |s1
, s2
| s1
+ "\n" + s2
);
26 tcx
.sess
.delay_span_bug(rustc_span
::DUMMY_SP
, &message
);
30 struct HirIdValidator
<'a
, 'hir
> {
32 owner
: Option
<LocalDefId
>,
33 hir_ids_seen
: FxHashSet
<ItemLocalId
>,
34 errors
: &'a Lock
<Vec
<String
>>,
37 struct OuterVisitor
<'a
, 'hir
> {
39 errors
: &'a Lock
<Vec
<String
>>,
42 impl<'a
, 'hir
> OuterVisitor
<'a
, 'hir
> {
43 fn new_inner_visitor(&self, hir_map
: Map
<'hir
>) -> HirIdValidator
<'a
, 'hir
> {
47 hir_ids_seen
: Default
::default(),
53 impl<'a
, 'hir
> ItemLikeVisitor
<'hir
> for OuterVisitor
<'a
, 'hir
> {
54 fn visit_item(&mut self, i
: &'hir hir
::Item
<'hir
>) {
55 let mut inner_visitor
= self.new_inner_visitor(self.hir_map
);
56 inner_visitor
.check(i
.hir_id(), |this
| intravisit
::walk_item(this
, i
));
59 fn visit_trait_item(&mut self, i
: &'hir hir
::TraitItem
<'hir
>) {
60 let mut inner_visitor
= self.new_inner_visitor(self.hir_map
);
61 inner_visitor
.check(i
.hir_id(), |this
| intravisit
::walk_trait_item(this
, i
));
64 fn visit_impl_item(&mut self, i
: &'hir hir
::ImplItem
<'hir
>) {
65 let mut inner_visitor
= self.new_inner_visitor(self.hir_map
);
66 inner_visitor
.check(i
.hir_id(), |this
| intravisit
::walk_impl_item(this
, i
));
69 fn visit_foreign_item(&mut self, i
: &'hir hir
::ForeignItem
<'hir
>) {
70 let mut inner_visitor
= self.new_inner_visitor(self.hir_map
);
71 inner_visitor
.check(i
.hir_id(), |this
| intravisit
::walk_foreign_item(this
, i
));
75 impl<'a
, 'hir
> HirIdValidator
<'a
, 'hir
> {
78 fn error(&self, f
: impl FnOnce() -> String
) {
79 self.errors
.lock().push(f());
82 fn check
<F
: FnOnce(&mut HirIdValidator
<'a
, 'hir
>)>(&mut self, hir_id
: HirId
, walk
: F
) {
83 assert
!(self.owner
.is_none());
84 let owner
= self.hir_map
.local_def_id(hir_id
);
85 self.owner
= Some(owner
);
88 if owner
.local_def_index
== CRATE_DEF_INDEX
{
92 // There's always at least one entry for the owning item itself
96 .map(|local_id
| local_id
.as_usize())
98 .expect("owning item has no entry");
100 if max
!= self.hir_ids_seen
.len() - 1 {
101 // Collect the missing ItemLocalIds
102 let missing
: Vec
<_
> = (0..=max
as u32)
103 .filter(|&i
| !self.hir_ids_seen
.contains(&ItemLocalId
::from_u32(i
)))
106 // Try to map those to something more useful
107 let mut missing_items
= Vec
::with_capacity(missing
.len());
109 for local_id
in missing
{
110 let hir_id
= HirId { owner, local_id: ItemLocalId::from_u32(local_id) }
;
112 trace
!("missing hir id {:#?}", hir_id
);
114 missing_items
.push(format
!(
115 "[local_id: {}, owner: {}]",
117 self.hir_map
.def_path(owner
).to_string_no_crate_verbose()
122 "ItemLocalIds not assigned densely in {}. \
123 Max ItemLocalId = {}, missing IDs = {:?}; seens IDs = {:?}",
124 self.hir_map
.def_path(owner
).to_string_no_crate_verbose(),
129 .map(|&local_id
| HirId { owner, local_id }
)
130 .map(|h
| format
!("({:?} {})", h
, self.hir_map
.node_to_string(h
)))
138 impl<'a
, 'hir
> intravisit
::Visitor
<'hir
> for HirIdValidator
<'a
, 'hir
> {
139 type Map
= Map
<'hir
>;
141 fn nested_visit_map(&mut self) -> intravisit
::NestedVisitorMap
<Self::Map
> {
142 intravisit
::NestedVisitorMap
::OnlyBodies(self.hir_map
)
145 fn visit_id(&mut self, hir_id
: HirId
) {
146 let owner
= self.owner
.expect("no owner");
148 if owner
!= hir_id
.owner
{
151 "HirIdValidator: The recorded owner of {} is {} instead of {}",
152 self.hir_map
.node_to_string(hir_id
),
153 self.hir_map
.def_path(hir_id
.owner
).to_string_no_crate_verbose(),
154 self.hir_map
.def_path(owner
).to_string_no_crate_verbose()
159 self.hir_ids_seen
.insert(hir_id
.local_id
);
162 fn visit_impl_item_ref(&mut self, _
: &'hir hir
::ImplItemRef
<'hir
>) {
163 // Explicitly do nothing here. ImplItemRefs contain hir::Visibility
164 // values that actually belong to an ImplItem instead of the ItemKind::Impl
165 // we are currently in. So for those it's correct that they have a
169 fn visit_foreign_item_ref(&mut self, _
: &'hir hir
::ForeignItemRef
<'hir
>) {
170 // Explicitly do nothing here. ForeignItemRefs contain hir::Visibility
171 // values that actually belong to an ForeignItem instead of the ItemKind::ForeignMod
172 // we are currently in. So for those it's correct that they have a