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