]> git.lizzy.rs Git - rust.git/blob - src/librustc_trans/save/dump_csv.rs
Replace usage of String::from_str with String:from
[rust.git] / src / librustc_trans / save / dump_csv.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 //! Output a CSV file containing the output from rustc's analysis. 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 //! Recorder is used for recording the output in csv format. FmtStrs separates
27 //! the format of the output away from extracting it from the compiler.
28 //! DumpCsvVisitor walks the AST and processes it.
29
30
31 use super::{escape, generated_code, recorder, SaveContext, PathCollector};
32
33 use session::Session;
34
35 use middle::def;
36 use middle::ty::{self, Ty};
37
38 use std::cell::Cell;
39 use std::fs::File;
40 use std::path::Path;
41
42 use syntax::ast_util;
43 use syntax::ast::{self, NodeId, DefId};
44 use syntax::ast_map::NodeItem;
45 use syntax::codemap::*;
46 use syntax::parse::token::{self, get_ident, keywords};
47 use syntax::owned_slice::OwnedSlice;
48 use syntax::visit::{self, Visitor};
49 use syntax::print::pprust::{path_to_string, ty_to_string};
50 use syntax::ptr::P;
51
52 use super::span_utils::SpanUtils;
53 use super::recorder::{Recorder, FmtStrs};
54
55 use util::ppaux;
56
57
58 pub struct DumpCsvVisitor<'l, 'tcx: 'l> {
59     save_ctxt: SaveContext<'l, 'tcx>,
60     sess: &'l Session,
61     analysis: &'l ty::CrateAnalysis<'tcx>,
62
63     span: SpanUtils<'l>,
64     fmt: FmtStrs<'l>,
65
66     cur_scope: NodeId
67 }
68
69 impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> {
70     pub fn new(sess: &'l Session,
71                analysis: &'l ty::CrateAnalysis<'tcx>,
72                output_file: Box<File>) -> DumpCsvVisitor<'l, 'tcx> {
73         DumpCsvVisitor {
74             sess: sess,
75             save_ctxt: SaveContext::new(sess, analysis, SpanUtils {
76                 sess: sess,
77                 err_count: Cell::new(0)
78             }),
79             analysis: analysis,
80             span: SpanUtils {
81                 sess: sess,
82                 err_count: Cell::new(0)
83             },
84             fmt: FmtStrs::new(box Recorder {
85                                 out: output_file,
86                                 dump_spans: false,
87                             },
88                             SpanUtils {
89                                 sess: sess,
90                                 err_count: Cell::new(0)
91                             }),
92             cur_scope: 0
93         }
94     }
95
96     fn nest<F>(&mut self, scope_id: NodeId, f: F) where
97         F: FnOnce(&mut DumpCsvVisitor<'l, 'tcx>),
98     {
99         let parent_scope = self.cur_scope;
100         self.cur_scope = scope_id;
101         f(self);
102         self.cur_scope = parent_scope;
103     }
104
105     pub fn dump_crate_info(&mut self, name: &str, krate: &ast::Crate) {
106         // The current crate.
107         self.fmt.crate_str(krate.span, name);
108
109         // Dump info about all the external crates referenced from this crate.
110         for c in &self.save_ctxt.get_external_crates() {
111             self.fmt.external_crate_str(krate.span, &c.name, c.number);
112         }
113         self.fmt.recorder.record("end_external_crates\n");
114     }
115
116     // Return all non-empty prefixes of a path.
117     // For each prefix, we return the span for the last segment in the prefix and
118     // a str representation of the entire prefix.
119     fn process_path_prefixes(&self, path: &ast::Path) -> Vec<(Span, String)> {
120         let spans = self.span.spans_for_path_segments(path);
121
122         // Paths to enums seem to not match their spans - the span includes all the
123         // variants too. But they seem to always be at the end, so I hope we can cope with
124         // always using the first ones. So, only error out if we don't have enough spans.
125         // What could go wrong...?
126         if spans.len() < path.segments.len() {
127             error!("Mis-calculated spans for path '{}'. \
128                     Found {} spans, expected {}. Found spans:",
129                    path_to_string(path), spans.len(), path.segments.len());
130             for s in &spans {
131                 let loc = self.sess.codemap().lookup_char_pos(s.lo);
132                 error!("    '{}' in {}, line {}",
133                        self.span.snippet(*s), loc.file.name, loc.line);
134             }
135             return vec!();
136         }
137
138         let mut result: Vec<(Span, String)> = vec!();
139
140         let mut segs = vec!();
141         for (i, (seg, span)) in path.segments.iter().zip(spans.iter()).enumerate() {
142             segs.push(seg.clone());
143             let sub_path = ast::Path{span: *span, // span for the last segment
144                                      global: path.global,
145                                      segments: segs};
146             let qualname = if i == 0 && path.global {
147                 format!("::{}", path_to_string(&sub_path))
148             } else {
149                 path_to_string(&sub_path)
150             };
151             result.push((*span, qualname));
152             segs = sub_path.segments;
153         }
154
155         result
156     }
157
158     // The global arg allows us to override the global-ness of the path (which
159     // actually means 'does the path start with `::`', rather than 'is the path
160     // semantically global). We use the override for `use` imports (etc.) where
161     // the syntax is non-global, but the semantics are global.
162     fn write_sub_paths(&mut self, path: &ast::Path, global: bool) {
163         let sub_paths = self.process_path_prefixes(path);
164         for (i, &(ref span, ref qualname)) in sub_paths.iter().enumerate() {
165             let qualname = if i == 0 && global && !path.global {
166                 format!("::{}", qualname)
167             } else {
168                 qualname.clone()
169             };
170             self.fmt.sub_mod_ref_str(path.span,
171                                      *span,
172                                      &qualname,
173                                      self.cur_scope);
174         }
175     }
176
177     // As write_sub_paths, but does not process the last ident in the path (assuming it
178     // will be processed elsewhere). See note on write_sub_paths about global.
179     fn write_sub_paths_truncated(&mut self, path: &ast::Path, global: bool) {
180         let sub_paths = self.process_path_prefixes(path);
181         let len = sub_paths.len();
182         if len <= 1 {
183             return;
184         }
185
186         let sub_paths = &sub_paths[..len-1];
187         for (i, &(ref span, ref qualname)) in sub_paths.iter().enumerate() {
188             let qualname = if i == 0 && global && !path.global {
189                 format!("::{}", qualname)
190             } else {
191                 qualname.clone()
192             };
193             self.fmt.sub_mod_ref_str(path.span,
194                                      *span,
195                                      &qualname,
196                                      self.cur_scope);
197         }
198     }
199
200     // As write_sub_paths, but expects a path of the form module_path::trait::method
201     // Where trait could actually be a struct too.
202     fn write_sub_path_trait_truncated(&mut self, path: &ast::Path) {
203         let sub_paths = self.process_path_prefixes(path);
204         let len = sub_paths.len();
205         if len <= 1 {
206             return;
207         }
208         let sub_paths = &sub_paths[.. (len-1)];
209
210         // write the trait part of the sub-path
211         let (ref span, ref qualname) = sub_paths[len-2];
212         self.fmt.sub_type_ref_str(path.span,
213                                   *span,
214                                   &qualname);
215
216         // write the other sub-paths
217         if len <= 2 {
218             return;
219         }
220         let sub_paths = &sub_paths[..len-2];
221         for &(ref span, ref qualname) in sub_paths {
222             self.fmt.sub_mod_ref_str(path.span,
223                                      *span,
224                                      &qualname,
225                                      self.cur_scope);
226         }
227     }
228
229     // looks up anything, not just a type
230     fn lookup_type_ref(&self, ref_id: NodeId) -> Option<DefId> {
231         if !self.analysis.ty_cx.def_map.borrow().contains_key(&ref_id) {
232             self.sess.bug(&format!("def_map has no key for {} in lookup_type_ref",
233                                   ref_id));
234         }
235         let def = self.analysis.ty_cx.def_map.borrow().get(&ref_id).unwrap().full_def();
236         match def {
237             def::DefPrimTy(_) => None,
238             _ => Some(def.def_id()),
239         }
240     }
241
242     fn lookup_def_kind(&self, ref_id: NodeId, span: Span) -> Option<recorder::Row> {
243         let def_map = self.analysis.ty_cx.def_map.borrow();
244         if !def_map.contains_key(&ref_id) {
245             self.sess.span_bug(span, &format!("def_map has no key for {} in lookup_def_kind",
246                                              ref_id));
247         }
248         let def = def_map.get(&ref_id).unwrap().full_def();
249         match def {
250             def::DefMod(_) |
251             def::DefForeignMod(_) => Some(recorder::ModRef),
252             def::DefStruct(_) => Some(recorder::StructRef),
253             def::DefTy(..) |
254             def::DefAssociatedTy(..) |
255             def::DefTrait(_) => Some(recorder::TypeRef),
256             def::DefStatic(_, _) |
257             def::DefConst(_) |
258             def::DefAssociatedConst(..) |
259             def::DefLocal(_) |
260             def::DefVariant(_, _, _) |
261             def::DefUpvar(..) => Some(recorder::VarRef),
262
263             def::DefFn(..) => Some(recorder::FnRef),
264
265             def::DefSelfTy(..) |
266             def::DefRegion(_) |
267             def::DefLabel(_) |
268             def::DefTyParam(..) |
269             def::DefUse(_) |
270             def::DefMethod(..) |
271             def::DefPrimTy(_) => {
272                 self.sess.span_bug(span, &format!("lookup_def_kind for unexpected item: {:?}",
273                                                  def));
274             },
275         }
276     }
277
278     fn process_formals(&mut self, formals: &Vec<ast::Arg>, qualname: &str) {
279         for arg in formals {
280             self.visit_pat(&arg.pat);
281             let mut collector = PathCollector::new();
282             collector.visit_pat(&arg.pat);
283             let span_utils = self.span.clone();
284             for &(id, ref p, _, _) in &collector.collected_paths {
285                 let typ =
286                     ppaux::ty_to_string(
287                         &self.analysis.ty_cx,
288                         *self.analysis.ty_cx.node_types().get(&id).unwrap());
289                 // get the span only for the name of the variable (I hope the path is only ever a
290                 // variable name, but who knows?)
291                 self.fmt.formal_str(p.span,
292                                     span_utils.span_for_last_ident(p.span),
293                                     id,
294                                     qualname,
295                                     &path_to_string(p),
296                                     &typ);
297             }
298         }
299     }
300
301     fn process_method(&mut self, sig: &ast::MethodSig,
302                       body: Option<&ast::Block>,
303                       id: ast::NodeId, name: ast::Name,
304                       span: Span) {
305         if generated_code(span) {
306             return;
307         }
308
309         debug!("process_method: {}:{}", id, token::get_name(name));
310
311         let mut scope_id;
312         // The qualname for a method is the trait name or name of the struct in an impl in
313         // which the method is declared in, followed by the method's name.
314         let qualname = match ty::impl_of_method(&self.analysis.ty_cx,
315                                                 ast_util::local_def(id)) {
316             Some(impl_id) => match self.analysis.ty_cx.map.get(impl_id.node) {
317                 NodeItem(item) => {
318                     scope_id = item.id;
319                     match item.node {
320                         ast::ItemImpl(_, _, _, _, ref ty, _) => {
321                             let mut result = String::from("<");
322                             result.push_str(&ty_to_string(&**ty));
323
324                             match ty::trait_of_item(&self.analysis.ty_cx,
325                                                     ast_util::local_def(id)) {
326                                 Some(def_id) => {
327                                     result.push_str(" as ");
328                                     result.push_str(
329                                         &ty::item_path_str(&self.analysis.ty_cx, def_id));
330                                 },
331                                 None => {}
332                             }
333                             result.push_str(">");
334                             result
335                         }
336                         _ => {
337                             self.sess.span_bug(span,
338                                 &format!("Container {} for method {} not an impl?",
339                                          impl_id.node, id));
340                         },
341                     }
342                 },
343                 _ => {
344                     self.sess.span_bug(span,
345                         &format!("Container {} for method {} is not a node item {:?}",
346                                  impl_id.node, id, self.analysis.ty_cx.map.get(impl_id.node)));
347                 },
348             },
349             None => match ty::trait_of_item(&self.analysis.ty_cx,
350                                             ast_util::local_def(id)) {
351                 Some(def_id) => {
352                     scope_id = def_id.node;
353                     match self.analysis.ty_cx.map.get(def_id.node) {
354                         NodeItem(_) => {
355                             format!("::{}", ty::item_path_str(&self.analysis.ty_cx, def_id))
356                         }
357                         _ => {
358                             self.sess.span_bug(span,
359                                 &format!("Could not find container {} for method {}",
360                                          def_id.node, id));
361                         }
362                     }
363                 },
364                 None => {
365                     self.sess.span_bug(span,
366                         &format!("Could not find container for method {}", id));
367                 },
368             },
369         };
370
371         let qualname = &format!("{}::{}", qualname, &token::get_name(name));
372
373         // record the decl for this def (if it has one)
374         let decl_id = ty::trait_item_of_item(&self.analysis.ty_cx,
375                                              ast_util::local_def(id))
376             .and_then(|new_id| {
377                 let def_id = new_id.def_id();
378                 if def_id.node != 0 && def_id != ast_util::local_def(id) {
379                     Some(def_id)
380                 } else {
381                     None
382                 }
383             });
384
385         let sub_span = self.span.sub_span_after_keyword(span, keywords::Fn);
386         if body.is_some() {
387             self.fmt.method_str(span,
388                                 sub_span,
389                                 id,
390                                 qualname,
391                                 decl_id,
392                                 scope_id);
393             self.process_formals(&sig.decl.inputs, qualname);
394         } else {
395             self.fmt.method_decl_str(span,
396                                      sub_span,
397                                      id,
398                                      qualname,
399                                      scope_id);
400         }
401
402         // walk arg and return types
403         for arg in &sig.decl.inputs {
404             self.visit_ty(&arg.ty);
405         }
406
407         if let ast::Return(ref ret_ty) = sig.decl.output {
408             self.visit_ty(ret_ty);
409         }
410
411         // walk the fn body
412         if let Some(body) = body {
413             self.nest(id, |v| v.visit_block(body));
414         }
415
416         self.process_generic_params(&sig.generics,
417                                     span,
418                                     qualname,
419                                     id);
420     }
421
422     fn process_trait_ref(&mut self,
423                          trait_ref: &ast::TraitRef) {
424         match self.lookup_type_ref(trait_ref.ref_id) {
425             Some(id) => {
426                 let sub_span = self.span.sub_span_for_type_name(trait_ref.path.span);
427                 self.fmt.ref_str(recorder::TypeRef,
428                                  trait_ref.path.span,
429                                  sub_span,
430                                  id,
431                                  self.cur_scope);
432                 visit::walk_path(self, &trait_ref.path);
433             },
434             None => ()
435         }
436     }
437
438     fn process_struct_field_def(&mut self,
439                                 field: &ast::StructField,
440                                 qualname: &str,
441                                 scope_id: NodeId) {
442         match field.node.kind {
443             ast::NamedField(ident, _) => {
444                 let name = get_ident(ident);
445                 let qualname = format!("{}::{}", qualname, name);
446                 let typ =
447                     ppaux::ty_to_string(
448                         &self.analysis.ty_cx,
449                         *self.analysis.ty_cx.node_types().get(&field.node.id).unwrap());
450                 match self.span.sub_span_before_token(field.span, token::Colon) {
451                     Some(sub_span) => self.fmt.field_str(field.span,
452                                                          Some(sub_span),
453                                                          field.node.id,
454                                                          &name,
455                                                          &qualname,
456                                                          &typ,
457                                                          scope_id),
458                     None => self.sess.span_bug(field.span,
459                                                &format!("Could not find sub-span for field {}",
460                                                        qualname)),
461                 }
462             },
463             _ => (),
464         }
465     }
466
467     // Dump generic params bindings, then visit_generics
468     fn process_generic_params(&mut self,
469                               generics:&ast::Generics,
470                               full_span: Span,
471                               prefix: &str,
472                               id: NodeId) {
473         // We can't only use visit_generics since we don't have spans for param
474         // bindings, so we reparse the full_span to get those sub spans.
475         // However full span is the entire enum/fn/struct block, so we only want
476         // the first few to match the number of generics we're looking for.
477         let param_sub_spans = self.span.spans_for_ty_params(full_span,
478                                                            (generics.ty_params.len() as isize));
479         for (param, param_ss) in generics.ty_params.iter().zip(param_sub_spans.iter()) {
480             // Append $id to name to make sure each one is unique
481             let name = format!("{}::{}${}",
482                                prefix,
483                                escape(self.span.snippet(*param_ss)),
484                                id);
485             self.fmt.typedef_str(full_span,
486                                  Some(*param_ss),
487                                  param.id,
488                                  &name,
489                                  "");
490         }
491         self.visit_generics(generics);
492     }
493
494     fn process_fn(&mut self,
495                   item: &ast::Item,
496                   decl: &ast::FnDecl,
497                   ty_params: &ast::Generics,
498                   body: &ast::Block) {
499         let fn_data = self.save_ctxt.get_item_data(item);
500         if let super::Data::FunctionData(fn_data) = fn_data {
501             self.fmt.fn_str(item.span,
502                             Some(fn_data.span),
503                             fn_data.id,
504                             &fn_data.qualname,
505                             fn_data.scope);
506
507
508             self.process_formals(&decl.inputs, &fn_data.qualname);
509             self.process_generic_params(ty_params, item.span, &fn_data.qualname, item.id);
510         } else {
511             self.sess.span_bug(item.span, "expected FunctionData");
512         }
513
514         for arg in &decl.inputs {
515             self.visit_ty(&arg.ty);
516         }
517
518         if let ast::Return(ref ret_ty) = decl.output {
519             self.visit_ty(&ret_ty);
520         }
521
522         self.nest(item.id, |v| v.visit_block(&body));
523     }
524
525     fn process_static_or_const_item(&mut self,
526                                     item: &ast::Item,
527                                     typ: &ast::Ty,
528                                     expr: &ast::Expr)
529     {
530         let var_data = self.save_ctxt.get_item_data(item);
531         if let super::Data::VariableData(var_data) = var_data {
532             self.fmt.static_str(item.span,
533                                 Some(var_data.span),
534                                 var_data.id,
535                                 &var_data.name,
536                                 &var_data.qualname,
537                                 &var_data.value,
538                                 &var_data.type_value,
539                                 var_data.scope);
540         } else {
541             self.sess.span_bug(item.span, "expected VariableData");
542         }
543
544         self.visit_ty(&typ);
545         self.visit_expr(expr);
546     }
547
548     fn process_const(&mut self,
549                      id: ast::NodeId,
550                      ident: &ast::Ident,
551                      span: Span,
552                      typ: &ast::Ty,
553                      expr: &ast::Expr)
554     {
555         let qualname = format!("::{}", self.analysis.ty_cx.map.path_to_string(id));
556
557         let sub_span = self.span.sub_span_after_keyword(span,
558                                                         keywords::Const);
559
560         self.fmt.static_str(span,
561                             sub_span,
562                             id,
563                             &get_ident((*ident).clone()),
564                             &qualname,
565                             &self.span.snippet(expr.span),
566                             &ty_to_string(&*typ),
567                             self.cur_scope);
568
569         // walk type and init value
570         self.visit_ty(typ);
571         self.visit_expr(expr);
572     }
573
574     fn process_struct(&mut self,
575                       item: &ast::Item,
576                       def: &ast::StructDef,
577                       ty_params: &ast::Generics) {
578         let qualname = format!("::{}", self.analysis.ty_cx.map.path_to_string(item.id));
579
580         let ctor_id = match def.ctor_id {
581             Some(node_id) => node_id,
582             None => -1,
583         };
584         let val = self.span.snippet(item.span);
585         let sub_span = self.span.sub_span_after_keyword(item.span, keywords::Struct);
586         self.fmt.struct_str(item.span,
587                             sub_span,
588                             item.id,
589                             ctor_id,
590                             &qualname,
591                             self.cur_scope,
592                             &val);
593
594         // fields
595         for field in &def.fields {
596             self.process_struct_field_def(field, &qualname, item.id);
597             self.visit_ty(&*field.node.ty);
598         }
599
600         self.process_generic_params(ty_params, item.span, &qualname, item.id);
601     }
602
603     fn process_enum(&mut self,
604                     item: &ast::Item,
605                     enum_definition: &ast::EnumDef,
606                     ty_params: &ast::Generics) {
607         let enum_data = self.save_ctxt.get_item_data(item);
608         if let super::Data::EnumData(enum_data) = enum_data {
609             self.fmt.enum_str(item.span,
610                               Some(enum_data.span),
611                               enum_data.id,
612                               &enum_data.qualname,
613                               self.cur_scope,
614                               &enum_data.value);
615             for variant in &enum_definition.variants {
616                 let name = &get_ident(variant.node.name);
617                 let mut qualname = enum_data.qualname.clone();
618                 qualname.push_str("::");
619                 qualname.push_str(name);
620                 let val = self.span.snippet(variant.span);
621                 match variant.node.kind {
622                     ast::TupleVariantKind(ref args) => {
623                         // first ident in span is the variant's name
624                         self.fmt.tuple_variant_str(variant.span,
625                                                    self.span.span_for_first_ident(variant.span),
626                                                    variant.node.id,
627                                                    name,
628                                                    &qualname,
629                                                    &enum_data.qualname,
630                                                    &val,
631                                                    item.id);
632                         for arg in args {
633                             self.visit_ty(&*arg.ty);
634                         }
635                     }
636                     ast::StructVariantKind(ref struct_def) => {
637                         let ctor_id = match struct_def.ctor_id {
638                             Some(node_id) => node_id,
639                             None => -1,
640                         };
641                         self.fmt.struct_variant_str(variant.span,
642                                                     self.span.span_for_first_ident(variant.span),
643                                                     variant.node.id,
644                                                     ctor_id,
645                                                     &qualname,
646                                                     &enum_data.qualname,
647                                                     &val,
648                                                     item.id);
649
650                         for field in &struct_def.fields {
651                             self.process_struct_field_def(field, &qualname, variant.node.id);
652                             self.visit_ty(&*field.node.ty);
653                         }
654                     }
655                 }
656             }
657             self.process_generic_params(ty_params, item.span, &enum_data.qualname, item.id);
658         } else {
659             self.sess.span_bug(item.span, "expected EnumData");
660         }
661     }
662
663     fn process_impl(&mut self,
664                     item: &ast::Item,
665                     type_parameters: &ast::Generics,
666                     trait_ref: &Option<ast::TraitRef>,
667                     typ: &ast::Ty,
668                     impl_items: &[P<ast::ImplItem>]) {
669         let trait_id = trait_ref.as_ref().and_then(|tr| self.lookup_type_ref(tr.ref_id));
670         match typ.node {
671             // Common case impl for a struct or something basic.
672             ast::TyPath(None, ref path) => {
673                 let sub_span = self.span.sub_span_for_type_name(path.span);
674                 let self_id = self.lookup_type_ref(typ.id).map(|id| {
675                     self.fmt.ref_str(recorder::TypeRef,
676                                      path.span,
677                                      sub_span,
678                                      id,
679                                      self.cur_scope);
680                     id
681                 });
682                 self.fmt.impl_str(path.span,
683                                   sub_span,
684                                   item.id,
685                                   self_id,
686                                   trait_id,
687                                   self.cur_scope);
688             },
689             _ => {
690                 // Less useful case, impl for a compound type.
691                 self.visit_ty(&*typ);
692
693                 let sub_span = self.span.sub_span_for_type_name(typ.span);
694                 self.fmt.impl_str(typ.span,
695                                   sub_span,
696                                   item.id,
697                                   None,
698                                   trait_id,
699                                   self.cur_scope);
700             }
701         }
702
703         match *trait_ref {
704             Some(ref trait_ref) => self.process_trait_ref(trait_ref),
705             None => (),
706         }
707
708         self.process_generic_params(type_parameters, item.span, "", item.id);
709         for impl_item in impl_items {
710             self.visit_impl_item(impl_item);
711         }
712     }
713
714     fn process_trait(&mut self,
715                      item: &ast::Item,
716                      generics: &ast::Generics,
717                      trait_refs: &OwnedSlice<ast::TyParamBound>,
718                      methods: &[P<ast::TraitItem>]) {
719         let qualname = format!("::{}", self.analysis.ty_cx.map.path_to_string(item.id));
720         let val = self.span.snippet(item.span);
721         let sub_span = self.span.sub_span_after_keyword(item.span, keywords::Trait);
722         self.fmt.trait_str(item.span,
723                            sub_span,
724                            item.id,
725                            &qualname,
726                            self.cur_scope,
727                            &val);
728
729         // super-traits
730         for super_bound in &**trait_refs {
731             let trait_ref = match *super_bound {
732                 ast::TraitTyParamBound(ref trait_ref, _) => {
733                     trait_ref
734                 }
735                 ast::RegionTyParamBound(..) => {
736                     continue;
737                 }
738             };
739
740             let trait_ref = &trait_ref.trait_ref;
741             match self.lookup_type_ref(trait_ref.ref_id) {
742                 Some(id) => {
743                     let sub_span = self.span.sub_span_for_type_name(trait_ref.path.span);
744                     self.fmt.ref_str(recorder::TypeRef,
745                                      trait_ref.path.span,
746                                      sub_span,
747                                      id,
748                                      self.cur_scope);
749                     self.fmt.inherit_str(trait_ref.path.span,
750                                          sub_span,
751                                          id,
752                                          item.id);
753                 },
754                 None => ()
755             }
756         }
757
758         // walk generics and methods
759         self.process_generic_params(generics, item.span, &qualname, item.id);
760         for method in methods {
761             self.visit_trait_item(method)
762         }
763     }
764
765     fn process_mod(&mut self,
766                    item: &ast::Item) {  // The module in question, represented as an item.
767         let mod_data = self.save_ctxt.get_item_data(item);
768         if let super::Data::ModData(mod_data) = mod_data {
769             self.fmt.mod_str(item.span,
770                              Some(mod_data.span),
771                              mod_data.id,
772                              &mod_data.qualname,
773                              mod_data.scope,
774                              &mod_data.filename);
775         } else {
776             self.sess.span_bug(item.span, "expected ModData");
777         }
778     }
779
780     fn process_path(&mut self,
781                     id: NodeId,
782                     span: Span,
783                     path: &ast::Path,
784                     ref_kind: Option<recorder::Row>) {
785         if generated_code(span) {
786             return
787         }
788
789         let def_map = self.analysis.ty_cx.def_map.borrow();
790         if !def_map.contains_key(&id) {
791             self.sess.span_bug(span,
792                                &format!("def_map has no key for {} in visit_expr", id));
793         }
794         let def = def_map.get(&id).unwrap().full_def();
795         let sub_span = self.span.span_for_last_ident(span);
796         match def {
797             def::DefUpvar(..) |
798             def::DefLocal(..) |
799             def::DefStatic(..) |
800             def::DefConst(..) |
801             def::DefAssociatedConst(..) |
802             def::DefVariant(..) => self.fmt.ref_str(ref_kind.unwrap_or(recorder::VarRef),
803                                                     span,
804                                                     sub_span,
805                                                     def.def_id(),
806                                                     self.cur_scope),
807             def::DefStruct(def_id) => self.fmt.ref_str(recorder::StructRef,
808                                                        span,
809                                                        sub_span,
810                                                        def_id,
811                                                        self.cur_scope),
812             def::DefTy(def_id, _) => self.fmt.ref_str(recorder::TypeRef,
813                                                       span,
814                                                       sub_span,
815                                                       def_id,
816                                                       self.cur_scope),
817             def::DefMethod(declid, provenence) => {
818                 let sub_span = self.span.sub_span_for_meth_name(span);
819                 let defid = if declid.krate == ast::LOCAL_CRATE {
820                     let ti = ty::impl_or_trait_item(&self.analysis.ty_cx,
821                                                     declid);
822                     match provenence {
823                         def::FromTrait(def_id) => {
824                             Some(ty::trait_items(&self.analysis.ty_cx,
825                                                  def_id)
826                                     .iter()
827                                     .find(|mr| {
828                                         mr.name() == ti.name()
829                                     })
830                                     .unwrap()
831                                     .def_id())
832                         }
833                         def::FromImpl(def_id) => {
834                             let impl_items = self.analysis
835                                                  .ty_cx
836                                                  .impl_items
837                                                  .borrow();
838                             Some(impl_items.get(&def_id)
839                                            .unwrap()
840                                            .iter()
841                                            .find(|mr| {
842                                                 ty::impl_or_trait_item(
843                                                     &self.analysis.ty_cx,
844                                                     mr.def_id()
845                                                 ).name() == ti.name()
846                                             })
847                                            .unwrap()
848                                            .def_id())
849                         }
850                     }
851                 } else {
852                     None
853                 };
854                 self.fmt.meth_call_str(span,
855                                        sub_span,
856                                        defid,
857                                        Some(declid),
858                                        self.cur_scope);
859             },
860             def::DefFn(def_id, _) => {
861                 self.fmt.fn_call_str(span,
862                                      sub_span,
863                                      def_id,
864                                      self.cur_scope)
865             }
866             _ => self.sess.span_bug(span,
867                                     &format!("Unexpected def kind while looking \
868                                               up path in `{}`: `{:?}`",
869                                              self.span.snippet(span),
870                                              def)),
871         }
872         // modules or types in the path prefix
873         match def {
874             def::DefMethod(did, _) => {
875                 let ti = ty::impl_or_trait_item(&self.analysis.ty_cx, did);
876                 if let ty::MethodTraitItem(m) = ti {
877                     if m.explicit_self == ty::StaticExplicitSelfCategory {
878                         self.write_sub_path_trait_truncated(path);
879                     }
880                 }
881             }
882             def::DefLocal(_) |
883             def::DefStatic(_,_) |
884             def::DefConst(..) |
885             def::DefAssociatedConst(..) |
886             def::DefStruct(_) |
887             def::DefVariant(..) |
888             def::DefFn(..) => self.write_sub_paths_truncated(path, false),
889             _ => {},
890         }
891     }
892
893     fn process_struct_lit(&mut self,
894                           ex: &ast::Expr,
895                           path: &ast::Path,
896                           fields: &Vec<ast::Field>,
897                           base: &Option<P<ast::Expr>>) {
898         if generated_code(path.span) {
899             return
900         }
901
902         self.write_sub_paths_truncated(path, false);
903
904         let ty = &ty::expr_ty_adjusted(&self.analysis.ty_cx, ex).sty;
905         let struct_def = match *ty {
906             ty::ty_struct(def_id, _) => {
907                 let sub_span = self.span.span_for_last_ident(path.span);
908                 self.fmt.ref_str(recorder::StructRef,
909                                  path.span,
910                                  sub_span,
911                                  def_id,
912                                  self.cur_scope);
913                 Some(def_id)
914             }
915             _ => None
916         };
917
918         for field in fields {
919             match struct_def {
920                 Some(struct_def) => {
921                     let fields = ty::lookup_struct_fields(&self.analysis.ty_cx, struct_def);
922                     for f in &fields {
923                         if generated_code(field.ident.span) {
924                             continue;
925                         }
926                         if f.name == field.ident.node.name {
927                             // We don't really need a sub-span here, but no harm done
928                             let sub_span = self.span.span_for_last_ident(field.ident.span);
929                             self.fmt.ref_str(recorder::VarRef,
930                                              field.ident.span,
931                                              sub_span,
932                                              f.id,
933                                              self.cur_scope);
934                         }
935                     }
936                 }
937                 None => {}
938             }
939
940             self.visit_expr(&*field.expr)
941         }
942         visit::walk_expr_opt(self, base)
943     }
944
945     fn process_method_call(&mut self,
946                            ex: &ast::Expr,
947                            args: &Vec<P<ast::Expr>>) {
948         let method_map = self.analysis.ty_cx.method_map.borrow();
949         let method_callee = method_map.get(&ty::MethodCall::expr(ex.id)).unwrap();
950         let (def_id, decl_id) = match method_callee.origin {
951             ty::MethodStatic(def_id) |
952             ty::MethodStaticClosure(def_id) => {
953                 // method invoked on an object with a concrete type (not a static method)
954                 let decl_id =
955                     match ty::trait_item_of_item(&self.analysis.ty_cx,
956                                                  def_id) {
957                         None => None,
958                         Some(decl_id) => Some(decl_id.def_id()),
959                     };
960
961                 // This incantation is required if the method referenced is a
962                 // trait's default implementation.
963                 let def_id = match ty::impl_or_trait_item(&self.analysis
964                                                                .ty_cx,
965                                                           def_id) {
966                     ty::MethodTraitItem(method) => {
967                         method.provided_source.unwrap_or(def_id)
968                     }
969                     _ => self.sess
970                              .span_bug(ex.span,
971                                        "save::process_method_call: non-method \
972                                         DefId in MethodStatic or MethodStaticClosure"),
973                 };
974                 (Some(def_id), decl_id)
975             }
976             ty::MethodTypeParam(ref mp) => {
977                 // method invoked on a type parameter
978                 let trait_item = ty::trait_item(&self.analysis.ty_cx,
979                                                 mp.trait_ref.def_id,
980                                                 mp.method_num);
981                 (None, Some(trait_item.def_id()))
982             }
983             ty::MethodTraitObject(ref mo) => {
984                 // method invoked on a trait instance
985                 let trait_item = ty::trait_item(&self.analysis.ty_cx,
986                                                 mo.trait_ref.def_id,
987                                                 mo.method_num);
988                 (None, Some(trait_item.def_id()))
989             }
990         };
991         let sub_span = self.span.sub_span_for_meth_name(ex.span);
992         self.fmt.meth_call_str(ex.span,
993                                sub_span,
994                                def_id,
995                                decl_id,
996                                self.cur_scope);
997
998         // walk receiver and args
999         visit::walk_exprs(self, &args);
1000     }
1001
1002     fn process_pat(&mut self, p:&ast::Pat) {
1003         if generated_code(p.span) {
1004             return
1005         }
1006
1007         match p.node {
1008             ast::PatStruct(ref path, ref fields, _) => {
1009                 visit::walk_path(self, path);
1010
1011                 let def = self.analysis.ty_cx.def_map.borrow().get(&p.id).unwrap().full_def();
1012                 let struct_def = match def {
1013                     def::DefConst(..) | def::DefAssociatedConst(..) => None,
1014                     def::DefVariant(_, variant_id, _) => Some(variant_id),
1015                     _ => {
1016                         match ty::ty_to_def_id(ty::node_id_to_type(&self.analysis.ty_cx, p.id)) {
1017                             None => {
1018                                 self.sess.span_bug(p.span,
1019                                                    &format!("Could not find struct_def for `{}`",
1020                                                             self.span.snippet(p.span)));
1021                             }
1022                             Some(def_id) => Some(def_id),
1023                         }
1024                     }
1025                 };
1026
1027                 if let Some(struct_def) = struct_def {
1028                     let struct_fields = ty::lookup_struct_fields(&self.analysis.ty_cx, struct_def);
1029                     for &Spanned { node: ref field, span } in fields {
1030                         let sub_span = self.span.span_for_first_ident(span);
1031                         for f in &struct_fields {
1032                             if f.name == field.ident.name {
1033                                 self.fmt.ref_str(recorder::VarRef,
1034                                                  span,
1035                                                  sub_span,
1036                                                  f.id,
1037                                                  self.cur_scope);
1038                                 break;
1039                             }
1040                         }
1041                         self.visit_pat(&*field.pat);
1042                     }
1043                 }
1044             }
1045             _ => visit::walk_pat(self, p)
1046         }
1047     }
1048 }
1049
1050 impl<'l, 'tcx, 'v> Visitor<'v> for DumpCsvVisitor<'l, 'tcx> {
1051     fn visit_item(&mut self, item: &ast::Item) {
1052         if generated_code(item.span) {
1053             return
1054         }
1055
1056         match item.node {
1057             ast::ItemUse(ref use_item) => {
1058                 match use_item.node {
1059                     ast::ViewPathSimple(ident, ref path) => {
1060                         let sub_span = self.span.span_for_last_ident(path.span);
1061                         let mod_id = match self.lookup_type_ref(item.id) {
1062                             Some(def_id) => {
1063                                 match self.lookup_def_kind(item.id, path.span) {
1064                                     Some(kind) => self.fmt.ref_str(kind,
1065                                                                    path.span,
1066                                                                    sub_span,
1067                                                                    def_id,
1068                                                                    self.cur_scope),
1069                                     None => {},
1070                                 }
1071                                 Some(def_id)
1072                             },
1073                             None => None,
1074                         };
1075
1076                         // 'use' always introduces an alias, if there is not an explicit
1077                         // one, there is an implicit one.
1078                         let sub_span =
1079                             match self.span.sub_span_after_keyword(use_item.span, keywords::As) {
1080                                 Some(sub_span) => Some(sub_span),
1081                                 None => sub_span,
1082                             };
1083
1084                         self.fmt.use_alias_str(path.span,
1085                                                sub_span,
1086                                                item.id,
1087                                                mod_id,
1088                                                &get_ident(ident),
1089                                                self.cur_scope);
1090                         self.write_sub_paths_truncated(path, true);
1091                     }
1092                     ast::ViewPathGlob(ref path) => {
1093                         // Make a comma-separated list of names of imported modules.
1094                         let mut name_string = String::new();
1095                         let glob_map = &self.analysis.glob_map;
1096                         let glob_map = glob_map.as_ref().unwrap();
1097                         if glob_map.contains_key(&item.id) {
1098                             for n in glob_map.get(&item.id).unwrap() {
1099                                 if !name_string.is_empty() {
1100                                     name_string.push_str(", ");
1101                                 }
1102                                 name_string.push_str(n.as_str());
1103                             }
1104                         }
1105
1106                         let sub_span = self.span.sub_span_of_token(path.span,
1107                                                                    token::BinOp(token::Star));
1108                         self.fmt.use_glob_str(path.span,
1109                                               sub_span,
1110                                               item.id,
1111                                               &name_string,
1112                                               self.cur_scope);
1113                         self.write_sub_paths(path, true);
1114                     }
1115                     ast::ViewPathList(ref path, ref list) => {
1116                         for plid in list {
1117                             match plid.node {
1118                                 ast::PathListIdent { id, .. } => {
1119                                     match self.lookup_type_ref(id) {
1120                                         Some(def_id) =>
1121                                             match self.lookup_def_kind(id, plid.span) {
1122                                                 Some(kind) => {
1123                                                     self.fmt.ref_str(
1124                                                         kind, plid.span,
1125                                                         Some(plid.span),
1126                                                         def_id, self.cur_scope);
1127                                                 }
1128                                                 None => ()
1129                                             },
1130                                         None => ()
1131                                     }
1132                                 },
1133                                 ast::PathListMod { .. } => ()
1134                             }
1135                         }
1136
1137                         self.write_sub_paths(path, true);
1138                     }
1139                 }
1140             }
1141             ast::ItemExternCrate(ref s) => {
1142                 let name = get_ident(item.ident);
1143                 let name = &name;
1144                 let location = match *s {
1145                     Some(s) => s.to_string(),
1146                     None => name.to_string(),
1147                 };
1148                 let alias_span = self.span.span_for_last_ident(item.span);
1149                 let cnum = match self.sess.cstore.find_extern_mod_stmt_cnum(item.id) {
1150                     Some(cnum) => cnum,
1151                     None => 0,
1152                 };
1153                 self.fmt.extern_crate_str(item.span,
1154                                           alias_span,
1155                                           item.id,
1156                                           cnum,
1157                                           name,
1158                                           &location,
1159                                           self.cur_scope);
1160             }
1161             ast::ItemFn(ref decl, _, _, _, ref ty_params, ref body) =>
1162                 self.process_fn(item, &**decl, ty_params, &**body),
1163             ast::ItemStatic(ref typ, _, ref expr) =>
1164                 self.process_static_or_const_item(item, typ, expr),
1165             ast::ItemConst(ref typ, ref expr) =>
1166                 self.process_static_or_const_item(item, &typ, &expr),
1167             ast::ItemStruct(ref def, ref ty_params) => self.process_struct(item, &**def, ty_params),
1168             ast::ItemEnum(ref def, ref ty_params) => self.process_enum(item, def, ty_params),
1169             ast::ItemImpl(_, _,
1170                           ref ty_params,
1171                           ref trait_ref,
1172                           ref typ,
1173                           ref impl_items) => {
1174                 self.process_impl(item,
1175                                   ty_params,
1176                                   trait_ref,
1177                                   &**typ,
1178                                   impl_items)
1179             }
1180             ast::ItemTrait(_, ref generics, ref trait_refs, ref methods) =>
1181                 self.process_trait(item, generics, trait_refs, methods),
1182             ast::ItemMod(ref m) => {
1183                 self.process_mod(item);
1184                 self.nest(item.id, |v| visit::walk_mod(v, m));
1185             }
1186             ast::ItemTy(ref ty, ref ty_params) => {
1187                 let qualname = format!("::{}", self.analysis.ty_cx.map.path_to_string(item.id));
1188                 let value = ty_to_string(&**ty);
1189                 let sub_span = self.span.sub_span_after_keyword(item.span, keywords::Type);
1190                 self.fmt.typedef_str(item.span,
1191                                      sub_span,
1192                                      item.id,
1193                                      &qualname,
1194                                      &value);
1195
1196                 self.visit_ty(&**ty);
1197                 self.process_generic_params(ty_params, item.span, &qualname, item.id);
1198             },
1199             ast::ItemMac(_) => (),
1200             _ => visit::walk_item(self, item),
1201         }
1202     }
1203
1204     fn visit_generics(&mut self, generics: &ast::Generics) {
1205         for param in &*generics.ty_params {
1206             for bound in &*param.bounds {
1207                 if let ast::TraitTyParamBound(ref trait_ref, _) = *bound {
1208                     self.process_trait_ref(&trait_ref.trait_ref);
1209                 }
1210             }
1211             if let Some(ref ty) = param.default {
1212                 self.visit_ty(&**ty);
1213             }
1214         }
1215     }
1216
1217     fn visit_trait_item(&mut self, trait_item: &ast::TraitItem) {
1218         match trait_item.node {
1219             ast::ConstTraitItem(ref ty, Some(ref expr)) => {
1220                 self.process_const(trait_item.id, &trait_item.ident,
1221                                    trait_item.span, &*ty, &*expr);
1222             }
1223             ast::MethodTraitItem(ref sig, ref body) => {
1224                 self.process_method(sig, body.as_ref().map(|x| &**x),
1225                                     trait_item.id, trait_item.ident.name, trait_item.span);
1226             }
1227             ast::ConstTraitItem(_, None) |
1228             ast::TypeTraitItem(..) => {}
1229         }
1230     }
1231
1232     fn visit_impl_item(&mut self, impl_item: &ast::ImplItem) {
1233         match impl_item.node {
1234             ast::ConstImplItem(ref ty, ref expr) => {
1235                 self.process_const(impl_item.id, &impl_item.ident,
1236                                    impl_item.span, &ty, &expr);
1237             }
1238             ast::MethodImplItem(ref sig, ref body) => {
1239                 self.process_method(sig, Some(body), impl_item.id,
1240                                     impl_item.ident.name, impl_item.span);
1241             }
1242             ast::TypeImplItem(_) |
1243             ast::MacImplItem(_) => {}
1244         }
1245     }
1246
1247     fn visit_ty(&mut self, t: &ast::Ty) {
1248         if generated_code(t.span) {
1249             return
1250         }
1251
1252         match t.node {
1253             ast::TyPath(_, ref path) => {
1254                 match self.lookup_type_ref(t.id) {
1255                     Some(id) => {
1256                         let sub_span = self.span.sub_span_for_type_name(t.span);
1257                         self.fmt.ref_str(recorder::TypeRef,
1258                                          t.span,
1259                                          sub_span,
1260                                          id,
1261                                          self.cur_scope);
1262                     },
1263                     None => ()
1264                 }
1265
1266                 self.write_sub_paths_truncated(path, false);
1267
1268                 visit::walk_path(self, path);
1269             },
1270             _ => visit::walk_ty(self, t),
1271         }
1272     }
1273
1274     fn visit_expr(&mut self, ex: &ast::Expr) {
1275         if generated_code(ex.span) {
1276             return
1277         }
1278
1279         match ex.node {
1280             ast::ExprCall(ref _f, ref _args) => {
1281                 // Don't need to do anything for function calls,
1282                 // because just walking the callee path does what we want.
1283                 visit::walk_expr(self, ex);
1284             }
1285             ast::ExprPath(_, ref path) => {
1286                 self.process_path(ex.id, path.span, path, None);
1287                 visit::walk_expr(self, ex);
1288             }
1289             ast::ExprStruct(ref path, ref fields, ref base) =>
1290                 self.process_struct_lit(ex, path, fields, base),
1291             ast::ExprMethodCall(_, _, ref args) => self.process_method_call(ex, args),
1292             ast::ExprField(ref sub_ex, _) => {
1293                 if generated_code(sub_ex.span) {
1294                     return
1295                 }
1296
1297                 self.visit_expr(&sub_ex);
1298
1299                 let field_data = self.save_ctxt.get_expr_data(ex);
1300                 if let super::Data::VariableRefData(field_data) = field_data {
1301                     self.fmt.ref_str(recorder::VarRef,
1302                                      ex.span,
1303                                      Some(field_data.span),
1304                                      field_data.ref_id,
1305                                      field_data.scope);
1306                 } else {
1307                     self.sess.span_bug(ex.span, "expected VariableRefData");
1308                 }
1309             },
1310             ast::ExprTupField(ref sub_ex, idx) => {
1311                 if generated_code(sub_ex.span) {
1312                     return
1313                 }
1314
1315                 self.visit_expr(&**sub_ex);
1316
1317                 let ty = &ty::expr_ty_adjusted(&self.analysis.ty_cx, &**sub_ex).sty;
1318                 match *ty {
1319                     ty::ty_struct(def_id, _) => {
1320                         let fields = ty::lookup_struct_fields(&self.analysis.ty_cx, def_id);
1321                         for (i, f) in fields.iter().enumerate() {
1322                             if i == idx.node {
1323                                 let sub_span = self.span.sub_span_after_token(ex.span, token::Dot);
1324                                 self.fmt.ref_str(recorder::VarRef,
1325                                                  ex.span,
1326                                                  sub_span,
1327                                                  f.id,
1328                                                  self.cur_scope);
1329                                 break;
1330                             }
1331                         }
1332                     }
1333                     ty::ty_tup(_) => {}
1334                     _ => self.sess.span_bug(ex.span,
1335                                             &format!("Expected struct or tuple \
1336                                                       type, found {:?}", ty)),
1337                 }
1338             },
1339             ast::ExprClosure(_, ref decl, ref body) => {
1340                 if generated_code(body.span) {
1341                     return
1342                 }
1343
1344                 let mut id = String::from("$");
1345                 id.push_str(&ex.id.to_string());
1346                 self.process_formals(&decl.inputs, &id);
1347
1348                 // walk arg and return types
1349                 for arg in &decl.inputs {
1350                     self.visit_ty(&*arg.ty);
1351                 }
1352
1353                 if let ast::Return(ref ret_ty) = decl.output {
1354                     self.visit_ty(&**ret_ty);
1355                 }
1356
1357                 // walk the body
1358                 self.nest(ex.id, |v| v.visit_block(&**body));
1359             },
1360             _ => {
1361                 visit::walk_expr(self, ex)
1362             }
1363         }
1364     }
1365
1366     fn visit_mac(&mut self, _: &ast::Mac) {
1367         // Just stop, macros are poison to us.
1368     }
1369
1370     fn visit_pat(&mut self, p: &ast::Pat) {
1371         self.process_pat(p);
1372     }
1373
1374     fn visit_arm(&mut self, arm: &ast::Arm) {
1375         let mut collector = PathCollector::new();
1376         for pattern in &arm.pats {
1377             // collect paths from the arm's patterns
1378             collector.visit_pat(&pattern);
1379             self.visit_pat(&pattern);
1380         }
1381
1382         // This is to get around borrow checking, because we need mut self to call process_path.
1383         let mut paths_to_process = vec![];
1384         // process collected paths
1385         for &(id, ref p, immut, ref_kind) in &collector.collected_paths {
1386             let def_map = self.analysis.ty_cx.def_map.borrow();
1387             if !def_map.contains_key(&id) {
1388                 self.sess.span_bug(p.span,
1389                                    &format!("def_map has no key for {} in visit_arm",
1390                                            id));
1391             }
1392             let def = def_map.get(&id).unwrap().full_def();
1393             match def {
1394                 def::DefLocal(id)  => {
1395                     let value = if immut == ast::MutImmutable {
1396                         self.span.snippet(p.span).to_string()
1397                     } else {
1398                         "<mutable>".to_string()
1399                     };
1400
1401                     assert!(p.segments.len() == 1, "qualified path for local variable def in arm");
1402                     self.fmt.variable_str(p.span,
1403                                           Some(p.span),
1404                                           id,
1405                                           &path_to_string(p),
1406                                           &value,
1407                                           "")
1408                 }
1409                 def::DefVariant(..) | def::DefTy(..) | def::DefStruct(..) => {
1410                     paths_to_process.push((id, p.clone(), Some(ref_kind)))
1411                 }
1412                 // FIXME(nrc) what are these doing here?
1413                 def::DefStatic(_, _) |
1414                 def::DefConst(..) |
1415                 def::DefAssociatedConst(..) => {}
1416                 _ => error!("unexpected definition kind when processing collected paths: {:?}",
1417                             def)
1418             }
1419         }
1420         for &(id, ref path, ref_kind) in &paths_to_process {
1421             self.process_path(id, path.span, path, ref_kind);
1422         }
1423         visit::walk_expr_opt(self, &arm.guard);
1424         self.visit_expr(&*arm.body);
1425     }
1426
1427     fn visit_stmt(&mut self, s: &ast::Stmt) {
1428         if generated_code(s.span) {
1429             return
1430         }
1431
1432         visit::walk_stmt(self, s)
1433     }
1434
1435     fn visit_local(&mut self, l: &ast::Local) {
1436         if generated_code(l.span) {
1437             return
1438         }
1439
1440         // The local could declare multiple new vars, we must walk the
1441         // pattern and collect them all.
1442         let mut collector = PathCollector::new();
1443         collector.visit_pat(&l.pat);
1444         self.visit_pat(&l.pat);
1445
1446         let value = self.span.snippet(l.span);
1447
1448         for &(id, ref p, immut, _) in &collector.collected_paths {
1449             let value = if immut == ast::MutImmutable {
1450                 value.to_string()
1451             } else {
1452                 "<mutable>".to_string()
1453             };
1454             let types = self.analysis.ty_cx.node_types();
1455             let typ = ppaux::ty_to_string(&self.analysis.ty_cx, *types.get(&id).unwrap());
1456             // Get the span only for the name of the variable (I hope the path
1457             // is only ever a variable name, but who knows?).
1458             let sub_span = self.span.span_for_last_ident(p.span);
1459             // Rust uses the id of the pattern for var lookups, so we'll use it too.
1460             self.fmt.variable_str(p.span,
1461                                   sub_span,
1462                                   id,
1463                                   &path_to_string(p),
1464                                   &value,
1465                                   &typ);
1466         }
1467
1468         // Just walk the initialiser and type (don't want to walk the pattern again).
1469         visit::walk_ty_opt(self, &l.ty);
1470         visit::walk_expr_opt(self, &l.init);
1471     }
1472 }