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