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