]>
Commit | Line | Data |
---|---|---|
dfeec247 | 1 | use crate::hir::map::Map; |
9fa01778 | 2 | use rustc_data_structures::fx::FxHashSet; |
60c5eb7d | 3 | use rustc_data_structures::sync::{par_iter, Lock, ParallelIterator}; |
dfeec247 XL |
4 | use rustc_hir as hir; |
5 | use rustc_hir::def_id::{DefId, DefIndex, CRATE_DEF_INDEX}; | |
6 | use rustc_hir::intravisit; | |
7 | use rustc_hir::itemlikevisit::ItemLikeVisitor; | |
8 | use rustc_hir::{HirId, ItemLocalId}; | |
cc61c64b | 9 | |
dfeec247 | 10 | pub fn check_crate(hir_map: &Map<'_>, sess: &rustc_session::Session) { |
2c00a5a8 XL |
11 | hir_map.dep_graph.assert_ignored(); |
12 | ||
0731742a XL |
13 | let errors = Lock::new(Vec::new()); |
14 | ||
74b04a01 | 15 | par_iter(&hir_map.krate.modules).for_each(|(module_id, _)| { |
e74abb32 | 16 | let local_def_id = hir_map.local_def_id(*module_id); |
60c5eb7d XL |
17 | hir_map.visit_item_likes_in_module( |
18 | local_def_id, | |
19 | &mut OuterVisitor { hir_map, errors: &errors }, | |
20 | ); | |
0731742a XL |
21 | }); |
22 | ||
23 | let errors = errors.into_inner(); | |
24 | ||
25 | if !errors.is_empty() { | |
60c5eb7d | 26 | let message = errors.iter().fold(String::new(), |s1, s2| s1 + "\n" + s2); |
dfeec247 | 27 | sess.delay_span_bug(rustc_span::DUMMY_SP, &message); |
2c00a5a8 | 28 | } |
cc61c64b XL |
29 | } |
30 | ||
dc9dc135 | 31 | struct HirIdValidator<'a, 'hir> { |
dfeec247 | 32 | hir_map: &'a Map<'hir>, |
cc61c64b | 33 | owner_def_index: Option<DefIndex>, |
9fa01778 | 34 | hir_ids_seen: FxHashSet<ItemLocalId>, |
0731742a | 35 | errors: &'a Lock<Vec<String>>, |
cc61c64b XL |
36 | } |
37 | ||
dc9dc135 | 38 | struct OuterVisitor<'a, 'hir> { |
dfeec247 | 39 | hir_map: &'a Map<'hir>, |
0731742a | 40 | errors: &'a Lock<Vec<String>>, |
cc61c64b XL |
41 | } |
42 | ||
dc9dc135 | 43 | impl<'a, 'hir> OuterVisitor<'a, 'hir> { |
dfeec247 | 44 | fn new_inner_visitor(&self, hir_map: &'a Map<'hir>) -> HirIdValidator<'a, 'hir> { |
cc61c64b | 45 | HirIdValidator { |
041b39d2 | 46 | hir_map, |
cc61c64b | 47 | owner_def_index: None, |
0bf4aa26 | 48 | hir_ids_seen: Default::default(), |
0731742a | 49 | errors: self.errors, |
cc61c64b XL |
50 | } |
51 | } | |
52 | } | |
53 | ||
dc9dc135 | 54 | impl<'a, 'hir> ItemLikeVisitor<'hir> for OuterVisitor<'a, 'hir> { |
dfeec247 | 55 | fn visit_item(&mut self, i: &'hir hir::Item<'hir>) { |
cc61c64b | 56 | let mut inner_visitor = self.new_inner_visitor(self.hir_map); |
9fa01778 | 57 | inner_visitor.check(i.hir_id, |this| intravisit::walk_item(this, i)); |
cc61c64b XL |
58 | } |
59 | ||
dfeec247 | 60 | fn visit_trait_item(&mut self, i: &'hir hir::TraitItem<'hir>) { |
cc61c64b | 61 | let mut inner_visitor = self.new_inner_visitor(self.hir_map); |
9fa01778 | 62 | inner_visitor.check(i.hir_id, |this| intravisit::walk_trait_item(this, i)); |
cc61c64b XL |
63 | } |
64 | ||
dfeec247 | 65 | fn visit_impl_item(&mut self, i: &'hir hir::ImplItem<'hir>) { |
cc61c64b | 66 | let mut inner_visitor = self.new_inner_visitor(self.hir_map); |
9fa01778 | 67 | inner_visitor.check(i.hir_id, |this| intravisit::walk_impl_item(this, i)); |
cc61c64b XL |
68 | } |
69 | } | |
70 | ||
dc9dc135 | 71 | impl<'a, 'hir> HirIdValidator<'a, 'hir> { |
0731742a XL |
72 | #[cold] |
73 | #[inline(never)] | |
74 | fn error(&self, f: impl FnOnce() -> String) { | |
75 | self.errors.lock().push(f()); | |
76 | } | |
cc61c64b | 77 | |
60c5eb7d | 78 | fn check<F: FnOnce(&mut HirIdValidator<'a, 'hir>)>(&mut self, hir_id: HirId, walk: F) { |
cc61c64b | 79 | assert!(self.owner_def_index.is_none()); |
416331ca | 80 | let owner_def_index = self.hir_map.local_def_id(hir_id).index; |
cc61c64b XL |
81 | self.owner_def_index = Some(owner_def_index); |
82 | walk(self); | |
83 | ||
84 | if owner_def_index == CRATE_DEF_INDEX { | |
13cf67c4 | 85 | return; |
cc61c64b XL |
86 | } |
87 | ||
88 | // There's always at least one entry for the owning item itself | |
60c5eb7d XL |
89 | let max = self |
90 | .hir_ids_seen | |
91 | .iter() | |
92 | .map(|local_id| local_id.as_usize()) | |
93 | .max() | |
94 | .expect("owning item has no entry"); | |
cc61c64b XL |
95 | |
96 | if max != self.hir_ids_seen.len() - 1 { | |
97 | // Collect the missing ItemLocalIds | |
60c5eb7d XL |
98 | let missing: Vec<_> = (0..=max as u32) |
99 | .filter(|&i| !self.hir_ids_seen.contains(&ItemLocalId::from_u32(i))) | |
100 | .collect(); | |
cc61c64b XL |
101 | |
102 | // Try to map those to something more useful | |
8faf50e0 | 103 | let mut missing_items = Vec::with_capacity(missing.len()); |
cc61c64b XL |
104 | |
105 | for local_id in missing { | |
60c5eb7d XL |
106 | let hir_id = |
107 | HirId { owner: owner_def_index, local_id: ItemLocalId::from_u32(local_id) }; | |
cc61c64b | 108 | |
94b46f34 XL |
109 | trace!("missing hir id {:#?}", hir_id); |
110 | ||
60c5eb7d XL |
111 | missing_items.push(format!( |
112 | "[local_id: {}, node:{}]", | |
113 | local_id, | |
114 | self.hir_map.node_to_string(hir_id) | |
115 | )); | |
cc61c64b | 116 | } |
60c5eb7d XL |
117 | self.error(|| { |
118 | format!( | |
119 | "ItemLocalIds not assigned densely in {}. \ | |
13cf67c4 | 120 | Max ItemLocalId = {}, missing IDs = {:?}; seens IDs = {:?}", |
60c5eb7d XL |
121 | self.hir_map.def_path(DefId::local(owner_def_index)).to_string_no_crate(), |
122 | max, | |
123 | missing_items, | |
124 | self.hir_ids_seen | |
125 | .iter() | |
126 | .map(|&local_id| HirId { owner: owner_def_index, local_id }) | |
127 | .map(|h| format!("({:?} {})", h, self.hir_map.node_to_string(h))) | |
128 | .collect::<Vec<_>>() | |
129 | ) | |
130 | }); | |
cc61c64b XL |
131 | } |
132 | } | |
133 | } | |
134 | ||
dc9dc135 | 135 | impl<'a, 'hir> intravisit::Visitor<'hir> for HirIdValidator<'a, 'hir> { |
dfeec247 XL |
136 | type Map = Map<'hir>; |
137 | ||
138 | fn nested_visit_map<'this>(&'this mut self) -> intravisit::NestedVisitorMap<'this, Self::Map> { | |
cc61c64b XL |
139 | intravisit::NestedVisitorMap::OnlyBodies(self.hir_map) |
140 | } | |
141 | ||
9fa01778 | 142 | fn visit_id(&mut self, hir_id: HirId) { |
94b46f34 | 143 | let owner = self.owner_def_index.expect("no owner_def_index"); |
cc61c64b | 144 | |
9fa01778 | 145 | if hir_id == hir::DUMMY_HIR_ID { |
60c5eb7d XL |
146 | self.error(|| { |
147 | format!( | |
148 | "HirIdValidator: HirId {:?} is invalid", | |
149 | self.hir_map.node_to_string(hir_id) | |
150 | ) | |
151 | }); | |
13cf67c4 | 152 | return; |
cc61c64b XL |
153 | } |
154 | ||
9fa01778 | 155 | if owner != hir_id.owner { |
60c5eb7d XL |
156 | self.error(|| { |
157 | format!( | |
158 | "HirIdValidator: The recorded owner of {} is {} instead of {}", | |
159 | self.hir_map.node_to_string(hir_id), | |
160 | self.hir_map.def_path(DefId::local(hir_id.owner)).to_string_no_crate(), | |
161 | self.hir_map.def_path(DefId::local(owner)).to_string_no_crate() | |
162 | ) | |
163 | }); | |
cc61c64b XL |
164 | } |
165 | ||
9fa01778 | 166 | self.hir_ids_seen.insert(hir_id.local_id); |
cc61c64b XL |
167 | } |
168 | ||
dfeec247 | 169 | fn visit_impl_item_ref(&mut self, _: &'hir hir::ImplItemRef<'hir>) { |
cc61c64b | 170 | // Explicitly do nothing here. ImplItemRefs contain hir::Visibility |
8faf50e0 | 171 | // values that actually belong to an ImplItem instead of the ItemKind::Impl |
cc61c64b XL |
172 | // we are currently in. So for those it's correct that they have a |
173 | // different owner. | |
174 | } | |
175 | } |