]> git.lizzy.rs Git - rust.git/blob - src/librustc/hir/map/collector.rs
64bf4bbf08039d45737d102ae889cfe00847dae4
[rust.git] / src / librustc / hir / map / collector.rs
1 // Copyright 2015-2016 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 use super::*;
12
13 use hir::intravisit::Visitor;
14 use hir::def_id::DefId;
15 use middle::cstore::InlinedItem;
16 use std::iter::repeat;
17 use syntax::ast::{NodeId, CRATE_NODE_ID};
18 use syntax_pos::Span;
19
20 /// A Visitor that walks over the HIR and collects Nodes into a HIR map
21 pub struct NodeCollector<'ast> {
22     /// The crate
23     pub krate: &'ast Crate,
24     /// The node map
25     pub map: Vec<MapEntry<'ast>>,
26     /// The parent of this node
27     pub parent_node: NodeId,
28     /// If true, completely ignore nested items. We set this when loading
29     /// HIR from metadata, since in that case we only want the HIR for
30     /// one specific item (and not the ones nested inside of it).
31     pub ignore_nested_items: bool
32 }
33
34 impl<'ast> NodeCollector<'ast> {
35     pub fn root(krate: &'ast Crate) -> NodeCollector<'ast> {
36         let mut collector = NodeCollector {
37             krate: krate,
38             map: vec![],
39             parent_node: CRATE_NODE_ID,
40             ignore_nested_items: false
41         };
42         collector.insert_entry(CRATE_NODE_ID, RootCrate);
43
44         collector
45     }
46
47     pub fn extend(krate: &'ast Crate,
48                   parent: &'ast InlinedItem,
49                   parent_node: NodeId,
50                   parent_def_path: DefPath,
51                   parent_def_id: DefId,
52                   map: Vec<MapEntry<'ast>>)
53                   -> NodeCollector<'ast> {
54         let mut collector = NodeCollector {
55             krate: krate,
56             map: map,
57             parent_node: parent_node,
58             ignore_nested_items: true
59         };
60
61         assert_eq!(parent_def_path.krate, parent_def_id.krate);
62         collector.insert_entry(parent_node, RootInlinedParent(parent));
63
64         collector
65     }
66
67     fn insert_entry(&mut self, id: NodeId, entry: MapEntry<'ast>) {
68         debug!("ast_map: {:?} => {:?}", id, entry);
69         let len = self.map.len();
70         if id.as_usize() >= len {
71             self.map.extend(repeat(NotPresent).take(id.as_usize() - len + 1));
72         }
73         self.map[id.as_usize()] = entry;
74     }
75
76     fn insert(&mut self, id: NodeId, node: Node<'ast>) {
77         let entry = MapEntry::from_node(self.parent_node, node);
78         self.insert_entry(id, entry);
79     }
80
81     fn with_parent<F: FnOnce(&mut Self)>(&mut self, parent_id: NodeId, f: F) {
82         let parent_node = self.parent_node;
83         self.parent_node = parent_id;
84         f(self);
85         self.parent_node = parent_node;
86     }
87 }
88
89 impl<'ast> Visitor<'ast> for NodeCollector<'ast> {
90     /// Because we want to track parent items and so forth, enable
91     /// deep walking so that we walk nested items in the context of
92     /// their outer items.
93
94     fn nested_visit_map(&mut self) -> Option<&map::Map<'ast>> {
95         panic!("visit_nested_xxx must be manually implemented in this visitor")
96     }
97
98     fn visit_nested_item(&mut self, item: ItemId) {
99         debug!("visit_nested_item: {:?}", item);
100         if !self.ignore_nested_items {
101             self.visit_item(self.krate.item(item.id))
102         }
103     }
104
105     fn visit_nested_impl_item(&mut self, item_id: ImplItemId) {
106         self.visit_impl_item(self.krate.impl_item(item_id))
107     }
108
109     fn visit_item(&mut self, i: &'ast Item) {
110         debug!("visit_item: {:?}", i);
111
112         self.insert(i.id, NodeItem(i));
113
114         self.with_parent(i.id, |this| {
115             match i.node {
116                 ItemEnum(ref enum_definition, _) => {
117                     for v in &enum_definition.variants {
118                         this.insert(v.node.data.id(), NodeVariant(v));
119                     }
120                 }
121                 ItemStruct(ref struct_def, _) => {
122                     // If this is a tuple-like struct, register the constructor.
123                     if !struct_def.is_struct() {
124                         this.insert(struct_def.id(), NodeStructCtor(struct_def));
125                     }
126                 }
127                 ItemUse(ref view_path) => {
128                     match view_path.node {
129                         ViewPathList(_, ref paths) => {
130                             for path in paths {
131                                 this.insert(path.node.id, NodeItem(i));
132                             }
133                         }
134                         _ => ()
135                     }
136                 }
137                 _ => {}
138             }
139             intravisit::walk_item(this, i);
140         });
141     }
142
143     fn visit_foreign_item(&mut self, foreign_item: &'ast ForeignItem) {
144         self.insert(foreign_item.id, NodeForeignItem(foreign_item));
145
146         self.with_parent(foreign_item.id, |this| {
147             intravisit::walk_foreign_item(this, foreign_item);
148         });
149     }
150
151     fn visit_generics(&mut self, generics: &'ast Generics) {
152         for ty_param in generics.ty_params.iter() {
153             self.insert(ty_param.id, NodeTyParam(ty_param));
154         }
155
156         intravisit::walk_generics(self, generics);
157     }
158
159     fn visit_trait_item(&mut self, ti: &'ast TraitItem) {
160         self.insert(ti.id, NodeTraitItem(ti));
161
162         self.with_parent(ti.id, |this| {
163             intravisit::walk_trait_item(this, ti);
164         });
165     }
166
167     fn visit_impl_item(&mut self, ii: &'ast ImplItem) {
168         self.insert(ii.id, NodeImplItem(ii));
169
170         self.with_parent(ii.id, |this| {
171             intravisit::walk_impl_item(this, ii);
172         });
173     }
174
175     fn visit_pat(&mut self, pat: &'ast Pat) {
176         let node = if let PatKind::Binding(..) = pat.node {
177             NodeLocal(pat)
178         } else {
179             NodePat(pat)
180         };
181         self.insert(pat.id, node);
182
183         self.with_parent(pat.id, |this| {
184             intravisit::walk_pat(this, pat);
185         });
186     }
187
188     fn visit_expr(&mut self, expr: &'ast Expr) {
189         self.insert(expr.id, NodeExpr(expr));
190
191         self.with_parent(expr.id, |this| {
192             intravisit::walk_expr(this, expr);
193         });
194     }
195
196     fn visit_stmt(&mut self, stmt: &'ast Stmt) {
197         let id = stmt.node.id();
198         self.insert(id, NodeStmt(stmt));
199
200         self.with_parent(id, |this| {
201             intravisit::walk_stmt(this, stmt);
202         });
203     }
204
205     fn visit_ty(&mut self, ty: &'ast Ty) {
206         self.insert(ty.id, NodeTy(ty));
207
208         self.with_parent(ty.id, |this| {
209             intravisit::walk_ty(this, ty);
210         });
211     }
212
213     fn visit_trait_ref(&mut self, tr: &'ast TraitRef) {
214         self.insert(tr.ref_id, NodeTraitRef(tr));
215
216         self.with_parent(tr.ref_id, |this| {
217             intravisit::walk_trait_ref(this, tr);
218         });
219     }
220
221     fn visit_fn(&mut self, fk: intravisit::FnKind<'ast>, fd: &'ast FnDecl,
222                 b: &'ast Expr, s: Span, id: NodeId) {
223         assert_eq!(self.parent_node, id);
224         intravisit::walk_fn(self, fk, fd, b, s, id);
225     }
226
227     fn visit_block(&mut self, block: &'ast Block) {
228         self.insert(block.id, NodeBlock(block));
229         self.with_parent(block.id, |this| {
230             intravisit::walk_block(this, block);
231         });
232     }
233
234     fn visit_lifetime(&mut self, lifetime: &'ast Lifetime) {
235         self.insert(lifetime.id, NodeLifetime(lifetime));
236     }
237
238     fn visit_vis(&mut self, visibility: &'ast Visibility) {
239         match *visibility {
240             Visibility::Public |
241             Visibility::Crate |
242             Visibility::Inherited => {}
243             Visibility::Restricted { id, .. } => {
244                 self.insert(id, NodeVisibility(visibility));
245                 self.with_parent(id, |this| {
246                     intravisit::walk_vis(this, visibility);
247                 });
248             }
249         }
250     }
251
252     fn visit_macro_def(&mut self, macro_def: &'ast MacroDef) {
253         self.insert_entry(macro_def.id, NotPresent);
254     }
255 }