]> git.lizzy.rs Git - rust.git/blob - src/librustc_save_analysis/dump_visitor.rs
Rollup merge of #47277 - tspiteri:log-correctness, r=frewsxcv
[rust.git] / src / librustc_save_analysis / dump_visitor.rs
1 // Copyright 2015 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 //! Write the output of rustc's analysis to an implementor of Dump.
12 //!
13 //! Dumping the analysis is implemented by walking the AST and getting a bunch of
14 //! info out from all over the place. We use Def IDs to identify objects. The
15 //! tricky part is getting syntactic (span, source text) and semantic (reference
16 //! Def IDs) information for parts of expressions which the compiler has discarded.
17 //! E.g., in a path `foo::bar::baz`, the compiler only keeps a span for the whole
18 //! path and a reference to `baz`, but we want spans and references for all three
19 //! idents.
20 //!
21 //! SpanUtils is used to manipulate spans. In particular, to extract sub-spans
22 //! from spans (e.g., the span for `bar` from the above example path).
23 //! DumpVisitor walks the AST and processes it, and an implementor of Dump
24 //! is used for recording the output in a format-agnostic way (see CsvDumper
25 //! for an example).
26
27 use rustc::hir::def::Def as HirDef;
28 use rustc::hir::def_id::DefId;
29 use rustc::hir::map::Node;
30 use rustc::ty::{self, TyCtxt};
31 use rustc_data_structures::fx::FxHashSet;
32
33 use std::path::Path;
34
35 use syntax::ast::{self, Attribute, NodeId, PatKind, CRATE_NODE_ID};
36 use syntax::parse::token;
37 use syntax::symbol::keywords;
38 use syntax::visit::{self, Visitor};
39 use syntax::print::pprust::{
40     bounds_to_string,
41     generic_params_to_string,
42     path_to_string,
43     ty_to_string
44 };
45 use syntax::ptr::P;
46 use syntax::codemap::{Spanned, DUMMY_SP};
47 use syntax_pos::*;
48
49 use {escape, generated_code, lower_attributes, PathCollector, SaveContext};
50 use json_dumper::{Access, DumpOutput, JsonDumper};
51 use span_utils::SpanUtils;
52 use sig;
53
54 use rls_data::{CratePreludeData, Def, DefKind, GlobalCrateId, Import, ImportKind, Ref, RefKind,
55                Relation, RelationKind, SpanData};
56
57 macro_rules! down_cast_data {
58     ($id:ident, $kind:ident, $sp:expr) => {
59         let $id = if let super::Data::$kind(data) = $id {
60             data
61         } else {
62             span_bug!($sp, "unexpected data kind: {:?}", $id);
63         };
64     };
65 }
66
67 macro_rules! access_from {
68     ($save_ctxt:expr, $item:expr) => {
69         Access {
70             public: $item.vis == ast::Visibility::Public,
71             reachable: $save_ctxt.analysis.access_levels.is_reachable($item.id),
72         }
73     }
74 }
75
76 pub struct DumpVisitor<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> {
77     save_ctxt: SaveContext<'l, 'tcx>,
78     tcx: TyCtxt<'l, 'tcx, 'tcx>,
79     dumper: &'ll mut JsonDumper<O>,
80
81     span: SpanUtils<'l>,
82
83     cur_scope: NodeId,
84
85     // Set of macro definition (callee) spans, and the set
86     // of macro use (callsite) spans. We store these to ensure
87     // we only write one macro def per unique macro definition, and
88     // one macro use per unique callsite span.
89     // mac_defs: HashSet<Span>,
90     macro_calls: FxHashSet<Span>,
91 }
92
93 impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
94     pub fn new(
95         save_ctxt: SaveContext<'l, 'tcx>,
96         dumper: &'ll mut JsonDumper<O>,
97     ) -> DumpVisitor<'l, 'tcx, 'll, O> {
98         let span_utils = SpanUtils::new(&save_ctxt.tcx.sess);
99         DumpVisitor {
100             tcx: save_ctxt.tcx,
101             save_ctxt,
102             dumper,
103             span: span_utils.clone(),
104             cur_scope: CRATE_NODE_ID,
105             // mac_defs: HashSet::new(),
106             macro_calls: FxHashSet(),
107         }
108     }
109
110     fn nest_scope<F>(&mut self, scope_id: NodeId, f: F)
111     where
112         F: FnOnce(&mut DumpVisitor<'l, 'tcx, 'll, O>),
113     {
114         let parent_scope = self.cur_scope;
115         self.cur_scope = scope_id;
116         f(self);
117         self.cur_scope = parent_scope;
118     }
119
120     fn nest_tables<F>(&mut self, item_id: NodeId, f: F)
121     where
122         F: FnOnce(&mut DumpVisitor<'l, 'tcx, 'll, O>),
123     {
124         let item_def_id = self.tcx.hir.local_def_id(item_id);
125         if self.tcx.has_typeck_tables(item_def_id) {
126             let tables = self.tcx.typeck_tables_of(item_def_id);
127             let old_tables = self.save_ctxt.tables;
128             self.save_ctxt.tables = tables;
129             f(self);
130             self.save_ctxt.tables = old_tables;
131         } else {
132             f(self);
133         }
134     }
135
136     fn span_from_span(&self, span: Span) -> SpanData {
137         self.save_ctxt.span_from_span(span)
138     }
139
140     pub fn dump_crate_info(&mut self, name: &str, krate: &ast::Crate) {
141         let source_file = self.tcx.sess.local_crate_source_file.as_ref();
142         let crate_root = source_file.map(|source_file| {
143             let source_file = Path::new(source_file);
144             match source_file.file_name() {
145                 Some(_) => source_file.parent().unwrap().display().to_string(),
146                 None => source_file.display().to_string(),
147             }
148         });
149
150         let data = CratePreludeData {
151             crate_id: GlobalCrateId {
152                 name: name.into(),
153                 disambiguator: self.tcx
154                     .sess
155                     .local_crate_disambiguator()
156                     .to_fingerprint()
157                     .as_value(),
158             },
159             crate_root: crate_root.unwrap_or("<no source>".to_owned()),
160             external_crates: self.save_ctxt.get_external_crates(),
161             span: self.span_from_span(krate.span),
162         };
163
164         self.dumper.crate_prelude(data);
165     }
166
167     // Return all non-empty prefixes of a path.
168     // For each prefix, we return the span for the last segment in the prefix and
169     // a str representation of the entire prefix.
170     fn process_path_prefixes(&self, path: &ast::Path) -> Vec<(Span, String)> {
171         let segments = &path.segments[if path.is_global() { 1 } else { 0 }..];
172
173         let mut result = Vec::with_capacity(segments.len());
174
175         let mut segs = vec![];
176         for (i, seg) in segments.iter().enumerate() {
177             segs.push(seg.clone());
178             let sub_path = ast::Path {
179                 span: seg.span, // span for the last segment
180                 segments: segs,
181             };
182             let qualname = if i == 0 && path.is_global() {
183                 format!("::{}", path_to_string(&sub_path))
184             } else {
185                 path_to_string(&sub_path)
186             };
187             result.push((seg.span, qualname));
188             segs = sub_path.segments;
189         }
190
191         result
192     }
193
194     fn write_sub_paths(&mut self, path: &ast::Path) {
195         let sub_paths = self.process_path_prefixes(path);
196         for (span, _) in sub_paths {
197             let span = self.span_from_span(span);
198             self.dumper.dump_ref(Ref {
199                 kind: RefKind::Mod,
200                 span,
201                 ref_id: ::null_id(),
202             });
203         }
204     }
205
206     // As write_sub_paths, but does not process the last ident in the path (assuming it
207     // will be processed elsewhere). See note on write_sub_paths about global.
208     fn write_sub_paths_truncated(&mut self, path: &ast::Path) {
209         let sub_paths = self.process_path_prefixes(path);
210         let len = sub_paths.len();
211         if len <= 1 {
212             return;
213         }
214
215         for (span, _) in sub_paths.into_iter().take(len - 1) {
216             let span = self.span_from_span(span);
217             self.dumper.dump_ref(Ref {
218                 kind: RefKind::Mod,
219                 span,
220                 ref_id: ::null_id(),
221             });
222         }
223     }
224
225     // As write_sub_paths, but expects a path of the form module_path::trait::method
226     // Where trait could actually be a struct too.
227     fn write_sub_path_trait_truncated(&mut self, path: &ast::Path) {
228         let sub_paths = self.process_path_prefixes(path);
229         let len = sub_paths.len();
230         if len <= 1 {
231             return;
232         }
233         let sub_paths = &sub_paths[..(len - 1)];
234
235         // write the trait part of the sub-path
236         let (ref span, _) = sub_paths[len - 2];
237         let span = self.span_from_span(*span);
238         self.dumper.dump_ref(Ref {
239             kind: RefKind::Type,
240             ref_id: ::null_id(),
241             span,
242         });
243
244         // write the other sub-paths
245         if len <= 2 {
246             return;
247         }
248         let sub_paths = &sub_paths[..len - 2];
249         for &(ref span, _) in sub_paths {
250             let span = self.span_from_span(*span);
251             self.dumper.dump_ref(Ref {
252                 kind: RefKind::Mod,
253                 span,
254                 ref_id: ::null_id(),
255             });
256         }
257     }
258
259     fn lookup_def_id(&self, ref_id: NodeId) -> Option<DefId> {
260         match self.save_ctxt.get_path_def(ref_id) {
261             HirDef::PrimTy(..) | HirDef::SelfTy(..) | HirDef::Err => None,
262             def => Some(def.def_id()),
263         }
264     }
265
266     fn process_def_kind(
267         &mut self,
268         ref_id: NodeId,
269         span: Span,
270         sub_span: Option<Span>,
271         def_id: DefId,
272     ) {
273         if self.span.filter_generated(sub_span, span) {
274             return;
275         }
276
277         let def = self.save_ctxt.get_path_def(ref_id);
278         match def {
279             HirDef::Mod(_) => {
280                 let span = self.span_from_span(sub_span.expect("No span found for mod ref"));
281                 self.dumper.dump_ref(Ref {
282                     kind: RefKind::Mod,
283                     span,
284                     ref_id: ::id_from_def_id(def_id),
285                 });
286             }
287             HirDef::Struct(..) |
288             HirDef::Variant(..) |
289             HirDef::Union(..) |
290             HirDef::Enum(..) |
291             HirDef::TyAlias(..) |
292             HirDef::TyForeign(..) |
293             HirDef::TraitAlias(..) |
294             HirDef::Trait(_) => {
295                 let span = self.span_from_span(sub_span.expect("No span found for type ref"));
296                 self.dumper.dump_ref(Ref {
297                     kind: RefKind::Type,
298                     span,
299                     ref_id: ::id_from_def_id(def_id),
300                 });
301             }
302             HirDef::Static(..) |
303             HirDef::Const(..) |
304             HirDef::StructCtor(..) |
305             HirDef::VariantCtor(..) => {
306                 let span = self.span_from_span(sub_span.expect("No span found for var ref"));
307                 self.dumper.dump_ref(Ref {
308                     kind: RefKind::Variable,
309                     span,
310                     ref_id: ::id_from_def_id(def_id),
311                 });
312             }
313             HirDef::Fn(..) => {
314                 let span = self.span_from_span(sub_span.expect("No span found for fn ref"));
315                 self.dumper.dump_ref(Ref {
316                     kind: RefKind::Function,
317                     span,
318                     ref_id: ::id_from_def_id(def_id),
319                 });
320             }
321             // With macros 2.0, we can legitimately get a ref to a macro, but
322             // we don't handle it properly for now (FIXME).
323             HirDef::Macro(..) => {}
324             HirDef::Local(..) |
325             HirDef::Upvar(..) |
326             HirDef::SelfTy(..) |
327             HirDef::Label(_) |
328             HirDef::TyParam(..) |
329             HirDef::Method(..) |
330             HirDef::AssociatedTy(..) |
331             HirDef::AssociatedConst(..) |
332             HirDef::PrimTy(_) |
333             HirDef::GlobalAsm(_) |
334             HirDef::Err => {
335                 span_bug!(span, "process_def_kind for unexpected item: {:?}", def);
336             }
337         }
338     }
339
340     fn process_formals(&mut self, formals: &'l [ast::Arg], qualname: &str) {
341         for arg in formals {
342             self.visit_pat(&arg.pat);
343             let mut collector = PathCollector::new();
344             collector.visit_pat(&arg.pat);
345             let span_utils = self.span.clone();
346
347             for (id, i, sp, ..) in collector.collected_idents {
348                 let hir_id = self.tcx.hir.node_to_hir_id(id);
349                 let typ = match self.save_ctxt.tables.node_id_to_type_opt(hir_id) {
350                     Some(s) => s.to_string(),
351                     None => continue,
352                 };
353                 let sub_span = span_utils.span_for_last_ident(sp);
354                 if !self.span.filter_generated(sub_span, sp) {
355                     let id = ::id_from_node_id(id, &self.save_ctxt);
356                     let span = self.span_from_span(sub_span.expect("No span found for variable"));
357
358                     self.dumper.dump_def(
359                         &Access {
360                             public: false,
361                             reachable: false,
362                         },
363                         Def {
364                             kind: DefKind::Local,
365                             id,
366                             span,
367                             name: i.to_string(),
368                             qualname: format!("{}::{}", qualname, i.to_string()),
369                             value: typ,
370                             parent: None,
371                             children: vec![],
372                             decl_id: None,
373                             docs: String::new(),
374                             sig: None,
375                             attributes: vec![],
376                         },
377                     );
378                 }
379             }
380         }
381     }
382
383     fn process_method(
384         &mut self,
385         sig: &'l ast::MethodSig,
386         body: Option<&'l ast::Block>,
387         id: ast::NodeId,
388         name: ast::Ident,
389         generics: &'l ast::Generics,
390         vis: ast::Visibility,
391         span: Span,
392     ) {
393         debug!("process_method: {}:{}", id, name);
394
395         if let Some(mut method_data) = self.save_ctxt.get_method_data(id, name.name, span) {
396             let sig_str = ::make_signature(&sig.decl, &generics);
397             if body.is_some() {
398                 self.nest_tables(
399                     id,
400                     |v| v.process_formals(&sig.decl.inputs, &method_data.qualname),
401                 );
402             }
403
404             self.process_generic_params(&generics, span, &method_data.qualname, id);
405
406             method_data.value = sig_str;
407             method_data.sig = sig::method_signature(id, name, generics, sig, &self.save_ctxt);
408             self.dumper.dump_def(
409                 &Access {
410                     public: vis == ast::Visibility::Public,
411                     reachable: self.save_ctxt.analysis.access_levels.is_reachable(id),
412                 },
413                 method_data);
414         }
415
416         // walk arg and return types
417         for arg in &sig.decl.inputs {
418             self.visit_ty(&arg.ty);
419         }
420
421         if let ast::FunctionRetTy::Ty(ref ret_ty) = sig.decl.output {
422             self.visit_ty(ret_ty);
423         }
424
425         // walk the fn body
426         if let Some(body) = body {
427             self.nest_tables(id, |v| v.nest_scope(id, |v| v.visit_block(body)));
428         }
429     }
430
431     fn process_struct_field_def(&mut self, field: &ast::StructField, parent_id: NodeId) {
432         let field_data = self.save_ctxt.get_field_data(field, parent_id);
433         if let Some(field_data) = field_data {
434             self.dumper.dump_def(&access_from!(self.save_ctxt, field), field_data);
435         }
436     }
437
438     // Dump generic params bindings, then visit_generics
439     fn process_generic_params(
440         &mut self,
441         generics: &'l ast::Generics,
442         full_span: Span,
443         prefix: &str,
444         id: NodeId,
445     ) {
446         for param in &generics.params {
447             if let ast::GenericParam::Type(ref ty_param) = *param {
448                 let param_ss = ty_param.span;
449                 let name = escape(self.span.snippet(param_ss));
450                 // Append $id to name to make sure each one is unique
451                 let qualname = format!("{}::{}${}", prefix, name, id);
452                 if !self.span.filter_generated(Some(param_ss), full_span) {
453                     let id = ::id_from_node_id(ty_param.id, &self.save_ctxt);
454                     let span = self.span_from_span(param_ss);
455
456                     self.dumper.dump_def(
457                         &Access {
458                             public: false,
459                             reachable: false,
460                         },
461                         Def {
462                             kind: DefKind::Type,
463                             id,
464                             span,
465                             name,
466                             qualname,
467                             value: String::new(),
468                             parent: None,
469                             children: vec![],
470                             decl_id: None,
471                             docs: String::new(),
472                             sig: None,
473                             attributes: vec![],
474                         },
475                     );
476                 }
477             }
478         }
479         self.visit_generics(generics);
480     }
481
482     fn process_fn(
483         &mut self,
484         item: &'l ast::Item,
485         decl: &'l ast::FnDecl,
486         ty_params: &'l ast::Generics,
487         body: &'l ast::Block,
488     ) {
489         if let Some(fn_data) = self.save_ctxt.get_item_data(item) {
490             down_cast_data!(fn_data, DefData, item.span);
491             self.nest_tables(
492                 item.id,
493                 |v| v.process_formals(&decl.inputs, &fn_data.qualname),
494             );
495             self.process_generic_params(ty_params, item.span, &fn_data.qualname, item.id);
496             self.dumper.dump_def(&access_from!(self.save_ctxt, item), fn_data);
497         }
498
499         for arg in &decl.inputs {
500             self.visit_ty(&arg.ty);
501         }
502
503         if let ast::FunctionRetTy::Ty(ref ret_ty) = decl.output {
504             self.visit_ty(&ret_ty);
505         }
506
507         self.nest_tables(item.id, |v| v.nest_scope(item.id, |v| v.visit_block(&body)));
508     }
509
510     fn process_static_or_const_item(
511         &mut self,
512         item: &'l ast::Item,
513         typ: &'l ast::Ty,
514         expr: &'l ast::Expr,
515     ) {
516         self.nest_tables(item.id, |v| {
517             if let Some(var_data) = v.save_ctxt.get_item_data(item) {
518                 down_cast_data!(var_data, DefData, item.span);
519                 v.dumper.dump_def(&access_from!(v.save_ctxt, item), var_data);
520             }
521             v.visit_ty(&typ);
522             v.visit_expr(expr);
523         });
524     }
525
526     fn process_assoc_const(
527         &mut self,
528         id: ast::NodeId,
529         name: ast::Name,
530         span: Span,
531         typ: &'l ast::Ty,
532         expr: Option<&'l ast::Expr>,
533         parent_id: DefId,
534         vis: ast::Visibility,
535         attrs: &'l [Attribute],
536     ) {
537         let qualname = format!("::{}", self.tcx.node_path_str(id));
538
539         let sub_span = self.span.sub_span_after_keyword(span, keywords::Const);
540
541         if !self.span.filter_generated(sub_span, span) {
542             let sig = sig::assoc_const_signature(id, name, typ, expr, &self.save_ctxt);
543             let span = self.span_from_span(sub_span.expect("No span found for variable"));
544
545             self.dumper.dump_def(
546                 &Access {
547                     public: vis == ast::Visibility::Public,
548                     reachable: self.save_ctxt.analysis.access_levels.is_reachable(id),
549                 },
550                 Def {
551                     kind: DefKind::Const,
552                     id: ::id_from_node_id(id, &self.save_ctxt),
553                     span,
554                     name: name.to_string(),
555                     qualname,
556                     value: ty_to_string(&typ),
557                     parent: Some(::id_from_def_id(parent_id)),
558                     children: vec![],
559                     decl_id: None,
560                     docs: self.save_ctxt.docs_for_attrs(attrs),
561                     sig,
562                     attributes: lower_attributes(attrs.to_owned(), &self.save_ctxt),
563                 },
564             );
565         }
566
567         // walk type and init value
568         self.visit_ty(typ);
569         if let Some(expr) = expr {
570             self.visit_expr(expr);
571         }
572     }
573
574     // FIXME tuple structs should generate tuple-specific data.
575     fn process_struct(
576         &mut self,
577         item: &'l ast::Item,
578         def: &'l ast::VariantData,
579         ty_params: &'l ast::Generics,
580     ) {
581         debug!("process_struct {:?} {:?}", item, item.span);
582         let name = item.ident.to_string();
583         let qualname = format!("::{}", self.tcx.node_path_str(item.id));
584
585         let (kind, keyword) = match item.node {
586             ast::ItemKind::Struct(_, _) => (DefKind::Struct, keywords::Struct),
587             ast::ItemKind::Union(_, _) => (DefKind::Union, keywords::Union),
588             _ => unreachable!(),
589         };
590
591         let sub_span = self.span.sub_span_after_keyword(item.span, keyword);
592         let (value, fields) = match item.node {
593             ast::ItemKind::Struct(ast::VariantData::Struct(ref fields, _), _) |
594             ast::ItemKind::Union(ast::VariantData::Struct(ref fields, _), _) => {
595                 let include_priv_fields = !self.save_ctxt.config.pub_only;
596                 let fields_str = fields
597                     .iter()
598                     .enumerate()
599                     .filter_map(|(i, f)| {
600                         if include_priv_fields || f.vis == ast::Visibility::Public {
601                             f.ident
602                                 .map(|i| i.to_string())
603                                 .or_else(|| Some(i.to_string()))
604                         } else {
605                             None
606                         }
607                     })
608                     .collect::<Vec<_>>()
609                     .join(", ");
610                 let value = format!("{} {{ {} }}", name, fields_str);
611                 (
612                     value,
613                     fields
614                         .iter()
615                         .map(|f| ::id_from_node_id(f.id, &self.save_ctxt))
616                         .collect(),
617                 )
618             }
619             _ => (String::new(), vec![]),
620         };
621
622         if !self.span.filter_generated(sub_span, item.span) {
623             let span = self.span_from_span(sub_span.expect("No span found for struct"));
624             self.dumper.dump_def(
625                 &access_from!(self.save_ctxt, item),
626                 Def {
627                     kind,
628                     id: ::id_from_node_id(item.id, &self.save_ctxt),
629                     span,
630                     name,
631                     qualname: qualname.clone(),
632                     value,
633                     parent: None,
634                     children: fields,
635                     decl_id: None,
636                     docs: self.save_ctxt.docs_for_attrs(&item.attrs),
637                     sig: sig::item_signature(item, &self.save_ctxt),
638                     attributes: lower_attributes(item.attrs.clone(), &self.save_ctxt),
639                 },
640             );
641         }
642
643         for field in def.fields() {
644             self.process_struct_field_def(field, item.id);
645             self.visit_ty(&field.ty);
646         }
647
648         self.process_generic_params(ty_params, item.span, &qualname, item.id);
649     }
650
651     fn process_enum(
652         &mut self,
653         item: &'l ast::Item,
654         enum_definition: &'l ast::EnumDef,
655         ty_params: &'l ast::Generics,
656     ) {
657         let enum_data = self.save_ctxt.get_item_data(item);
658         let enum_data = match enum_data {
659             None => return,
660             Some(data) => data,
661         };
662         down_cast_data!(enum_data, DefData, item.span);
663
664         let access = access_from!(self.save_ctxt, item);
665
666         for variant in &enum_definition.variants {
667             let name = variant.node.name.name.to_string();
668             let mut qualname = enum_data.qualname.clone();
669             qualname.push_str("::");
670             qualname.push_str(&name);
671
672             match variant.node.data {
673                 ast::VariantData::Struct(ref fields, _) => {
674                     let sub_span = self.span.span_for_first_ident(variant.span);
675                     let fields_str = fields
676                         .iter()
677                         .enumerate()
678                         .map(|(i, f)| {
679                             f.ident.map(|i| i.to_string()).unwrap_or(i.to_string())
680                         })
681                         .collect::<Vec<_>>()
682                         .join(", ");
683                     let value = format!("{}::{} {{ {} }}", enum_data.name, name, fields_str);
684                     if !self.span.filter_generated(sub_span, variant.span) {
685                         let span = self
686                             .span_from_span(sub_span.expect("No span found for struct variant"));
687                         let id = ::id_from_node_id(variant.node.data.id(), &self.save_ctxt);
688                         let parent = Some(::id_from_node_id(item.id, &self.save_ctxt));
689
690                         self.dumper.dump_def(
691                             &access,
692                             Def {
693                                 kind: DefKind::StructVariant,
694                                 id,
695                                 span,
696                                 name,
697                                 qualname,
698                                 value,
699                                 parent,
700                                 children: vec![],
701                                 decl_id: None,
702                                 docs: self.save_ctxt.docs_for_attrs(&variant.node.attrs),
703                                 sig: sig::variant_signature(variant, &self.save_ctxt),
704                                 attributes: lower_attributes(
705                                     variant.node.attrs.clone(),
706                                     &self.save_ctxt,
707                                 ),
708                             },
709                         );
710                     }
711                 }
712                 ref v => {
713                     let sub_span = self.span.span_for_first_ident(variant.span);
714                     let mut value = format!("{}::{}", enum_data.name, name);
715                     if let &ast::VariantData::Tuple(ref fields, _) = v {
716                         value.push('(');
717                         value.push_str(&fields
718                             .iter()
719                             .map(|f| ty_to_string(&f.ty))
720                             .collect::<Vec<_>>()
721                             .join(", "));
722                         value.push(')');
723                     }
724                     if !self.span.filter_generated(sub_span, variant.span) {
725                         let span =
726                             self.span_from_span(sub_span.expect("No span found for tuple variant"));
727                         let id = ::id_from_node_id(variant.node.data.id(), &self.save_ctxt);
728                         let parent = Some(::id_from_node_id(item.id, &self.save_ctxt));
729
730                         self.dumper.dump_def(
731                             &access,
732                             Def {
733                                 kind: DefKind::TupleVariant,
734                                 id,
735                                 span,
736                                 name,
737                                 qualname,
738                                 value,
739                                 parent,
740                                 children: vec![],
741                                 decl_id: None,
742                                 docs: self.save_ctxt.docs_for_attrs(&variant.node.attrs),
743                                 sig: sig::variant_signature(variant, &self.save_ctxt),
744                                 attributes: lower_attributes(
745                                     variant.node.attrs.clone(),
746                                     &self.save_ctxt,
747                                 ),
748                             },
749                         );
750                     }
751                 }
752             }
753
754
755             for field in variant.node.data.fields() {
756                 self.process_struct_field_def(field, variant.node.data.id());
757                 self.visit_ty(&field.ty);
758             }
759         }
760         self.process_generic_params(ty_params, item.span, &enum_data.qualname, item.id);
761         self.dumper.dump_def(&access, enum_data);
762     }
763
764     fn process_impl(
765         &mut self,
766         item: &'l ast::Item,
767         type_parameters: &'l ast::Generics,
768         trait_ref: &'l Option<ast::TraitRef>,
769         typ: &'l ast::Ty,
770         impl_items: &'l [ast::ImplItem],
771     ) {
772         if let Some(impl_data) = self.save_ctxt.get_item_data(item) {
773             down_cast_data!(impl_data, RelationData, item.span);
774             self.dumper.dump_relation(impl_data);
775         }
776         self.visit_ty(&typ);
777         if let &Some(ref trait_ref) = trait_ref {
778             self.process_path(trait_ref.ref_id, &trait_ref.path);
779         }
780         self.process_generic_params(type_parameters, item.span, "", item.id);
781         for impl_item in impl_items {
782             let map = &self.tcx.hir;
783             self.process_impl_item(impl_item, map.local_def_id(item.id));
784         }
785     }
786
787     fn process_trait(
788         &mut self,
789         item: &'l ast::Item,
790         generics: &'l ast::Generics,
791         trait_refs: &'l ast::TyParamBounds,
792         methods: &'l [ast::TraitItem],
793     ) {
794         let name = item.ident.to_string();
795         let qualname = format!("::{}", self.tcx.node_path_str(item.id));
796         let mut val = name.clone();
797         if !generics.params.is_empty() {
798             val.push_str(&generic_params_to_string(&generics.params));
799         }
800         if !trait_refs.is_empty() {
801             val.push_str(": ");
802             val.push_str(&bounds_to_string(trait_refs));
803         }
804         let sub_span = self.span.sub_span_after_keyword(item.span, keywords::Trait);
805         if !self.span.filter_generated(sub_span, item.span) {
806             let id = ::id_from_node_id(item.id, &self.save_ctxt);
807             let span = self.span_from_span(sub_span.expect("No span found for trait"));
808             let children = methods
809                 .iter()
810                 .map(|i| ::id_from_node_id(i.id, &self.save_ctxt))
811                 .collect();
812             self.dumper.dump_def(
813                 &access_from!(self.save_ctxt, item),
814                 Def {
815                     kind: DefKind::Trait,
816                     id,
817                     span,
818                     name,
819                     qualname: qualname.clone(),
820                     value: val,
821                     parent: None,
822                     children,
823                     decl_id: None,
824                     docs: self.save_ctxt.docs_for_attrs(&item.attrs),
825                     sig: sig::item_signature(item, &self.save_ctxt),
826                     attributes: lower_attributes(item.attrs.clone(), &self.save_ctxt),
827                 },
828             );
829         }
830
831         // super-traits
832         for super_bound in trait_refs.iter() {
833             let trait_ref = match *super_bound {
834                 ast::TraitTyParamBound(ref trait_ref, _) => trait_ref,
835                 ast::RegionTyParamBound(..) => {
836                     continue;
837                 }
838             };
839
840             let trait_ref = &trait_ref.trait_ref;
841             if let Some(id) = self.lookup_def_id(trait_ref.ref_id) {
842                 let sub_span = self.span.sub_span_for_type_name(trait_ref.path.span);
843                 if !self.span.filter_generated(sub_span, trait_ref.path.span) {
844                     let span = self.span_from_span(sub_span.expect("No span found for trait ref"));
845                     self.dumper.dump_ref(Ref {
846                         kind: RefKind::Type,
847                         span,
848                         ref_id: ::id_from_def_id(id),
849                     });
850                 }
851
852                 if !self.span.filter_generated(sub_span, trait_ref.path.span) {
853                     let sub_span = self.span_from_span(sub_span.expect("No span for inheritance"));
854                     self.dumper.dump_relation(Relation {
855                         kind: RelationKind::SuperTrait,
856                         span: sub_span,
857                         from: ::id_from_def_id(id),
858                         to: ::id_from_node_id(item.id, &self.save_ctxt),
859                     });
860                 }
861             }
862         }
863
864         // walk generics and methods
865         self.process_generic_params(generics, item.span, &qualname, item.id);
866         for method in methods {
867             let map = &self.tcx.hir;
868             self.process_trait_item(method, map.local_def_id(item.id))
869         }
870     }
871
872     // `item` is the module in question, represented as an item.
873     fn process_mod(&mut self, item: &ast::Item) {
874         if let Some(mod_data) = self.save_ctxt.get_item_data(item) {
875             down_cast_data!(mod_data, DefData, item.span);
876             self.dumper.dump_def(&access_from!(self.save_ctxt, item), mod_data);
877         }
878     }
879
880     fn dump_path_ref(&mut self, id: NodeId, path: &ast::Path) {
881         let path_data = self.save_ctxt.get_path_data(id, path);
882         if let Some(path_data) = path_data {
883             self.dumper.dump_ref(path_data);
884         }
885     }
886
887     fn process_path(&mut self, id: NodeId, path: &'l ast::Path) {
888         debug!("process_path {:?}", path);
889         if generated_code(path.span) {
890             return;
891         }
892         self.dump_path_ref(id, path);
893
894         // Type parameters
895         for seg in &path.segments {
896             if let Some(ref params) = seg.parameters {
897                 match **params {
898                     ast::PathParameters::AngleBracketed(ref data) => for t in &data.types {
899                         self.visit_ty(t);
900                     },
901                     ast::PathParameters::Parenthesized(ref data) => {
902                         for t in &data.inputs {
903                             self.visit_ty(t);
904                         }
905                         if let Some(ref t) = data.output {
906                             self.visit_ty(t);
907                         }
908                     }
909                 }
910             }
911         }
912
913         // Modules or types in the path prefix.
914         match self.save_ctxt.get_path_def(id) {
915             HirDef::Method(did) => {
916                 let ti = self.tcx.associated_item(did);
917                 if ti.kind == ty::AssociatedKind::Method && ti.method_has_self_argument {
918                     self.write_sub_path_trait_truncated(path);
919                 }
920             }
921             HirDef::Fn(..) |
922             HirDef::Const(..) |
923             HirDef::Static(..) |
924             HirDef::StructCtor(..) |
925             HirDef::VariantCtor(..) |
926             HirDef::AssociatedConst(..) |
927             HirDef::Local(..) |
928             HirDef::Upvar(..) |
929             HirDef::Struct(..) |
930             HirDef::Union(..) |
931             HirDef::Variant(..) |
932             HirDef::TyAlias(..) |
933             HirDef::AssociatedTy(..) => self.write_sub_paths_truncated(path),
934             _ => {}
935         }
936     }
937
938     fn process_struct_lit(
939         &mut self,
940         ex: &'l ast::Expr,
941         path: &'l ast::Path,
942         fields: &'l [ast::Field],
943         variant: &'l ty::VariantDef,
944         base: &'l Option<P<ast::Expr>>,
945     ) {
946         self.write_sub_paths_truncated(path);
947
948         if let Some(struct_lit_data) = self.save_ctxt.get_expr_data(ex) {
949             down_cast_data!(struct_lit_data, RefData, ex.span);
950             if !generated_code(ex.span) {
951                 self.dumper.dump_ref(struct_lit_data);
952             }
953
954             for field in fields {
955                 if let Some(field_data) = self.save_ctxt.get_field_ref_data(field, variant) {
956                     self.dumper.dump_ref(field_data);
957                 }
958
959                 self.visit_expr(&field.expr)
960             }
961         }
962
963         walk_list!(self, visit_expr, base);
964     }
965
966     fn process_method_call(
967         &mut self,
968         ex: &'l ast::Expr,
969         seg: &'l ast::PathSegment,
970         args: &'l [P<ast::Expr>],
971     ) {
972         debug!("process_method_call {:?} {:?}", ex, ex.span);
973         if let Some(mcd) = self.save_ctxt.get_expr_data(ex) {
974             down_cast_data!(mcd, RefData, ex.span);
975             if !generated_code(ex.span) {
976                 self.dumper.dump_ref(mcd);
977             }
978         }
979
980         // Explicit types in the turbo-fish.
981         if let Some(ref params) = seg.parameters {
982             if let ast::PathParameters::AngleBracketed(ref data) = **params {
983                 for t in &data.types {
984                     self.visit_ty(t);
985                 }
986             }
987         }
988
989         // walk receiver and args
990         walk_list!(self, visit_expr, args);
991     }
992
993     fn process_pat(&mut self, p: &'l ast::Pat) {
994         match p.node {
995             PatKind::Struct(ref _path, ref fields, _) => {
996                 // FIXME do something with _path?
997                 let hir_id = self.tcx.hir.node_to_hir_id(p.id);
998                 let adt = match self.save_ctxt.tables.node_id_to_type_opt(hir_id) {
999                     Some(ty) => ty.ty_adt_def().unwrap(),
1000                     None => {
1001                         visit::walk_pat(self, p);
1002                         return;
1003                     }
1004                 };
1005                 let variant = adt.variant_of_def(self.save_ctxt.get_path_def(p.id));
1006
1007                 for &Spanned {
1008                     node: ref field,
1009                     span,
1010                 } in fields
1011                 {
1012                     let sub_span = self.span.span_for_first_ident(span);
1013                     if let Some(f) = variant.find_field_named(field.ident.name) {
1014                         if !self.span.filter_generated(sub_span, span) {
1015                             let span =
1016                                 self.span_from_span(sub_span.expect("No span fund for var ref"));
1017                             self.dumper.dump_ref(Ref {
1018                                 kind: RefKind::Variable,
1019                                 span,
1020                                 ref_id: ::id_from_def_id(f.did),
1021                             });
1022                         }
1023                     }
1024                     self.visit_pat(&field.pat);
1025                 }
1026             }
1027             _ => visit::walk_pat(self, p),
1028         }
1029     }
1030
1031
1032     fn process_var_decl(&mut self, p: &'l ast::Pat, value: String) {
1033         // The local could declare multiple new vars, we must walk the
1034         // pattern and collect them all.
1035         let mut collector = PathCollector::new();
1036         collector.visit_pat(&p);
1037         self.visit_pat(&p);
1038
1039         for (id, i, sp, immut) in collector.collected_idents {
1040             let mut value = match immut {
1041                 ast::Mutability::Immutable => value.to_string(),
1042                 _ => String::new(),
1043             };
1044             let hir_id = self.tcx.hir.node_to_hir_id(id);
1045             let typ = match self.save_ctxt.tables.node_id_to_type_opt(hir_id) {
1046                 Some(typ) => {
1047                     let typ = typ.to_string();
1048                     if !value.is_empty() {
1049                         value.push_str(": ");
1050                     }
1051                     value.push_str(&typ);
1052                     typ
1053                 }
1054                 None => String::new(),
1055             };
1056
1057             // Get the span only for the name of the variable (I hope the path
1058             // is only ever a variable name, but who knows?).
1059             let sub_span = self.span.span_for_last_ident(sp);
1060             // Rust uses the id of the pattern for var lookups, so we'll use it too.
1061             if !self.span.filter_generated(sub_span, sp) {
1062                 let qualname = format!("{}${}", i.to_string(), id);
1063                 let id = ::id_from_node_id(id, &self.save_ctxt);
1064                 let span = self.span_from_span(sub_span.expect("No span found for variable"));
1065
1066                 self.dumper.dump_def(
1067                     &Access {
1068                         public: false,
1069                         reachable: false,
1070                     },
1071                     Def {
1072                         kind: DefKind::Local,
1073                         id,
1074                         span,
1075                         name: i.to_string(),
1076                         qualname,
1077                         value: typ,
1078                         parent: None,
1079                         children: vec![],
1080                         decl_id: None,
1081                         docs: String::new(),
1082                         sig: None,
1083                         attributes: vec![],
1084                     },
1085                 );
1086             }
1087         }
1088     }
1089
1090     /// Extract macro use and definition information from the AST node defined
1091     /// by the given NodeId, using the expansion information from the node's
1092     /// span.
1093     ///
1094     /// If the span is not macro-generated, do nothing, else use callee and
1095     /// callsite spans to record macro definition and use data, using the
1096     /// mac_uses and mac_defs sets to prevent multiples.
1097     fn process_macro_use(&mut self, span: Span) {
1098         let source_span = span.source_callsite();
1099         if self.macro_calls.contains(&source_span) {
1100             return;
1101         }
1102         self.macro_calls.insert(source_span);
1103
1104         let data = match self.save_ctxt.get_macro_use_data(span) {
1105             None => return,
1106             Some(data) => data,
1107         };
1108
1109         self.dumper.macro_use(data);
1110
1111         // FIXME write the macro def
1112         // let mut hasher = DefaultHasher::new();
1113         // data.callee_span.hash(&mut hasher);
1114         // let hash = hasher.finish();
1115         // let qualname = format!("{}::{}", data.name, hash);
1116         // Don't write macro definition for imported macros
1117         // if !self.mac_defs.contains(&data.callee_span)
1118         //     && !data.imported {
1119         //     self.mac_defs.insert(data.callee_span);
1120         //     if let Some(sub_span) = self.span.span_for_macro_def_name(data.callee_span) {
1121         //         self.dumper.macro_data(MacroData {
1122         //             span: sub_span,
1123         //             name: data.name.clone(),
1124         //             qualname: qualname.clone(),
1125         //             // FIXME where do macro docs come from?
1126         //             docs: String::new(),
1127         //         }.lower(self.tcx));
1128         //     }
1129         // }
1130     }
1131
1132     fn process_trait_item(&mut self, trait_item: &'l ast::TraitItem, trait_id: DefId) {
1133         self.process_macro_use(trait_item.span);
1134         match trait_item.node {
1135             ast::TraitItemKind::Const(ref ty, ref expr) => {
1136                 self.process_assoc_const(
1137                     trait_item.id,
1138                     trait_item.ident.name,
1139                     trait_item.span,
1140                     &ty,
1141                     expr.as_ref().map(|e| &**e),
1142                     trait_id,
1143                     ast::Visibility::Public,
1144                     &trait_item.attrs,
1145                 );
1146             }
1147             ast::TraitItemKind::Method(ref sig, ref body) => {
1148                 self.process_method(
1149                     sig,
1150                     body.as_ref().map(|x| &**x),
1151                     trait_item.id,
1152                     trait_item.ident,
1153                     &trait_item.generics,
1154                     ast::Visibility::Public,
1155                     trait_item.span,
1156                 );
1157             }
1158             ast::TraitItemKind::Type(ref bounds, ref default_ty) => {
1159                 // FIXME do something with _bounds (for type refs)
1160                 let name = trait_item.ident.name.to_string();
1161                 let qualname = format!("::{}", self.tcx.node_path_str(trait_item.id));
1162                 let sub_span = self.span
1163                     .sub_span_after_keyword(trait_item.span, keywords::Type);
1164
1165                 if !self.span.filter_generated(sub_span, trait_item.span) {
1166                     let span = self.span_from_span(sub_span.expect("No span found for assoc type"));
1167                     let id = ::id_from_node_id(trait_item.id, &self.save_ctxt);
1168
1169                     self.dumper.dump_def(
1170                         &Access {
1171                             public: true,
1172                             reachable: true,
1173                         },
1174                         Def {
1175                             kind: DefKind::Type,
1176                             id,
1177                             span,
1178                             name,
1179                             qualname,
1180                             value: self.span.snippet(trait_item.span),
1181                             parent: Some(::id_from_def_id(trait_id)),
1182                             children: vec![],
1183                             decl_id: None,
1184                             docs: self.save_ctxt.docs_for_attrs(&trait_item.attrs),
1185                             sig: sig::assoc_type_signature(
1186                                 trait_item.id,
1187                                 trait_item.ident,
1188                                 Some(bounds),
1189                                 default_ty.as_ref().map(|ty| &**ty),
1190                                 &self.save_ctxt,
1191                             ),
1192                             attributes: lower_attributes(trait_item.attrs.clone(), &self.save_ctxt),
1193                         },
1194                     );
1195                 }
1196
1197                 if let &Some(ref default_ty) = default_ty {
1198                     self.visit_ty(default_ty)
1199                 }
1200             }
1201             ast::TraitItemKind::Macro(_) => {}
1202         }
1203     }
1204
1205     fn process_impl_item(&mut self, impl_item: &'l ast::ImplItem, impl_id: DefId) {
1206         self.process_macro_use(impl_item.span);
1207         match impl_item.node {
1208             ast::ImplItemKind::Const(ref ty, ref expr) => {
1209                 self.process_assoc_const(
1210                     impl_item.id,
1211                     impl_item.ident.name,
1212                     impl_item.span,
1213                     &ty,
1214                     Some(expr),
1215                     impl_id,
1216                     impl_item.vis.clone(),
1217                     &impl_item.attrs,
1218                 );
1219             }
1220             ast::ImplItemKind::Method(ref sig, ref body) => {
1221                 self.process_method(
1222                     sig,
1223                     Some(body),
1224                     impl_item.id,
1225                     impl_item.ident,
1226                     &impl_item.generics,
1227                     impl_item.vis.clone(),
1228                     impl_item.span,
1229                 );
1230             }
1231             ast::ImplItemKind::Type(ref ty) => {
1232                 // FIXME uses of the assoc type should ideally point to this
1233                 // 'def' and the name here should be a ref to the def in the
1234                 // trait.
1235                 self.visit_ty(ty)
1236             }
1237             ast::ImplItemKind::Macro(_) => {}
1238         }
1239     }
1240
1241     /// Dumps imports in a use tree recursively.
1242     ///
1243     /// A use tree is an import that may contain nested braces (RFC 2128). The `use_tree` parameter
1244     /// is the current use tree under scrutiny, while `id` and `prefix` are its corresponding node
1245     /// id and path. `root_item` is the topmost use tree in the hierarchy.
1246     ///
1247     /// If `use_tree` is a simple or glob import, it is dumped into the analysis data. Otherwise,
1248     /// each child use tree is dumped recursively.
1249     fn process_use_tree(&mut self,
1250                          use_tree: &'l ast::UseTree,
1251                          id: NodeId,
1252                          root_item: &'l ast::Item,
1253                          prefix: &ast::Path) {
1254         let path = &use_tree.prefix;
1255
1256         // The access is calculated using the current tree ID, but with the root tree's visibility
1257         // (since nested trees don't have their own visibility).
1258         let access = Access {
1259             public: root_item.vis == ast::Visibility::Public,
1260             reachable: self.save_ctxt.analysis.access_levels.is_reachable(id),
1261         };
1262
1263         // The parent def id of a given use tree is always the enclosing item.
1264         let parent = self.save_ctxt.tcx.hir.opt_local_def_id(id)
1265             .and_then(|id| self.save_ctxt.tcx.parent_def_id(id))
1266             .map(::id_from_def_id);
1267
1268         match use_tree.kind {
1269             ast::UseTreeKind::Simple(ident) => {
1270                 let path = ast::Path {
1271                     segments: prefix.segments
1272                         .iter()
1273                         .chain(path.segments.iter())
1274                         .cloned()
1275                         .collect(),
1276                     span: path.span,
1277                 };
1278
1279                 let sub_span = self.span.span_for_last_ident(path.span);
1280                 let mod_id = match self.lookup_def_id(id) {
1281                     Some(def_id) => {
1282                         self.process_def_kind(id, path.span, sub_span, def_id);
1283                         Some(def_id)
1284                     }
1285                     None => None,
1286                 };
1287
1288                 // 'use' always introduces an alias, if there is not an explicit
1289                 // one, there is an implicit one.
1290                 let sub_span = match self.span.sub_span_after_keyword(use_tree.span,
1291                                                                       keywords::As) {
1292                     Some(sub_span) => Some(sub_span),
1293                     None => sub_span,
1294                 };
1295
1296                 if !self.span.filter_generated(sub_span, path.span) {
1297                     let span =
1298                         self.span_from_span(sub_span.expect("No span found for use"));
1299                     self.dumper.import(&access, Import {
1300                         kind: ImportKind::Use,
1301                         ref_id: mod_id.map(|id| ::id_from_def_id(id)),
1302                         span,
1303                         name: ident.to_string(),
1304                         value: String::new(),
1305                         parent,
1306                     });
1307                 }
1308                 self.write_sub_paths_truncated(&path);
1309             }
1310             ast::UseTreeKind::Glob => {
1311                 let path = ast::Path {
1312                     segments: prefix.segments
1313                         .iter()
1314                         .chain(path.segments.iter())
1315                         .cloned()
1316                         .collect(),
1317                     span: path.span,
1318                 };
1319
1320                 // Make a comma-separated list of names of imported modules.
1321                 let mut names = vec![];
1322                 let glob_map = &self.save_ctxt.analysis.glob_map;
1323                 let glob_map = glob_map.as_ref().unwrap();
1324                 if glob_map.contains_key(&id) {
1325                     for n in glob_map.get(&id).unwrap() {
1326                         names.push(n.to_string());
1327                     }
1328                 }
1329
1330                 let sub_span = self.span.sub_span_of_token(use_tree.span,
1331                                                            token::BinOp(token::Star));
1332                 if !self.span.filter_generated(sub_span, use_tree.span) {
1333                     let span =
1334                         self.span_from_span(sub_span.expect("No span found for use glob"));
1335                     self.dumper.import(&access, Import {
1336                         kind: ImportKind::GlobUse,
1337                         ref_id: None,
1338                         span,
1339                         name: "*".to_owned(),
1340                         value: names.join(", "),
1341                         parent,
1342                     });
1343                 }
1344                 self.write_sub_paths(&path);
1345             }
1346             ast::UseTreeKind::Nested(ref nested_items) => {
1347                 let prefix = ast::Path {
1348                     segments: prefix.segments
1349                         .iter()
1350                         .chain(path.segments.iter())
1351                         .cloned()
1352                         .collect(),
1353                     span: path.span,
1354                 };
1355                 for &(ref tree, id) in nested_items {
1356                     self.process_use_tree(tree, id, root_item, &prefix);
1357                 }
1358             }
1359         }
1360     }
1361 }
1362
1363 impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> Visitor<'l> for DumpVisitor<'l, 'tcx, 'll, O> {
1364     fn visit_mod(&mut self, m: &'l ast::Mod, span: Span, attrs: &[ast::Attribute], id: NodeId) {
1365         // Since we handle explicit modules ourselves in visit_item, this should
1366         // only get called for the root module of a crate.
1367         assert_eq!(id, ast::CRATE_NODE_ID);
1368
1369         let qualname = format!("::{}", self.tcx.node_path_str(id));
1370
1371         let cm = self.tcx.sess.codemap();
1372         let filename = cm.span_to_filename(span);
1373         let data_id = ::id_from_node_id(id, &self.save_ctxt);
1374         let children = m.items
1375             .iter()
1376             .map(|i| ::id_from_node_id(i.id, &self.save_ctxt))
1377             .collect();
1378         let span = self.span_from_span(span);
1379
1380         self.dumper.dump_def(
1381             &Access {
1382                 public: true,
1383                 reachable: true,
1384             },
1385             Def {
1386                 kind: DefKind::Mod,
1387                 id: data_id,
1388                 name: String::new(),
1389                 qualname,
1390                 span,
1391                 value: filename.to_string(),
1392                 children,
1393                 parent: None,
1394                 decl_id: None,
1395                 docs: self.save_ctxt.docs_for_attrs(attrs),
1396                 sig: None,
1397                 attributes: lower_attributes(attrs.to_owned(), &self.save_ctxt),
1398             },
1399         );
1400         self.nest_scope(id, |v| visit::walk_mod(v, m));
1401     }
1402
1403     fn visit_item(&mut self, item: &'l ast::Item) {
1404         use syntax::ast::ItemKind::*;
1405         self.process_macro_use(item.span);
1406         match item.node {
1407             Use(ref use_tree) => {
1408                 let prefix = ast::Path {
1409                     segments: vec![],
1410                     span: DUMMY_SP,
1411                 };
1412                 self.process_use_tree(use_tree, item.id, item, &prefix);
1413             }
1414             ExternCrate(_) => {
1415                 let alias_span = self.span.span_for_last_ident(item.span);
1416
1417                 if !self.span.filter_generated(alias_span, item.span) {
1418                     let span =
1419                         self.span_from_span(alias_span.expect("No span found for extern crate"));
1420                     let parent = self.save_ctxt.tcx.hir.opt_local_def_id(item.id)
1421                         .and_then(|id| self.save_ctxt.tcx.parent_def_id(id))
1422                         .map(::id_from_def_id);
1423                     self.dumper.import(
1424                         &Access {
1425                             public: false,
1426                             reachable: false,
1427                         },
1428                         Import {
1429                             kind: ImportKind::ExternCrate,
1430                             ref_id: None,
1431                             span,
1432                             name: item.ident.to_string(),
1433                             value: String::new(),
1434                             parent,
1435                         },
1436                     );
1437                 }
1438             }
1439             Fn(ref decl, .., ref ty_params, ref body) => {
1440                 self.process_fn(item, &decl, ty_params, &body)
1441             }
1442             Static(ref typ, _, ref expr) => self.process_static_or_const_item(item, typ, expr),
1443             Const(ref typ, ref expr) => self.process_static_or_const_item(item, &typ, &expr),
1444             Struct(ref def, ref ty_params) | Union(ref def, ref ty_params) => {
1445                 self.process_struct(item, def, ty_params)
1446             }
1447             Enum(ref def, ref ty_params) => self.process_enum(item, def, ty_params),
1448             Impl(.., ref ty_params, ref trait_ref, ref typ, ref impl_items) => {
1449                 self.process_impl(item, ty_params, trait_ref, &typ, impl_items)
1450             }
1451             Trait(_, _, ref generics, ref trait_refs, ref methods) => {
1452                 self.process_trait(item, generics, trait_refs, methods)
1453             }
1454             Mod(ref m) => {
1455                 self.process_mod(item);
1456                 self.nest_scope(item.id, |v| visit::walk_mod(v, m));
1457             }
1458             Ty(ref ty, ref ty_params) => {
1459                 let qualname = format!("::{}", self.tcx.node_path_str(item.id));
1460                 let value = ty_to_string(&ty);
1461                 let sub_span = self.span.sub_span_after_keyword(item.span, keywords::Type);
1462                 if !self.span.filter_generated(sub_span, item.span) {
1463                     let span = self.span_from_span(sub_span.expect("No span found for typedef"));
1464                     let id = ::id_from_node_id(item.id, &self.save_ctxt);
1465
1466                     self.dumper.dump_def(
1467                         &access_from!(self.save_ctxt, item),
1468                         Def {
1469                             kind: DefKind::Type,
1470                             id,
1471                             span,
1472                             name: item.ident.to_string(),
1473                             qualname: qualname.clone(),
1474                             value,
1475                             parent: None,
1476                             children: vec![],
1477                             decl_id: None,
1478                             docs: self.save_ctxt.docs_for_attrs(&item.attrs),
1479                             sig: sig::item_signature(item, &self.save_ctxt),
1480                             attributes: lower_attributes(item.attrs.clone(), &self.save_ctxt),
1481                         },
1482                     );
1483                 }
1484
1485                 self.visit_ty(&ty);
1486                 self.process_generic_params(ty_params, item.span, &qualname, item.id);
1487             }
1488             Mac(_) => (),
1489             _ => visit::walk_item(self, item),
1490         }
1491     }
1492
1493     fn visit_generics(&mut self, generics: &'l ast::Generics) {
1494         for param in &generics.params {
1495             if let ast::GenericParam::Type(ref ty_param) = *param {
1496                 for bound in ty_param.bounds.iter() {
1497                     if let ast::TraitTyParamBound(ref trait_ref, _) = *bound {
1498                         self.process_path(trait_ref.trait_ref.ref_id, &trait_ref.trait_ref.path)
1499                     }
1500                 }
1501                 if let Some(ref ty) = ty_param.default {
1502                     self.visit_ty(&ty);
1503                 }
1504             }
1505         }
1506     }
1507
1508     fn visit_ty(&mut self, t: &'l ast::Ty) {
1509         self.process_macro_use(t.span);
1510         match t.node {
1511             ast::TyKind::Path(_, ref path) => {
1512                 if generated_code(t.span) {
1513                     return;
1514                 }
1515
1516                 if let Some(id) = self.lookup_def_id(t.id) {
1517                     if let Some(sub_span) = self.span.sub_span_for_type_name(t.span) {
1518                         let span = self.span_from_span(sub_span);
1519                         self.dumper.dump_ref(Ref {
1520                             kind: RefKind::Type,
1521                             span,
1522                             ref_id: ::id_from_def_id(id),
1523                         });
1524                     }
1525                 }
1526
1527                 self.write_sub_paths_truncated(path);
1528                 visit::walk_path(self, path);
1529             }
1530             ast::TyKind::Array(ref element, ref length) => {
1531                 self.visit_ty(element);
1532                 self.nest_tables(length.id, |v| v.visit_expr(length));
1533             }
1534             _ => visit::walk_ty(self, t),
1535         }
1536     }
1537
1538     fn visit_expr(&mut self, ex: &'l ast::Expr) {
1539         debug!("visit_expr {:?}", ex.node);
1540         self.process_macro_use(ex.span);
1541         match ex.node {
1542             ast::ExprKind::Struct(ref path, ref fields, ref base) => {
1543                 let hir_expr = self.save_ctxt.tcx.hir.expect_expr(ex.id);
1544                 let adt = match self.save_ctxt.tables.expr_ty_opt(&hir_expr) {
1545                     Some(ty) if ty.ty_adt_def().is_some() => ty.ty_adt_def().unwrap(),
1546                     _ => {
1547                         visit::walk_expr(self, ex);
1548                         return;
1549                     }
1550                 };
1551                 let def = self.save_ctxt.get_path_def(hir_expr.id);
1552                 self.process_struct_lit(ex, path, fields, adt.variant_of_def(def), base)
1553             }
1554             ast::ExprKind::MethodCall(ref seg, ref args) => self.process_method_call(ex, seg, args),
1555             ast::ExprKind::Field(ref sub_ex, _) => {
1556                 self.visit_expr(&sub_ex);
1557
1558                 if let Some(field_data) = self.save_ctxt.get_expr_data(ex) {
1559                     down_cast_data!(field_data, RefData, ex.span);
1560                     if !generated_code(ex.span) {
1561                         self.dumper.dump_ref(field_data);
1562                     }
1563                 }
1564             }
1565             ast::ExprKind::TupField(ref sub_ex, idx) => {
1566                 self.visit_expr(&sub_ex);
1567
1568                 let hir_node = match self.save_ctxt.tcx.hir.find(sub_ex.id) {
1569                     Some(Node::NodeExpr(expr)) => expr,
1570                     _ => {
1571                         debug!(
1572                             "Missing or weird node for sub-expression {} in {:?}",
1573                             sub_ex.id,
1574                             ex
1575                         );
1576                         return;
1577                     }
1578                 };
1579                 let ty = match self.save_ctxt.tables.expr_ty_adjusted_opt(&hir_node) {
1580                     Some(ty) => &ty.sty,
1581                     None => {
1582                         visit::walk_expr(self, ex);
1583                         return;
1584                     }
1585                 };
1586                 match *ty {
1587                     ty::TyAdt(def, _) => {
1588                         let sub_span = self.span.sub_span_after_token(ex.span, token::Dot);
1589                         if !self.span.filter_generated(sub_span, ex.span) {
1590                             let span =
1591                                 self.span_from_span(sub_span.expect("No span found for var ref"));
1592                             let ref_id =
1593                                 ::id_from_def_id(def.non_enum_variant().fields[idx.node].did);
1594                             self.dumper.dump_ref(Ref {
1595                                 kind: RefKind::Variable,
1596                                 span,
1597                                 ref_id,
1598                             });
1599                         }
1600                     }
1601                     ty::TyTuple(..) => {}
1602                     _ => span_bug!(ex.span, "Expected struct or tuple type, found {:?}", ty),
1603                 }
1604             }
1605             ast::ExprKind::Closure(_, ref decl, ref body, _fn_decl_span) => {
1606                 let mut id = String::from("$");
1607                 id.push_str(&ex.id.to_string());
1608
1609                 // walk arg and return types
1610                 for arg in &decl.inputs {
1611                     self.visit_ty(&arg.ty);
1612                 }
1613
1614                 if let ast::FunctionRetTy::Ty(ref ret_ty) = decl.output {
1615                     self.visit_ty(&ret_ty);
1616                 }
1617
1618                 // walk the body
1619                 self.nest_tables(ex.id, |v| {
1620                     v.process_formals(&decl.inputs, &id);
1621                     v.nest_scope(ex.id, |v| v.visit_expr(body))
1622                 });
1623             }
1624             ast::ExprKind::ForLoop(ref pattern, ref subexpression, ref block, _) |
1625             ast::ExprKind::WhileLet(ref pattern, ref subexpression, ref block, _) => {
1626                 let value = self.span.snippet(subexpression.span);
1627                 self.process_var_decl(pattern, value);
1628                 debug!("for loop, walk sub-expr: {:?}", subexpression.node);
1629                 self.visit_expr(subexpression);
1630                 visit::walk_block(self, block);
1631             }
1632             ast::ExprKind::IfLet(ref pattern, ref subexpression, ref block, ref opt_else) => {
1633                 let value = self.span.snippet(subexpression.span);
1634                 self.process_var_decl(pattern, value);
1635                 self.visit_expr(subexpression);
1636                 visit::walk_block(self, block);
1637                 opt_else.as_ref().map(|el| self.visit_expr(el));
1638             }
1639             ast::ExprKind::Repeat(ref element, ref count) => {
1640                 self.visit_expr(element);
1641                 self.nest_tables(count.id, |v| v.visit_expr(count));
1642             }
1643             // In particular, we take this branch for call and path expressions,
1644             // where we'll index the idents involved just by continuing to walk.
1645             _ => visit::walk_expr(self, ex),
1646         }
1647     }
1648
1649     fn visit_mac(&mut self, mac: &'l ast::Mac) {
1650         // These shouldn't exist in the AST at this point, log a span bug.
1651         span_bug!(
1652             mac.span,
1653             "macro invocation should have been expanded out of AST"
1654         );
1655     }
1656
1657     fn visit_pat(&mut self, p: &'l ast::Pat) {
1658         self.process_macro_use(p.span);
1659         self.process_pat(p);
1660     }
1661
1662     fn visit_arm(&mut self, arm: &'l ast::Arm) {
1663         let mut collector = PathCollector::new();
1664         for pattern in &arm.pats {
1665             // collect paths from the arm's patterns
1666             collector.visit_pat(&pattern);
1667             self.visit_pat(&pattern);
1668         }
1669
1670         // process collected paths
1671         for (id, i, sp, immut) in collector.collected_idents {
1672             match self.save_ctxt.get_path_def(id) {
1673                 HirDef::Local(id) => {
1674                     let mut value = if immut == ast::Mutability::Immutable {
1675                         self.span.snippet(sp).to_string()
1676                     } else {
1677                         "<mutable>".to_string()
1678                     };
1679                     let hir_id = self.tcx.hir.node_to_hir_id(id);
1680                     let typ = self.save_ctxt
1681                         .tables
1682                         .node_id_to_type_opt(hir_id)
1683                         .map(|t| t.to_string())
1684                         .unwrap_or(String::new());
1685                     value.push_str(": ");
1686                     value.push_str(&typ);
1687
1688                     if !self.span.filter_generated(Some(sp), sp) {
1689                         let qualname = format!("{}${}", i.to_string(), id);
1690                         let id = ::id_from_node_id(id, &self.save_ctxt);
1691                         let span = self.span_from_span(sp);
1692
1693                         self.dumper.dump_def(
1694                             &Access {
1695                                 public: false,
1696                                 reachable: false,
1697                             },
1698                             Def {
1699                                 kind: DefKind::Local,
1700                                 id,
1701                                 span,
1702                                 name: i.to_string(),
1703                                 qualname,
1704                                 value: typ,
1705                                 parent: None,
1706                                 children: vec![],
1707                                 decl_id: None,
1708                                 docs: String::new(),
1709                                 sig: None,
1710                                 attributes: vec![],
1711                             },
1712                         );
1713                     }
1714                 }
1715                 HirDef::StructCtor(..) |
1716                 HirDef::VariantCtor(..) |
1717                 HirDef::Const(..) |
1718                 HirDef::AssociatedConst(..) |
1719                 HirDef::Struct(..) |
1720                 HirDef::Variant(..) |
1721                 HirDef::TyAlias(..) |
1722                 HirDef::AssociatedTy(..) |
1723                 HirDef::SelfTy(..) => {
1724                     self.dump_path_ref(id, &ast::Path::from_ident(sp, i));
1725                 }
1726                 def => error!(
1727                     "unexpected definition kind when processing collected idents: {:?}",
1728                     def
1729                 ),
1730             }
1731         }
1732
1733         for (id, ref path) in collector.collected_paths {
1734             self.process_path(id, path);
1735         }
1736         walk_list!(self, visit_expr, &arm.guard);
1737         self.visit_expr(&arm.body);
1738     }
1739
1740     fn visit_path(&mut self, p: &'l ast::Path, id: NodeId) {
1741         self.process_path(id, p);
1742     }
1743
1744     fn visit_stmt(&mut self, s: &'l ast::Stmt) {
1745         self.process_macro_use(s.span);
1746         visit::walk_stmt(self, s)
1747     }
1748
1749     fn visit_local(&mut self, l: &'l ast::Local) {
1750         self.process_macro_use(l.span);
1751         let value = l.init
1752             .as_ref()
1753             .map(|i| self.span.snippet(i.span))
1754             .unwrap_or(String::new());
1755         self.process_var_decl(&l.pat, value);
1756
1757         // Just walk the initialiser and type (don't want to walk the pattern again).
1758         walk_list!(self, visit_ty, &l.ty);
1759         walk_list!(self, visit_expr, &l.init);
1760     }
1761
1762     fn visit_foreign_item(&mut self, item: &'l ast::ForeignItem) {
1763         let access = access_from!(self.save_ctxt, item);
1764
1765         match item.node {
1766             ast::ForeignItemKind::Fn(ref decl, ref generics) => {
1767                 if let Some(fn_data) = self.save_ctxt.get_extern_item_data(item) {
1768                     down_cast_data!(fn_data, DefData, item.span);
1769
1770                     self.nest_tables(
1771                         item.id,
1772                         |v| v.process_formals(&decl.inputs, &fn_data.qualname),
1773                     );
1774                     self.process_generic_params(generics, item.span, &fn_data.qualname, item.id);
1775                     self.dumper.dump_def(&access, fn_data);
1776                 }
1777
1778                 for arg in &decl.inputs {
1779                     self.visit_ty(&arg.ty);
1780                 }
1781
1782                 if let ast::FunctionRetTy::Ty(ref ret_ty) = decl.output {
1783                     self.visit_ty(&ret_ty);
1784                 }
1785             }
1786             ast::ForeignItemKind::Static(ref ty, _) => {
1787                 if let Some(var_data) = self.save_ctxt.get_extern_item_data(item) {
1788                     down_cast_data!(var_data, DefData, item.span);
1789                     self.dumper.dump_def(&access, var_data);
1790                 }
1791
1792                 self.visit_ty(ty);
1793             }
1794             ast::ForeignItemKind::Ty => {
1795                 if let Some(var_data) = self.save_ctxt.get_extern_item_data(item) {
1796                     down_cast_data!(var_data, DefData, item.span);
1797                     self.dumper.dump_def(&access, var_data);
1798                 }
1799             }
1800         }
1801     }
1802 }