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