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