]> git.proxmox.com Git - rustc.git/blame - src/librustc/hir/map/hir_id_validator.rs
New upstream version 1.31.0~beta.4+dfsg1
[rustc.git] / src / librustc / hir / map / hir_id_validator.rs
CommitLineData
cc61c64b
XL
1// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2// file at the top-level directory of this distribution and at
3// http://rust-lang.org/COPYRIGHT.
4//
5// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8// option. This file may not be copied, modified, or distributed
9// except according to those terms.
10
11use hir::def_id::{DefId, DefIndex, CRATE_DEF_INDEX};
12use hir::{self, intravisit, HirId, ItemLocalId};
13use syntax::ast::NodeId;
14use hir::itemlikevisit::ItemLikeVisitor;
15use rustc_data_structures::fx::FxHashMap;
16
17pub fn check_crate<'hir>(hir_map: &hir::map::Map<'hir>) {
18 let mut outer_visitor = OuterVisitor {
041b39d2 19 hir_map,
cc61c64b
XL
20 errors: vec![],
21 };
22
2c00a5a8
XL
23 hir_map.dep_graph.assert_ignored();
24
25 hir_map.krate().visit_all_item_likes(&mut outer_visitor);
26 if !outer_visitor.errors.is_empty() {
27 let message = outer_visitor
28 .errors
29 .iter()
30 .fold(String::new(), |s1, s2| s1 + "\n" + s2);
31 bug!("{}", message);
32 }
cc61c64b
XL
33}
34
35struct HirIdValidator<'a, 'hir: 'a> {
36 hir_map: &'a hir::map::Map<'hir>,
37 owner_def_index: Option<DefIndex>,
38 hir_ids_seen: FxHashMap<ItemLocalId, NodeId>,
39 errors: Vec<String>,
40}
41
42struct OuterVisitor<'a, 'hir: 'a> {
43 hir_map: &'a hir::map::Map<'hir>,
44 errors: Vec<String>,
45}
46
47impl<'a, 'hir: 'a> OuterVisitor<'a, 'hir> {
48 fn new_inner_visitor(&self,
49 hir_map: &'a hir::map::Map<'hir>)
50 -> HirIdValidator<'a, 'hir> {
51 HirIdValidator {
041b39d2 52 hir_map,
cc61c64b 53 owner_def_index: None,
0bf4aa26 54 hir_ids_seen: Default::default(),
cc61c64b
XL
55 errors: Vec::new(),
56 }
57 }
58}
59
60impl<'a, 'hir: 'a> ItemLikeVisitor<'hir> for OuterVisitor<'a, 'hir> {
61 fn visit_item(&mut self, i: &'hir hir::Item) {
62 let mut inner_visitor = self.new_inner_visitor(self.hir_map);
63 inner_visitor.check(i.id, |this| intravisit::walk_item(this, i));
64 self.errors.extend(inner_visitor.errors.drain(..));
65 }
66
67 fn visit_trait_item(&mut self, i: &'hir hir::TraitItem) {
68 let mut inner_visitor = self.new_inner_visitor(self.hir_map);
69 inner_visitor.check(i.id, |this| intravisit::walk_trait_item(this, i));
70 self.errors.extend(inner_visitor.errors.drain(..));
71 }
72
73 fn visit_impl_item(&mut self, i: &'hir hir::ImplItem) {
74 let mut inner_visitor = self.new_inner_visitor(self.hir_map);
75 inner_visitor.check(i.id, |this| intravisit::walk_impl_item(this, i));
76 self.errors.extend(inner_visitor.errors.drain(..));
77 }
78}
79
80impl<'a, 'hir: 'a> HirIdValidator<'a, 'hir> {
81
82 fn check<F: FnOnce(&mut HirIdValidator<'a, 'hir>)>(&mut self,
83 node_id: NodeId,
84 walk: F) {
85 assert!(self.owner_def_index.is_none());
86 let owner_def_index = self.hir_map.local_def_id(node_id).index;
87 self.owner_def_index = Some(owner_def_index);
88 walk(self);
89
90 if owner_def_index == CRATE_DEF_INDEX {
91 return
92 }
93
94 // There's always at least one entry for the owning item itself
95 let max = self.hir_ids_seen
96 .keys()
97 .map(|local_id| local_id.as_usize())
98 .max()
94b46f34 99 .expect("owning item has no entry");
cc61c64b
XL
100
101 if max != self.hir_ids_seen.len() - 1 {
102 // Collect the missing ItemLocalIds
b7449926
XL
103 let missing: Vec<_> = (0 .. max as u32 + 1)
104 .filter(|&i| !self.hir_ids_seen.contains_key(&ItemLocalId(i)))
cc61c64b
XL
105 .collect();
106
107 // Try to map those to something more useful
8faf50e0 108 let mut missing_items = Vec::with_capacity(missing.len());
cc61c64b
XL
109
110 for local_id in missing {
111 let hir_id = HirId {
112 owner: owner_def_index,
113 local_id: ItemLocalId(local_id as u32),
114 };
115
94b46f34
XL
116 trace!("missing hir id {:#?}", hir_id);
117
cc61c64b
XL
118 // We are already in ICE mode here, so doing a linear search
119 // should be fine.
120 let (node_id, _) = self.hir_map
121 .definitions()
122 .node_to_hir_id
123 .iter()
124 .enumerate()
125 .find(|&(_, &entry)| hir_id == entry)
94b46f34 126 .expect("no node_to_hir_id entry");
cc61c64b
XL
127 let node_id = NodeId::new(node_id);
128 missing_items.push(format!("[local_id: {}, node:{}]",
129 local_id,
130 self.hir_map.node_to_string(node_id)));
131 }
132
133 self.errors.push(format!(
134 "ItemLocalIds not assigned densely in {}. \
135 Max ItemLocalId = {}, missing IDs = {:?}",
136 self.hir_map.def_path(DefId::local(owner_def_index)).to_string_no_crate(),
137 max,
138 missing_items));
139 }
140 }
141}
142
143impl<'a, 'hir: 'a> intravisit::Visitor<'hir> for HirIdValidator<'a, 'hir> {
144
145 fn nested_visit_map<'this>(&'this mut self)
146 -> intravisit::NestedVisitorMap<'this, 'hir> {
147 intravisit::NestedVisitorMap::OnlyBodies(self.hir_map)
148 }
149
150 fn visit_id(&mut self, node_id: NodeId) {
94b46f34 151 let owner = self.owner_def_index.expect("no owner_def_index");
cc61c64b
XL
152 let stable_id = self.hir_map.definitions().node_to_hir_id[node_id];
153
154 if stable_id == hir::DUMMY_HIR_ID {
155 self.errors.push(format!("HirIdValidator: No HirId assigned for NodeId {}: {:?}",
156 node_id,
157 self.hir_map.node_to_string(node_id)));
158 }
159
160 if owner != stable_id.owner {
161 self.errors.push(format!(
162 "HirIdValidator: The recorded owner of {} is {} instead of {}",
163 self.hir_map.node_to_string(node_id),
164 self.hir_map.def_path(DefId::local(stable_id.owner)).to_string_no_crate(),
165 self.hir_map.def_path(DefId::local(owner)).to_string_no_crate()));
166 }
167
168 if let Some(prev) = self.hir_ids_seen.insert(stable_id.local_id, node_id) {
169 if prev != node_id {
170 self.errors.push(format!(
171 "HirIdValidator: Same HirId {}/{} assigned for nodes {} and {}",
172 self.hir_map.def_path(DefId::local(stable_id.owner)).to_string_no_crate(),
173 stable_id.local_id.as_usize(),
174 self.hir_map.node_to_string(prev),
175 self.hir_map.node_to_string(node_id)));
176 }
177 }
178 }
179
180 fn visit_impl_item_ref(&mut self, _: &'hir hir::ImplItemRef) {
181 // Explicitly do nothing here. ImplItemRefs contain hir::Visibility
8faf50e0 182 // values that actually belong to an ImplItem instead of the ItemKind::Impl
cc61c64b
XL
183 // we are currently in. So for those it's correct that they have a
184 // different owner.
185 }
186}