]>
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 | ||
11 | pub use self::Node::*; | |
12 | pub use self::PathElem::*; | |
13 | use self::MapEntry::*; | |
b039eaaf SL |
14 | use self::collector::NodeCollector; |
15 | pub use self::definitions::{Definitions, DefKey, DefPath, DefPathData, DisambiguatedDefPathData}; | |
1a4d82fc | 16 | |
7453a54e SL |
17 | use dep_graph::{DepGraph, DepNode}; |
18 | ||
92a42be0 SL |
19 | use middle::cstore::InlinedItem; |
20 | use middle::cstore::InlinedItem as II; | |
e9174d1e SL |
21 | use middle::def_id::DefId; |
22 | ||
7453a54e | 23 | use syntax::abi::Abi; |
b039eaaf | 24 | use syntax::ast::{self, Name, NodeId, DUMMY_NODE_ID}; |
e9174d1e | 25 | use syntax::codemap::{Span, Spanned}; |
62682a34 | 26 | use syntax::parse::token; |
e9174d1e SL |
27 | |
28 | use rustc_front::hir::*; | |
29 | use rustc_front::fold::Folder; | |
92a42be0 | 30 | use rustc_front::intravisit; |
e9174d1e | 31 | use rustc_front::print::pprust; |
1a4d82fc JJ |
32 | |
33 | use arena::TypedArena; | |
34 | use std::cell::RefCell; | |
35 | use std::fmt; | |
c34b1796 | 36 | use std::io; |
b039eaaf | 37 | use std::iter; |
1a4d82fc JJ |
38 | use std::mem; |
39 | use std::slice; | |
40 | ||
41 | pub mod blocks; | |
b039eaaf SL |
42 | mod collector; |
43 | pub mod definitions; | |
1a4d82fc | 44 | |
85aaf69f | 45 | #[derive(Clone, Copy, PartialEq, Debug)] |
1a4d82fc JJ |
46 | pub enum PathElem { |
47 | PathMod(Name), | |
48 | PathName(Name) | |
49 | } | |
50 | ||
51 | impl PathElem { | |
52 | pub fn name(&self) -> Name { | |
53 | match *self { | |
54 | PathMod(name) | PathName(name) => name | |
55 | } | |
56 | } | |
57 | } | |
58 | ||
85aaf69f | 59 | impl fmt::Display for PathElem { |
1a4d82fc | 60 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
c1a9b12d | 61 | write!(f, "{}", self.name()) |
1a4d82fc JJ |
62 | } |
63 | } | |
64 | ||
65 | #[derive(Clone)] | |
c34b1796 | 66 | pub struct LinkedPathNode<'a> { |
1a4d82fc JJ |
67 | node: PathElem, |
68 | next: LinkedPath<'a>, | |
69 | } | |
70 | ||
c34b1796 AL |
71 | #[derive(Copy, Clone)] |
72 | pub struct LinkedPath<'a>(Option<&'a LinkedPathNode<'a>>); | |
73 | ||
74 | impl<'a> LinkedPath<'a> { | |
75 | pub fn empty() -> LinkedPath<'a> { | |
76 | LinkedPath(None) | |
77 | } | |
78 | ||
79 | pub fn from(node: &'a LinkedPathNode) -> LinkedPath<'a> { | |
80 | LinkedPath(Some(node)) | |
81 | } | |
82 | } | |
1a4d82fc JJ |
83 | |
84 | impl<'a> Iterator for LinkedPath<'a> { | |
85 | type Item = PathElem; | |
86 | ||
87 | fn next(&mut self) -> Option<PathElem> { | |
c34b1796 | 88 | match self.0 { |
1a4d82fc JJ |
89 | Some(node) => { |
90 | *self = node.next; | |
91 | Some(node.node) | |
92 | } | |
93 | None => None | |
94 | } | |
95 | } | |
96 | } | |
97 | ||
1a4d82fc | 98 | /// The type of the iterator used by with_path. |
85aaf69f | 99 | pub type PathElems<'a, 'b> = iter::Chain<iter::Cloned<slice::Iter<'a, PathElem>>, LinkedPath<'b>>; |
1a4d82fc JJ |
100 | |
101 | pub fn path_to_string<PI: Iterator<Item=PathElem>>(path: PI) -> String { | |
102 | let itr = token::get_ident_interner(); | |
103 | ||
104 | path.fold(String::new(), |mut s, e| { | |
105 | let e = itr.get(e.name()); | |
106 | if !s.is_empty() { | |
107 | s.push_str("::"); | |
108 | } | |
85aaf69f | 109 | s.push_str(&e[..]); |
1a4d82fc | 110 | s |
85aaf69f | 111 | }) |
1a4d82fc JJ |
112 | } |
113 | ||
c34b1796 | 114 | #[derive(Copy, Clone, Debug)] |
1a4d82fc JJ |
115 | pub enum Node<'ast> { |
116 | NodeItem(&'ast Item), | |
117 | NodeForeignItem(&'ast ForeignItem), | |
118 | NodeTraitItem(&'ast TraitItem), | |
119 | NodeImplItem(&'ast ImplItem), | |
120 | NodeVariant(&'ast Variant), | |
121 | NodeExpr(&'ast Expr), | |
122 | NodeStmt(&'ast Stmt), | |
1a4d82fc JJ |
123 | NodeLocal(&'ast Pat), |
124 | NodePat(&'ast Pat), | |
125 | NodeBlock(&'ast Block), | |
126 | ||
127 | /// NodeStructCtor represents a tuple struct. | |
b039eaaf | 128 | NodeStructCtor(&'ast VariantData), |
1a4d82fc JJ |
129 | |
130 | NodeLifetime(&'ast Lifetime), | |
c1a9b12d | 131 | NodeTyParam(&'ast TyParam) |
1a4d82fc JJ |
132 | } |
133 | ||
c1a9b12d | 134 | /// Represents an entry and its parent NodeID. |
1a4d82fc | 135 | /// The odd layout is to bring down the total size. |
85aaf69f | 136 | #[derive(Copy, Debug)] |
b039eaaf | 137 | pub enum MapEntry<'ast> { |
1a4d82fc JJ |
138 | /// Placeholder for holes in the map. |
139 | NotPresent, | |
140 | ||
141 | /// All the node types, with a parent ID. | |
142 | EntryItem(NodeId, &'ast Item), | |
143 | EntryForeignItem(NodeId, &'ast ForeignItem), | |
144 | EntryTraitItem(NodeId, &'ast TraitItem), | |
145 | EntryImplItem(NodeId, &'ast ImplItem), | |
146 | EntryVariant(NodeId, &'ast Variant), | |
147 | EntryExpr(NodeId, &'ast Expr), | |
148 | EntryStmt(NodeId, &'ast Stmt), | |
1a4d82fc JJ |
149 | EntryLocal(NodeId, &'ast Pat), |
150 | EntryPat(NodeId, &'ast Pat), | |
151 | EntryBlock(NodeId, &'ast Block), | |
b039eaaf | 152 | EntryStructCtor(NodeId, &'ast VariantData), |
1a4d82fc | 153 | EntryLifetime(NodeId, &'ast Lifetime), |
c1a9b12d | 154 | EntryTyParam(NodeId, &'ast TyParam), |
1a4d82fc JJ |
155 | |
156 | /// Roots for node trees. | |
157 | RootCrate, | |
158 | RootInlinedParent(&'ast InlinedParent) | |
159 | } | |
160 | ||
161 | impl<'ast> Clone for MapEntry<'ast> { | |
162 | fn clone(&self) -> MapEntry<'ast> { | |
163 | *self | |
164 | } | |
165 | } | |
166 | ||
85aaf69f | 167 | #[derive(Debug)] |
e9174d1e | 168 | pub struct InlinedParent { |
1a4d82fc JJ |
169 | path: Vec<PathElem>, |
170 | ii: InlinedItem | |
171 | } | |
172 | ||
173 | impl<'ast> MapEntry<'ast> { | |
174 | fn from_node(p: NodeId, node: Node<'ast>) -> MapEntry<'ast> { | |
175 | match node { | |
176 | NodeItem(n) => EntryItem(p, n), | |
177 | NodeForeignItem(n) => EntryForeignItem(p, n), | |
178 | NodeTraitItem(n) => EntryTraitItem(p, n), | |
179 | NodeImplItem(n) => EntryImplItem(p, n), | |
180 | NodeVariant(n) => EntryVariant(p, n), | |
181 | NodeExpr(n) => EntryExpr(p, n), | |
182 | NodeStmt(n) => EntryStmt(p, n), | |
1a4d82fc JJ |
183 | NodeLocal(n) => EntryLocal(p, n), |
184 | NodePat(n) => EntryPat(p, n), | |
185 | NodeBlock(n) => EntryBlock(p, n), | |
186 | NodeStructCtor(n) => EntryStructCtor(p, n), | |
c1a9b12d SL |
187 | NodeLifetime(n) => EntryLifetime(p, n), |
188 | NodeTyParam(n) => EntryTyParam(p, n), | |
1a4d82fc JJ |
189 | } |
190 | } | |
191 | ||
c1a9b12d | 192 | fn parent_node(self) -> Option<NodeId> { |
1a4d82fc JJ |
193 | Some(match self { |
194 | EntryItem(id, _) => id, | |
195 | EntryForeignItem(id, _) => id, | |
196 | EntryTraitItem(id, _) => id, | |
197 | EntryImplItem(id, _) => id, | |
198 | EntryVariant(id, _) => id, | |
199 | EntryExpr(id, _) => id, | |
200 | EntryStmt(id, _) => id, | |
1a4d82fc JJ |
201 | EntryLocal(id, _) => id, |
202 | EntryPat(id, _) => id, | |
203 | EntryBlock(id, _) => id, | |
204 | EntryStructCtor(id, _) => id, | |
205 | EntryLifetime(id, _) => id, | |
c1a9b12d | 206 | EntryTyParam(id, _) => id, |
1a4d82fc JJ |
207 | _ => return None |
208 | }) | |
209 | } | |
210 | ||
211 | fn to_node(self) -> Option<Node<'ast>> { | |
212 | Some(match self { | |
213 | EntryItem(_, n) => NodeItem(n), | |
214 | EntryForeignItem(_, n) => NodeForeignItem(n), | |
215 | EntryTraitItem(_, n) => NodeTraitItem(n), | |
216 | EntryImplItem(_, n) => NodeImplItem(n), | |
217 | EntryVariant(_, n) => NodeVariant(n), | |
218 | EntryExpr(_, n) => NodeExpr(n), | |
219 | EntryStmt(_, n) => NodeStmt(n), | |
1a4d82fc JJ |
220 | EntryLocal(_, n) => NodeLocal(n), |
221 | EntryPat(_, n) => NodePat(n), | |
222 | EntryBlock(_, n) => NodeBlock(n), | |
223 | EntryStructCtor(_, n) => NodeStructCtor(n), | |
224 | EntryLifetime(_, n) => NodeLifetime(n), | |
c1a9b12d | 225 | EntryTyParam(_, n) => NodeTyParam(n), |
1a4d82fc JJ |
226 | _ => return None |
227 | }) | |
228 | } | |
229 | } | |
230 | ||
231 | /// Stores a crate and any number of inlined items from other crates. | |
232 | pub struct Forest { | |
7453a54e SL |
233 | krate: Crate, |
234 | pub dep_graph: DepGraph, | |
1a4d82fc JJ |
235 | inlined_items: TypedArena<InlinedParent> |
236 | } | |
237 | ||
238 | impl Forest { | |
7453a54e | 239 | pub fn new(krate: Crate, dep_graph: DepGraph) -> Forest { |
1a4d82fc JJ |
240 | Forest { |
241 | krate: krate, | |
7453a54e | 242 | dep_graph: dep_graph, |
1a4d82fc JJ |
243 | inlined_items: TypedArena::new() |
244 | } | |
245 | } | |
246 | ||
247 | pub fn krate<'ast>(&'ast self) -> &'ast Crate { | |
7453a54e | 248 | self.dep_graph.read(DepNode::Krate); |
1a4d82fc JJ |
249 | &self.krate |
250 | } | |
251 | } | |
252 | ||
253 | /// Represents a mapping from Node IDs to AST elements and their parent | |
254 | /// Node IDs | |
e9174d1e | 255 | #[derive(Clone)] |
1a4d82fc JJ |
256 | pub struct Map<'ast> { |
257 | /// The backing storage for all the AST nodes. | |
e9174d1e | 258 | pub forest: &'ast Forest, |
1a4d82fc | 259 | |
7453a54e SL |
260 | /// Same as the dep_graph in forest, just available with one fewer |
261 | /// deref. This is a gratuitious micro-optimization. | |
262 | pub dep_graph: DepGraph, | |
263 | ||
1a4d82fc JJ |
264 | /// NodeIds are sequential integers from 0, so we can be |
265 | /// super-compact by storing them in a vector. Not everything with | |
266 | /// a NodeId is in the map, but empirically the occupancy is about | |
267 | /// 75-80%, so there's not too much overhead (certainly less than | |
268 | /// a hashmap, since they (at the time of writing) have a maximum | |
269 | /// of 75% occupancy). | |
270 | /// | |
271 | /// Also, indexing is pretty quick when you've got a vector and | |
272 | /// plain old integers. | |
b039eaaf SL |
273 | map: RefCell<Vec<MapEntry<'ast>>>, |
274 | ||
275 | definitions: RefCell<Definitions>, | |
1a4d82fc JJ |
276 | } |
277 | ||
278 | impl<'ast> Map<'ast> { | |
7453a54e SL |
279 | /// Registers a read in the dependency graph of the AST node with |
280 | /// the given `id`. This needs to be called each time a public | |
281 | /// function returns the HIR for a node -- in other words, when it | |
282 | /// "reveals" the content of a node to the caller (who might not | |
283 | /// otherwise have had access to those contents, and hence needs a | |
284 | /// read recorded). If the function just returns a DefId or | |
285 | /// NodeId, no actual content was returned, so no read is needed. | |
286 | fn read(&self, id: NodeId) { | |
287 | self.dep_graph.read(self.dep_node(id)); | |
288 | } | |
289 | ||
290 | fn dep_node(&self, id0: NodeId) -> DepNode { | |
291 | let map = self.map.borrow(); | |
292 | let mut id = id0; | |
293 | loop { | |
294 | match map[id as usize] { | |
295 | EntryItem(_, item) => { | |
296 | let def_id = self.local_def_id(item.id); | |
297 | // NB ^~~~~~~ | |
298 | // | |
299 | // You would expect that `item.id == id`, but this | |
300 | // is not always the case. In particular, for a | |
301 | // ViewPath item like `use self::{mem, foo}`, we | |
302 | // map the ids for `mem` and `foo` to the | |
303 | // enclosing view path item. This seems mega super | |
304 | // ultra wrong, but then who am I to judge? | |
305 | // -nmatsakis | |
306 | return DepNode::Hir(def_id); | |
307 | } | |
308 | ||
309 | EntryForeignItem(p, _) | | |
310 | EntryTraitItem(p, _) | | |
311 | EntryImplItem(p, _) | | |
312 | EntryVariant(p, _) | | |
313 | EntryExpr(p, _) | | |
314 | EntryStmt(p, _) | | |
315 | EntryLocal(p, _) | | |
316 | EntryPat(p, _) | | |
317 | EntryBlock(p, _) | | |
318 | EntryStructCtor(p, _) | | |
319 | EntryLifetime(p, _) | | |
320 | EntryTyParam(p, _) => | |
321 | id = p, | |
322 | ||
323 | RootCrate | | |
324 | RootInlinedParent(_) => // FIXME(#2369) clarify story about cross-crate dep tracking | |
325 | return DepNode::Krate, | |
326 | ||
327 | NotPresent => | |
328 | // Some nodes, notably struct fields, are not | |
329 | // present in the map for whatever reason, but | |
330 | // they *do* have def-ids. So if we encounter an | |
331 | // empty hole, check for that case. | |
332 | return self.opt_local_def_id(id) | |
333 | .map(|def_id| DepNode::Hir(def_id)) | |
334 | .unwrap_or_else(|| { | |
335 | panic!("Walking parents from `{}` \ | |
336 | led to `NotPresent` at `{}`", | |
337 | id0, id) | |
338 | }), | |
339 | } | |
340 | } | |
341 | } | |
342 | ||
b039eaaf SL |
343 | pub fn num_local_def_ids(&self) -> usize { |
344 | self.definitions.borrow().len() | |
345 | } | |
346 | ||
347 | pub fn def_key(&self, def_id: DefId) -> DefKey { | |
348 | assert!(def_id.is_local()); | |
349 | self.definitions.borrow().def_key(def_id.index) | |
350 | } | |
351 | ||
352 | pub fn def_path_from_id(&self, id: NodeId) -> DefPath { | |
353 | self.def_path(self.local_def_id(id)) | |
354 | } | |
355 | ||
356 | pub fn def_path(&self, def_id: DefId) -> DefPath { | |
357 | assert!(def_id.is_local()); | |
358 | self.definitions.borrow().def_path(def_id.index) | |
359 | } | |
360 | ||
361 | pub fn local_def_id(&self, node: NodeId) -> DefId { | |
362 | self.opt_local_def_id(node).unwrap_or_else(|| { | |
363 | panic!("local_def_id: no entry for `{}`, which has a map of `{:?}`", | |
364 | node, self.find_entry(node)) | |
365 | }) | |
366 | } | |
367 | ||
368 | pub fn opt_local_def_id(&self, node: NodeId) -> Option<DefId> { | |
369 | self.definitions.borrow().opt_local_def_id(node) | |
370 | } | |
371 | ||
372 | pub fn as_local_node_id(&self, def_id: DefId) -> Option<NodeId> { | |
373 | self.definitions.borrow().as_local_node_id(def_id) | |
374 | } | |
375 | ||
85aaf69f | 376 | fn entry_count(&self) -> usize { |
1a4d82fc JJ |
377 | self.map.borrow().len() |
378 | } | |
379 | ||
380 | fn find_entry(&self, id: NodeId) -> Option<MapEntry<'ast>> { | |
85aaf69f | 381 | self.map.borrow().get(id as usize).cloned() |
1a4d82fc JJ |
382 | } |
383 | ||
384 | pub fn krate(&self) -> &'ast Crate { | |
7453a54e | 385 | self.forest.krate() |
1a4d82fc JJ |
386 | } |
387 | ||
388 | /// Retrieve the Node corresponding to `id`, panicking if it cannot | |
389 | /// be found. | |
390 | pub fn get(&self, id: NodeId) -> Node<'ast> { | |
391 | match self.find(id) { | |
7453a54e | 392 | Some(node) => node, // read recorded by `find` |
1a4d82fc JJ |
393 | None => panic!("couldn't find node id {} in the AST map", id) |
394 | } | |
395 | } | |
396 | ||
b039eaaf | 397 | pub fn get_if_local(&self, id: DefId) -> Option<Node<'ast>> { |
7453a54e | 398 | self.as_local_node_id(id).map(|id| self.get(id)) // read recorded by `get` |
b039eaaf SL |
399 | } |
400 | ||
1a4d82fc JJ |
401 | /// Retrieve the Node corresponding to `id`, returning None if |
402 | /// cannot be found. | |
403 | pub fn find(&self, id: NodeId) -> Option<Node<'ast>> { | |
7453a54e SL |
404 | let result = self.find_entry(id).and_then(|x| x.to_node()); |
405 | if result.is_some() { | |
406 | self.read(id); | |
407 | } | |
408 | result | |
1a4d82fc JJ |
409 | } |
410 | ||
c1a9b12d SL |
411 | /// Similar to get_parent, returns the parent node id or id if there is no |
412 | /// parent. | |
413 | /// This function returns the immediate parent in the AST, whereas get_parent | |
414 | /// returns the enclosing item. Note that this might not be the actual parent | |
415 | /// node in the AST - some kinds of nodes are not in the map and these will | |
416 | /// never appear as the parent_node. So you can always walk the parent_nodes | |
417 | /// from a node to the root of the ast (unless you get the same id back here | |
418 | /// that can happen if the id is not in the map itself or is just weird). | |
419 | pub fn get_parent_node(&self, id: NodeId) -> NodeId { | |
420 | self.find_entry(id).and_then(|x| x.parent_node()).unwrap_or(id) | |
421 | } | |
422 | ||
b039eaaf SL |
423 | /// Check if the node is an argument. An argument is a local variable whose |
424 | /// immediate parent is an item or a closure. | |
425 | pub fn is_argument(&self, id: NodeId) -> bool { | |
426 | match self.find(id) { | |
427 | Some(NodeLocal(_)) => (), | |
428 | _ => return false, | |
429 | } | |
430 | match self.find(self.get_parent_node(id)) { | |
431 | Some(NodeItem(_)) | | |
432 | Some(NodeTraitItem(_)) | | |
433 | Some(NodeImplItem(_)) => true, | |
434 | Some(NodeExpr(e)) => { | |
435 | match e.node { | |
436 | ExprClosure(..) => true, | |
437 | _ => false, | |
438 | } | |
439 | } | |
440 | _ => false, | |
441 | } | |
442 | } | |
443 | ||
c1a9b12d SL |
444 | /// If there is some error when walking the parents (e.g., a node does not |
445 | /// have a parent in the map or a node can't be found), then we return the | |
446 | /// last good node id we found. Note that reaching the crate root (id == 0), | |
447 | /// is not an error, since items in the crate module have the crate root as | |
448 | /// parent. | |
449 | fn walk_parent_nodes<F>(&self, start_id: NodeId, found: F) -> Result<NodeId, NodeId> | |
450 | where F: Fn(&Node<'ast>) -> bool | |
451 | { | |
452 | let mut id = start_id; | |
453 | loop { | |
454 | let parent_node = self.get_parent_node(id); | |
455 | if parent_node == 0 { | |
456 | return Ok(0); | |
457 | } | |
458 | if parent_node == id { | |
459 | return Err(id); | |
460 | } | |
461 | ||
462 | let node = self.find_entry(parent_node); | |
463 | if node.is_none() { | |
464 | return Err(id); | |
465 | } | |
466 | let node = node.unwrap().to_node(); | |
467 | match node { | |
468 | Some(ref node) => { | |
469 | if found(node) { | |
470 | return Ok(parent_node); | |
471 | } | |
472 | } | |
473 | None => { | |
474 | return Err(parent_node); | |
475 | } | |
476 | } | |
477 | id = parent_node; | |
478 | } | |
479 | } | |
480 | ||
481 | /// Retrieve the NodeId for `id`'s parent item, or `id` itself if no | |
482 | /// parent item is in this map. The "parent item" is the closest parent node | |
483 | /// in the AST which is recorded by the map and is an item, either an item | |
484 | /// in a module, trait, or impl. | |
1a4d82fc | 485 | pub fn get_parent(&self, id: NodeId) -> NodeId { |
c1a9b12d SL |
486 | match self.walk_parent_nodes(id, |node| match *node { |
487 | NodeItem(_) | | |
488 | NodeForeignItem(_) | | |
489 | NodeTraitItem(_) | | |
490 | NodeImplItem(_) => true, | |
491 | _ => false, | |
492 | }) { | |
493 | Ok(id) => id, | |
494 | Err(id) => id, | |
495 | } | |
496 | } | |
497 | ||
498 | /// Returns the nearest enclosing scope. A scope is an item or block. | |
499 | /// FIXME it is not clear to me that all items qualify as scopes - statics | |
500 | /// and associated types probably shouldn't, for example. Behaviour in this | |
501 | /// regard should be expected to be highly unstable. | |
502 | pub fn get_enclosing_scope(&self, id: NodeId) -> Option<NodeId> { | |
503 | match self.walk_parent_nodes(id, |node| match *node { | |
504 | NodeItem(_) | | |
505 | NodeForeignItem(_) | | |
506 | NodeTraitItem(_) | | |
507 | NodeImplItem(_) | | |
508 | NodeBlock(_) => true, | |
509 | _ => false, | |
510 | }) { | |
511 | Ok(id) => Some(id), | |
512 | Err(_) => None, | |
513 | } | |
1a4d82fc JJ |
514 | } |
515 | ||
516 | pub fn get_parent_did(&self, id: NodeId) -> DefId { | |
517 | let parent = self.get_parent(id); | |
518 | match self.find_entry(parent) { | |
e9174d1e SL |
519 | Some(RootInlinedParent(&InlinedParent {ii: II::TraitItem(did, _), ..})) => did, |
520 | Some(RootInlinedParent(&InlinedParent {ii: II::ImplItem(did, _), ..})) => did, | |
b039eaaf | 521 | _ => self.local_def_id(parent) |
1a4d82fc JJ |
522 | } |
523 | } | |
524 | ||
7453a54e | 525 | pub fn get_foreign_abi(&self, id: NodeId) -> Abi { |
1a4d82fc JJ |
526 | let parent = self.get_parent(id); |
527 | let abi = match self.find_entry(parent) { | |
528 | Some(EntryItem(_, i)) => { | |
529 | match i.node { | |
530 | ItemForeignMod(ref nm) => Some(nm.abi), | |
531 | _ => None | |
532 | } | |
533 | } | |
534 | /// Wrong but OK, because the only inlined foreign items are intrinsics. | |
7453a54e | 535 | Some(RootInlinedParent(_)) => Some(Abi::RustIntrinsic), |
1a4d82fc JJ |
536 | _ => None |
537 | }; | |
538 | match abi { | |
7453a54e SL |
539 | Some(abi) => { |
540 | self.read(id); // reveals some of the content of a node | |
541 | abi | |
542 | } | |
1a4d82fc JJ |
543 | None => panic!("expected foreign mod or inlined parent, found {}", |
544 | self.node_to_string(parent)) | |
545 | } | |
546 | } | |
547 | ||
548 | pub fn get_foreign_vis(&self, id: NodeId) -> Visibility { | |
7453a54e SL |
549 | let vis = self.expect_foreign_item(id).vis; // read recorded by `expect_foreign_item` |
550 | match self.find(self.get_parent(id)) { // read recorded by `find` | |
1a4d82fc JJ |
551 | Some(NodeItem(i)) => vis.inherit_from(i.vis), |
552 | _ => vis | |
553 | } | |
554 | } | |
555 | ||
556 | pub fn expect_item(&self, id: NodeId) -> &'ast Item { | |
7453a54e | 557 | match self.find(id) { // read recorded by `find` |
1a4d82fc JJ |
558 | Some(NodeItem(item)) => item, |
559 | _ => panic!("expected item, found {}", self.node_to_string(id)) | |
560 | } | |
561 | } | |
562 | ||
c1a9b12d SL |
563 | pub fn expect_trait_item(&self, id: NodeId) -> &'ast TraitItem { |
564 | match self.find(id) { | |
565 | Some(NodeTraitItem(item)) => item, | |
566 | _ => panic!("expected trait item, found {}", self.node_to_string(id)) | |
567 | } | |
568 | } | |
569 | ||
b039eaaf | 570 | pub fn expect_struct(&self, id: NodeId) -> &'ast VariantData { |
1a4d82fc JJ |
571 | match self.find(id) { |
572 | Some(NodeItem(i)) => { | |
573 | match i.node { | |
b039eaaf | 574 | ItemStruct(ref struct_def, _) => struct_def, |
1a4d82fc JJ |
575 | _ => panic!("struct ID bound to non-struct") |
576 | } | |
577 | } | |
578 | Some(NodeVariant(variant)) => { | |
b039eaaf SL |
579 | if variant.node.data.is_struct() { |
580 | &variant.node.data | |
581 | } else { | |
582 | panic!("struct ID bound to enum variant that isn't struct-like") | |
1a4d82fc JJ |
583 | } |
584 | } | |
585 | _ => panic!(format!("expected struct, found {}", self.node_to_string(id))), | |
586 | } | |
587 | } | |
588 | ||
589 | pub fn expect_variant(&self, id: NodeId) -> &'ast Variant { | |
590 | match self.find(id) { | |
591 | Some(NodeVariant(variant)) => variant, | |
592 | _ => panic!(format!("expected variant, found {}", self.node_to_string(id))), | |
593 | } | |
594 | } | |
595 | ||
596 | pub fn expect_foreign_item(&self, id: NodeId) -> &'ast ForeignItem { | |
597 | match self.find(id) { | |
598 | Some(NodeForeignItem(item)) => item, | |
599 | _ => panic!("expected foreign item, found {}", self.node_to_string(id)) | |
600 | } | |
601 | } | |
602 | ||
603 | pub fn expect_expr(&self, id: NodeId) -> &'ast Expr { | |
7453a54e | 604 | match self.find(id) { // read recorded by find |
1a4d82fc JJ |
605 | Some(NodeExpr(expr)) => expr, |
606 | _ => panic!("expected expr, found {}", self.node_to_string(id)) | |
607 | } | |
608 | } | |
609 | ||
610 | /// returns the name associated with the given NodeId's AST | |
611 | pub fn get_path_elem(&self, id: NodeId) -> PathElem { | |
612 | let node = self.get(id); | |
613 | match node { | |
614 | NodeItem(item) => { | |
615 | match item.node { | |
616 | ItemMod(_) | ItemForeignMod(_) => { | |
b039eaaf | 617 | PathMod(item.name) |
1a4d82fc | 618 | } |
b039eaaf | 619 | _ => PathName(item.name) |
1a4d82fc JJ |
620 | } |
621 | } | |
b039eaaf SL |
622 | NodeForeignItem(i) => PathName(i.name), |
623 | NodeImplItem(ii) => PathName(ii.name), | |
624 | NodeTraitItem(ti) => PathName(ti.name), | |
625 | NodeVariant(v) => PathName(v.node.name), | |
e9174d1e | 626 | NodeLifetime(lt) => PathName(lt.name), |
b039eaaf | 627 | NodeTyParam(tp) => PathName(tp.name), |
7453a54e | 628 | NodeLocal(&Pat { node: PatKind::Ident(_,l,_), .. }) => { |
b039eaaf SL |
629 | PathName(l.node.name) |
630 | }, | |
1a4d82fc JJ |
631 | _ => panic!("no path elem for {:?}", node) |
632 | } | |
633 | } | |
634 | ||
635 | pub fn with_path<T, F>(&self, id: NodeId, f: F) -> T where | |
636 | F: FnOnce(PathElems) -> T, | |
637 | { | |
c34b1796 | 638 | self.with_path_next(id, LinkedPath::empty(), f) |
1a4d82fc JJ |
639 | } |
640 | ||
641 | pub fn path_to_string(&self, id: NodeId) -> String { | |
642 | self.with_path(id, |path| path_to_string(path)) | |
643 | } | |
644 | ||
b039eaaf | 645 | fn path_to_str_with_name(&self, id: NodeId, name: Name) -> String { |
1a4d82fc | 646 | self.with_path(id, |path| { |
b039eaaf | 647 | path_to_string(path.chain(Some(PathName(name)))) |
1a4d82fc JJ |
648 | }) |
649 | } | |
650 | ||
651 | fn with_path_next<T, F>(&self, id: NodeId, next: LinkedPath, f: F) -> T where | |
652 | F: FnOnce(PathElems) -> T, | |
653 | { | |
7453a54e SL |
654 | // This function reveals the name of the item and hence is a |
655 | // kind of read. This is inefficient, since it walks ancestors | |
656 | // and we are walking them anyhow, but whatever. | |
657 | self.read(id); | |
658 | ||
1a4d82fc JJ |
659 | let parent = self.get_parent(id); |
660 | let parent = match self.find_entry(id) { | |
c1a9b12d SL |
661 | Some(EntryForeignItem(..)) => { |
662 | // Anonymous extern items go in the parent scope. | |
1a4d82fc JJ |
663 | self.get_parent(parent) |
664 | } | |
665 | // But tuple struct ctors don't have names, so use the path of its | |
666 | // parent, the struct item. Similarly with closure expressions. | |
667 | Some(EntryStructCtor(..)) | Some(EntryExpr(..)) => { | |
668 | return self.with_path_next(parent, next, f); | |
669 | } | |
670 | _ => parent | |
671 | }; | |
672 | if parent == id { | |
673 | match self.find_entry(id) { | |
674 | Some(RootInlinedParent(data)) => { | |
85aaf69f | 675 | f(data.path.iter().cloned().chain(next)) |
1a4d82fc | 676 | } |
85aaf69f | 677 | _ => f([].iter().cloned().chain(next)) |
1a4d82fc JJ |
678 | } |
679 | } else { | |
c34b1796 | 680 | self.with_path_next(parent, LinkedPath::from(&LinkedPathNode { |
1a4d82fc JJ |
681 | node: self.get_path_elem(id), |
682 | next: next | |
683 | }), f) | |
684 | } | |
685 | } | |
686 | ||
b039eaaf | 687 | /// Given a node ID, get a list of attributes associated with the AST |
c34b1796 | 688 | /// corresponding to the Node ID |
b039eaaf | 689 | pub fn attrs(&self, id: NodeId) -> &'ast [ast::Attribute] { |
7453a54e | 690 | self.read(id); // reveals attributes on the node |
c34b1796 AL |
691 | let attrs = match self.find(id) { |
692 | Some(NodeItem(i)) => Some(&i.attrs[..]), | |
693 | Some(NodeForeignItem(fi)) => Some(&fi.attrs[..]), | |
694 | Some(NodeTraitItem(ref ti)) => Some(&ti.attrs[..]), | |
695 | Some(NodeImplItem(ref ii)) => Some(&ii.attrs[..]), | |
696 | Some(NodeVariant(ref v)) => Some(&v.node.attrs[..]), | |
1a4d82fc JJ |
697 | // unit/tuple structs take the attributes straight from |
698 | // the struct definition. | |
c34b1796 AL |
699 | Some(NodeStructCtor(_)) => { |
700 | return self.attrs(self.get_parent(id)); | |
1a4d82fc JJ |
701 | } |
702 | _ => None | |
703 | }; | |
c34b1796 | 704 | attrs.unwrap_or(&[]) |
1a4d82fc JJ |
705 | } |
706 | ||
707 | /// Returns an iterator that yields the node id's with paths that | |
708 | /// match `parts`. (Requires `parts` is non-empty.) | |
709 | /// | |
710 | /// For example, if given `parts` equal to `["bar", "quux"]`, then | |
711 | /// the iterator will produce node id's for items with paths | |
712 | /// such as `foo::bar::quux`, `bar::quux`, `other::bar::quux`, and | |
713 | /// any other such items it can find in the map. | |
714 | pub fn nodes_matching_suffix<'a>(&'a self, parts: &'a [String]) | |
715 | -> NodesMatchingSuffix<'a, 'ast> { | |
716 | NodesMatchingSuffix { | |
717 | map: self, | |
718 | item_name: parts.last().unwrap(), | |
85aaf69f | 719 | in_which: &parts[..parts.len() - 1], |
1a4d82fc JJ |
720 | idx: 0, |
721 | } | |
722 | } | |
723 | ||
724 | pub fn opt_span(&self, id: NodeId) -> Option<Span> { | |
725 | let sp = match self.find(id) { | |
726 | Some(NodeItem(item)) => item.span, | |
727 | Some(NodeForeignItem(foreign_item)) => foreign_item.span, | |
c34b1796 AL |
728 | Some(NodeTraitItem(trait_method)) => trait_method.span, |
729 | Some(NodeImplItem(ref impl_item)) => impl_item.span, | |
1a4d82fc JJ |
730 | Some(NodeVariant(variant)) => variant.span, |
731 | Some(NodeExpr(expr)) => expr.span, | |
732 | Some(NodeStmt(stmt)) => stmt.span, | |
b039eaaf | 733 | Some(NodeLocal(pat)) => pat.span, |
1a4d82fc JJ |
734 | Some(NodePat(pat)) => pat.span, |
735 | Some(NodeBlock(block)) => block.span, | |
736 | Some(NodeStructCtor(_)) => self.expect_item(self.get_parent(id)).span, | |
c1a9b12d | 737 | Some(NodeTyParam(ty_param)) => ty_param.span, |
1a4d82fc JJ |
738 | _ => return None, |
739 | }; | |
740 | Some(sp) | |
741 | } | |
742 | ||
743 | pub fn span(&self, id: NodeId) -> Span { | |
7453a54e | 744 | self.read(id); // reveals span from node |
1a4d82fc JJ |
745 | self.opt_span(id) |
746 | .unwrap_or_else(|| panic!("AstMap.span: could not find span for id {:?}", id)) | |
747 | } | |
748 | ||
b039eaaf SL |
749 | pub fn span_if_local(&self, id: DefId) -> Option<Span> { |
750 | self.as_local_node_id(id).map(|id| self.span(id)) | |
751 | } | |
752 | ||
1a4d82fc | 753 | pub fn def_id_span(&self, def_id: DefId, fallback: Span) -> Span { |
b039eaaf SL |
754 | if let Some(node_id) = self.as_local_node_id(def_id) { |
755 | self.opt_span(node_id).unwrap_or(fallback) | |
1a4d82fc JJ |
756 | } else { |
757 | fallback | |
758 | } | |
759 | } | |
760 | ||
761 | pub fn node_to_string(&self, id: NodeId) -> String { | |
762 | node_id_to_string(self, id, true) | |
763 | } | |
764 | ||
765 | pub fn node_to_user_string(&self, id: NodeId) -> String { | |
766 | node_id_to_string(self, id, false) | |
767 | } | |
768 | } | |
769 | ||
770 | pub struct NodesMatchingSuffix<'a, 'ast:'a> { | |
771 | map: &'a Map<'ast>, | |
772 | item_name: &'a String, | |
773 | in_which: &'a [String], | |
774 | idx: NodeId, | |
775 | } | |
776 | ||
777 | impl<'a, 'ast> NodesMatchingSuffix<'a, 'ast> { | |
778 | /// Returns true only if some suffix of the module path for parent | |
779 | /// matches `self.in_which`. | |
780 | /// | |
781 | /// In other words: let `[x_0,x_1,...,x_k]` be `self.in_which`; | |
782 | /// returns true if parent's path ends with the suffix | |
783 | /// `x_0::x_1::...::x_k`. | |
784 | fn suffix_matches(&self, parent: NodeId) -> bool { | |
785 | let mut cursor = parent; | |
786 | for part in self.in_which.iter().rev() { | |
787 | let (mod_id, mod_name) = match find_first_mod_parent(self.map, cursor) { | |
788 | None => return false, | |
789 | Some((node_id, name)) => (node_id, name), | |
790 | }; | |
85aaf69f | 791 | if &part[..] != mod_name.as_str() { |
1a4d82fc JJ |
792 | return false; |
793 | } | |
794 | cursor = self.map.get_parent(mod_id); | |
795 | } | |
796 | return true; | |
797 | ||
798 | // Finds the first mod in parent chain for `id`, along with | |
799 | // that mod's name. | |
800 | // | |
801 | // If `id` itself is a mod named `m` with parent `p`, then | |
802 | // returns `Some(id, m, p)`. If `id` has no mod in its parent | |
803 | // chain, then returns `None`. | |
804 | fn find_first_mod_parent<'a>(map: &'a Map, mut id: NodeId) -> Option<(NodeId, Name)> { | |
805 | loop { | |
806 | match map.find(id) { | |
807 | None => return None, | |
7453a54e | 808 | Some(NodeItem(item)) if item_is_mod(&item) => |
b039eaaf | 809 | return Some((id, item.name)), |
1a4d82fc JJ |
810 | _ => {} |
811 | } | |
812 | let parent = map.get_parent(id); | |
813 | if parent == id { return None } | |
814 | id = parent; | |
815 | } | |
816 | ||
817 | fn item_is_mod(item: &Item) -> bool { | |
818 | match item.node { | |
819 | ItemMod(_) => true, | |
820 | _ => false, | |
821 | } | |
822 | } | |
823 | } | |
824 | } | |
825 | ||
826 | // We are looking at some node `n` with a given name and parent | |
827 | // id; do their names match what I am seeking? | |
828 | fn matches_names(&self, parent_of_n: NodeId, name: Name) -> bool { | |
85aaf69f | 829 | name.as_str() == &self.item_name[..] && |
1a4d82fc JJ |
830 | self.suffix_matches(parent_of_n) |
831 | } | |
832 | } | |
833 | ||
834 | impl<'a, 'ast> Iterator for NodesMatchingSuffix<'a, 'ast> { | |
835 | type Item = NodeId; | |
836 | ||
837 | fn next(&mut self) -> Option<NodeId> { | |
838 | loop { | |
839 | let idx = self.idx; | |
85aaf69f | 840 | if idx as usize >= self.map.entry_count() { |
1a4d82fc JJ |
841 | return None; |
842 | } | |
843 | self.idx += 1; | |
c1a9b12d SL |
844 | let name = match self.map.find_entry(idx) { |
845 | Some(EntryItem(_, n)) => n.name(), | |
846 | Some(EntryForeignItem(_, n))=> n.name(), | |
847 | Some(EntryTraitItem(_, n)) => n.name(), | |
848 | Some(EntryImplItem(_, n)) => n.name(), | |
849 | Some(EntryVariant(_, n)) => n.name(), | |
1a4d82fc JJ |
850 | _ => continue, |
851 | }; | |
c1a9b12d | 852 | if self.matches_names(self.map.get_parent(idx), name) { |
1a4d82fc JJ |
853 | return Some(idx) |
854 | } | |
855 | } | |
856 | } | |
857 | } | |
858 | ||
859 | trait Named { | |
860 | fn name(&self) -> Name; | |
861 | } | |
862 | ||
863 | impl<T:Named> Named for Spanned<T> { fn name(&self) -> Name { self.node.name() } } | |
864 | ||
b039eaaf SL |
865 | impl Named for Item { fn name(&self) -> Name { self.name } } |
866 | impl Named for ForeignItem { fn name(&self) -> Name { self.name } } | |
867 | impl Named for Variant_ { fn name(&self) -> Name { self.name } } | |
868 | impl Named for TraitItem { fn name(&self) -> Name { self.name } } | |
869 | impl Named for ImplItem { fn name(&self) -> Name { self.name } } | |
1a4d82fc JJ |
870 | |
871 | pub trait FoldOps { | |
872 | fn new_id(&self, id: NodeId) -> NodeId { | |
873 | id | |
874 | } | |
875 | fn new_def_id(&self, def_id: DefId) -> DefId { | |
876 | def_id | |
877 | } | |
878 | fn new_span(&self, span: Span) -> Span { | |
879 | span | |
880 | } | |
881 | } | |
882 | ||
883 | /// A Folder that updates IDs and Span's according to fold_ops. | |
884 | struct IdAndSpanUpdater<F> { | |
885 | fold_ops: F | |
886 | } | |
887 | ||
888 | impl<F: FoldOps> Folder for IdAndSpanUpdater<F> { | |
889 | fn new_id(&mut self, id: NodeId) -> NodeId { | |
890 | self.fold_ops.new_id(id) | |
891 | } | |
892 | ||
893 | fn new_span(&mut self, span: Span) -> Span { | |
894 | self.fold_ops.new_span(span) | |
895 | } | |
896 | } | |
897 | ||
e9174d1e | 898 | pub fn map_crate<'ast>(forest: &'ast mut Forest) -> Map<'ast> { |
92a42be0 SL |
899 | let (map, definitions) = { |
900 | let mut collector = NodeCollector::root(&forest.krate); | |
901 | intravisit::walk_crate(&mut collector, &forest.krate); | |
902 | (collector.map, collector.definitions) | |
903 | }; | |
1a4d82fc JJ |
904 | |
905 | if log_enabled!(::log::DEBUG) { | |
906 | // This only makes sense for ordered stores; note the | |
907 | // enumerate to count the number of entries. | |
908 | let (entries_less_1, _) = map.iter().filter(|&x| { | |
909 | match *x { | |
910 | NotPresent => false, | |
911 | _ => true | |
912 | } | |
913 | }).enumerate().last().expect("AST map was empty after folding?"); | |
914 | ||
915 | let entries = entries_less_1 + 1; | |
916 | let vector_length = map.len(); | |
917 | debug!("The AST map has {} entries with a maximum of {}: occupancy {:.1}%", | |
918 | entries, vector_length, (entries as f64 / vector_length as f64) * 100.); | |
919 | } | |
920 | ||
921 | Map { | |
922 | forest: forest, | |
7453a54e | 923 | dep_graph: forest.dep_graph.clone(), |
b039eaaf SL |
924 | map: RefCell::new(map), |
925 | definitions: RefCell::new(definitions), | |
1a4d82fc JJ |
926 | } |
927 | } | |
928 | ||
929 | /// Used for items loaded from external crate that are being inlined into this | |
9cc50fc6 | 930 | /// crate. |
1a4d82fc | 931 | pub fn map_decoded_item<'ast, F: FoldOps>(map: &Map<'ast>, |
9cc50fc6 SL |
932 | parent_path: Vec<PathElem>, |
933 | parent_def_path: DefPath, | |
1a4d82fc JJ |
934 | ii: InlinedItem, |
935 | fold_ops: F) | |
936 | -> &'ast InlinedItem { | |
937 | let mut fld = IdAndSpanUpdater { fold_ops: fold_ops }; | |
938 | let ii = match ii { | |
92a42be0 | 939 | II::Item(i) => II::Item(i.map(|i| fld.fold_item(i))), |
e9174d1e SL |
940 | II::TraitItem(d, ti) => { |
941 | II::TraitItem(fld.fold_ops.new_def_id(d), | |
92a42be0 | 942 | ti.map(|ti| fld.fold_trait_item(ti))) |
c34b1796 | 943 | } |
e9174d1e SL |
944 | II::ImplItem(d, ii) => { |
945 | II::ImplItem(fld.fold_ops.new_def_id(d), | |
92a42be0 | 946 | ii.map(|ii| fld.fold_impl_item(ii))) |
c34b1796 | 947 | } |
92a42be0 | 948 | II::Foreign(i) => II::Foreign(i.map(|i| fld.fold_foreign_item(i))) |
1a4d82fc JJ |
949 | }; |
950 | ||
951 | let ii_parent = map.forest.inlined_items.alloc(InlinedParent { | |
9cc50fc6 | 952 | path: parent_path, |
1a4d82fc JJ |
953 | ii: ii |
954 | }); | |
955 | ||
c1a9b12d | 956 | let ii_parent_id = fld.new_id(DUMMY_NODE_ID); |
b039eaaf SL |
957 | let mut collector = |
958 | NodeCollector::extend( | |
92a42be0 | 959 | map.krate(), |
b039eaaf SL |
960 | ii_parent, |
961 | ii_parent_id, | |
9cc50fc6 | 962 | parent_def_path, |
b039eaaf SL |
963 | mem::replace(&mut *map.map.borrow_mut(), vec![]), |
964 | mem::replace(&mut *map.definitions.borrow_mut(), Definitions::new())); | |
e9174d1e | 965 | ii_parent.ii.visit(&mut collector); |
1a4d82fc | 966 | |
1a4d82fc | 967 | *map.map.borrow_mut() = collector.map; |
b039eaaf SL |
968 | *map.definitions.borrow_mut() = collector.definitions; |
969 | ||
1a4d82fc JJ |
970 | &ii_parent.ii |
971 | } | |
972 | ||
973 | pub trait NodePrinter { | |
c34b1796 | 974 | fn print_node(&mut self, node: &Node) -> io::Result<()>; |
1a4d82fc JJ |
975 | } |
976 | ||
977 | impl<'a> NodePrinter for pprust::State<'a> { | |
c34b1796 | 978 | fn print_node(&mut self, node: &Node) -> io::Result<()> { |
1a4d82fc | 979 | match *node { |
7453a54e SL |
980 | NodeItem(a) => self.print_item(&a), |
981 | NodeForeignItem(a) => self.print_foreign_item(&a), | |
c34b1796 AL |
982 | NodeTraitItem(a) => self.print_trait_item(a), |
983 | NodeImplItem(a) => self.print_impl_item(a), | |
7453a54e SL |
984 | NodeVariant(a) => self.print_variant(&a), |
985 | NodeExpr(a) => self.print_expr(&a), | |
986 | NodeStmt(a) => self.print_stmt(&a), | |
987 | NodePat(a) => self.print_pat(&a), | |
988 | NodeBlock(a) => self.print_block(&a), | |
989 | NodeLifetime(a) => self.print_lifetime(&a), | |
c1a9b12d | 990 | NodeTyParam(_) => panic!("cannot print TyParam"), |
1a4d82fc JJ |
991 | // these cases do not carry enough information in the |
992 | // ast_map to reconstruct their full structure for pretty | |
993 | // printing. | |
994 | NodeLocal(_) => panic!("cannot print isolated Local"), | |
1a4d82fc JJ |
995 | NodeStructCtor(_) => panic!("cannot print isolated StructCtor"), |
996 | } | |
997 | } | |
998 | } | |
999 | ||
1000 | fn node_id_to_string(map: &Map, id: NodeId, include_id: bool) -> String { | |
1001 | let id_str = format!(" (id={})", id); | |
85aaf69f | 1002 | let id_str = if include_id { &id_str[..] } else { "" }; |
1a4d82fc JJ |
1003 | |
1004 | match map.find(id) { | |
1005 | Some(NodeItem(item)) => { | |
b039eaaf | 1006 | let path_str = map.path_to_str_with_name(id, item.name); |
1a4d82fc | 1007 | let item_str = match item.node { |
85aaf69f SL |
1008 | ItemExternCrate(..) => "extern crate", |
1009 | ItemUse(..) => "use", | |
1a4d82fc JJ |
1010 | ItemStatic(..) => "static", |
1011 | ItemConst(..) => "const", | |
1012 | ItemFn(..) => "fn", | |
1013 | ItemMod(..) => "mod", | |
1014 | ItemForeignMod(..) => "foreign mod", | |
1015 | ItemTy(..) => "ty", | |
1016 | ItemEnum(..) => "enum", | |
1017 | ItemStruct(..) => "struct", | |
1018 | ItemTrait(..) => "trait", | |
1019 | ItemImpl(..) => "impl", | |
c34b1796 | 1020 | ItemDefaultImpl(..) => "default impl", |
1a4d82fc JJ |
1021 | }; |
1022 | format!("{} {}{}", item_str, path_str, id_str) | |
1023 | } | |
1024 | Some(NodeForeignItem(item)) => { | |
b039eaaf | 1025 | let path_str = map.path_to_str_with_name(id, item.name); |
1a4d82fc JJ |
1026 | format!("foreign item {}{}", path_str, id_str) |
1027 | } | |
c34b1796 AL |
1028 | Some(NodeImplItem(ii)) => { |
1029 | match ii.node { | |
92a42be0 | 1030 | ImplItemKind::Const(..) => { |
d9579d0f | 1031 | format!("assoc const {} in {}{}", |
b039eaaf | 1032 | ii.name, |
d9579d0f AL |
1033 | map.path_to_string(id), |
1034 | id_str) | |
1035 | } | |
92a42be0 | 1036 | ImplItemKind::Method(..) => { |
1a4d82fc | 1037 | format!("method {} in {}{}", |
b039eaaf | 1038 | ii.name, |
c34b1796 | 1039 | map.path_to_string(id), id_str) |
1a4d82fc | 1040 | } |
92a42be0 | 1041 | ImplItemKind::Type(_) => { |
c34b1796 | 1042 | format!("assoc type {} in {}{}", |
b039eaaf | 1043 | ii.name, |
1a4d82fc JJ |
1044 | map.path_to_string(id), |
1045 | id_str) | |
1046 | } | |
1047 | } | |
1048 | } | |
c34b1796 AL |
1049 | Some(NodeTraitItem(ti)) => { |
1050 | let kind = match ti.node { | |
d9579d0f | 1051 | ConstTraitItem(..) => "assoc constant", |
c34b1796 AL |
1052 | MethodTraitItem(..) => "trait method", |
1053 | TypeTraitItem(..) => "assoc type", | |
c34b1796 AL |
1054 | }; |
1055 | ||
1056 | format!("{} {} in {}{}", | |
1057 | kind, | |
b039eaaf | 1058 | ti.name, |
c34b1796 AL |
1059 | map.path_to_string(id), |
1060 | id_str) | |
1061 | } | |
1a4d82fc JJ |
1062 | Some(NodeVariant(ref variant)) => { |
1063 | format!("variant {} in {}{}", | |
c1a9b12d | 1064 | variant.node.name, |
1a4d82fc JJ |
1065 | map.path_to_string(id), id_str) |
1066 | } | |
1067 | Some(NodeExpr(ref expr)) => { | |
7453a54e | 1068 | format!("expr {}{}", pprust::expr_to_string(&expr), id_str) |
1a4d82fc JJ |
1069 | } |
1070 | Some(NodeStmt(ref stmt)) => { | |
7453a54e | 1071 | format!("stmt {}{}", pprust::stmt_to_string(&stmt), id_str) |
1a4d82fc | 1072 | } |
1a4d82fc | 1073 | Some(NodeLocal(ref pat)) => { |
7453a54e | 1074 | format!("local {}{}", pprust::pat_to_string(&pat), id_str) |
1a4d82fc JJ |
1075 | } |
1076 | Some(NodePat(ref pat)) => { | |
7453a54e | 1077 | format!("pat {}{}", pprust::pat_to_string(&pat), id_str) |
1a4d82fc JJ |
1078 | } |
1079 | Some(NodeBlock(ref block)) => { | |
7453a54e | 1080 | format!("block {}{}", pprust::block_to_string(&block), id_str) |
1a4d82fc JJ |
1081 | } |
1082 | Some(NodeStructCtor(_)) => { | |
1083 | format!("struct_ctor {}{}", map.path_to_string(id), id_str) | |
1084 | } | |
1085 | Some(NodeLifetime(ref l)) => { | |
1086 | format!("lifetime {}{}", | |
7453a54e | 1087 | pprust::lifetime_to_string(&l), id_str) |
1a4d82fc | 1088 | } |
c1a9b12d SL |
1089 | Some(NodeTyParam(ref ty_param)) => { |
1090 | format!("typaram {:?}{}", ty_param, id_str) | |
1091 | } | |
1a4d82fc JJ |
1092 | None => { |
1093 | format!("unknown node{}", id_str) | |
1094 | } | |
1095 | } | |
1096 | } |