]> git.lizzy.rs Git - rust.git/blob - src/librustc/hir/map/collector.rs
80fadcda2775d426501f90b5ceb66811834d00a9
[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 dep_graph::{DepGraph, DepKind, DepNodeIndex};
14 use hir::intravisit::{Visitor, NestedVisitorMap};
15 use std::iter::repeat;
16 use syntax::ast::{NodeId, CRATE_NODE_ID};
17 use syntax_pos::Span;
18
19 use ich::StableHashingContext;
20 use rustc_data_structures::stable_hasher::{HashStable, StableHasher, StableHasherResult};
21
22 /// A Visitor that walks over the HIR and collects Nodes into a HIR map
23 pub(super) struct NodeCollector<'a, 'hir> {
24     /// The crate
25     krate: &'hir Crate,
26     /// The node map
27     map: Vec<MapEntry<'hir>>,
28     /// The parent of this node
29     parent_node: NodeId,
30
31     // These fields keep track of the currently relevant DepNodes during
32     // the visitor's traversal.
33     current_dep_node_owner: DefIndex,
34     current_signature_dep_index: DepNodeIndex,
35     current_full_dep_index: DepNodeIndex,
36     currently_in_body: bool,
37
38     dep_graph: &'a DepGraph,
39     definitions: &'a definitions::Definitions,
40
41     hcx: StableHashingContext<'a>,
42
43     // We are collecting DepNode::HirBody hashes here so we can compute the
44     // crate hash from then later on.
45     hir_body_nodes: Vec<DefPathHash>,
46 }
47
48 impl<'a, 'hir> NodeCollector<'a, 'hir> {
49     pub(super) fn root(krate: &'hir Crate,
50                        dep_graph: &'a DepGraph,
51                        definitions: &'a definitions::Definitions,
52                        hcx: StableHashingContext<'a>)
53                 -> NodeCollector<'a, 'hir> {
54         let root_mod_def_path_hash = definitions.def_path_hash(CRATE_DEF_INDEX);
55
56         // Allocate DepNodes for the root module
57         let (root_mod_sig_dep_index, root_mod_full_dep_index);
58         {
59             let Crate {
60                 ref module,
61                 // Crate attributes are not copied over to the root `Mod`, so hash
62                 // them explicitly here.
63                 ref attrs,
64                 span,
65
66                 // These fields are handled separately:
67                 exported_macros: _,
68                 items: _,
69                 trait_items: _,
70                 impl_items: _,
71                 bodies: _,
72                 trait_impls: _,
73                 trait_default_impl: _,
74                 body_ids: _,
75             } = *krate;
76
77             root_mod_sig_dep_index = dep_graph.with_task(
78                 root_mod_def_path_hash.to_dep_node(DepKind::Hir),
79                 &hcx,
80                 HirItemLike { item_like: (module, attrs, span), hash_bodies: false },
81                 identity_fn
82             ).1;
83             root_mod_full_dep_index = dep_graph.with_task(
84                 root_mod_def_path_hash.to_dep_node(DepKind::HirBody),
85                 &hcx,
86                 HirItemLike { item_like: (module, attrs, span), hash_bodies: true },
87                 identity_fn
88             ).1;
89         }
90
91         {
92             dep_graph.with_task(
93                 DepNode::new_no_params(DepKind::AllLocalTraitImpls),
94                 &hcx,
95                 &krate.trait_impls,
96                 identity_fn
97             );
98         }
99
100         let hir_body_nodes = vec![root_mod_def_path_hash];
101
102         let mut collector = NodeCollector {
103             krate,
104             map: vec![],
105             parent_node: CRATE_NODE_ID,
106             current_signature_dep_index: root_mod_sig_dep_index,
107             current_full_dep_index: root_mod_full_dep_index,
108             current_dep_node_owner: CRATE_DEF_INDEX,
109             currently_in_body: false,
110             dep_graph,
111             definitions,
112             hcx,
113             hir_body_nodes,
114         };
115         collector.insert_entry(CRATE_NODE_ID, RootCrate(root_mod_sig_dep_index));
116
117         collector
118     }
119
120     pub(super) fn finalize_and_compute_crate_hash(self,
121                                                   crate_disambiguator: &str)
122                                                   -> Vec<MapEntry<'hir>> {
123         let mut node_hashes: Vec<_> = self
124             .hir_body_nodes
125             .iter()
126             .map(|&def_path_hash| {
127                 let dep_node = def_path_hash.to_dep_node(DepKind::HirBody);
128                 (def_path_hash, self.dep_graph.fingerprint_of(&dep_node))
129             })
130             .collect();
131
132         node_hashes.sort_unstable_by(|&(ref d1, _), &(ref d2, _)| d1.cmp(d2));
133
134         self.dep_graph.with_task(DepNode::new_no_params(DepKind::Krate),
135                                  &self.hcx,
136                                  (node_hashes, crate_disambiguator),
137                                  identity_fn);
138         self.map
139     }
140
141     fn insert_entry(&mut self, id: NodeId, entry: MapEntry<'hir>) {
142         debug!("hir_map: {:?} => {:?}", id, entry);
143         let len = self.map.len();
144         if id.as_usize() >= len {
145             self.map.extend(repeat(NotPresent).take(id.as_usize() - len + 1));
146         }
147         self.map[id.as_usize()] = entry;
148     }
149
150     fn insert(&mut self, id: NodeId, node: Node<'hir>) {
151         let parent = self.parent_node;
152         let dep_node_index = if self.currently_in_body {
153             self.current_full_dep_index
154         } else {
155             self.current_signature_dep_index
156         };
157
158         let entry = match node {
159             NodeItem(n) => EntryItem(parent, dep_node_index, n),
160             NodeForeignItem(n) => EntryForeignItem(parent, dep_node_index, n),
161             NodeTraitItem(n) => EntryTraitItem(parent, dep_node_index, n),
162             NodeImplItem(n) => EntryImplItem(parent, dep_node_index, n),
163             NodeVariant(n) => EntryVariant(parent, dep_node_index, n),
164             NodeField(n) => EntryField(parent, dep_node_index, n),
165             NodeExpr(n) => EntryExpr(parent, dep_node_index, n),
166             NodeStmt(n) => EntryStmt(parent, dep_node_index, n),
167             NodeTy(n) => EntryTy(parent, dep_node_index, n),
168             NodeTraitRef(n) => EntryTraitRef(parent, dep_node_index, n),
169             NodeBinding(n) => EntryBinding(parent, dep_node_index, n),
170             NodePat(n) => EntryPat(parent, dep_node_index, n),
171             NodeBlock(n) => EntryBlock(parent, dep_node_index, n),
172             NodeStructCtor(n) => EntryStructCtor(parent, dep_node_index, n),
173             NodeLifetime(n) => EntryLifetime(parent, dep_node_index, n),
174             NodeTyParam(n) => EntryTyParam(parent, dep_node_index, n),
175             NodeVisibility(n) => EntryVisibility(parent, dep_node_index, n),
176             NodeLocal(n) => EntryLocal(parent, dep_node_index, n),
177             NodeMacroDef(n) => EntryMacroDef(dep_node_index, n),
178         };
179
180         // Make sure that the DepNode of some node coincides with the HirId
181         // owner of that node.
182         if cfg!(debug_assertions) {
183             let hir_id_owner = self.definitions.node_to_hir_id(id).owner;
184
185             if hir_id_owner != self.current_dep_node_owner {
186                 let node_str = match self.definitions.opt_def_index(id) {
187                     Some(def_index) => {
188                         self.definitions.def_path(def_index).to_string_no_crate()
189                     }
190                     None => format!("{:?}", node)
191                 };
192
193                 bug!("inconsistent DepNode for `{}`: \
194                       current_dep_node_owner={}, hir_id.owner={}",
195                     node_str,
196                     self.definitions
197                         .def_path(self.current_dep_node_owner)
198                         .to_string_no_crate(),
199                     self.definitions.def_path(hir_id_owner).to_string_no_crate())
200             }
201         }
202
203         self.insert_entry(id, entry);
204
205     }
206
207     fn with_parent<F: FnOnce(&mut Self)>(&mut self, parent_id: NodeId, f: F) {
208         let parent_node = self.parent_node;
209         self.parent_node = parent_id;
210         f(self);
211         self.parent_node = parent_node;
212     }
213
214     fn with_dep_node_owner<T: HashStable<StableHashingContext<'a>>,
215                            F: FnOnce(&mut Self)>(&mut self,
216                                                  dep_node_owner: DefIndex,
217                                                  item_like: &T,
218                                                  f: F) {
219         let prev_owner = self.current_dep_node_owner;
220         let prev_signature_dep_index = self.current_signature_dep_index;
221         let prev_full_dep_index = self.current_signature_dep_index;
222         let prev_in_body = self.currently_in_body;
223
224         let def_path_hash = self.definitions.def_path_hash(dep_node_owner);
225
226         self.current_signature_dep_index = self.dep_graph.with_task(
227             def_path_hash.to_dep_node(DepKind::Hir),
228             &self.hcx,
229             HirItemLike { item_like, hash_bodies: false },
230             identity_fn
231         ).1;
232
233         self.current_full_dep_index = self.dep_graph.with_task(
234             def_path_hash.to_dep_node(DepKind::HirBody),
235             &self.hcx,
236             HirItemLike { item_like, hash_bodies: true },
237             identity_fn
238         ).1;
239
240         self.hir_body_nodes.push(def_path_hash);
241
242         self.current_dep_node_owner = dep_node_owner;
243         self.currently_in_body = false;
244         f(self);
245         self.currently_in_body = prev_in_body;
246         self.current_dep_node_owner = prev_owner;
247         self.current_full_dep_index = prev_full_dep_index;
248         self.current_signature_dep_index = prev_signature_dep_index;
249     }
250 }
251
252 impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
253     /// Because we want to track parent items and so forth, enable
254     /// deep walking so that we walk nested items in the context of
255     /// their outer items.
256
257     fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'hir> {
258         panic!("visit_nested_xxx must be manually implemented in this visitor")
259     }
260
261     fn visit_nested_item(&mut self, item: ItemId) {
262         debug!("visit_nested_item: {:?}", item);
263         self.visit_item(self.krate.item(item.id));
264     }
265
266     fn visit_nested_trait_item(&mut self, item_id: TraitItemId) {
267         self.visit_trait_item(self.krate.trait_item(item_id));
268     }
269
270     fn visit_nested_impl_item(&mut self, item_id: ImplItemId) {
271         self.visit_impl_item(self.krate.impl_item(item_id));
272     }
273
274     fn visit_nested_body(&mut self, id: BodyId) {
275         let prev_in_body = self.currently_in_body;
276         self.currently_in_body = true;
277         self.visit_body(self.krate.body(id));
278         self.currently_in_body = prev_in_body;
279     }
280
281     fn visit_item(&mut self, i: &'hir Item) {
282         debug!("visit_item: {:?}", i);
283         debug_assert_eq!(i.hir_id.owner,
284                          self.definitions.opt_def_index(i.id).unwrap());
285         self.with_dep_node_owner(i.hir_id.owner, i, |this| {
286             this.insert(i.id, NodeItem(i));
287             this.with_parent(i.id, |this| {
288                 match i.node {
289                     ItemStruct(ref struct_def, _) => {
290                         // If this is a tuple-like struct, register the constructor.
291                         if !struct_def.is_struct() {
292                             this.insert(struct_def.id(), NodeStructCtor(struct_def));
293                         }
294                     }
295                     _ => {}
296                 }
297                 intravisit::walk_item(this, i);
298             });
299         });
300     }
301
302     fn visit_foreign_item(&mut self, foreign_item: &'hir ForeignItem) {
303         self.insert(foreign_item.id, NodeForeignItem(foreign_item));
304
305         self.with_parent(foreign_item.id, |this| {
306             intravisit::walk_foreign_item(this, foreign_item);
307         });
308     }
309
310     fn visit_generics(&mut self, generics: &'hir Generics) {
311         for ty_param in generics.ty_params.iter() {
312             self.insert(ty_param.id, NodeTyParam(ty_param));
313         }
314
315         intravisit::walk_generics(self, generics);
316     }
317
318     fn visit_trait_item(&mut self, ti: &'hir TraitItem) {
319         debug_assert_eq!(ti.hir_id.owner,
320                          self.definitions.opt_def_index(ti.id).unwrap());
321         self.with_dep_node_owner(ti.hir_id.owner, ti, |this| {
322             this.insert(ti.id, NodeTraitItem(ti));
323
324             this.with_parent(ti.id, |this| {
325                 intravisit::walk_trait_item(this, ti);
326             });
327         });
328     }
329
330     fn visit_impl_item(&mut self, ii: &'hir ImplItem) {
331         debug_assert_eq!(ii.hir_id.owner,
332                          self.definitions.opt_def_index(ii.id).unwrap());
333         self.with_dep_node_owner(ii.hir_id.owner, ii, |this| {
334             this.insert(ii.id, NodeImplItem(ii));
335
336             this.with_parent(ii.id, |this| {
337                 intravisit::walk_impl_item(this, ii);
338             });
339         });
340     }
341
342     fn visit_pat(&mut self, pat: &'hir Pat) {
343         let node = if let PatKind::Binding(..) = pat.node {
344             NodeBinding(pat)
345         } else {
346             NodePat(pat)
347         };
348         self.insert(pat.id, node);
349
350         self.with_parent(pat.id, |this| {
351             intravisit::walk_pat(this, pat);
352         });
353     }
354
355     fn visit_expr(&mut self, expr: &'hir Expr) {
356         self.insert(expr.id, NodeExpr(expr));
357
358         self.with_parent(expr.id, |this| {
359             intravisit::walk_expr(this, expr);
360         });
361     }
362
363     fn visit_stmt(&mut self, stmt: &'hir Stmt) {
364         let id = stmt.node.id();
365         self.insert(id, NodeStmt(stmt));
366
367         self.with_parent(id, |this| {
368             intravisit::walk_stmt(this, stmt);
369         });
370     }
371
372     fn visit_ty(&mut self, ty: &'hir Ty) {
373         self.insert(ty.id, NodeTy(ty));
374
375         self.with_parent(ty.id, |this| {
376             intravisit::walk_ty(this, ty);
377         });
378     }
379
380     fn visit_trait_ref(&mut self, tr: &'hir TraitRef) {
381         self.insert(tr.ref_id, NodeTraitRef(tr));
382
383         self.with_parent(tr.ref_id, |this| {
384             intravisit::walk_trait_ref(this, tr);
385         });
386     }
387
388     fn visit_fn(&mut self, fk: intravisit::FnKind<'hir>, fd: &'hir FnDecl,
389                 b: BodyId, s: Span, id: NodeId) {
390         assert_eq!(self.parent_node, id);
391         intravisit::walk_fn(self, fk, fd, b, s, id);
392     }
393
394     fn visit_block(&mut self, block: &'hir Block) {
395         self.insert(block.id, NodeBlock(block));
396         self.with_parent(block.id, |this| {
397             intravisit::walk_block(this, block);
398         });
399     }
400
401     fn visit_local(&mut self, l: &'hir Local) {
402         self.insert(l.id, NodeLocal(l));
403         self.with_parent(l.id, |this| {
404             intravisit::walk_local(this, l)
405         })
406     }
407
408     fn visit_lifetime(&mut self, lifetime: &'hir Lifetime) {
409         self.insert(lifetime.id, NodeLifetime(lifetime));
410     }
411
412     fn visit_vis(&mut self, visibility: &'hir Visibility) {
413         match *visibility {
414             Visibility::Public |
415             Visibility::Crate |
416             Visibility::Inherited => {}
417             Visibility::Restricted { id, .. } => {
418                 self.insert(id, NodeVisibility(visibility));
419                 self.with_parent(id, |this| {
420                     intravisit::walk_vis(this, visibility);
421                 });
422             }
423         }
424     }
425
426     fn visit_macro_def(&mut self, macro_def: &'hir MacroDef) {
427         let def_index = self.definitions.opt_def_index(macro_def.id).unwrap();
428
429         self.with_dep_node_owner(def_index, macro_def, |this| {
430             this.insert(macro_def.id, NodeMacroDef(macro_def));
431         });
432     }
433
434     fn visit_variant(&mut self, v: &'hir Variant, g: &'hir Generics, item_id: NodeId) {
435         let id = v.node.data.id();
436         self.insert(id, NodeVariant(v));
437         self.with_parent(id, |this| {
438             intravisit::walk_variant(this, v, g, item_id);
439         });
440     }
441
442     fn visit_struct_field(&mut self, field: &'hir StructField) {
443         self.insert(field.id, NodeField(field));
444         self.with_parent(field.id, |this| {
445             intravisit::walk_struct_field(this, field);
446         });
447     }
448
449     fn visit_trait_item_ref(&mut self, ii: &'hir TraitItemRef) {
450         // Do not visit the duplicate information in TraitItemRef. We want to
451         // map the actual nodes, not the duplicate ones in the *Ref.
452         let TraitItemRef {
453             id,
454             name: _,
455             kind: _,
456             span: _,
457             defaultness: _,
458         } = *ii;
459
460         self.visit_nested_trait_item(id);
461     }
462
463     fn visit_impl_item_ref(&mut self, ii: &'hir ImplItemRef) {
464         // Do not visit the duplicate information in ImplItemRef. We want to
465         // map the actual nodes, not the duplicate ones in the *Ref.
466         let ImplItemRef {
467             id,
468             name: _,
469             kind: _,
470             span: _,
471             vis: _,
472             defaultness: _,
473         } = *ii;
474
475         self.visit_nested_impl_item(id);
476     }
477 }
478
479 // We use this with DepGraph::with_task(). Since we are handling only input
480 // values here, the "task" computing them just passes them through.
481 fn identity_fn<T>(_: &StableHashingContext, item_like: T) -> T {
482     item_like
483 }
484
485 // This is a wrapper structure that allows determining if span values within
486 // the wrapped item should be hashed or not.
487 struct HirItemLike<T> {
488     item_like: T,
489     hash_bodies: bool,
490 }
491
492 impl<'hir, T> HashStable<StableHashingContext<'hir>> for HirItemLike<T>
493     where T: HashStable<StableHashingContext<'hir>>
494 {
495     fn hash_stable<W: StableHasherResult>(&self,
496                                           hcx: &mut StableHashingContext<'hir>,
497                                           hasher: &mut StableHasher<W>) {
498         hcx.while_hashing_hir_bodies(self.hash_bodies, |hcx| {
499             self.item_like.hash_stable(hcx, hasher);
500         });
501     }
502 }