]>
Commit | Line | Data |
---|---|---|
e9174d1e | 1 | // Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT |
1a4d82fc JJ |
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 | ||
b039eaaf | 11 | use self::collector::NodeCollector; |
c30ab7b3 | 12 | pub use self::def_collector::{DefCollector, MacroInvocationData}; |
54a0048b | 13 | pub use self::definitions::{Definitions, DefKey, DefPath, DefPathData, |
7cac9316 | 14 | DisambiguatedDefPathData, DefPathHash}; |
1a4d82fc | 15 | |
3b2f2976 | 16 | use dep_graph::{DepGraph, DepNode, DepKind, DepNodeIndex}; |
7453a54e | 17 | |
abe05a73 | 18 | use hir::def_id::{CRATE_DEF_INDEX, DefId, LocalDefId, DefIndexAddressSpace}; |
e9174d1e | 19 | |
0531ce1d XL |
20 | use middle::cstore::CrateStore; |
21 | ||
83c7162d | 22 | use rustc_target::spec::abi::Abi; |
b7449926 | 23 | use rustc_data_structures::svh::Svh; |
9e0c209e | 24 | use syntax::ast::{self, Name, NodeId, CRATE_NODE_ID}; |
b7449926 | 25 | use syntax::source_map::Spanned; |
0531ce1d | 26 | use syntax::ext::base::MacroKind; |
8faf50e0 | 27 | use syntax_pos::{Span, DUMMY_SP}; |
e9174d1e | 28 | |
54a0048b | 29 | use hir::*; |
32a655c1 | 30 | use hir::print::Nested; |
83c7162d | 31 | use util::nodemap::FxHashMap; |
1a4d82fc | 32 | |
c34b1796 | 33 | use std::io; |
8faf50e0 | 34 | use std::result::Result::Err; |
0531ce1d | 35 | use ty::TyCtxt; |
1a4d82fc JJ |
36 | |
37 | pub mod blocks; | |
b039eaaf | 38 | mod collector; |
a7813a04 | 39 | mod def_collector; |
b039eaaf | 40 | pub mod definitions; |
cc61c64b XL |
41 | mod hir_id_validator; |
42 | ||
43 | pub const ITEM_LIKE_SPACE: DefIndexAddressSpace = DefIndexAddressSpace::Low; | |
44 | pub const REGULAR_SPACE: DefIndexAddressSpace = DefIndexAddressSpace::High; | |
1a4d82fc | 45 | |
b7449926 | 46 | /// Represents an entry and its parent NodeId. |
c34b1796 | 47 | #[derive(Copy, Clone, Debug)] |
b7449926 XL |
48 | pub struct Entry<'hir> { |
49 | parent: NodeId, | |
50 | dep_node: DepNodeIndex, | |
51 | node: Node<'hir>, | |
1a4d82fc JJ |
52 | } |
53 | ||
b7449926 | 54 | impl<'hir> Entry<'hir> { |
c1a9b12d | 55 | fn parent_node(self) -> Option<NodeId> { |
b7449926 XL |
56 | match self.node { |
57 | Node::Crate | Node::MacroDef(_) => None, | |
58 | _ => Some(self.parent), | |
59 | } | |
1a4d82fc | 60 | } |
32a655c1 | 61 | |
94b46f34 | 62 | fn fn_decl(&self) -> Option<&FnDecl> { |
b7449926 XL |
63 | match self.node { |
64 | Node::Item(ref item) => { | |
94b46f34 | 65 | match item.node { |
8faf50e0 | 66 | ItemKind::Fn(ref fn_decl, _, _, _) => Some(&fn_decl), |
94b46f34 XL |
67 | _ => None, |
68 | } | |
69 | } | |
70 | ||
b7449926 | 71 | Node::TraitItem(ref item) => { |
94b46f34 XL |
72 | match item.node { |
73 | TraitItemKind::Method(ref method_sig, _) => Some(&method_sig.decl), | |
74 | _ => None | |
75 | } | |
76 | } | |
77 | ||
b7449926 | 78 | Node::ImplItem(ref item) => { |
94b46f34 XL |
79 | match item.node { |
80 | ImplItemKind::Method(ref method_sig, _) => Some(&method_sig.decl), | |
81 | _ => None, | |
82 | } | |
83 | } | |
84 | ||
b7449926 | 85 | Node::Expr(ref expr) => { |
94b46f34 | 86 | match expr.node { |
8faf50e0 | 87 | ExprKind::Closure(_, ref fn_decl, ..) => Some(&fn_decl), |
94b46f34 XL |
88 | _ => None, |
89 | } | |
90 | } | |
91 | ||
b7449926 | 92 | _ => None, |
94b46f34 XL |
93 | } |
94 | } | |
95 | ||
8bb4bdeb | 96 | fn associated_body(self) -> Option<BodyId> { |
b7449926 XL |
97 | match self.node { |
98 | Node::Item(item) => { | |
32a655c1 | 99 | match item.node { |
8faf50e0 XL |
100 | ItemKind::Const(_, body) | |
101 | ItemKind::Static(.., body) | | |
102 | ItemKind::Fn(_, _, _, body) => Some(body), | |
8bb4bdeb | 103 | _ => None, |
32a655c1 SL |
104 | } |
105 | } | |
106 | ||
b7449926 | 107 | Node::TraitItem(item) => { |
32a655c1 SL |
108 | match item.node { |
109 | TraitItemKind::Const(_, Some(body)) | | |
8bb4bdeb XL |
110 | TraitItemKind::Method(_, TraitMethod::Provided(body)) => Some(body), |
111 | _ => None | |
32a655c1 SL |
112 | } |
113 | } | |
114 | ||
b7449926 | 115 | Node::ImplItem(item) => { |
32a655c1 SL |
116 | match item.node { |
117 | ImplItemKind::Const(_, body) | | |
8bb4bdeb XL |
118 | ImplItemKind::Method(_, body) => Some(body), |
119 | _ => None, | |
32a655c1 SL |
120 | } |
121 | } | |
122 | ||
b7449926 | 123 | Node::AnonConst(constant) => Some(constant.body), |
94b46f34 | 124 | |
b7449926 | 125 | Node::Expr(expr) => { |
32a655c1 | 126 | match expr.node { |
8faf50e0 | 127 | ExprKind::Closure(.., body, _, _) => Some(body), |
8bb4bdeb | 128 | _ => None, |
32a655c1 SL |
129 | } |
130 | } | |
131 | ||
8bb4bdeb XL |
132 | _ => None |
133 | } | |
134 | } | |
135 | ||
136 | fn is_body_owner(self, node_id: NodeId) -> bool { | |
137 | match self.associated_body() { | |
138 | Some(b) => b.node_id == node_id, | |
139 | None => false, | |
32a655c1 SL |
140 | } |
141 | } | |
1a4d82fc JJ |
142 | } |
143 | ||
144 | /// Stores a crate and any number of inlined items from other crates. | |
145 | pub struct Forest { | |
7453a54e SL |
146 | krate: Crate, |
147 | pub dep_graph: DepGraph, | |
1a4d82fc JJ |
148 | } |
149 | ||
150 | impl Forest { | |
a7813a04 | 151 | pub fn new(krate: Crate, dep_graph: &DepGraph) -> Forest { |
1a4d82fc | 152 | Forest { |
041b39d2 | 153 | krate, |
a7813a04 | 154 | dep_graph: dep_graph.clone(), |
1a4d82fc JJ |
155 | } |
156 | } | |
157 | ||
32a655c1 | 158 | pub fn krate<'hir>(&'hir self) -> &'hir Crate { |
041b39d2 | 159 | self.dep_graph.read(DepNode::new_no_params(DepKind::Krate)); |
1a4d82fc JJ |
160 | &self.krate |
161 | } | |
162 | } | |
163 | ||
164 | /// Represents a mapping from Node IDs to AST elements and their parent | |
165 | /// Node IDs | |
e9174d1e | 166 | #[derive(Clone)] |
32a655c1 | 167 | pub struct Map<'hir> { |
1a4d82fc | 168 | /// The backing storage for all the AST nodes. |
32a655c1 | 169 | pub forest: &'hir Forest, |
1a4d82fc | 170 | |
7453a54e | 171 | /// Same as the dep_graph in forest, just available with one fewer |
3b2f2976 | 172 | /// deref. This is a gratuitous micro-optimization. |
7453a54e SL |
173 | pub dep_graph: DepGraph, |
174 | ||
ff7c6d11 XL |
175 | /// The SVH of the local crate. |
176 | pub crate_hash: Svh, | |
177 | ||
b7449926 | 178 | /// `NodeId`s are sequential integers from 0, so we can be |
1a4d82fc | 179 | /// super-compact by storing them in a vector. Not everything with |
b7449926 | 180 | /// a `NodeId` is in the map, but empirically the occupancy is about |
1a4d82fc JJ |
181 | /// 75-80%, so there's not too much overhead (certainly less than |
182 | /// a hashmap, since they (at the time of writing) have a maximum | |
183 | /// of 75% occupancy). | |
184 | /// | |
185 | /// Also, indexing is pretty quick when you've got a vector and | |
186 | /// plain old integers. | |
b7449926 | 187 | map: Vec<Option<Entry<'hir>>>, |
5bcae85e | 188 | |
ea8adc8c | 189 | definitions: &'hir Definitions, |
5bcae85e | 190 | |
ea8adc8c XL |
191 | /// The reverse mapping of `node_to_hir_id`. |
192 | hir_to_node_id: FxHashMap<HirId, NodeId>, | |
1a4d82fc JJ |
193 | } |
194 | ||
32a655c1 | 195 | impl<'hir> Map<'hir> { |
7453a54e SL |
196 | /// Registers a read in the dependency graph of the AST node with |
197 | /// the given `id`. This needs to be called each time a public | |
198 | /// function returns the HIR for a node -- in other words, when it | |
199 | /// "reveals" the content of a node to the caller (who might not | |
200 | /// otherwise have had access to those contents, and hence needs a | |
201 | /// read recorded). If the function just returns a DefId or | |
202 | /// NodeId, no actual content was returned, so no read is needed. | |
5bcae85e | 203 | pub fn read(&self, id: NodeId) { |
b7449926 XL |
204 | if let Some(entry) = self.map[id.as_usize()] { |
205 | self.dep_graph.read_index(entry.dep_node); | |
206 | } else { | |
207 | bug!("called `HirMap::read()` with invalid `NodeId`") | |
476ff2be SL |
208 | } |
209 | } | |
210 | ||
3b2f2976 | 211 | #[inline] |
ea8adc8c XL |
212 | pub fn definitions(&self) -> &'hir Definitions { |
213 | self.definitions | |
b039eaaf SL |
214 | } |
215 | ||
216 | pub fn def_key(&self, def_id: DefId) -> DefKey { | |
217 | assert!(def_id.is_local()); | |
32a655c1 | 218 | self.definitions.def_key(def_id.index) |
b039eaaf SL |
219 | } |
220 | ||
54a0048b SL |
221 | pub fn def_path_from_id(&self, id: NodeId) -> Option<DefPath> { |
222 | self.opt_local_def_id(id).map(|def_id| { | |
223 | self.def_path(def_id) | |
224 | }) | |
b039eaaf SL |
225 | } |
226 | ||
227 | pub fn def_path(&self, def_id: DefId) -> DefPath { | |
228 | assert!(def_id.is_local()); | |
32a655c1 | 229 | self.definitions.def_path(def_id.index) |
b039eaaf SL |
230 | } |
231 | ||
3b2f2976 | 232 | #[inline] |
b039eaaf SL |
233 | pub fn local_def_id(&self, node: NodeId) -> DefId { |
234 | self.opt_local_def_id(node).unwrap_or_else(|| { | |
54a0048b SL |
235 | bug!("local_def_id: no entry for `{}`, which has a map of `{:?}`", |
236 | node, self.find_entry(node)) | |
b039eaaf SL |
237 | }) |
238 | } | |
239 | ||
3b2f2976 | 240 | #[inline] |
b039eaaf | 241 | pub fn opt_local_def_id(&self, node: NodeId) -> Option<DefId> { |
32a655c1 | 242 | self.definitions.opt_local_def_id(node) |
b039eaaf SL |
243 | } |
244 | ||
3b2f2976 | 245 | #[inline] |
b039eaaf | 246 | pub fn as_local_node_id(&self, def_id: DefId) -> Option<NodeId> { |
32a655c1 | 247 | self.definitions.as_local_node_id(def_id) |
b039eaaf SL |
248 | } |
249 | ||
ea8adc8c XL |
250 | #[inline] |
251 | pub fn hir_to_node_id(&self, hir_id: HirId) -> NodeId { | |
252 | self.hir_to_node_id[&hir_id] | |
253 | } | |
254 | ||
3b2f2976 XL |
255 | #[inline] |
256 | pub fn node_to_hir_id(&self, node_id: NodeId) -> HirId { | |
257 | self.definitions.node_to_hir_id(node_id) | |
258 | } | |
259 | ||
260 | #[inline] | |
261 | pub fn def_index_to_hir_id(&self, def_index: DefIndex) -> HirId { | |
262 | self.definitions.def_index_to_hir_id(def_index) | |
263 | } | |
264 | ||
265 | #[inline] | |
266 | pub fn def_index_to_node_id(&self, def_index: DefIndex) -> NodeId { | |
267 | self.definitions.as_local_node_id(DefId::local(def_index)).unwrap() | |
268 | } | |
269 | ||
abe05a73 XL |
270 | #[inline] |
271 | pub fn local_def_id_to_hir_id(&self, def_id: LocalDefId) -> HirId { | |
272 | self.definitions.def_index_to_hir_id(def_id.to_def_id().index) | |
273 | } | |
274 | ||
275 | #[inline] | |
276 | pub fn local_def_id_to_node_id(&self, def_id: LocalDefId) -> NodeId { | |
277 | self.definitions.as_local_node_id(def_id.to_def_id()).unwrap() | |
278 | } | |
279 | ||
0531ce1d XL |
280 | pub fn describe_def(&self, node_id: NodeId) -> Option<Def> { |
281 | let node = if let Some(node) = self.find(node_id) { | |
282 | node | |
283 | } else { | |
284 | return None | |
285 | }; | |
286 | ||
287 | match node { | |
b7449926 | 288 | Node::Item(item) => { |
0531ce1d XL |
289 | let def_id = || { |
290 | self.local_def_id(item.id) | |
291 | }; | |
292 | ||
293 | match item.node { | |
b7449926 | 294 | ItemKind::Static(_, m, _) => Some(Def::Static(def_id(), m == MutMutable)), |
8faf50e0 XL |
295 | ItemKind::Const(..) => Some(Def::Const(def_id())), |
296 | ItemKind::Fn(..) => Some(Def::Fn(def_id())), | |
297 | ItemKind::Mod(..) => Some(Def::Mod(def_id())), | |
8faf50e0 XL |
298 | ItemKind::Existential(..) => Some(Def::Existential(def_id())), |
299 | ItemKind::Ty(..) => Some(Def::TyAlias(def_id())), | |
300 | ItemKind::Enum(..) => Some(Def::Enum(def_id())), | |
301 | ItemKind::Struct(..) => Some(Def::Struct(def_id())), | |
302 | ItemKind::Union(..) => Some(Def::Union(def_id())), | |
303 | ItemKind::Trait(..) => Some(Def::Trait(def_id())), | |
304 | ItemKind::TraitAlias(..) => { | |
0531ce1d XL |
305 | bug!("trait aliases are not yet implemented (see issue #41517)") |
306 | }, | |
8faf50e0 XL |
307 | ItemKind::ExternCrate(_) | |
308 | ItemKind::Use(..) | | |
309 | ItemKind::ForeignMod(..) | | |
b7449926 | 310 | ItemKind::GlobalAsm(..) | |
8faf50e0 | 311 | ItemKind::Impl(..) => None, |
0531ce1d XL |
312 | } |
313 | } | |
b7449926 | 314 | Node::ForeignItem(item) => { |
0531ce1d XL |
315 | let def_id = self.local_def_id(item.id); |
316 | match item.node { | |
8faf50e0 XL |
317 | ForeignItemKind::Fn(..) => Some(Def::Fn(def_id)), |
318 | ForeignItemKind::Static(_, m) => Some(Def::Static(def_id, m)), | |
b7449926 | 319 | ForeignItemKind::Type => Some(Def::ForeignTy(def_id)), |
0531ce1d XL |
320 | } |
321 | } | |
b7449926 | 322 | Node::TraitItem(item) => { |
0531ce1d XL |
323 | let def_id = self.local_def_id(item.id); |
324 | match item.node { | |
325 | TraitItemKind::Const(..) => Some(Def::AssociatedConst(def_id)), | |
326 | TraitItemKind::Method(..) => Some(Def::Method(def_id)), | |
327 | TraitItemKind::Type(..) => Some(Def::AssociatedTy(def_id)), | |
328 | } | |
329 | } | |
b7449926 | 330 | Node::ImplItem(item) => { |
0531ce1d XL |
331 | let def_id = self.local_def_id(item.id); |
332 | match item.node { | |
333 | ImplItemKind::Const(..) => Some(Def::AssociatedConst(def_id)), | |
334 | ImplItemKind::Method(..) => Some(Def::Method(def_id)), | |
335 | ImplItemKind::Type(..) => Some(Def::AssociatedTy(def_id)), | |
8faf50e0 | 336 | ImplItemKind::Existential(..) => Some(Def::AssociatedExistential(def_id)), |
0531ce1d XL |
337 | } |
338 | } | |
b7449926 | 339 | Node::Variant(variant) => { |
0531ce1d XL |
340 | let def_id = self.local_def_id(variant.node.data.id()); |
341 | Some(Def::Variant(def_id)) | |
342 | } | |
b7449926 XL |
343 | Node::Field(_) | |
344 | Node::AnonConst(_) | | |
345 | Node::Expr(_) | | |
346 | Node::Stmt(_) | | |
347 | Node::Ty(_) | | |
348 | Node::TraitRef(_) | | |
349 | Node::Pat(_) | | |
350 | Node::Binding(_) | | |
351 | Node::StructCtor(_) | | |
352 | Node::Lifetime(_) | | |
353 | Node::Visibility(_) | | |
354 | Node::Block(_) | | |
355 | Node::Crate => None, | |
356 | Node::Local(local) => { | |
0531ce1d XL |
357 | Some(Def::Local(local.id)) |
358 | } | |
b7449926 | 359 | Node::MacroDef(macro_def) => { |
0531ce1d XL |
360 | Some(Def::Macro(self.local_def_id(macro_def.id), |
361 | MacroKind::Bang)) | |
362 | } | |
b7449926 | 363 | Node::GenericParam(param) => { |
8faf50e0 XL |
364 | Some(match param.kind { |
365 | GenericParamKind::Lifetime { .. } => Def::Local(param.id), | |
366 | GenericParamKind::Type { .. } => Def::TyParam(self.local_def_id(param.id)), | |
367 | }) | |
0531ce1d XL |
368 | } |
369 | } | |
370 | } | |
371 | ||
85aaf69f | 372 | fn entry_count(&self) -> usize { |
32a655c1 | 373 | self.map.len() |
1a4d82fc JJ |
374 | } |
375 | ||
b7449926 XL |
376 | fn find_entry(&self, id: NodeId) -> Option<Entry<'hir>> { |
377 | self.map.get(id.as_usize()).cloned().unwrap_or(None) | |
1a4d82fc JJ |
378 | } |
379 | ||
32a655c1 | 380 | pub fn krate(&self) -> &'hir Crate { |
7453a54e | 381 | self.forest.krate() |
1a4d82fc JJ |
382 | } |
383 | ||
32a655c1 SL |
384 | pub fn trait_item(&self, id: TraitItemId) -> &'hir TraitItem { |
385 | self.read(id.node_id); | |
386 | ||
387 | // NB: intentionally bypass `self.forest.krate()` so that we | |
388 | // do not trigger a read of the whole krate here | |
389 | self.forest.krate.trait_item(id) | |
390 | } | |
391 | ||
392 | pub fn impl_item(&self, id: ImplItemId) -> &'hir ImplItem { | |
476ff2be SL |
393 | self.read(id.node_id); |
394 | ||
395 | // NB: intentionally bypass `self.forest.krate()` so that we | |
396 | // do not trigger a read of the whole krate here | |
397 | self.forest.krate.impl_item(id) | |
398 | } | |
399 | ||
32a655c1 SL |
400 | pub fn body(&self, id: BodyId) -> &'hir Body { |
401 | self.read(id.node_id); | |
402 | ||
403 | // NB: intentionally bypass `self.forest.krate()` so that we | |
404 | // do not trigger a read of the whole krate here | |
405 | self.forest.krate.body(id) | |
406 | } | |
407 | ||
94b46f34 XL |
408 | pub fn fn_decl(&self, node_id: ast::NodeId) -> Option<FnDecl> { |
409 | if let Some(entry) = self.find_entry(node_id) { | |
b7449926 | 410 | entry.fn_decl().cloned() |
94b46f34 XL |
411 | } else { |
412 | bug!("no entry for node_id `{}`", node_id) | |
413 | } | |
414 | } | |
415 | ||
32a655c1 SL |
416 | /// Returns the `NodeId` that corresponds to the definition of |
417 | /// which this is the body of, i.e. a `fn`, `const` or `static` | |
94b46f34 | 418 | /// item (possibly associated), a closure, or a `hir::AnonConst`. |
32a655c1 SL |
419 | pub fn body_owner(&self, BodyId { node_id }: BodyId) -> NodeId { |
420 | let parent = self.get_parent_node(node_id); | |
b7449926 | 421 | assert!(self.map[parent.as_usize()].map_or(false, |e| e.is_body_owner(node_id))); |
94b46f34 | 422 | parent |
32a655c1 SL |
423 | } |
424 | ||
425 | pub fn body_owner_def_id(&self, id: BodyId) -> DefId { | |
426 | self.local_def_id(self.body_owner(id)) | |
427 | } | |
428 | ||
7cac9316 XL |
429 | /// Given a node id, returns the `BodyId` associated with it, |
430 | /// if the node is a body owner, otherwise returns `None`. | |
431 | pub fn maybe_body_owned_by(&self, id: NodeId) -> Option<BodyId> { | |
cc61c64b | 432 | if let Some(entry) = self.find_entry(id) { |
abe05a73 XL |
433 | if self.dep_graph.is_fully_enabled() { |
434 | let hir_id_owner = self.node_to_hir_id(id).owner; | |
435 | let def_path_hash = self.definitions.def_path_hash(hir_id_owner); | |
436 | self.dep_graph.read(def_path_hash.to_dep_node(DepKind::HirBody)); | |
437 | } | |
438 | ||
94b46f34 | 439 | entry.associated_body() |
cc61c64b XL |
440 | } else { |
441 | bug!("no entry for id `{}`", id) | |
442 | } | |
443 | } | |
444 | ||
7cac9316 XL |
445 | /// Given a body owner's id, returns the `BodyId` associated with it. |
446 | pub fn body_owned_by(&self, id: NodeId) -> BodyId { | |
447 | self.maybe_body_owned_by(id).unwrap_or_else(|| { | |
448 | span_bug!(self.span(id), "body_owned_by: {} has no associated body", | |
449 | self.node_to_string(id)); | |
450 | }) | |
451 | } | |
452 | ||
abe05a73 | 453 | pub fn body_owner_kind(&self, id: NodeId) -> BodyOwnerKind { |
abe05a73 | 454 | match self.get(id) { |
b7449926 XL |
455 | Node::Item(&Item { node: ItemKind::Const(..), .. }) | |
456 | Node::TraitItem(&TraitItem { node: TraitItemKind::Const(..), .. }) | | |
457 | Node::ImplItem(&ImplItem { node: ImplItemKind::Const(..), .. }) | | |
458 | Node::AnonConst(_) => { | |
abe05a73 XL |
459 | BodyOwnerKind::Const |
460 | } | |
b7449926 | 461 | Node::Item(&Item { node: ItemKind::Static(_, m, _), .. }) => { |
abe05a73 XL |
462 | BodyOwnerKind::Static(m) |
463 | } | |
464 | // Default to function if it's not a constant or static. | |
465 | _ => BodyOwnerKind::Fn | |
466 | } | |
467 | } | |
468 | ||
8bb4bdeb XL |
469 | pub fn ty_param_owner(&self, id: NodeId) -> NodeId { |
470 | match self.get(id) { | |
b7449926 XL |
471 | Node::Item(&Item { node: ItemKind::Trait(..), .. }) => id, |
472 | Node::GenericParam(_) => self.get_parent_node(id), | |
473 | _ => bug!("ty_param_owner: {} not a type parameter", self.node_to_string(id)) | |
8bb4bdeb XL |
474 | } |
475 | } | |
476 | ||
477 | pub fn ty_param_name(&self, id: NodeId) -> Name { | |
478 | match self.get(id) { | |
b7449926 XL |
479 | Node::Item(&Item { node: ItemKind::Trait(..), .. }) => keywords::SelfType.name(), |
480 | Node::GenericParam(param) => param.name.ident().name, | |
8faf50e0 | 481 | _ => bug!("ty_param_name: {} not a type parameter", self.node_to_string(id)), |
8bb4bdeb XL |
482 | } |
483 | } | |
484 | ||
485 | pub fn trait_impls(&self, trait_did: DefId) -> &'hir [NodeId] { | |
041b39d2 | 486 | self.dep_graph.read(DepNode::new_no_params(DepKind::AllLocalTraitImpls)); |
8bb4bdeb XL |
487 | |
488 | // NB: intentionally bypass `self.forest.krate()` so that we | |
489 | // do not trigger a read of the whole krate here | |
490 | self.forest.krate.trait_impls.get(&trait_did).map_or(&[], |xs| &xs[..]) | |
491 | } | |
492 | ||
abe05a73 | 493 | pub fn trait_auto_impl(&self, trait_did: DefId) -> Option<NodeId> { |
041b39d2 | 494 | self.dep_graph.read(DepNode::new_no_params(DepKind::AllLocalTraitImpls)); |
8bb4bdeb XL |
495 | |
496 | // NB: intentionally bypass `self.forest.krate()` so that we | |
497 | // do not trigger a read of the whole krate here | |
abe05a73 | 498 | self.forest.krate.trait_auto_impl.get(&trait_did).cloned() |
8bb4bdeb XL |
499 | } |
500 | ||
501 | pub fn trait_is_auto(&self, trait_did: DefId) -> bool { | |
abe05a73 | 502 | self.trait_auto_impl(trait_did).is_some() |
8bb4bdeb XL |
503 | } |
504 | ||
54a0048b SL |
505 | /// Get the attributes on the krate. This is preferable to |
506 | /// invoking `krate.attrs` because it registers a tighter | |
507 | /// dep-graph access. | |
32a655c1 | 508 | pub fn krate_attrs(&self) -> &'hir [ast::Attribute] { |
041b39d2 XL |
509 | let def_path_hash = self.definitions.def_path_hash(CRATE_DEF_INDEX); |
510 | ||
511 | self.dep_graph.read(def_path_hash.to_dep_node(DepKind::Hir)); | |
54a0048b SL |
512 | &self.forest.krate.attrs |
513 | } | |
514 | ||
1a4d82fc JJ |
515 | /// Retrieve the Node corresponding to `id`, panicking if it cannot |
516 | /// be found. | |
32a655c1 | 517 | pub fn get(&self, id: NodeId) -> Node<'hir> { |
b7449926 XL |
518 | // read recorded by `find` |
519 | self.find(id).unwrap_or_else(|| bug!("couldn't find node id {} in the AST map", id)) | |
1a4d82fc JJ |
520 | } |
521 | ||
32a655c1 | 522 | pub fn get_if_local(&self, id: DefId) -> Option<Node<'hir>> { |
7453a54e | 523 | self.as_local_node_id(id).map(|id| self.get(id)) // read recorded by `get` |
b039eaaf SL |
524 | } |
525 | ||
8faf50e0 XL |
526 | pub fn get_generics(&self, id: DefId) -> Option<&'hir Generics> { |
527 | self.get_if_local(id).and_then(|node| { | |
528 | match node { | |
b7449926 XL |
529 | Node::ImplItem(ref impl_item) => Some(&impl_item.generics), |
530 | Node::TraitItem(ref trait_item) => Some(&trait_item.generics), | |
531 | Node::Item(ref item) => { | |
8faf50e0 XL |
532 | match item.node { |
533 | ItemKind::Fn(_, _, ref generics, _) | | |
534 | ItemKind::Ty(_, ref generics) | | |
535 | ItemKind::Enum(_, ref generics) | | |
536 | ItemKind::Struct(_, ref generics) | | |
537 | ItemKind::Union(_, ref generics) | | |
538 | ItemKind::Trait(_, _, ref generics, ..) | | |
539 | ItemKind::TraitAlias(ref generics, _) | | |
540 | ItemKind::Impl(_, _, _, ref generics, ..) => Some(generics), | |
541 | _ => None, | |
542 | } | |
543 | } | |
544 | _ => None, | |
545 | } | |
546 | }) | |
547 | } | |
548 | ||
549 | pub fn get_generics_span(&self, id: DefId) -> Option<Span> { | |
550 | self.get_generics(id).map(|generics| generics.span).filter(|sp| *sp != DUMMY_SP) | |
551 | } | |
552 | ||
1a4d82fc JJ |
553 | /// Retrieve the Node corresponding to `id`, returning None if |
554 | /// cannot be found. | |
32a655c1 | 555 | pub fn find(&self, id: NodeId) -> Option<Node<'hir>> { |
b7449926 XL |
556 | let result = self.find_entry(id).and_then(|entry| { |
557 | if let Node::Crate = entry.node { | |
558 | None | |
559 | } else { | |
560 | Some(entry.node) | |
561 | } | |
562 | }); | |
7453a54e SL |
563 | if result.is_some() { |
564 | self.read(id); | |
565 | } | |
566 | result | |
1a4d82fc JJ |
567 | } |
568 | ||
c1a9b12d | 569 | /// Similar to get_parent, returns the parent node id or id if there is no |
3b2f2976 XL |
570 | /// parent. Note that the parent may be CRATE_NODE_ID, which is not itself |
571 | /// present in the map -- so passing the return value of get_parent_node to | |
572 | /// get may actually panic. | |
c1a9b12d SL |
573 | /// This function returns the immediate parent in the AST, whereas get_parent |
574 | /// returns the enclosing item. Note that this might not be the actual parent | |
575 | /// node in the AST - some kinds of nodes are not in the map and these will | |
576 | /// never appear as the parent_node. So you can always walk the parent_nodes | |
577 | /// from a node to the root of the ast (unless you get the same id back here | |
578 | /// that can happen if the id is not in the map itself or is just weird). | |
579 | pub fn get_parent_node(&self, id: NodeId) -> NodeId { | |
abe05a73 XL |
580 | if self.dep_graph.is_fully_enabled() { |
581 | let hir_id_owner = self.node_to_hir_id(id).owner; | |
582 | let def_path_hash = self.definitions.def_path_hash(hir_id_owner); | |
583 | self.dep_graph.read(def_path_hash.to_dep_node(DepKind::HirBody)); | |
584 | } | |
585 | ||
c1a9b12d SL |
586 | self.find_entry(id).and_then(|x| x.parent_node()).unwrap_or(id) |
587 | } | |
588 | ||
b039eaaf SL |
589 | /// Check if the node is an argument. An argument is a local variable whose |
590 | /// immediate parent is an item or a closure. | |
591 | pub fn is_argument(&self, id: NodeId) -> bool { | |
592 | match self.find(id) { | |
b7449926 | 593 | Some(Node::Binding(_)) => (), |
b039eaaf SL |
594 | _ => return false, |
595 | } | |
596 | match self.find(self.get_parent_node(id)) { | |
b7449926 XL |
597 | Some(Node::Item(_)) | |
598 | Some(Node::TraitItem(_)) | | |
599 | Some(Node::ImplItem(_)) => true, | |
600 | Some(Node::Expr(e)) => { | |
b039eaaf | 601 | match e.node { |
8faf50e0 | 602 | ExprKind::Closure(..) => true, |
b039eaaf SL |
603 | _ => false, |
604 | } | |
605 | } | |
606 | _ => false, | |
607 | } | |
608 | } | |
609 | ||
c1a9b12d SL |
610 | /// If there is some error when walking the parents (e.g., a node does not |
611 | /// have a parent in the map or a node can't be found), then we return the | |
612 | /// last good node id we found. Note that reaching the crate root (id == 0), | |
613 | /// is not an error, since items in the crate module have the crate root as | |
614 | /// parent. | |
041b39d2 XL |
615 | fn walk_parent_nodes<F, F2>(&self, |
616 | start_id: NodeId, | |
617 | found: F, | |
618 | bail_early: F2) | |
619 | -> Result<NodeId, NodeId> | |
620 | where F: Fn(&Node<'hir>) -> bool, F2: Fn(&Node<'hir>) -> bool | |
c1a9b12d SL |
621 | { |
622 | let mut id = start_id; | |
623 | loop { | |
624 | let parent_node = self.get_parent_node(id); | |
9e0c209e SL |
625 | if parent_node == CRATE_NODE_ID { |
626 | return Ok(CRATE_NODE_ID); | |
c1a9b12d SL |
627 | } |
628 | if parent_node == id { | |
629 | return Err(id); | |
630 | } | |
631 | ||
b7449926 XL |
632 | if let Some(entry) = self.find_entry(parent_node) { |
633 | if let Node::Crate = entry.node { | |
634 | return Err(id); | |
c1a9b12d | 635 | } |
b7449926 XL |
636 | if found(&entry.node) { |
637 | return Ok(parent_node); | |
638 | } else if bail_early(&entry.node) { | |
c1a9b12d SL |
639 | return Err(parent_node); |
640 | } | |
b7449926 XL |
641 | id = parent_node; |
642 | } else { | |
643 | return Err(id); | |
c1a9b12d | 644 | } |
c1a9b12d SL |
645 | } |
646 | } | |
647 | ||
041b39d2 | 648 | /// Retrieve the NodeId for `id`'s enclosing method, unless there's a |
3b2f2976 | 649 | /// `while` or `loop` before reaching it, as block tail returns are not |
041b39d2 XL |
650 | /// available in them. |
651 | /// | |
652 | /// ``` | |
653 | /// fn foo(x: usize) -> bool { | |
654 | /// if x == 1 { | |
655 | /// true // `get_return_block` gets passed the `id` corresponding | |
656 | /// } else { // to this, it will return `foo`'s `NodeId`. | |
657 | /// false | |
658 | /// } | |
659 | /// } | |
660 | /// ``` | |
661 | /// | |
662 | /// ``` | |
663 | /// fn foo(x: usize) -> bool { | |
664 | /// loop { | |
665 | /// true // `get_return_block` gets passed the `id` corresponding | |
666 | /// } // to this, it will return `None`. | |
667 | /// false | |
668 | /// } | |
669 | /// ``` | |
670 | pub fn get_return_block(&self, id: NodeId) -> Option<NodeId> { | |
671 | let match_fn = |node: &Node| { | |
672 | match *node { | |
b7449926 XL |
673 | Node::Item(_) | |
674 | Node::ForeignItem(_) | | |
675 | Node::TraitItem(_) | | |
676 | Node::ImplItem(_) => true, | |
041b39d2 XL |
677 | _ => false, |
678 | } | |
679 | }; | |
680 | let match_non_returning_block = |node: &Node| { | |
681 | match *node { | |
b7449926 | 682 | Node::Expr(ref expr) => { |
041b39d2 | 683 | match expr.node { |
8faf50e0 | 684 | ExprKind::While(..) | ExprKind::Loop(..) => true, |
041b39d2 XL |
685 | _ => false, |
686 | } | |
687 | } | |
688 | _ => false, | |
689 | } | |
690 | }; | |
691 | ||
b7449926 | 692 | self.walk_parent_nodes(id, match_fn, match_non_returning_block).ok() |
041b39d2 XL |
693 | } |
694 | ||
c1a9b12d SL |
695 | /// Retrieve the NodeId for `id`'s parent item, or `id` itself if no |
696 | /// parent item is in this map. The "parent item" is the closest parent node | |
94b46f34 | 697 | /// in the HIR which is recorded by the map and is an item, either an item |
c1a9b12d | 698 | /// in a module, trait, or impl. |
1a4d82fc | 699 | pub fn get_parent(&self, id: NodeId) -> NodeId { |
c1a9b12d | 700 | match self.walk_parent_nodes(id, |node| match *node { |
b7449926 XL |
701 | Node::Item(_) | |
702 | Node::ForeignItem(_) | | |
703 | Node::TraitItem(_) | | |
704 | Node::ImplItem(_) => true, | |
c1a9b12d | 705 | _ => false, |
041b39d2 | 706 | }, |_| false) { |
c1a9b12d SL |
707 | Ok(id) => id, |
708 | Err(id) => id, | |
709 | } | |
710 | } | |
711 | ||
54a0048b SL |
712 | /// Returns the NodeId of `id`'s nearest module parent, or `id` itself if no |
713 | /// module parent is in this map. | |
7cac9316 XL |
714 | pub fn get_module_parent(&self, id: NodeId) -> DefId { |
715 | let id = match self.walk_parent_nodes(id, |node| match *node { | |
b7449926 | 716 | Node::Item(&Item { node: ItemKind::Mod(_), .. }) => true, |
54a0048b | 717 | _ => false, |
041b39d2 | 718 | }, |_| false) { |
54a0048b SL |
719 | Ok(id) => id, |
720 | Err(id) => id, | |
7cac9316 XL |
721 | }; |
722 | self.local_def_id(id) | |
54a0048b SL |
723 | } |
724 | ||
c1a9b12d SL |
725 | /// Returns the nearest enclosing scope. A scope is an item or block. |
726 | /// FIXME it is not clear to me that all items qualify as scopes - statics | |
3b2f2976 | 727 | /// and associated types probably shouldn't, for example. Behavior in this |
c1a9b12d SL |
728 | /// regard should be expected to be highly unstable. |
729 | pub fn get_enclosing_scope(&self, id: NodeId) -> Option<NodeId> { | |
b7449926 XL |
730 | self.walk_parent_nodes(id, |node| match *node { |
731 | Node::Item(_) | | |
732 | Node::ForeignItem(_) | | |
733 | Node::TraitItem(_) | | |
734 | Node::ImplItem(_) | | |
735 | Node::Block(_) => true, | |
c1a9b12d | 736 | _ => false, |
b7449926 | 737 | }, |_| false).ok() |
1a4d82fc JJ |
738 | } |
739 | ||
740 | pub fn get_parent_did(&self, id: NodeId) -> DefId { | |
32a655c1 | 741 | self.local_def_id(self.get_parent(id)) |
1a4d82fc JJ |
742 | } |
743 | ||
7453a54e | 744 | pub fn get_foreign_abi(&self, id: NodeId) -> Abi { |
1a4d82fc | 745 | let parent = self.get_parent(id); |
b7449926 XL |
746 | if let Some(entry) = self.find_entry(parent) { |
747 | if let Entry { | |
748 | node: Node::Item(Item { node: ItemKind::ForeignMod(ref nm), .. }), .. } = entry | |
749 | { | |
7453a54e | 750 | self.read(id); // reveals some of the content of a node |
b7449926 | 751 | return nm.abi; |
7453a54e | 752 | } |
1a4d82fc | 753 | } |
b7449926 | 754 | bug!("expected foreign mod or inlined parent, found {}", self.node_to_string(parent)) |
1a4d82fc JJ |
755 | } |
756 | ||
32a655c1 | 757 | pub fn expect_item(&self, id: NodeId) -> &'hir Item { |
7453a54e | 758 | match self.find(id) { // read recorded by `find` |
b7449926 | 759 | Some(Node::Item(item)) => item, |
54a0048b | 760 | _ => bug!("expected item, found {}", self.node_to_string(id)) |
1a4d82fc JJ |
761 | } |
762 | } | |
763 | ||
32a655c1 | 764 | pub fn expect_impl_item(&self, id: NodeId) -> &'hir ImplItem { |
9e0c209e | 765 | match self.find(id) { |
b7449926 | 766 | Some(Node::ImplItem(item)) => item, |
9e0c209e SL |
767 | _ => bug!("expected impl item, found {}", self.node_to_string(id)) |
768 | } | |
769 | } | |
770 | ||
32a655c1 | 771 | pub fn expect_trait_item(&self, id: NodeId) -> &'hir TraitItem { |
c1a9b12d | 772 | match self.find(id) { |
b7449926 | 773 | Some(Node::TraitItem(item)) => item, |
54a0048b | 774 | _ => bug!("expected trait item, found {}", self.node_to_string(id)) |
c1a9b12d SL |
775 | } |
776 | } | |
777 | ||
32a655c1 | 778 | pub fn expect_variant_data(&self, id: NodeId) -> &'hir VariantData { |
1a4d82fc | 779 | match self.find(id) { |
b7449926 | 780 | Some(Node::Item(i)) => { |
1a4d82fc | 781 | match i.node { |
8faf50e0 XL |
782 | ItemKind::Struct(ref struct_def, _) | |
783 | ItemKind::Union(ref struct_def, _) => struct_def, | |
b7449926 | 784 | _ => bug!("struct ID bound to non-struct {}", self.node_to_string(id)) |
1a4d82fc JJ |
785 | } |
786 | } | |
b7449926 XL |
787 | Some(Node::StructCtor(data)) => data, |
788 | Some(Node::Variant(variant)) => &variant.node.data, | |
789 | _ => bug!("expected struct or variant, found {}", self.node_to_string(id)) | |
1a4d82fc JJ |
790 | } |
791 | } | |
792 | ||
32a655c1 | 793 | pub fn expect_variant(&self, id: NodeId) -> &'hir Variant { |
1a4d82fc | 794 | match self.find(id) { |
b7449926 | 795 | Some(Node::Variant(variant)) => variant, |
54a0048b | 796 | _ => bug!("expected variant, found {}", self.node_to_string(id)), |
1a4d82fc JJ |
797 | } |
798 | } | |
799 | ||
32a655c1 | 800 | pub fn expect_foreign_item(&self, id: NodeId) -> &'hir ForeignItem { |
1a4d82fc | 801 | match self.find(id) { |
b7449926 | 802 | Some(Node::ForeignItem(item)) => item, |
54a0048b | 803 | _ => bug!("expected foreign item, found {}", self.node_to_string(id)) |
1a4d82fc JJ |
804 | } |
805 | } | |
806 | ||
32a655c1 | 807 | pub fn expect_expr(&self, id: NodeId) -> &'hir Expr { |
7453a54e | 808 | match self.find(id) { // read recorded by find |
b7449926 | 809 | Some(Node::Expr(expr)) => expr, |
54a0048b | 810 | _ => bug!("expected expr, found {}", self.node_to_string(id)) |
1a4d82fc JJ |
811 | } |
812 | } | |
813 | ||
54a0048b SL |
814 | /// Returns the name associated with the given NodeId's AST. |
815 | pub fn name(&self, id: NodeId) -> Name { | |
816 | match self.get(id) { | |
b7449926 XL |
817 | Node::Item(i) => i.name, |
818 | Node::ForeignItem(i) => i.name, | |
819 | Node::ImplItem(ii) => ii.ident.name, | |
820 | Node::TraitItem(ti) => ti.ident.name, | |
821 | Node::Variant(v) => v.node.name, | |
822 | Node::Field(f) => f.ident.name, | |
823 | Node::Lifetime(lt) => lt.name.ident().name, | |
824 | Node::GenericParam(param) => param.name.ident().name, | |
825 | Node::Binding(&Pat { node: PatKind::Binding(_,_,l,_), .. }) => l.name, | |
826 | Node::StructCtor(_) => self.name(self.get_parent(id)), | |
54a0048b | 827 | _ => bug!("no name for {}", self.node_to_string(id)) |
1a4d82fc JJ |
828 | } |
829 | } | |
830 | ||
b039eaaf | 831 | /// Given a node ID, get a list of attributes associated with the AST |
c34b1796 | 832 | /// corresponding to the Node ID |
32a655c1 | 833 | pub fn attrs(&self, id: NodeId) -> &'hir [ast::Attribute] { |
7453a54e | 834 | self.read(id); // reveals attributes on the node |
c34b1796 | 835 | let attrs = match self.find(id) { |
b7449926 XL |
836 | Some(Node::Item(i)) => Some(&i.attrs[..]), |
837 | Some(Node::ForeignItem(fi)) => Some(&fi.attrs[..]), | |
838 | Some(Node::TraitItem(ref ti)) => Some(&ti.attrs[..]), | |
839 | Some(Node::ImplItem(ref ii)) => Some(&ii.attrs[..]), | |
840 | Some(Node::Variant(ref v)) => Some(&v.node.attrs[..]), | |
841 | Some(Node::Field(ref f)) => Some(&f.attrs[..]), | |
842 | Some(Node::Expr(ref e)) => Some(&*e.attrs), | |
843 | Some(Node::Stmt(ref s)) => Some(s.node.attrs()), | |
844 | Some(Node::GenericParam(param)) => Some(¶m.attrs[..]), | |
1a4d82fc JJ |
845 | // unit/tuple structs take the attributes straight from |
846 | // the struct definition. | |
b7449926 | 847 | Some(Node::StructCtor(_)) => return self.attrs(self.get_parent(id)), |
1a4d82fc JJ |
848 | _ => None |
849 | }; | |
c34b1796 | 850 | attrs.unwrap_or(&[]) |
1a4d82fc JJ |
851 | } |
852 | ||
853 | /// Returns an iterator that yields the node id's with paths that | |
854 | /// match `parts`. (Requires `parts` is non-empty.) | |
855 | /// | |
856 | /// For example, if given `parts` equal to `["bar", "quux"]`, then | |
857 | /// the iterator will produce node id's for items with paths | |
858 | /// such as `foo::bar::quux`, `bar::quux`, `other::bar::quux`, and | |
859 | /// any other such items it can find in the map. | |
860 | pub fn nodes_matching_suffix<'a>(&'a self, parts: &'a [String]) | |
32a655c1 | 861 | -> NodesMatchingSuffix<'a, 'hir> { |
1a4d82fc JJ |
862 | NodesMatchingSuffix { |
863 | map: self, | |
864 | item_name: parts.last().unwrap(), | |
85aaf69f | 865 | in_which: &parts[..parts.len() - 1], |
9e0c209e | 866 | idx: CRATE_NODE_ID, |
1a4d82fc JJ |
867 | } |
868 | } | |
869 | ||
1a4d82fc | 870 | pub fn span(&self, id: NodeId) -> Span { |
7453a54e | 871 | self.read(id); // reveals span from node |
b7449926 XL |
872 | match self.find_entry(id).map(|entry| entry.node) { |
873 | Some(Node::Item(item)) => item.span, | |
874 | Some(Node::ForeignItem(foreign_item)) => foreign_item.span, | |
875 | Some(Node::TraitItem(trait_method)) => trait_method.span, | |
876 | Some(Node::ImplItem(impl_item)) => impl_item.span, | |
877 | Some(Node::Variant(variant)) => variant.span, | |
878 | Some(Node::Field(field)) => field.span, | |
879 | Some(Node::AnonConst(constant)) => self.body(constant.body).value.span, | |
880 | Some(Node::Expr(expr)) => expr.span, | |
881 | Some(Node::Stmt(stmt)) => stmt.span, | |
882 | Some(Node::Ty(ty)) => ty.span, | |
883 | Some(Node::TraitRef(tr)) => tr.path.span, | |
884 | Some(Node::Binding(pat)) => pat.span, | |
885 | Some(Node::Pat(pat)) => pat.span, | |
886 | Some(Node::Block(block)) => block.span, | |
887 | Some(Node::StructCtor(_)) => self.expect_item(self.get_parent(id)).span, | |
888 | Some(Node::Lifetime(lifetime)) => lifetime.span, | |
889 | Some(Node::GenericParam(param)) => param.span, | |
890 | Some(Node::Visibility(&Spanned { | |
8faf50e0 XL |
891 | node: VisibilityKind::Restricted { ref path, .. }, .. |
892 | })) => path.span, | |
b7449926 XL |
893 | Some(Node::Visibility(v)) => bug!("unexpected Visibility {:?}", v), |
894 | Some(Node::Local(local)) => local.span, | |
895 | Some(Node::MacroDef(macro_def)) => macro_def.span, | |
896 | Some(Node::Crate) => self.forest.krate.span, | |
897 | None => bug!("hir::map::Map::span: id not in map: {:?}", id), | |
476ff2be | 898 | } |
1a4d82fc JJ |
899 | } |
900 | ||
b039eaaf SL |
901 | pub fn span_if_local(&self, id: DefId) -> Option<Span> { |
902 | self.as_local_node_id(id).map(|id| self.span(id)) | |
903 | } | |
904 | ||
1a4d82fc JJ |
905 | pub fn node_to_string(&self, id: NodeId) -> String { |
906 | node_id_to_string(self, id, true) | |
907 | } | |
908 | ||
909 | pub fn node_to_user_string(&self, id: NodeId) -> String { | |
910 | node_id_to_string(self, id, false) | |
911 | } | |
32a655c1 SL |
912 | |
913 | pub fn node_to_pretty_string(&self, id: NodeId) -> String { | |
914 | print::to_string(self, |s| s.print_node(self.get(id))) | |
915 | } | |
1a4d82fc JJ |
916 | } |
917 | ||
32a655c1 SL |
918 | pub struct NodesMatchingSuffix<'a, 'hir:'a> { |
919 | map: &'a Map<'hir>, | |
1a4d82fc JJ |
920 | item_name: &'a String, |
921 | in_which: &'a [String], | |
922 | idx: NodeId, | |
923 | } | |
924 | ||
32a655c1 | 925 | impl<'a, 'hir> NodesMatchingSuffix<'a, 'hir> { |
1a4d82fc JJ |
926 | /// Returns true only if some suffix of the module path for parent |
927 | /// matches `self.in_which`. | |
928 | /// | |
929 | /// In other words: let `[x_0,x_1,...,x_k]` be `self.in_which`; | |
930 | /// returns true if parent's path ends with the suffix | |
931 | /// `x_0::x_1::...::x_k`. | |
932 | fn suffix_matches(&self, parent: NodeId) -> bool { | |
933 | let mut cursor = parent; | |
934 | for part in self.in_which.iter().rev() { | |
935 | let (mod_id, mod_name) = match find_first_mod_parent(self.map, cursor) { | |
936 | None => return false, | |
937 | Some((node_id, name)) => (node_id, name), | |
938 | }; | |
476ff2be | 939 | if mod_name != &**part { |
1a4d82fc JJ |
940 | return false; |
941 | } | |
942 | cursor = self.map.get_parent(mod_id); | |
943 | } | |
944 | return true; | |
945 | ||
946 | // Finds the first mod in parent chain for `id`, along with | |
947 | // that mod's name. | |
948 | // | |
949 | // If `id` itself is a mod named `m` with parent `p`, then | |
950 | // returns `Some(id, m, p)`. If `id` has no mod in its parent | |
951 | // chain, then returns `None`. | |
952 | fn find_first_mod_parent<'a>(map: &'a Map, mut id: NodeId) -> Option<(NodeId, Name)> { | |
953 | loop { | |
b7449926 XL |
954 | if let Node::Item(item) = map.find(id)? { |
955 | if item_is_mod(&item) { | |
956 | return Some((id, item.name)) | |
957 | } | |
1a4d82fc JJ |
958 | } |
959 | let parent = map.get_parent(id); | |
960 | if parent == id { return None } | |
961 | id = parent; | |
962 | } | |
963 | ||
964 | fn item_is_mod(item: &Item) -> bool { | |
965 | match item.node { | |
8faf50e0 | 966 | ItemKind::Mod(_) => true, |
1a4d82fc JJ |
967 | _ => false, |
968 | } | |
969 | } | |
970 | } | |
971 | } | |
972 | ||
973 | // We are looking at some node `n` with a given name and parent | |
974 | // id; do their names match what I am seeking? | |
975 | fn matches_names(&self, parent_of_n: NodeId, name: Name) -> bool { | |
476ff2be | 976 | name == &**self.item_name && self.suffix_matches(parent_of_n) |
1a4d82fc JJ |
977 | } |
978 | } | |
979 | ||
32a655c1 | 980 | impl<'a, 'hir> Iterator for NodesMatchingSuffix<'a, 'hir> { |
1a4d82fc JJ |
981 | type Item = NodeId; |
982 | ||
983 | fn next(&mut self) -> Option<NodeId> { | |
984 | loop { | |
985 | let idx = self.idx; | |
9e0c209e | 986 | if idx.as_usize() >= self.map.entry_count() { |
1a4d82fc JJ |
987 | return None; |
988 | } | |
9e0c209e | 989 | self.idx = NodeId::from_u32(self.idx.as_u32() + 1); |
b7449926 XL |
990 | let name = match self.map.find_entry(idx).map(|entry| entry.node) { |
991 | Some(Node::Item(n)) => n.name(), | |
992 | Some(Node::ForeignItem(n)) => n.name(), | |
993 | Some(Node::TraitItem(n)) => n.name(), | |
994 | Some(Node::ImplItem(n)) => n.name(), | |
995 | Some(Node::Variant(n)) => n.name(), | |
996 | Some(Node::Field(n)) => n.name(), | |
1a4d82fc JJ |
997 | _ => continue, |
998 | }; | |
c1a9b12d | 999 | if self.matches_names(self.map.get_parent(idx), name) { |
1a4d82fc JJ |
1000 | return Some(idx) |
1001 | } | |
1002 | } | |
1003 | } | |
1004 | } | |
1005 | ||
1006 | trait Named { | |
1007 | fn name(&self) -> Name; | |
1008 | } | |
1009 | ||
1010 | impl<T:Named> Named for Spanned<T> { fn name(&self) -> Name { self.node.name() } } | |
1011 | ||
b039eaaf SL |
1012 | impl Named for Item { fn name(&self) -> Name { self.name } } |
1013 | impl Named for ForeignItem { fn name(&self) -> Name { self.name } } | |
8faf50e0 | 1014 | impl Named for VariantKind { fn name(&self) -> Name { self.name } } |
94b46f34 | 1015 | impl Named for StructField { fn name(&self) -> Name { self.ident.name } } |
8faf50e0 XL |
1016 | impl Named for TraitItem { fn name(&self) -> Name { self.ident.name } } |
1017 | impl Named for ImplItem { fn name(&self) -> Name { self.ident.name } } | |
1a4d82fc | 1018 | |
ea8adc8c | 1019 | pub fn map_crate<'hir>(sess: &::session::Session, |
0531ce1d | 1020 | cstore: &dyn CrateStore, |
ea8adc8c XL |
1021 | forest: &'hir mut Forest, |
1022 | definitions: &'hir Definitions) | |
32a655c1 | 1023 | -> Map<'hir> { |
ff7c6d11 | 1024 | let (map, crate_hash) = { |
ea8adc8c XL |
1025 | let hcx = ::ich::StableHashingContext::new(sess, &forest.krate, definitions, cstore); |
1026 | ||
3b2f2976 XL |
1027 | let mut collector = NodeCollector::root(&forest.krate, |
1028 | &forest.dep_graph, | |
ea8adc8c XL |
1029 | &definitions, |
1030 | hcx); | |
3b2f2976 | 1031 | intravisit::walk_crate(&mut collector, &forest.krate); |
ea8adc8c | 1032 | |
abe05a73 | 1033 | let crate_disambiguator = sess.local_crate_disambiguator(); |
ff7c6d11 XL |
1034 | let cmdline_args = sess.opts.dep_tracking_hash(); |
1035 | collector.finalize_and_compute_crate_hash(crate_disambiguator, | |
1036 | cstore, | |
b7449926 | 1037 | sess.source_map(), |
ff7c6d11 | 1038 | cmdline_args) |
3b2f2976 | 1039 | }; |
1a4d82fc | 1040 | |
ff7c6d11 | 1041 | if log_enabled!(::log::Level::Debug) { |
1a4d82fc JJ |
1042 | // This only makes sense for ordered stores; note the |
1043 | // enumerate to count the number of entries. | |
b7449926 XL |
1044 | let (entries_less_1, _) = map.iter().filter_map(|x| *x).enumerate().last() |
1045 | .expect("AST map was empty after folding?"); | |
1a4d82fc JJ |
1046 | |
1047 | let entries = entries_less_1 + 1; | |
1048 | let vector_length = map.len(); | |
1049 | debug!("The AST map has {} entries with a maximum of {}: occupancy {:.1}%", | |
1050 | entries, vector_length, (entries as f64 / vector_length as f64) * 100.); | |
1051 | } | |
1052 | ||
ea8adc8c XL |
1053 | // Build the reverse mapping of `node_to_hir_id`. |
1054 | let hir_to_node_id = definitions.node_to_hir_id.iter_enumerated() | |
1055 | .map(|(node_id, &hir_id)| (hir_id, node_id)).collect(); | |
1056 | ||
cc61c64b | 1057 | let map = Map { |
041b39d2 | 1058 | forest, |
7453a54e | 1059 | dep_graph: forest.dep_graph.clone(), |
ff7c6d11 | 1060 | crate_hash, |
041b39d2 | 1061 | map, |
ea8adc8c | 1062 | hir_to_node_id, |
041b39d2 | 1063 | definitions, |
cc61c64b XL |
1064 | }; |
1065 | ||
1066 | hir_id_validator::check_crate(&map); | |
1067 | ||
1068 | map | |
1a4d82fc JJ |
1069 | } |
1070 | ||
32a655c1 SL |
1071 | /// Identical to the `PpAnn` implementation for `hir::Crate`, |
1072 | /// except it avoids creating a dependency on the whole crate. | |
1073 | impl<'hir> print::PpAnn for Map<'hir> { | |
1074 | fn nested(&self, state: &mut print::State, nested: print::Nested) -> io::Result<()> { | |
1075 | match nested { | |
1076 | Nested::Item(id) => state.print_item(self.expect_item(id.id)), | |
1077 | Nested::TraitItem(id) => state.print_trait_item(self.trait_item(id)), | |
1078 | Nested::ImplItem(id) => state.print_impl_item(self.impl_item(id)), | |
1079 | Nested::Body(id) => state.print_expr(&self.body(id).value), | |
1080 | Nested::BodyArgPat(id, i) => state.print_pat(&self.body(id).arguments[i].pat) | |
1081 | } | |
1082 | } | |
1a4d82fc JJ |
1083 | } |
1084 | ||
32a655c1 SL |
1085 | impl<'a> print::State<'a> { |
1086 | pub fn print_node(&mut self, node: Node) -> io::Result<()> { | |
1087 | match node { | |
b7449926 XL |
1088 | Node::Item(a) => self.print_item(&a), |
1089 | Node::ForeignItem(a) => self.print_foreign_item(&a), | |
1090 | Node::TraitItem(a) => self.print_trait_item(a), | |
1091 | Node::ImplItem(a) => self.print_impl_item(a), | |
1092 | Node::Variant(a) => self.print_variant(&a), | |
1093 | Node::AnonConst(a) => self.print_anon_const(&a), | |
1094 | Node::Expr(a) => self.print_expr(&a), | |
1095 | Node::Stmt(a) => self.print_stmt(&a), | |
1096 | Node::Ty(a) => self.print_type(&a), | |
1097 | Node::TraitRef(a) => self.print_trait_ref(&a), | |
1098 | Node::Binding(a) | | |
1099 | Node::Pat(a) => self.print_pat(&a), | |
1100 | Node::Block(a) => { | |
32a655c1 SL |
1101 | use syntax::print::pprust::PrintState; |
1102 | ||
1103 | // containing cbox, will be closed by print-block at } | |
1104 | self.cbox(print::indent_unit)?; | |
1105 | // head-ibox, will be closed by print-block after { | |
1106 | self.ibox(0)?; | |
1107 | self.print_block(&a) | |
1108 | } | |
b7449926 XL |
1109 | Node::Lifetime(a) => self.print_lifetime(&a), |
1110 | Node::Visibility(a) => self.print_visibility(&a), | |
1111 | Node::GenericParam(_) => bug!("cannot print Node::GenericParam"), | |
1112 | Node::Field(_) => bug!("cannot print StructField"), | |
1a4d82fc | 1113 | // these cases do not carry enough information in the |
32a655c1 | 1114 | // hir_map to reconstruct their full structure for pretty |
1a4d82fc | 1115 | // printing. |
b7449926 XL |
1116 | Node::StructCtor(_) => bug!("cannot print isolated StructCtor"), |
1117 | Node::Local(a) => self.print_local_decl(&a), | |
1118 | Node::MacroDef(_) => bug!("cannot print MacroDef"), | |
1119 | Node::Crate => bug!("cannot print Crate"), | |
1a4d82fc JJ |
1120 | } |
1121 | } | |
1122 | } | |
1123 | ||
1124 | fn node_id_to_string(map: &Map, id: NodeId, include_id: bool) -> String { | |
1125 | let id_str = format!(" (id={})", id); | |
85aaf69f | 1126 | let id_str = if include_id { &id_str[..] } else { "" }; |
1a4d82fc | 1127 | |
54a0048b SL |
1128 | let path_str = || { |
1129 | // This functionality is used for debugging, try to use TyCtxt to get | |
1130 | // the user-friendly path, otherwise fall back to stringifying DefPath. | |
1131 | ::ty::tls::with_opt(|tcx| { | |
1132 | if let Some(tcx) = tcx { | |
1133 | tcx.node_path_str(id) | |
1134 | } else if let Some(path) = map.def_path_from_id(id) { | |
1135 | path.data.into_iter().map(|elem| { | |
1136 | elem.data.to_string() | |
1137 | }).collect::<Vec<_>>().join("::") | |
1138 | } else { | |
1139 | String::from("<missing path>") | |
1140 | } | |
1141 | }) | |
1142 | }; | |
1143 | ||
1a4d82fc | 1144 | match map.find(id) { |
b7449926 | 1145 | Some(Node::Item(item)) => { |
1a4d82fc | 1146 | let item_str = match item.node { |
8faf50e0 XL |
1147 | ItemKind::ExternCrate(..) => "extern crate", |
1148 | ItemKind::Use(..) => "use", | |
1149 | ItemKind::Static(..) => "static", | |
1150 | ItemKind::Const(..) => "const", | |
1151 | ItemKind::Fn(..) => "fn", | |
1152 | ItemKind::Mod(..) => "mod", | |
1153 | ItemKind::ForeignMod(..) => "foreign mod", | |
1154 | ItemKind::GlobalAsm(..) => "global asm", | |
1155 | ItemKind::Ty(..) => "ty", | |
1156 | ItemKind::Existential(..) => "existential type", | |
1157 | ItemKind::Enum(..) => "enum", | |
1158 | ItemKind::Struct(..) => "struct", | |
1159 | ItemKind::Union(..) => "union", | |
1160 | ItemKind::Trait(..) => "trait", | |
1161 | ItemKind::TraitAlias(..) => "trait alias", | |
1162 | ItemKind::Impl(..) => "impl", | |
1a4d82fc | 1163 | }; |
54a0048b | 1164 | format!("{} {}{}", item_str, path_str(), id_str) |
1a4d82fc | 1165 | } |
b7449926 | 1166 | Some(Node::ForeignItem(_)) => { |
54a0048b | 1167 | format!("foreign item {}{}", path_str(), id_str) |
1a4d82fc | 1168 | } |
b7449926 | 1169 | Some(Node::ImplItem(ii)) => { |
c34b1796 | 1170 | match ii.node { |
92a42be0 | 1171 | ImplItemKind::Const(..) => { |
8faf50e0 | 1172 | format!("assoc const {} in {}{}", ii.ident, path_str(), id_str) |
d9579d0f | 1173 | } |
92a42be0 | 1174 | ImplItemKind::Method(..) => { |
8faf50e0 | 1175 | format!("method {} in {}{}", ii.ident, path_str(), id_str) |
1a4d82fc | 1176 | } |
92a42be0 | 1177 | ImplItemKind::Type(_) => { |
8faf50e0 XL |
1178 | format!("assoc type {} in {}{}", ii.ident, path_str(), id_str) |
1179 | } | |
1180 | ImplItemKind::Existential(_) => { | |
1181 | format!("assoc existential type {} in {}{}", ii.ident, path_str(), id_str) | |
1a4d82fc JJ |
1182 | } |
1183 | } | |
1184 | } | |
b7449926 | 1185 | Some(Node::TraitItem(ti)) => { |
c34b1796 | 1186 | let kind = match ti.node { |
32a655c1 SL |
1187 | TraitItemKind::Const(..) => "assoc constant", |
1188 | TraitItemKind::Method(..) => "trait method", | |
1189 | TraitItemKind::Type(..) => "assoc type", | |
c34b1796 AL |
1190 | }; |
1191 | ||
8faf50e0 | 1192 | format!("{} {} in {}{}", kind, ti.ident, path_str(), id_str) |
c34b1796 | 1193 | } |
b7449926 | 1194 | Some(Node::Variant(ref variant)) => { |
1a4d82fc | 1195 | format!("variant {} in {}{}", |
c1a9b12d | 1196 | variant.node.name, |
54a0048b | 1197 | path_str(), id_str) |
1a4d82fc | 1198 | } |
b7449926 | 1199 | Some(Node::Field(ref field)) => { |
476ff2be | 1200 | format!("field {} in {}{}", |
94b46f34 | 1201 | field.ident, |
476ff2be SL |
1202 | path_str(), id_str) |
1203 | } | |
b7449926 | 1204 | Some(Node::AnonConst(_)) => { |
94b46f34 XL |
1205 | format!("const {}{}", map.node_to_pretty_string(id), id_str) |
1206 | } | |
b7449926 | 1207 | Some(Node::Expr(_)) => { |
32a655c1 | 1208 | format!("expr {}{}", map.node_to_pretty_string(id), id_str) |
1a4d82fc | 1209 | } |
b7449926 | 1210 | Some(Node::Stmt(_)) => { |
32a655c1 | 1211 | format!("stmt {}{}", map.node_to_pretty_string(id), id_str) |
1a4d82fc | 1212 | } |
b7449926 | 1213 | Some(Node::Ty(_)) => { |
32a655c1 | 1214 | format!("type {}{}", map.node_to_pretty_string(id), id_str) |
5bcae85e | 1215 | } |
b7449926 | 1216 | Some(Node::TraitRef(_)) => { |
32a655c1 | 1217 | format!("trait_ref {}{}", map.node_to_pretty_string(id), id_str) |
476ff2be | 1218 | } |
b7449926 | 1219 | Some(Node::Binding(_)) => { |
32a655c1 | 1220 | format!("local {}{}", map.node_to_pretty_string(id), id_str) |
1a4d82fc | 1221 | } |
b7449926 | 1222 | Some(Node::Pat(_)) => { |
32a655c1 | 1223 | format!("pat {}{}", map.node_to_pretty_string(id), id_str) |
1a4d82fc | 1224 | } |
b7449926 | 1225 | Some(Node::Block(_)) => { |
32a655c1 | 1226 | format!("block {}{}", map.node_to_pretty_string(id), id_str) |
1a4d82fc | 1227 | } |
b7449926 | 1228 | Some(Node::Local(_)) => { |
3b2f2976 XL |
1229 | format!("local {}{}", map.node_to_pretty_string(id), id_str) |
1230 | } | |
b7449926 | 1231 | Some(Node::StructCtor(_)) => { |
54a0048b | 1232 | format!("struct_ctor {}{}", path_str(), id_str) |
1a4d82fc | 1233 | } |
b7449926 | 1234 | Some(Node::Lifetime(_)) => { |
32a655c1 | 1235 | format!("lifetime {}{}", map.node_to_pretty_string(id), id_str) |
1a4d82fc | 1236 | } |
b7449926 | 1237 | Some(Node::GenericParam(ref param)) => { |
8faf50e0 | 1238 | format!("generic_param {:?}{}", param, id_str) |
c1a9b12d | 1239 | } |
b7449926 | 1240 | Some(Node::Visibility(ref vis)) => { |
476ff2be SL |
1241 | format!("visibility {:?}{}", vis, id_str) |
1242 | } | |
b7449926 | 1243 | Some(Node::MacroDef(_)) => { |
ea8adc8c XL |
1244 | format!("macro {}{}", path_str(), id_str) |
1245 | } | |
b7449926 XL |
1246 | Some(Node::Crate) => format!("root_crate"), |
1247 | None => format!("unknown node{}", id_str), | |
1a4d82fc JJ |
1248 | } |
1249 | } | |
0531ce1d XL |
1250 | |
1251 | pub fn describe_def(tcx: TyCtxt, def_id: DefId) -> Option<Def> { | |
1252 | if let Some(node_id) = tcx.hir.as_local_node_id(def_id) { | |
1253 | tcx.hir.describe_def(node_id) | |
1254 | } else { | |
1255 | bug!("Calling local describe_def query provider for upstream DefId: {:?}", | |
1256 | def_id) | |
1257 | } | |
1258 | } |