1 use crate::hir
::def_id
::{DefId, DefIndex, CRATE_DEF_INDEX}
;
2 use crate::hir
::{self, intravisit, HirId, ItemLocalId}
;
3 use syntax
::ast
::NodeId
;
4 use crate::hir
::itemlikevisit
::ItemLikeVisitor
;
5 use rustc_data_structures
::fx
::FxHashSet
;
6 use rustc_data_structures
::sync
::{Lock, ParallelIterator, par_iter}
;
8 pub fn check_crate
<'hir
>(hir_map
: &hir
::map
::Map
<'hir
>) {
9 hir_map
.dep_graph
.assert_ignored();
11 let errors
= Lock
::new(Vec
::new());
13 par_iter(&hir_map
.krate().modules
).for_each(|(module_id
, _
)| {
14 hir_map
.visit_item_likes_in_module(hir_map
.local_def_id(*module_id
), &mut OuterVisitor
{
20 let errors
= errors
.into_inner();
22 if !errors
.is_empty() {
25 .fold(String
::new(), |s1
, s2
| s1
+ "\n" + s2
);
30 struct HirIdValidator
<'a
, 'hir
: 'a
> {
31 hir_map
: &'a hir
::map
::Map
<'hir
>,
32 owner_def_index
: Option
<DefIndex
>,
33 hir_ids_seen
: FxHashSet
<ItemLocalId
>,
34 errors
: &'a Lock
<Vec
<String
>>,
37 struct OuterVisitor
<'a
, 'hir
: 'a
> {
38 hir_map
: &'a hir
::map
::Map
<'hir
>,
39 errors
: &'a Lock
<Vec
<String
>>,
42 impl<'a
, 'hir
: 'a
> OuterVisitor
<'a
, 'hir
> {
43 fn new_inner_visitor(&self,
44 hir_map
: &'a hir
::map
::Map
<'hir
>)
45 -> HirIdValidator
<'a
, 'hir
> {
48 owner_def_index
: None
,
49 hir_ids_seen
: Default
::default(),
55 impl<'a
, 'hir
: 'a
> ItemLikeVisitor
<'hir
> for OuterVisitor
<'a
, 'hir
> {
56 fn visit_item(&mut self, i
: &'hir hir
::Item
) {
57 let mut inner_visitor
= self.new_inner_visitor(self.hir_map
);
58 inner_visitor
.check(i
.hir_id
, |this
| intravisit
::walk_item(this
, i
));
61 fn visit_trait_item(&mut self, i
: &'hir hir
::TraitItem
) {
62 let mut inner_visitor
= self.new_inner_visitor(self.hir_map
);
63 inner_visitor
.check(i
.hir_id
, |this
| intravisit
::walk_trait_item(this
, i
));
66 fn visit_impl_item(&mut self, i
: &'hir hir
::ImplItem
) {
67 let mut inner_visitor
= self.new_inner_visitor(self.hir_map
);
68 inner_visitor
.check(i
.hir_id
, |this
| intravisit
::walk_impl_item(this
, i
));
72 impl<'a
, 'hir
: 'a
> HirIdValidator
<'a
, 'hir
> {
75 fn error(&self, f
: impl FnOnce() -> String
) {
76 self.errors
.lock().push(f());
79 fn check
<F
: FnOnce(&mut HirIdValidator
<'a
, 'hir
>)>(&mut self,
82 assert
!(self.owner_def_index
.is_none());
83 let owner_def_index
= self.hir_map
.local_def_id_from_hir_id(hir_id
).index
;
84 self.owner_def_index
= Some(owner_def_index
);
87 if owner_def_index
== CRATE_DEF_INDEX
{
91 // There's always at least one entry for the owning item itself
92 let max
= self.hir_ids_seen
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
{
109 owner
: owner_def_index
,
110 local_id
: ItemLocalId
::from_u32(local_id
),
113 trace
!("missing hir id {:#?}", hir_id
);
115 // We are already in ICE mode here, so doing a linear search
117 let (node_id
, _
) = self.hir_map
122 .find(|&(_
, &entry
)| hir_id
== entry
)
123 .expect("no node_to_hir_id entry");
124 let node_id
= NodeId
::from_usize(node_id
);
125 missing_items
.push(format
!("[local_id: {}, node:{}]",
127 self.hir_map
.node_to_string(node_id
)));
129 self.error(|| format
!(
130 "ItemLocalIds not assigned densely in {}. \
131 Max ItemLocalId = {}, missing IDs = {:?}; seens IDs = {:?}",
132 self.hir_map
.def_path(DefId
::local(owner_def_index
)).to_string_no_crate(),
137 .map(|&local_id
| HirId
{
138 owner
: owner_def_index
,
141 .map(|h
| format
!("({:?} {})", h
, self.hir_map
.hir_to_string(h
)))
142 .collect
::<Vec
<_
>>()));
147 impl<'a
, 'hir
: 'a
> intravisit
::Visitor
<'hir
> for HirIdValidator
<'a
, 'hir
> {
149 fn nested_visit_map
<'this
>(&'this
mut self)
150 -> intravisit
::NestedVisitorMap
<'this
, 'hir
> {
151 intravisit
::NestedVisitorMap
::OnlyBodies(self.hir_map
)
154 fn visit_id(&mut self, hir_id
: HirId
) {
155 let owner
= self.owner_def_index
.expect("no owner_def_index");
157 if hir_id
== hir
::DUMMY_HIR_ID
{
158 self.error(|| format
!("HirIdValidator: HirId {:?} is invalid",
159 self.hir_map
.hir_to_string(hir_id
)));
163 if owner
!= hir_id
.owner
{
164 self.error(|| format
!(
165 "HirIdValidator: The recorded owner of {} is {} instead of {}",
166 self.hir_map
.hir_to_string(hir_id
),
167 self.hir_map
.def_path(DefId
::local(hir_id
.owner
)).to_string_no_crate(),
168 self.hir_map
.def_path(DefId
::local(owner
)).to_string_no_crate()));
171 self.hir_ids_seen
.insert(hir_id
.local_id
);
174 fn visit_impl_item_ref(&mut self, _
: &'hir hir
::ImplItemRef
) {
175 // Explicitly do nothing here. ImplItemRefs contain hir::Visibility
176 // values that actually belong to an ImplItem instead of the ItemKind::Impl
177 // we are currently in. So for those it's correct that they have a