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