]> git.lizzy.rs Git - rust.git/blob - src/librustc_save_analysis/dump_visitor.rs
Rollup merge of #34175 - rwz:patch-2, r=alexcrichton
[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. The data is
12 //! primarily designed to be used as input to the DXR tool, specifically its
13 //! Rust plugin. It could also be used by IDEs or other code browsing, search, or
14 //! cross-referencing tools.
15 //!
16 //! Dumping the analysis is implemented by walking the AST and getting a bunch of
17 //! info out from all over the place. We use Def IDs to identify objects. The
18 //! tricky part is getting syntactic (span, source text) and semantic (reference
19 //! Def IDs) information for parts of expressions which the compiler has discarded.
20 //! E.g., in a path `foo::bar::baz`, the compiler only keeps a span for the whole
21 //! path and a reference to `baz`, but we want spans and references for all three
22 //! idents.
23 //!
24 //! SpanUtils is used to manipulate spans. In particular, to extract sub-spans
25 //! from spans (e.g., the span for `bar` from the above example path).
26 //! DumpVisitor walks the AST and processes it, and an implementor of Dump
27 //! is used for recording the output in a format-agnostic way (see CsvDumper
28 //! for an example).
29
30 use rustc::hir::def::Def;
31 use rustc::hir::def_id::DefId;
32 use rustc::session::Session;
33 use rustc::ty::{self, TyCtxt};
34
35 use std::collections::HashSet;
36 use std::hash::*;
37
38 use syntax::ast::{self, NodeId, PatKind};
39 use syntax::codemap::*;
40 use syntax::parse::token::{self, keywords};
41 use syntax::visit::{self, Visitor};
42 use syntax::print::pprust::{path_to_string, ty_to_string, bounds_to_string, generics_to_string};
43 use syntax::ptr::P;
44
45 use super::{escape, generated_code, SaveContext, PathCollector};
46 use super::data::*;
47 use super::dump::Dump;
48 use super::external_data::Lower;
49 use super::span_utils::SpanUtils;
50 use super::recorder;
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, D: 'll> {
63     save_ctxt: SaveContext<'l, 'tcx>,
64     sess: &'l Session,
65     tcx: TyCtxt<'l, 'tcx, 'tcx>,
66     analysis: &'l ty::CrateAnalysis<'l>,
67     dumper: &'ll mut D,
68
69     span: SpanUtils<'l>,
70
71     cur_scope: NodeId,
72
73     // Set of macro definition (callee) spans, and the set
74     // of macro use (callsite) spans. We store these to ensure
75     // we only write one macro def per unique macro definition, and
76     // one macro use per unique callsite span.
77     mac_defs: HashSet<Span>,
78     mac_uses: HashSet<Span>,
79 }
80
81 impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
82     pub fn new(tcx: TyCtxt<'l, 'tcx, 'tcx>,
83                save_ctxt: SaveContext<'l, 'tcx>,
84                analysis: &'l ty::CrateAnalysis<'l>,
85                dumper: &'ll mut D)
86                -> DumpVisitor<'l, 'tcx, 'll, D> {
87         let span_utils = SpanUtils::new(&tcx.sess);
88         DumpVisitor {
89             sess: &tcx.sess,
90             tcx: tcx,
91             save_ctxt: save_ctxt,
92             analysis: analysis,
93             dumper: dumper,
94             span: span_utils.clone(),
95             cur_scope: 0,
96             mac_defs: HashSet::new(),
97             mac_uses: HashSet::new(),
98         }
99     }
100
101     fn nest<F>(&mut self, scope_id: NodeId, f: F)
102         where F: FnOnce(&mut DumpVisitor<'l, 'tcx, 'll, D>)
103     {
104         let parent_scope = self.cur_scope;
105         self.cur_scope = scope_id;
106         f(self);
107         self.cur_scope = parent_scope;
108     }
109
110     pub fn dump_crate_info(&mut self, name: &str, krate: &ast::Crate) {
111         let source_file = self.tcx.sess.local_crate_source_file.as_ref();
112         let crate_root = source_file.map(|source_file| {
113             match source_file.file_name() {
114                 Some(_) => source_file.parent().unwrap().display().to_string(),
115                 None => source_file.display().to_string(),
116             }
117         });
118
119         // Info about all the external crates referenced from this crate.
120         let external_crates = self.save_ctxt.get_external_crates().into_iter().map(|c| {
121             let lo_loc = self.span.sess.codemap().lookup_char_pos(c.span.lo);
122             ExternalCrateData {
123                 name: c.name,
124                 num: c.number,
125                 file_name: SpanUtils::make_path_string(&lo_loc.file.name),
126             }
127         }).collect();
128
129         // The current crate.
130         let data = CratePreludeData {
131             crate_name: name.into(),
132             crate_root: crate_root.unwrap_or("<no source>".to_owned()),
133             external_crates: external_crates,
134             span: krate.span,
135         };
136
137         self.dumper.crate_prelude(data.lower(self.tcx));
138     }
139
140     // Return all non-empty prefixes of a path.
141     // For each prefix, we return the span for the last segment in the prefix and
142     // a str representation of the entire prefix.
143     fn process_path_prefixes(&self, path: &ast::Path) -> Vec<(Span, String)> {
144         let spans = self.span.spans_for_path_segments(path);
145
146         // Paths to enums seem to not match their spans - the span includes all the
147         // variants too. But they seem to always be at the end, so I hope we can cope with
148         // always using the first ones. So, only error out if we don't have enough spans.
149         // What could go wrong...?
150         if spans.len() < path.segments.len() {
151             if generated_code(path.span) {
152                 return vec!();
153             }
154             error!("Mis-calculated spans for path '{}'. Found {} spans, expected {}. Found spans:",
155                    path_to_string(path),
156                    spans.len(),
157                    path.segments.len());
158             for s in &spans {
159                 let loc = self.sess.codemap().lookup_char_pos(s.lo);
160                 error!("    '{}' in {}, line {}",
161                        self.span.snippet(*s),
162                        loc.file.name,
163                        loc.line);
164             }
165             return vec!();
166         }
167
168         let mut result: Vec<(Span, String)> = vec!();
169
170         let mut segs = vec!();
171         for (i, (seg, span)) in path.segments.iter().zip(&spans).enumerate() {
172             segs.push(seg.clone());
173             let sub_path = ast::Path {
174                 span: *span, // span for the last segment
175                 global: path.global,
176                 segments: segs,
177             };
178             let qualname = if i == 0 && path.global {
179                 format!("::{}", path_to_string(&sub_path))
180             } else {
181                 path_to_string(&sub_path)
182             };
183             result.push((*span, qualname));
184             segs = sub_path.segments;
185         }
186
187         result
188     }
189
190     // The global arg allows us to override the global-ness of the path (which
191     // actually means 'does the path start with `::`', rather than 'is the path
192     // semantically global). We use the override for `use` imports (etc.) where
193     // the syntax is non-global, but the semantics are global.
194     fn write_sub_paths(&mut self, path: &ast::Path, global: bool) {
195         let sub_paths = self.process_path_prefixes(path);
196         for (i, &(ref span, ref qualname)) in sub_paths.iter().enumerate() {
197             let qualname = if i == 0 && global && !path.global {
198                 format!("::{}", qualname)
199             } else {
200                 qualname.clone()
201             };
202             self.dumper.mod_ref(ModRefData {
203                 span: *span,
204                 qualname: qualname,
205                 scope: self.cur_scope,
206                 ref_id: None
207             }.lower(self.tcx));
208         }
209     }
210
211     // As write_sub_paths, but does not process the last ident in the path (assuming it
212     // will be processed elsewhere). See note on write_sub_paths about global.
213     fn write_sub_paths_truncated(&mut self, path: &ast::Path, global: bool) {
214         let sub_paths = self.process_path_prefixes(path);
215         let len = sub_paths.len();
216         if len <= 1 {
217             return;
218         }
219
220         let sub_paths = &sub_paths[..len-1];
221         for (i, &(ref span, ref qualname)) in sub_paths.iter().enumerate() {
222             let qualname = if i == 0 && global && !path.global {
223                 format!("::{}", qualname)
224             } else {
225                 qualname.clone()
226             };
227             self.dumper.mod_ref(ModRefData {
228                 span: *span,
229                 qualname: qualname,
230                 scope: self.cur_scope,
231                 ref_id: None
232             }.lower(self.tcx));
233         }
234     }
235
236     // As write_sub_paths, but expects a path of the form module_path::trait::method
237     // Where trait could actually be a struct too.
238     fn write_sub_path_trait_truncated(&mut self, path: &ast::Path) {
239         let sub_paths = self.process_path_prefixes(path);
240         let len = sub_paths.len();
241         if len <= 1 {
242             return;
243         }
244         let sub_paths = &sub_paths[.. (len-1)];
245
246         // write the trait part of the sub-path
247         let (ref span, ref qualname) = sub_paths[len-2];
248         self.dumper.type_ref(TypeRefData {
249             ref_id: None,
250             span: *span,
251             qualname: qualname.to_owned(),
252             scope: 0
253         }.lower(self.tcx));
254
255         // write the other sub-paths
256         if len <= 2 {
257             return;
258         }
259         let sub_paths = &sub_paths[..len-2];
260         for &(ref span, ref qualname) in sub_paths {
261             self.dumper.mod_ref(ModRefData {
262                 span: *span,
263                 qualname: qualname.to_owned(),
264                 scope: self.cur_scope,
265                 ref_id: None
266             }.lower(self.tcx));
267         }
268     }
269
270     // looks up anything, not just a type
271     fn lookup_type_ref(&self, ref_id: NodeId) -> Option<DefId> {
272         match self.tcx.expect_def(ref_id) {
273             Def::PrimTy(..) => None,
274             Def::SelfTy(..) => None,
275             def => Some(def.def_id()),
276         }
277     }
278
279     fn process_def_kind(&mut self,
280                         ref_id: NodeId,
281                         span: Span,
282                         sub_span: Option<Span>,
283                         def_id: DefId,
284                         scope: NodeId) {
285         if self.span.filter_generated(sub_span, span) {
286             return;
287         }
288
289         let def = self.tcx.expect_def(ref_id);
290         match def {
291             Def::Mod(_) |
292             Def::ForeignMod(_) => {
293                 self.dumper.mod_ref(ModRefData {
294                     span: sub_span.expect("No span found for mod ref"),
295                     ref_id: Some(def_id),
296                     scope: scope,
297                     qualname: String::new()
298                 }.lower(self.tcx));
299             }
300             Def::Struct(..) |
301             Def::Enum(..) |
302             Def::TyAlias(..) |
303             Def::AssociatedTy(..) |
304             Def::Trait(_) => {
305                 self.dumper.type_ref(TypeRefData {
306                     span: sub_span.expect("No span found for type ref"),
307                     ref_id: Some(def_id),
308                     scope: scope,
309                     qualname: String::new()
310                 }.lower(self.tcx));
311             }
312             Def::Static(_, _) |
313             Def::Const(_) |
314             Def::AssociatedConst(..) |
315             Def::Local(..) |
316             Def::Variant(..) |
317             Def::Upvar(..) => {
318                 self.dumper.variable_ref(VariableRefData {
319                     span: sub_span.expect("No span found for var ref"),
320                     ref_id: def_id,
321                     scope: scope,
322                     name: String::new()
323                 }.lower(self.tcx));
324             }
325             Def::Fn(..) => {
326                 self.dumper.function_ref(FunctionRefData {
327                     span: sub_span.expect("No span found for fn ref"),
328                     ref_id: def_id,
329                     scope: scope
330                 }.lower(self.tcx));
331             }
332             Def::SelfTy(..) |
333             Def::Label(_) |
334             Def::TyParam(..) |
335             Def::Method(..) |
336             Def::PrimTy(_) |
337             Def::Err => {
338                span_bug!(span,
339                          "process_def_kind for unexpected item: {:?}",
340                          def);
341             }
342         }
343     }
344
345     fn process_formals(&mut self, formals: &Vec<ast::Arg>, qualname: &str) {
346         for arg in formals {
347             self.visit_pat(&arg.pat);
348             let mut collector = PathCollector::new();
349             collector.visit_pat(&arg.pat);
350             let span_utils = self.span.clone();
351             for &(id, ref p, _, _) in &collector.collected_paths {
352                 let typ = self.tcx.node_types().get(&id).unwrap().to_string();
353                 // get the span only for the name of the variable (I hope the path is only ever a
354                 // variable name, but who knows?)
355                 let sub_span = span_utils.span_for_last_ident(p.span);
356                 if !self.span.filter_generated(sub_span, p.span) {
357                     self.dumper.variable(VariableData {
358                         id: id,
359                         span: sub_span.expect("No span found for variable"),
360                         name: path_to_string(p),
361                         qualname: format!("{}::{}", qualname, path_to_string(p)),
362                         type_value: typ,
363                         value: String::new(),
364                         scope: 0
365                     }.lower(self.tcx));
366                 }
367             }
368         }
369     }
370
371     fn process_method(&mut self,
372                       sig: &ast::MethodSig,
373                       body: Option<&ast::Block>,
374                       id: ast::NodeId,
375                       name: ast::Name,
376                       span: Span) {
377         debug!("process_method: {}:{}", id, name);
378
379         if let Some(method_data) = self.save_ctxt.get_method_data(id, name, span) {
380
381             let sig_str = ::make_signature(&sig.decl, &sig.generics);
382             if body.is_some() {
383                 if !self.span.filter_generated(Some(method_data.span), span) {
384                     let mut data = method_data.clone();
385                     data.value = sig_str;
386                     self.dumper.function(data.lower(self.tcx));
387                 }
388                 self.process_formals(&sig.decl.inputs, &method_data.qualname);
389             } else {
390                 if !self.span.filter_generated(Some(method_data.span), span) {
391                     self.dumper.method(MethodData {
392                         id: method_data.id,
393                         name: method_data.name,
394                         span: method_data.span,
395                         scope: method_data.scope,
396                         qualname: method_data.qualname.clone(),
397                         value: sig_str,
398                     }.lower(self.tcx));
399                 }
400             }
401             self.process_generic_params(&sig.generics, span, &method_data.qualname, id);
402         }
403
404         // walk arg and return types
405         for arg in &sig.decl.inputs {
406             self.visit_ty(&arg.ty);
407         }
408
409         if let ast::FunctionRetTy::Ty(ref ret_ty) = sig.decl.output {
410             self.visit_ty(ret_ty);
411         }
412
413         // walk the fn body
414         if let Some(body) = body {
415             self.nest(id, |v| v.visit_block(body));
416         }
417     }
418
419     fn process_trait_ref(&mut self, trait_ref: &ast::TraitRef) {
420         let trait_ref_data = self.save_ctxt.get_trait_ref_data(trait_ref, self.cur_scope);
421         if let Some(trait_ref_data) = trait_ref_data {
422             if !self.span.filter_generated(Some(trait_ref_data.span), trait_ref.path.span) {
423                 self.dumper.type_ref(trait_ref_data.lower(self.tcx));
424             }
425
426             visit::walk_path(self, &trait_ref.path);
427         }
428     }
429
430     fn process_struct_field_def(&mut self, field: &ast::StructField, parent_id: NodeId) {
431         let field_data = self.save_ctxt.get_field_data(field, parent_id);
432         if let Some(mut field_data) = field_data {
433             if !self.span.filter_generated(Some(field_data.span), field.span) {
434                 field_data.value = String::new();
435                 self.dumper.variable(field_data.lower(self.tcx));
436             }
437         }
438     }
439
440     // Dump generic params bindings, then visit_generics
441     fn process_generic_params(&mut self,
442                               generics: &ast::Generics,
443                               full_span: Span,
444                               prefix: &str,
445                               id: NodeId) {
446         // We can't only use visit_generics since we don't have spans for param
447         // bindings, so we reparse the full_span to get those sub spans.
448         // However full span is the entire enum/fn/struct block, so we only want
449         // the first few to match the number of generics we're looking for.
450         let param_sub_spans = self.span.spans_for_ty_params(full_span,
451                                                             (generics.ty_params.len() as isize));
452         for (param, param_ss) in generics.ty_params.iter().zip(param_sub_spans) {
453             let name = escape(self.span.snippet(param_ss));
454             // Append $id to name to make sure each one is unique
455             let qualname = format!("{}::{}${}",
456                                    prefix,
457                                    name,
458                                    id);
459             if !self.span.filter_generated(Some(param_ss), full_span) {
460                 self.dumper.typedef(TypeDefData {
461                     span: param_ss,
462                     name: name,
463                     id: param.id,
464                     qualname: qualname,
465                     value: String::new()
466                 }.lower(self.tcx));
467             }
468         }
469         self.visit_generics(generics);
470     }
471
472     fn process_fn(&mut self,
473                   item: &ast::Item,
474                   decl: &ast::FnDecl,
475                   ty_params: &ast::Generics,
476                   body: &ast::Block) {
477         if let Some(fn_data) = self.save_ctxt.get_item_data(item) {
478             down_cast_data!(fn_data, FunctionData, item.span);
479             if !self.span.filter_generated(Some(fn_data.span), item.span) {
480                 self.dumper.function(fn_data.clone().lower(self.tcx));
481             }
482
483             self.process_formals(&decl.inputs, &fn_data.qualname);
484             self.process_generic_params(ty_params, item.span, &fn_data.qualname, item.id);
485         }
486
487         for arg in &decl.inputs {
488             self.visit_ty(&arg.ty);
489         }
490
491         if let ast::FunctionRetTy::Ty(ref ret_ty) = decl.output {
492             self.visit_ty(&ret_ty);
493         }
494
495         self.nest(item.id, |v| v.visit_block(&body));
496     }
497
498     fn process_static_or_const_item(&mut self, item: &ast::Item, typ: &ast::Ty, expr: &ast::Expr) {
499         if let Some(var_data) = self.save_ctxt.get_item_data(item) {
500             down_cast_data!(var_data, VariableData, item.span);
501             if !self.span.filter_generated(Some(var_data.span), item.span) {
502                 self.dumper.variable(var_data.lower(self.tcx));
503             }
504         }
505         self.visit_ty(&typ);
506         self.visit_expr(expr);
507     }
508
509     fn process_const(&mut self,
510                      id: ast::NodeId,
511                      name: ast::Name,
512                      span: Span,
513                      typ: &ast::Ty,
514                      expr: &ast::Expr) {
515         let qualname = format!("::{}", self.tcx.node_path_str(id));
516
517         let sub_span = self.span.sub_span_after_keyword(span, keywords::Const);
518
519         if !self.span.filter_generated(sub_span, span) {
520             self.dumper.variable(VariableData {
521                 span: sub_span.expect("No span found for variable"),
522                 id: id,
523                 name: name.to_string(),
524                 qualname: qualname,
525                 value: self.span.snippet(expr.span),
526                 type_value: ty_to_string(&typ),
527                 scope: self.cur_scope
528             }.lower(self.tcx));
529         }
530
531         // walk type and init value
532         self.visit_ty(typ);
533         self.visit_expr(expr);
534     }
535
536     // FIXME tuple structs should generate tuple-specific data.
537     fn process_struct(&mut self,
538                       item: &ast::Item,
539                       def: &ast::VariantData,
540                       ty_params: &ast::Generics) {
541         let name = item.ident.to_string();
542         let qualname = format!("::{}", self.tcx.node_path_str(item.id));
543
544         let sub_span = self.span.sub_span_after_keyword(item.span, keywords::Struct);
545         let val = if let ast::ItemKind::Struct(ast::VariantData::Struct(ref fields, _), _) =
546                     item.node {
547             let fields_str = fields.iter()
548                                    .enumerate()
549                                    .map(|(i, f)| f.ident.map(|i| i.to_string())
550                                                   .unwrap_or(i.to_string()))
551                                    .collect::<Vec<_>>()
552                                    .join(", ");
553             format!("{} {{ {} }}", name, fields_str)
554         } else {
555             String::new()
556         };
557
558         if !self.span.filter_generated(sub_span, item.span) {
559             self.dumper.struct_data(StructData {
560                 span: sub_span.expect("No span found for struct"),
561                 id: item.id,
562                 name: name,
563                 ctor_id: def.id(),
564                 qualname: qualname.clone(),
565                 scope: self.cur_scope,
566                 value: val
567             }.lower(self.tcx));
568         }
569
570
571         // fields
572         for field in def.fields() {
573             self.process_struct_field_def(field, item.id);
574             self.visit_ty(&field.ty);
575         }
576
577         self.process_generic_params(ty_params, item.span, &qualname, item.id);
578     }
579
580     fn process_enum(&mut self,
581                     item: &ast::Item,
582                     enum_definition: &ast::EnumDef,
583                     ty_params: &ast::Generics) {
584         let enum_data = self.save_ctxt.get_item_data(item);
585         let enum_data = match enum_data {
586             None => return,
587             Some(data) => data,
588         };
589         down_cast_data!(enum_data, EnumData, item.span);
590         if !self.span.filter_generated(Some(enum_data.span), item.span) {
591             self.dumper.enum_data(enum_data.clone().lower(self.tcx));
592         }
593
594         for variant in &enum_definition.variants {
595             let name = variant.node.name.name.to_string();
596             let mut qualname = enum_data.qualname.clone();
597             qualname.push_str("::");
598             qualname.push_str(&name);
599
600             match variant.node.data {
601                 ast::VariantData::Struct(ref fields, _) => {
602                     let sub_span = self.span.span_for_first_ident(variant.span);
603                     let fields_str = fields.iter()
604                                            .enumerate()
605                                            .map(|(i, f)| f.ident.map(|i| i.to_string())
606                                                           .unwrap_or(i.to_string()))
607                                            .collect::<Vec<_>>()
608                                            .join(", ");
609                     let val = format!("{}::{} {{ {} }}", enum_data.name, name, fields_str);
610                     if !self.span.filter_generated(sub_span, variant.span) {
611                         self.dumper.struct_variant(StructVariantData {
612                             span: sub_span.expect("No span found for struct variant"),
613                             id: variant.node.data.id(),
614                             name: name,
615                             qualname: qualname,
616                             type_value: enum_data.qualname.clone(),
617                             value: val,
618                             scope: enum_data.scope
619                         }.lower(self.tcx));
620                     }
621                 }
622                 ref v => {
623                     let sub_span = self.span.span_for_first_ident(variant.span);
624                     let mut val = format!("{}::{}", enum_data.name, name);
625                     if let &ast::VariantData::Tuple(ref fields, _) = v {
626                         val.push('(');
627                         val.push_str(&fields.iter()
628                                             .map(|f| ty_to_string(&f.ty))
629                                             .collect::<Vec<_>>()
630                                             .join(", "));
631                         val.push(')');
632                     }
633                     if !self.span.filter_generated(sub_span, variant.span) {
634                         self.dumper.tuple_variant(TupleVariantData {
635                             span: sub_span.expect("No span found for tuple variant"),
636                             id: variant.node.data.id(),
637                             name: name,
638                             qualname: qualname,
639                             type_value: enum_data.qualname.clone(),
640                             value: val,
641                             scope: enum_data.scope
642                         }.lower(self.tcx));
643                     }
644                 }
645             }
646
647
648             for field in variant.node.data.fields() {
649                 self.process_struct_field_def(field, variant.node.data.id());
650                 self.visit_ty(&field.ty);
651             }
652         }
653         self.process_generic_params(ty_params, item.span, &enum_data.qualname, enum_data.id);
654     }
655
656     fn process_impl(&mut self,
657                     item: &ast::Item,
658                     type_parameters: &ast::Generics,
659                     trait_ref: &Option<ast::TraitRef>,
660                     typ: &ast::Ty,
661                     impl_items: &[ast::ImplItem]) {
662         let mut has_self_ref = false;
663         if let Some(impl_data) = self.save_ctxt.get_item_data(item) {
664             down_cast_data!(impl_data, ImplData, item.span);
665             if let Some(ref self_ref) = impl_data.self_ref {
666                 has_self_ref = true;
667                 if !self.span.filter_generated(Some(self_ref.span), item.span) {
668                     self.dumper.type_ref(self_ref.clone().lower(self.tcx));
669                 }
670             }
671             if let Some(ref trait_ref_data) = impl_data.trait_ref {
672                 if !self.span.filter_generated(Some(trait_ref_data.span), item.span) {
673                     self.dumper.type_ref(trait_ref_data.clone().lower(self.tcx));
674                 }
675
676                 visit::walk_path(self, &trait_ref.as_ref().unwrap().path);
677             }
678
679             if !self.span.filter_generated(Some(impl_data.span), item.span) {
680                 self.dumper.impl_data(ImplData {
681                     id: impl_data.id,
682                     span: impl_data.span,
683                     scope: impl_data.scope,
684                     trait_ref: impl_data.trait_ref.map(|d| d.ref_id.unwrap()),
685                     self_ref: impl_data.self_ref.map(|d| d.ref_id.unwrap())
686                 }.lower(self.tcx));
687             }
688         }
689         if !has_self_ref {
690             self.visit_ty(&typ);
691         }
692         self.process_generic_params(type_parameters, item.span, "", item.id);
693         for impl_item in impl_items {
694             self.visit_impl_item(impl_item);
695         }
696     }
697
698     fn process_trait(&mut self,
699                      item: &ast::Item,
700                      generics: &ast::Generics,
701                      trait_refs: &ast::TyParamBounds,
702                      methods: &[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             self.dumper.trait_data(TraitData {
716                 span: sub_span.expect("No span found for trait"),
717                 id: item.id,
718                 name: name,
719                 qualname: qualname.clone(),
720                 scope: self.cur_scope,
721                 value: val
722             }.lower(self.tcx));
723         }
724
725         // super-traits
726         for super_bound in trait_refs.iter() {
727             let trait_ref = match *super_bound {
728                 ast::TraitTyParamBound(ref trait_ref, _) => {
729                     trait_ref
730                 }
731                 ast::RegionTyParamBound(..) => {
732                     continue;
733                 }
734             };
735
736             let trait_ref = &trait_ref.trait_ref;
737             if let Some(id) = self.lookup_type_ref(trait_ref.ref_id) {
738                 let sub_span = self.span.sub_span_for_type_name(trait_ref.path.span);
739                 if !self.span.filter_generated(sub_span, trait_ref.path.span) {
740                     self.dumper.type_ref(TypeRefData {
741                         span: sub_span.expect("No span found for trait ref"),
742                         ref_id: Some(id),
743                         scope: self.cur_scope,
744                         qualname: String::new()
745                     }.lower(self.tcx));
746                 }
747
748                 if !self.span.filter_generated(sub_span, trait_ref.path.span) {
749                     let sub_span = sub_span.expect("No span for inheritance");
750                     self.dumper.inheritance(InheritanceData {
751                         span: sub_span,
752                         base_id: id,
753                         deriv_id: item.id
754                     }.lower(self.tcx));
755                 }
756             }
757         }
758
759         // walk generics and methods
760         self.process_generic_params(generics, item.span, &qualname, item.id);
761         for method in methods {
762             self.visit_trait_item(method)
763         }
764     }
765
766     // `item` is the module in question, represented as an item.
767     fn process_mod(&mut self, item: &ast::Item) {
768         if let Some(mod_data) = self.save_ctxt.get_item_data(item) {
769             down_cast_data!(mod_data, ModData, item.span);
770             if !self.span.filter_generated(Some(mod_data.span), item.span) {
771                 self.dumper.mod_data(mod_data.lower(self.tcx));
772             }
773         }
774     }
775
776     fn process_path(&mut self, id: NodeId, path: &ast::Path, ref_kind: Option<recorder::Row>) {
777         let path_data = self.save_ctxt.get_path_data(id, path);
778         if generated_code(path.span) && path_data.is_none() {
779             return;
780         }
781
782         let path_data = match path_data {
783             Some(pd) => pd,
784             None => {
785                 span_bug!(path.span,
786                           "Unexpected def kind while looking up path in `{}`",
787                           self.span.snippet(path.span))
788             }
789         };
790
791         match path_data {
792             Data::VariableRefData(vrd) => {
793                 // FIXME: this whole block duplicates the code in process_def_kind
794                 if !self.span.filter_generated(Some(vrd.span), path.span) {
795                     match ref_kind {
796                         Some(recorder::TypeRef) => {
797                             self.dumper.type_ref(TypeRefData {
798                                 span: vrd.span,
799                                 ref_id: Some(vrd.ref_id),
800                                 scope: vrd.scope,
801                                 qualname: String::new()
802                             }.lower(self.tcx));
803                         }
804                         Some(recorder::FnRef) => {
805                             self.dumper.function_ref(FunctionRefData {
806                                 span: vrd.span,
807                                 ref_id: vrd.ref_id,
808                                 scope: vrd.scope
809                             }.lower(self.tcx));
810                         }
811                         Some(recorder::ModRef) => {
812                             self.dumper.mod_ref( ModRefData {
813                                 span: vrd.span,
814                                 ref_id: Some(vrd.ref_id),
815                                 scope: vrd.scope,
816                                 qualname: String::new()
817                             }.lower(self.tcx));
818                         }
819                         Some(recorder::VarRef) | None
820                             => self.dumper.variable_ref(vrd.lower(self.tcx))
821                     }
822                 }
823
824             }
825             Data::TypeRefData(trd) => {
826                 if !self.span.filter_generated(Some(trd.span), path.span) {
827                     self.dumper.type_ref(trd.lower(self.tcx));
828                 }
829             }
830             Data::MethodCallData(mcd) => {
831                 if !self.span.filter_generated(Some(mcd.span), path.span) {
832                     self.dumper.method_call(mcd.lower(self.tcx));
833                 }
834             }
835             Data::FunctionCallData(fcd) => {
836                 if !self.span.filter_generated(Some(fcd.span), path.span) {
837                     self.dumper.function_call(fcd.lower(self.tcx));
838                 }
839             }
840             _ => {
841                span_bug!(path.span, "Unexpected data: {:?}", path_data);
842             }
843         }
844
845         // Modules or types in the path prefix.
846         match self.tcx.expect_def(id) {
847             Def::Method(did) => {
848                 let ti = self.tcx.impl_or_trait_item(did);
849                 if let ty::MethodTraitItem(m) = ti {
850                     if m.explicit_self == ty::ExplicitSelfCategory::Static {
851                         self.write_sub_path_trait_truncated(path);
852                     }
853                 }
854             }
855             Def::Local(..) |
856             Def::Static(_,_) |
857             Def::Const(..) |
858             Def::AssociatedConst(..) |
859             Def::Struct(..) |
860             Def::Variant(..) |
861             Def::Fn(..) => self.write_sub_paths_truncated(path, false),
862             _ => {}
863         }
864     }
865
866     fn process_struct_lit(&mut self,
867                           ex: &ast::Expr,
868                           path: &ast::Path,
869                           fields: &Vec<ast::Field>,
870                           variant: ty::VariantDef,
871                           base: &Option<P<ast::Expr>>) {
872         self.write_sub_paths_truncated(path, false);
873
874         if let Some(struct_lit_data) = self.save_ctxt.get_expr_data(ex) {
875             down_cast_data!(struct_lit_data, TypeRefData, ex.span);
876             if !self.span.filter_generated(Some(struct_lit_data.span), ex.span) {
877                 self.dumper.type_ref(struct_lit_data.lower(self.tcx));
878             }
879
880             let scope = self.save_ctxt.enclosing_scope(ex.id);
881
882             for field in fields {
883                 if let Some(field_data) = self.save_ctxt
884                                               .get_field_ref_data(field, variant, scope) {
885
886                     if !self.span.filter_generated(Some(field_data.span), field.ident.span) {
887                         self.dumper.variable_ref(field_data.lower(self.tcx));
888                     }
889                 }
890
891                 self.visit_expr(&field.expr)
892             }
893         }
894
895         walk_list!(self, visit_expr, base);
896     }
897
898     fn process_method_call(&mut self, ex: &ast::Expr, args: &Vec<P<ast::Expr>>) {
899         if let Some(mcd) = self.save_ctxt.get_expr_data(ex) {
900             down_cast_data!(mcd, MethodCallData, ex.span);
901             if !self.span.filter_generated(Some(mcd.span), ex.span) {
902                 self.dumper.method_call(mcd.lower(self.tcx));
903             }
904         }
905
906         // walk receiver and args
907         walk_list!(self, visit_expr, args);
908     }
909
910     fn process_pat(&mut self, p: &ast::Pat) {
911         match p.node {
912             PatKind::Struct(ref path, ref fields, _) => {
913                 visit::walk_path(self, path);
914                 let adt = self.tcx.node_id_to_type(p.id).ty_adt_def().unwrap();
915                 let variant = adt.variant_of_def(self.tcx.expect_def(p.id));
916
917                 for &Spanned { node: ref field, span } in fields {
918                     let sub_span = self.span.span_for_first_ident(span);
919                     if let Some(f) = variant.find_field_named(field.ident.name) {
920                         if !self.span.filter_generated(sub_span, span) {
921                             self.dumper.variable_ref(VariableRefData {
922                                 span: sub_span.expect("No span fund for var ref"),
923                                 ref_id: f.did,
924                                 scope: self.cur_scope,
925                                 name: String::new()
926                             }.lower(self.tcx));
927                         }
928                     }
929                     self.visit_pat(&field.pat);
930                 }
931             }
932             _ => visit::walk_pat(self, p),
933         }
934     }
935
936
937     fn process_var_decl(&mut self, p: &ast::Pat, value: String) {
938         // The local could declare multiple new vars, we must walk the
939         // pattern and collect them all.
940         let mut collector = PathCollector::new();
941         collector.visit_pat(&p);
942         self.visit_pat(&p);
943
944         for &(id, ref p, immut, _) in &collector.collected_paths {
945             let mut value = if immut == ast::Mutability::Immutable {
946                 value.to_string()
947             } else {
948                 "<mutable>".to_string()
949             };
950             let types = self.tcx.node_types();
951             let typ = types.get(&id).map(|t| t.to_string()).unwrap_or(String::new());
952             value.push_str(": ");
953             value.push_str(&typ);
954             // Get the span only for the name of the variable (I hope the path
955             // is only ever a variable name, but who knows?).
956             let sub_span = self.span.span_for_last_ident(p.span);
957             // Rust uses the id of the pattern for var lookups, so we'll use it too.
958             if !self.span.filter_generated(sub_span, p.span) {
959                 self.dumper.variable(VariableData {
960                     span: sub_span.expect("No span found for variable"),
961                     id: id,
962                     name: path_to_string(p),
963                     qualname: format!("{}${}", path_to_string(p), id),
964                     value: value,
965                     type_value: typ,
966                     scope: 0
967                 }.lower(self.tcx));
968             }
969         }
970     }
971
972     /// Extract macro use and definition information from the AST node defined
973     /// by the given NodeId, using the expansion information from the node's
974     /// span.
975     ///
976     /// If the span is not macro-generated, do nothing, else use callee and
977     /// callsite spans to record macro definition and use data, using the
978     /// mac_uses and mac_defs sets to prevent multiples.
979     fn process_macro_use(&mut self, span: Span, id: NodeId) {
980         let data = match self.save_ctxt.get_macro_use_data(span, id) {
981             None => return,
982             Some(data) => data,
983         };
984         let mut hasher = SipHasher::new();
985         data.callee_span.hash(&mut hasher);
986         let hash = hasher.finish();
987         let qualname = format!("{}::{}", data.name, hash);
988         // Don't write macro definition for imported macros
989         if !self.mac_defs.contains(&data.callee_span)
990             && !data.imported {
991             self.mac_defs.insert(data.callee_span);
992             if let Some(sub_span) = self.span.span_for_macro_def_name(data.callee_span) {
993                 self.dumper.macro_data(MacroData {
994                     span: sub_span,
995                     name: data.name.clone(),
996                     qualname: qualname.clone()
997                 }.lower(self.tcx));
998             }
999         }
1000         if !self.mac_uses.contains(&data.span) {
1001             self.mac_uses.insert(data.span);
1002             if let Some(sub_span) = self.span.span_for_macro_use_name(data.span) {
1003                 self.dumper.macro_use(MacroUseData {
1004                     span: sub_span,
1005                     name: data.name,
1006                     qualname: qualname,
1007                     scope: data.scope,
1008                     callee_span: data.callee_span,
1009                     imported: data.imported
1010                 }.lower(self.tcx));
1011             }
1012         }
1013     }
1014 }
1015
1016 impl<'v, 'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor<'v> for DumpVisitor<'l, 'tcx, 'll, D> {
1017     fn visit_item(&mut self, item: &ast::Item) {
1018         use syntax::ast::ItemKind::*;
1019         self.process_macro_use(item.span, item.id);
1020         match item.node {
1021             Use(ref use_item) => {
1022                 match use_item.node {
1023                     ast::ViewPathSimple(ident, ref path) => {
1024                         let sub_span = self.span.span_for_last_ident(path.span);
1025                         let mod_id = match self.lookup_type_ref(item.id) {
1026                             Some(def_id) => {
1027                                 let scope = self.cur_scope;
1028                                 self.process_def_kind(item.id, path.span, sub_span, def_id, scope);
1029
1030                                 Some(def_id)
1031                             }
1032                             None => None,
1033                         };
1034
1035                         // 'use' always introduces an alias, if there is not an explicit
1036                         // one, there is an implicit one.
1037                         let sub_span = match self.span.sub_span_after_keyword(use_item.span,
1038                                                                               keywords::As) {
1039                             Some(sub_span) => Some(sub_span),
1040                             None => sub_span,
1041                         };
1042
1043                         if !self.span.filter_generated(sub_span, path.span) {
1044                             self.dumper.use_data(UseData {
1045                                 span: sub_span.expect("No span found for use"),
1046                                 id: item.id,
1047                                 mod_id: mod_id,
1048                                 name: ident.to_string(),
1049                                 scope: self.cur_scope
1050                             }.lower(self.tcx));
1051                         }
1052                         self.write_sub_paths_truncated(path, true);
1053                     }
1054                     ast::ViewPathGlob(ref path) => {
1055                         // Make a comma-separated list of names of imported modules.
1056                         let mut names = vec![];
1057                         let glob_map = &self.analysis.glob_map;
1058                         let glob_map = glob_map.as_ref().unwrap();
1059                         if glob_map.contains_key(&item.id) {
1060                             for n in glob_map.get(&item.id).unwrap() {
1061                                 names.push(n.to_string());
1062                             }
1063                         }
1064
1065                         let sub_span = self.span
1066                                            .sub_span_of_token(item.span, token::BinOp(token::Star));
1067                         if !self.span.filter_generated(sub_span, item.span) {
1068                             self.dumper.use_glob(UseGlobData {
1069                                 span: sub_span.expect("No span found for use glob"),
1070                                 id: item.id,
1071                                 names: names,
1072                                 scope: self.cur_scope
1073                             }.lower(self.tcx));
1074                         }
1075                         self.write_sub_paths(path, true);
1076                     }
1077                     ast::ViewPathList(ref path, ref list) => {
1078                         for plid in list {
1079                             match plid.node {
1080                                 ast::PathListItemKind::Ident { id, .. } => {
1081                                     let scope = self.cur_scope;
1082                                     if let Some(def_id) = self.lookup_type_ref(id) {
1083                                         self.process_def_kind(id,
1084                                                               plid.span,
1085                                                               Some(plid.span),
1086                                                               def_id,
1087                                                               scope);
1088                                     }
1089                                 }
1090                                 ast::PathListItemKind::Mod { .. } => (),
1091                             }
1092                         }
1093
1094                         self.write_sub_paths(path, true);
1095                     }
1096                 }
1097             }
1098             ExternCrate(ref s) => {
1099                 let location = match *s {
1100                     Some(s) => s.to_string(),
1101                     None => item.ident.to_string(),
1102                 };
1103                 let alias_span = self.span.span_for_last_ident(item.span);
1104                 let cnum = match self.sess.cstore.extern_mod_stmt_cnum(item.id) {
1105                     Some(cnum) => cnum,
1106                     None => 0,
1107                 };
1108
1109                 if !self.span.filter_generated(alias_span, item.span) {
1110                     self.dumper.extern_crate(ExternCrateData {
1111                         id: item.id,
1112                         name: item.ident.to_string(),
1113                         crate_num: cnum,
1114                         location: location,
1115                         span: alias_span.expect("No span found for extern crate"),
1116                         scope: self.cur_scope,
1117                     }.lower(self.tcx));
1118                 }
1119             }
1120             Fn(ref decl, _, _, _, ref ty_params, ref body) =>
1121                 self.process_fn(item, &decl, ty_params, &body),
1122             Static(ref typ, _, ref expr) =>
1123                 self.process_static_or_const_item(item, typ, expr),
1124             Const(ref typ, ref expr) =>
1125                 self.process_static_or_const_item(item, &typ, &expr),
1126             Struct(ref def, ref ty_params) => self.process_struct(item, def, ty_params),
1127             Enum(ref def, ref ty_params) => self.process_enum(item, def, ty_params),
1128             Impl(_, _,
1129                           ref ty_params,
1130                           ref trait_ref,
1131                           ref typ,
1132                           ref impl_items) => {
1133                 self.process_impl(item, ty_params, trait_ref, &typ, impl_items)
1134             }
1135             Trait(_, ref generics, ref trait_refs, ref methods) =>
1136                 self.process_trait(item, generics, trait_refs, methods),
1137             Mod(ref m) => {
1138                 self.process_mod(item);
1139                 self.nest(item.id, |v| visit::walk_mod(v, m));
1140             }
1141             Ty(ref ty, ref ty_params) => {
1142                 let qualname = format!("::{}", self.tcx.node_path_str(item.id));
1143                 let value = ty_to_string(&ty);
1144                 let sub_span = self.span.sub_span_after_keyword(item.span, keywords::Type);
1145                 if !self.span.filter_generated(sub_span, item.span) {
1146                     self.dumper.typedef(TypeDefData {
1147                         span: sub_span.expect("No span found for typedef"),
1148                         name: item.ident.to_string(),
1149                         id: item.id,
1150                         qualname: qualname.clone(),
1151                         value: value
1152                     }.lower(self.tcx));
1153                 }
1154
1155                 self.visit_ty(&ty);
1156                 self.process_generic_params(ty_params, item.span, &qualname, item.id);
1157             }
1158             Mac(_) => (),
1159             _ => visit::walk_item(self, item),
1160         }
1161     }
1162
1163     fn visit_generics(&mut self, generics: &ast::Generics) {
1164         for param in generics.ty_params.iter() {
1165             for bound in param.bounds.iter() {
1166                 if let ast::TraitTyParamBound(ref trait_ref, _) = *bound {
1167                     self.process_trait_ref(&trait_ref.trait_ref);
1168                 }
1169             }
1170             if let Some(ref ty) = param.default {
1171                 self.visit_ty(&ty);
1172             }
1173         }
1174     }
1175
1176     fn visit_trait_item(&mut self, trait_item: &ast::TraitItem) {
1177         self.process_macro_use(trait_item.span, trait_item.id);
1178         match trait_item.node {
1179             ast::TraitItemKind::Const(ref ty, Some(ref expr)) => {
1180                 self.process_const(trait_item.id,
1181                                    trait_item.ident.name,
1182                                    trait_item.span,
1183                                    &ty,
1184                                    &expr);
1185             }
1186             ast::TraitItemKind::Method(ref sig, ref body) => {
1187                 self.process_method(sig,
1188                                     body.as_ref().map(|x| &**x),
1189                                     trait_item.id,
1190                                     trait_item.ident.name,
1191                                     trait_item.span);
1192             }
1193             ast::TraitItemKind::Const(_, None) |
1194             ast::TraitItemKind::Type(..) => {}
1195         }
1196     }
1197
1198     fn visit_impl_item(&mut self, impl_item: &ast::ImplItem) {
1199         self.process_macro_use(impl_item.span, impl_item.id);
1200         match impl_item.node {
1201             ast::ImplItemKind::Const(ref ty, ref expr) => {
1202                 self.process_const(impl_item.id,
1203                                    impl_item.ident.name,
1204                                    impl_item.span,
1205                                    &ty,
1206                                    &expr);
1207             }
1208             ast::ImplItemKind::Method(ref sig, ref body) => {
1209                 self.process_method(sig,
1210                                     Some(body),
1211                                     impl_item.id,
1212                                     impl_item.ident.name,
1213                                     impl_item.span);
1214             }
1215             ast::ImplItemKind::Type(_) |
1216             ast::ImplItemKind::Macro(_) => {}
1217         }
1218     }
1219
1220     fn visit_ty(&mut self, t: &ast::Ty) {
1221         self.process_macro_use(t.span, t.id);
1222         match t.node {
1223             ast::TyKind::Path(_, ref path) => {
1224                 if let Some(id) = self.lookup_type_ref(t.id) {
1225                     let sub_span = self.span.sub_span_for_type_name(t.span);
1226                     if !self.span.filter_generated(sub_span, t.span) {
1227                         self.dumper.type_ref(TypeRefData {
1228                             span: sub_span.expect("No span found for type ref"),
1229                             ref_id: Some(id),
1230                             scope: self.cur_scope,
1231                             qualname: String::new()
1232                         }.lower(self.tcx));
1233                     }
1234                 }
1235
1236                 self.write_sub_paths_truncated(path, false);
1237
1238                 visit::walk_path(self, path);
1239             }
1240             _ => visit::walk_ty(self, t),
1241         }
1242     }
1243
1244     fn visit_expr(&mut self, ex: &ast::Expr) {
1245         self.process_macro_use(ex.span, ex.id);
1246         match ex.node {
1247             ast::ExprKind::Call(ref _f, ref _args) => {
1248                 // Don't need to do anything for function calls,
1249                 // because just walking the callee path does what we want.
1250                 visit::walk_expr(self, ex);
1251             }
1252             ast::ExprKind::Path(_, ref path) => {
1253                 self.process_path(ex.id, path, None);
1254                 visit::walk_expr(self, ex);
1255             }
1256             ast::ExprKind::Struct(ref path, ref fields, ref base) => {
1257                 let hir_expr = self.save_ctxt.tcx.map.expect_expr(ex.id);
1258                 let adt = self.tcx.expr_ty(&hir_expr).ty_adt_def().unwrap();
1259                 let def = self.tcx.expect_def(hir_expr.id);
1260                 self.process_struct_lit(ex, path, fields, adt.variant_of_def(def), base)
1261             }
1262             ast::ExprKind::MethodCall(_, _, ref args) => self.process_method_call(ex, args),
1263             ast::ExprKind::Field(ref sub_ex, _) => {
1264                 self.visit_expr(&sub_ex);
1265
1266                 if let Some(field_data) = self.save_ctxt.get_expr_data(ex) {
1267                     down_cast_data!(field_data, VariableRefData, ex.span);
1268                     if !self.span.filter_generated(Some(field_data.span), ex.span) {
1269                         self.dumper.variable_ref(field_data.lower(self.tcx));
1270                     }
1271                 }
1272             }
1273             ast::ExprKind::TupField(ref sub_ex, idx) => {
1274                 self.visit_expr(&sub_ex);
1275
1276                 let hir_node = self.save_ctxt.tcx.map.expect_expr(sub_ex.id);
1277                 let ty = &self.tcx.expr_ty_adjusted(&hir_node).sty;
1278                 match *ty {
1279                     ty::TyStruct(def, _) => {
1280                         let sub_span = self.span.sub_span_after_token(ex.span, token::Dot);
1281                         if !self.span.filter_generated(sub_span, ex.span) {
1282                             self.dumper.variable_ref(VariableRefData {
1283                                 span: sub_span.expect("No span found for var ref"),
1284                                 ref_id: def.struct_variant().fields[idx.node].did,
1285                                 scope: self.cur_scope,
1286                                 name: String::new()
1287                             }.lower(self.tcx));
1288                         }
1289                     }
1290                     ty::TyTuple(_) => {}
1291                     _ => span_bug!(ex.span,
1292                                    "Expected struct or tuple type, found {:?}",
1293                                    ty),
1294                 }
1295             }
1296             ast::ExprKind::Closure(_, ref decl, ref body, _fn_decl_span) => {
1297                 let mut id = String::from("$");
1298                 id.push_str(&ex.id.to_string());
1299                 self.process_formals(&decl.inputs, &id);
1300
1301                 // walk arg and return types
1302                 for arg in &decl.inputs {
1303                     self.visit_ty(&arg.ty);
1304                 }
1305
1306                 if let ast::FunctionRetTy::Ty(ref ret_ty) = decl.output {
1307                     self.visit_ty(&ret_ty);
1308                 }
1309
1310                 // walk the body
1311                 self.nest(ex.id, |v| v.visit_block(&body));
1312             }
1313             ast::ExprKind::ForLoop(ref pattern, ref subexpression, ref block, _) |
1314             ast::ExprKind::WhileLet(ref pattern, ref subexpression, ref block, _) => {
1315                 let value = self.span.snippet(subexpression.span);
1316                 self.process_var_decl(pattern, value);
1317                 visit::walk_expr(self, subexpression);
1318                 visit::walk_block(self, block);
1319             }
1320             ast::ExprKind::IfLet(ref pattern, ref subexpression, ref block, ref opt_else) => {
1321                 let value = self.span.snippet(subexpression.span);
1322                 self.process_var_decl(pattern, value);
1323                 visit::walk_expr(self, subexpression);
1324                 visit::walk_block(self, block);
1325                 opt_else.as_ref().map(|el| visit::walk_expr(self, el));
1326             }
1327             _ => {
1328                 visit::walk_expr(self, ex)
1329             }
1330         }
1331     }
1332
1333     fn visit_mac(&mut self, mac: &ast::Mac) {
1334         // These shouldn't exist in the AST at this point, log a span bug.
1335         span_bug!(mac.span, "macro invocation should have been expanded out of AST");
1336     }
1337
1338     fn visit_pat(&mut self, p: &ast::Pat) {
1339         self.process_macro_use(p.span, p.id);
1340         self.process_pat(p);
1341     }
1342
1343     fn visit_arm(&mut self, arm: &ast::Arm) {
1344         let mut collector = PathCollector::new();
1345         for pattern in &arm.pats {
1346             // collect paths from the arm's patterns
1347             collector.visit_pat(&pattern);
1348             self.visit_pat(&pattern);
1349         }
1350
1351         // This is to get around borrow checking, because we need mut self to call process_path.
1352         let mut paths_to_process = vec![];
1353
1354         // process collected paths
1355         for &(id, ref p, immut, ref_kind) in &collector.collected_paths {
1356             match self.tcx.expect_def(id) {
1357                 Def::Local(_, id) => {
1358                     let value = if immut == ast::Mutability::Immutable {
1359                         self.span.snippet(p.span).to_string()
1360                     } else {
1361                         "<mutable>".to_string()
1362                     };
1363
1364                     assert!(p.segments.len() == 1,
1365                             "qualified path for local variable def in arm");
1366                     if !self.span.filter_generated(Some(p.span), p.span) {
1367                         self.dumper.variable(VariableData {
1368                             span: p.span,
1369                             id: id,
1370                             name: path_to_string(p),
1371                             qualname: format!("{}${}", path_to_string(p), id),
1372                             value: value,
1373                             type_value: String::new(),
1374                             scope: 0
1375                         }.lower(self.tcx));
1376                     }
1377                 }
1378                 Def::Variant(..) | Def::Enum(..) |
1379                 Def::TyAlias(..) | Def::Struct(..) => {
1380                     paths_to_process.push((id, p.clone(), Some(ref_kind)))
1381                 }
1382                 // FIXME(nrc) what are these doing here?
1383                 Def::Static(_, _) |
1384                 Def::Const(..) |
1385                 Def::AssociatedConst(..) => {}
1386                 def => error!("unexpected definition kind when processing collected paths: {:?}",
1387                               def),
1388             }
1389         }
1390
1391         for &(id, ref path, ref_kind) in &paths_to_process {
1392             self.process_path(id, path, ref_kind);
1393         }
1394         walk_list!(self, visit_expr, &arm.guard);
1395         self.visit_expr(&arm.body);
1396     }
1397
1398     fn visit_stmt(&mut self, s: &ast::Stmt) {
1399         let id = s.node.id();
1400         self.process_macro_use(s.span, id.unwrap());
1401         visit::walk_stmt(self, s)
1402     }
1403
1404     fn visit_local(&mut self, l: &ast::Local) {
1405         self.process_macro_use(l.span, l.id);
1406         let value = l.init.as_ref().map(|i| self.span.snippet(i.span)).unwrap_or(String::new());
1407         self.process_var_decl(&l.pat, value);
1408
1409         // Just walk the initialiser and type (don't want to walk the pattern again).
1410         walk_list!(self, visit_ty, &l.ty);
1411         walk_list!(self, visit_expr, &l.init);
1412     }
1413 }