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