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