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