]> git.lizzy.rs Git - rust.git/blob - src/librustc/hir/map/collector.rs
Changed issue number to 36105
[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 use super::MapEntry::*;
13
14 use hir::*;
15 use hir::intravisit::Visitor;
16 use hir::def_id::DefId;
17 use middle::cstore::InlinedItem;
18 use std::iter::repeat;
19 use syntax::ast::{NodeId, CRATE_NODE_ID};
20 use syntax_pos::Span;
21
22 /// A Visitor that walks over the HIR and collects Nodes into a HIR map
23 pub struct NodeCollector<'ast> {
24     /// The crate
25     pub krate: &'ast Crate,
26     /// The node map
27     pub map: Vec<MapEntry<'ast>>,
28     /// The parent of this node
29     pub parent_node: NodeId,
30 }
31
32 impl<'ast> NodeCollector<'ast> {
33     pub fn root(krate: &'ast Crate) -> NodeCollector<'ast> {
34         let mut collector = NodeCollector {
35             krate: krate,
36             map: vec![],
37             parent_node: CRATE_NODE_ID,
38         };
39         collector.insert_entry(CRATE_NODE_ID, RootCrate);
40
41         collector
42     }
43
44     pub fn extend(krate: &'ast Crate,
45                   parent: &'ast InlinedItem,
46                   parent_node: NodeId,
47                   parent_def_path: DefPath,
48                   parent_def_id: DefId,
49                   map: Vec<MapEntry<'ast>>)
50                   -> NodeCollector<'ast> {
51         let mut collector = NodeCollector {
52             krate: krate,
53             map: map,
54             parent_node: parent_node,
55         };
56
57         assert_eq!(parent_def_path.krate, parent_def_id.krate);
58         collector.insert_entry(parent_node, RootInlinedParent(parent));
59
60         collector
61     }
62
63     fn insert_entry(&mut self, id: NodeId, entry: MapEntry<'ast>) {
64         debug!("ast_map: {:?} => {:?}", id, entry);
65         let len = self.map.len();
66         if id as usize >= len {
67             self.map.extend(repeat(NotPresent).take(id as usize - len + 1));
68         }
69         self.map[id as usize] = entry;
70     }
71
72     fn insert(&mut self, id: NodeId, node: Node<'ast>) {
73         let entry = MapEntry::from_node(self.parent_node, node);
74         self.insert_entry(id, entry);
75     }
76
77     fn with_parent<F: FnOnce(&mut Self)>(&mut self, parent_id: NodeId, f: F) {
78         let parent_node = self.parent_node;
79         self.parent_node = parent_id;
80         f(self);
81         self.parent_node = parent_node;
82     }
83 }
84
85 impl<'ast> Visitor<'ast> for NodeCollector<'ast> {
86     /// Because we want to track parent items and so forth, enable
87     /// deep walking so that we walk nested items in the context of
88     /// their outer items.
89     fn visit_nested_item(&mut self, item: ItemId) {
90         debug!("visit_nested_item: {:?}", item);
91         self.visit_item(self.krate.item(item.id))
92     }
93
94     fn visit_item(&mut self, i: &'ast Item) {
95         debug!("visit_item: {:?}", i);
96
97         self.insert(i.id, NodeItem(i));
98
99         self.with_parent(i.id, |this| {
100             match i.node {
101                 ItemEnum(ref enum_definition, _) => {
102                     for v in &enum_definition.variants {
103                         this.insert(v.node.data.id(), NodeVariant(v));
104                     }
105                 }
106                 ItemStruct(ref struct_def, _) => {
107                     // If this is a tuple-like struct, register the constructor.
108                     if !struct_def.is_struct() {
109                         this.insert(struct_def.id(), NodeStructCtor(struct_def));
110                     }
111                 }
112                 ItemTrait(_, _, ref bounds, _) => {
113                     for b in bounds.iter() {
114                         if let TraitTyParamBound(ref t, TraitBoundModifier::None) = *b {
115                             this.insert(t.trait_ref.ref_id, NodeItem(i));
116                         }
117                     }
118                 }
119                 ItemUse(ref view_path) => {
120                     match view_path.node {
121                         ViewPathList(_, ref paths) => {
122                             for path in paths {
123                                 this.insert(path.node.id(), NodeItem(i));
124                             }
125                         }
126                         _ => ()
127                     }
128                 }
129                 _ => {}
130             }
131             intravisit::walk_item(this, i);
132         });
133     }
134
135     fn visit_foreign_item(&mut self, foreign_item: &'ast ForeignItem) {
136         self.insert(foreign_item.id, NodeForeignItem(foreign_item));
137
138         self.with_parent(foreign_item.id, |this| {
139             intravisit::walk_foreign_item(this, foreign_item);
140         });
141     }
142
143     fn visit_generics(&mut self, generics: &'ast Generics) {
144         for ty_param in generics.ty_params.iter() {
145             self.insert(ty_param.id, NodeTyParam(ty_param));
146         }
147
148         intravisit::walk_generics(self, generics);
149     }
150
151     fn visit_trait_item(&mut self, ti: &'ast TraitItem) {
152         self.insert(ti.id, NodeTraitItem(ti));
153
154         self.with_parent(ti.id, |this| {
155             intravisit::walk_trait_item(this, ti);
156         });
157     }
158
159     fn visit_impl_item(&mut self, ii: &'ast ImplItem) {
160         self.insert(ii.id, NodeImplItem(ii));
161
162         self.with_parent(ii.id, |this| {
163             intravisit::walk_impl_item(this, ii);
164         });
165     }
166
167     fn visit_pat(&mut self, pat: &'ast Pat) {
168         let node = if let PatKind::Binding(..) = pat.node {
169             NodeLocal(pat)
170         } else {
171             NodePat(pat)
172         };
173         self.insert(pat.id, node);
174
175         self.with_parent(pat.id, |this| {
176             intravisit::walk_pat(this, pat);
177         });
178     }
179
180     fn visit_expr(&mut self, expr: &'ast Expr) {
181         self.insert(expr.id, NodeExpr(expr));
182
183         self.with_parent(expr.id, |this| {
184             intravisit::walk_expr(this, expr);
185         });
186     }
187
188     fn visit_stmt(&mut self, stmt: &'ast Stmt) {
189         let id = stmt.node.id();
190         self.insert(id, NodeStmt(stmt));
191
192         self.with_parent(id, |this| {
193             intravisit::walk_stmt(this, stmt);
194         });
195     }
196
197     fn visit_ty(&mut self, ty: &'ast Ty) {
198         self.insert(ty.id, NodeTy(ty));
199
200         self.with_parent(ty.id, |this| {
201             intravisit::walk_ty(this, ty);
202         });
203     }
204
205     fn visit_fn(&mut self, fk: intravisit::FnKind<'ast>, fd: &'ast FnDecl,
206                 b: &'ast Block, s: Span, id: NodeId) {
207         assert_eq!(self.parent_node, id);
208         intravisit::walk_fn(self, fk, fd, b, s, id);
209     }
210
211     fn visit_block(&mut self, block: &'ast Block) {
212         self.insert(block.id, NodeBlock(block));
213         self.with_parent(block.id, |this| {
214             intravisit::walk_block(this, block);
215         });
216     }
217
218     fn visit_lifetime(&mut self, lifetime: &'ast Lifetime) {
219         self.insert(lifetime.id, NodeLifetime(lifetime));
220     }
221 }