]> git.lizzy.rs Git - rust.git/blob - src/librustc_trans/save/mod.rs
b12903c814cbf83db5e50deac0fda6bc6e189175
[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).as_slice());
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!(
312                                            "Container {} for method {} is not a node item {:?}",
313                                            impl_id.node,
314                                            method.id,
315                                            self.analysis.ty_cx.map.get(impl_id.node))[]);
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                         def_id.node != 0 && def_id != ast_util::local_def(method.id)
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         match self.lookup_type_ref(trait_ref.ref_id) {
397             Some(id) => {
398                 let sub_span = self.span.sub_span_for_type_name(trait_ref.path.span);
399                 self.fmt.ref_str(recorder::TypeRef,
400                                  trait_ref.path.span,
401                                  sub_span,
402                                  id,
403                                  self.cur_scope);
404                 visit::walk_path(self, &trait_ref.path);
405             },
406             None => ()
407         }
408     }
409
410     fn process_struct_field_def(&mut self,
411                                 field: &ast::StructField,
412                                 qualname: &str,
413                                 scope_id: NodeId) {
414         match field.node.kind {
415             ast::NamedField(ident, _) => {
416                 let name = get_ident(ident);
417                 let qualname = format!("{}::{}", qualname, name);
418                 let typ = ppaux::ty_to_string(&self.analysis.ty_cx,
419                     (*self.analysis.ty_cx.node_types.borrow())[field.node.id]);
420                 match self.span.sub_span_before_token(field.span, token::Colon) {
421                     Some(sub_span) => self.fmt.field_str(field.span,
422                                                          Some(sub_span),
423                                                          field.node.id,
424                                                          &name.get()[],
425                                                          &qualname[],
426                                                          &typ[],
427                                                          scope_id),
428                     None => self.sess.span_bug(field.span,
429                                                &format!("Could not find sub-span for field {}",
430                                                        qualname)[]),
431                 }
432             },
433             _ => (),
434         }
435     }
436
437     // Dump generic params bindings, then visit_generics
438     fn process_generic_params(&mut self, generics:&ast::Generics,
439                               full_span: Span,
440                               prefix: &str,
441                               id: NodeId) {
442         // We can't only use visit_generics since we don't have spans for param
443         // bindings, so we reparse the full_span to get those sub spans.
444         // However full span is the entire enum/fn/struct block, so we only want
445         // the first few to match the number of generics we're looking for.
446         let param_sub_spans = self.span.spans_for_ty_params(full_span,
447                                                            (generics.ty_params.len() as int));
448         for (param, param_ss) in generics.ty_params.iter().zip(param_sub_spans.iter()) {
449             // Append $id to name to make sure each one is unique
450             let name = format!("{}::{}${}",
451                                prefix,
452                                escape(self.span.snippet(*param_ss)),
453                                id);
454             self.fmt.typedef_str(full_span,
455                                  Some(*param_ss),
456                                  param.id,
457                                  &name[],
458                                  "");
459         }
460         self.visit_generics(generics);
461     }
462
463     fn process_fn(&mut self,
464                   item: &ast::Item,
465                   decl: &ast::FnDecl,
466                   ty_params: &ast::Generics,
467                   body: &ast::Block) {
468         let qualname = self.analysis.ty_cx.map.path_to_string(item.id);
469
470         let sub_span = self.span.sub_span_after_keyword(item.span, keywords::Fn);
471         self.fmt.fn_str(item.span,
472                         sub_span,
473                         item.id,
474                         &qualname[],
475                         self.cur_scope);
476
477         self.process_formals(&decl.inputs, &qualname[]);
478
479         // walk arg and return types
480         for arg in decl.inputs.iter() {
481             self.visit_ty(&*arg.ty);
482         }
483
484         if let ast::Return(ref ret_ty) = decl.output {
485             self.visit_ty(&**ret_ty);
486         }
487
488         // walk the body
489         self.nest(item.id, |v| v.visit_block(&*body));
490
491         self.process_generic_params(ty_params, item.span, &qualname[], item.id);
492     }
493
494     fn process_static(&mut self,
495                       item: &ast::Item,
496                       typ: &ast::Ty,
497                       mt: ast::Mutability,
498                       expr: &ast::Expr)
499     {
500         let qualname = self.analysis.ty_cx.map.path_to_string(item.id);
501
502         // If the variable is immutable, save the initialising expression.
503         let value = match mt {
504             ast::MutMutable => String::from_str("<mutable>"),
505             ast::MutImmutable => self.span.snippet(expr.span),
506         };
507
508         let sub_span = self.span.sub_span_after_keyword(item.span, keywords::Static);
509         self.fmt.static_str(item.span,
510                             sub_span,
511                             item.id,
512                             get_ident(item.ident).get(),
513                             &qualname[],
514                             &value[],
515                             &ty_to_string(&*typ)[],
516                             self.cur_scope);
517
518         // walk type and init value
519         self.visit_ty(&*typ);
520         self.visit_expr(expr);
521     }
522
523     fn process_const(&mut self,
524                       item: &ast::Item,
525                       typ: &ast::Ty,
526                       expr: &ast::Expr)
527     {
528         let qualname = self.analysis.ty_cx.map.path_to_string(item.id);
529
530         let sub_span = self.span.sub_span_after_keyword(item.span,
531                                                         keywords::Const);
532         self.fmt.static_str(item.span,
533                             sub_span,
534                             item.id,
535                             get_ident(item.ident).get(),
536                             &qualname[],
537                             "",
538                             &ty_to_string(&*typ)[],
539                             self.cur_scope);
540
541         // walk type and init value
542         self.visit_ty(&*typ);
543         self.visit_expr(expr);
544     }
545
546     fn process_struct(&mut self,
547                       item: &ast::Item,
548                       def: &ast::StructDef,
549                       ty_params: &ast::Generics) {
550         let qualname = self.analysis.ty_cx.map.path_to_string(item.id);
551
552         let ctor_id = match def.ctor_id {
553             Some(node_id) => node_id,
554             None => -1,
555         };
556         let val = self.span.snippet(item.span);
557         let sub_span = self.span.sub_span_after_keyword(item.span, keywords::Struct);
558         self.fmt.struct_str(item.span,
559                             sub_span,
560                             item.id,
561                             ctor_id,
562                             &qualname[],
563                             self.cur_scope,
564                             &val[]);
565
566         // fields
567         for field in def.fields.iter() {
568             self.process_struct_field_def(field, &qualname[], item.id);
569             self.visit_ty(&*field.node.ty);
570         }
571
572         self.process_generic_params(ty_params, item.span, &qualname[], item.id);
573     }
574
575     fn process_enum(&mut self,
576                     item: &ast::Item,
577                     enum_definition: &ast::EnumDef,
578                     ty_params: &ast::Generics) {
579         let enum_name = self.analysis.ty_cx.map.path_to_string(item.id);
580         let val = self.span.snippet(item.span);
581         match self.span.sub_span_after_keyword(item.span, keywords::Enum) {
582             Some(sub_span) => self.fmt.enum_str(item.span,
583                                                 Some(sub_span),
584                                                 item.id,
585                                                 &enum_name[],
586                                                 self.cur_scope,
587                                                 &val[]),
588             None => self.sess.span_bug(item.span,
589                                        &format!("Could not find subspan for enum {}",
590                                                enum_name)[]),
591         }
592         for variant in enum_definition.variants.iter() {
593             let name = get_ident(variant.node.name);
594             let name = name.get();
595             let mut qualname = enum_name.clone();
596             qualname.push_str("::");
597             qualname.push_str(name);
598             let val = self.span.snippet(variant.span);
599             match variant.node.kind {
600                 ast::TupleVariantKind(ref args) => {
601                     // first ident in span is the variant's name
602                     self.fmt.tuple_variant_str(variant.span,
603                                                self.span.span_for_first_ident(variant.span),
604                                                variant.node.id,
605                                                name,
606                                                &qualname[],
607                                                &enum_name[],
608                                                &val[],
609                                                item.id);
610                     for arg in args.iter() {
611                         self.visit_ty(&*arg.ty);
612                     }
613                 }
614                 ast::StructVariantKind(ref struct_def) => {
615                     let ctor_id = match struct_def.ctor_id {
616                         Some(node_id) => node_id,
617                         None => -1,
618                     };
619                     self.fmt.struct_variant_str(
620                         variant.span,
621                         self.span.span_for_first_ident(variant.span),
622                         variant.node.id,
623                         ctor_id,
624                         &qualname[],
625                         &enum_name[],
626                         &val[],
627                         item.id);
628
629                     for field in struct_def.fields.iter() {
630                         self.process_struct_field_def(field, qualname.as_slice(), variant.node.id);
631                         self.visit_ty(&*field.node.ty);
632                     }
633                 }
634             }
635         }
636
637         self.process_generic_params(ty_params, item.span, &enum_name[], item.id);
638     }
639
640     fn process_impl(&mut self,
641                     item: &ast::Item,
642                     type_parameters: &ast::Generics,
643                     trait_ref: &Option<ast::TraitRef>,
644                     typ: &ast::Ty,
645                     impl_items: &Vec<ast::ImplItem>) {
646         let trait_id = trait_ref.as_ref().and_then(|tr| self.lookup_type_ref(tr.ref_id));
647         match typ.node {
648             // Common case impl for a struct or something basic.
649             ast::TyPath(ref path, id) => {
650                 match self.lookup_type_ref(id) {
651                     Some(id) => {
652                         let sub_span = self.span.sub_span_for_type_name(path.span);
653                         self.fmt.ref_str(recorder::TypeRef,
654                                          path.span,
655                                          sub_span,
656                                          id,
657                                          self.cur_scope);
658                         self.fmt.impl_str(path.span,
659                                           sub_span,
660                                           item.id,
661                                           Some(id),
662                                           trait_id,
663                                           self.cur_scope);
664                     },
665                     None => ()
666                 }
667             },
668             _ => {
669                 // Less useful case, impl for a compound type.
670                 self.visit_ty(&*typ);
671
672                 let sub_span = self.span.sub_span_for_type_name(typ.span);
673                 self.fmt.impl_str(typ.span,
674                                   sub_span,
675                                   item.id,
676                                   None,
677                                   trait_id,
678                                   self.cur_scope);
679             }
680         }
681
682         match *trait_ref {
683             Some(ref trait_ref) => self.process_trait_ref(trait_ref),
684             None => (),
685         }
686
687         self.process_generic_params(type_parameters, item.span, "", item.id);
688         for impl_item in impl_items.iter() {
689             match *impl_item {
690                 ast::MethodImplItem(ref method) => {
691                     visit::walk_method_helper(self, &**method)
692                 }
693                 ast::TypeImplItem(ref typedef) => {
694                     visit::walk_ty(self, &*typedef.typ)
695                 }
696             }
697         }
698     }
699
700     fn process_trait(&mut self,
701                      item: &ast::Item,
702                      generics: &ast::Generics,
703                      trait_refs: &OwnedSlice<ast::TyParamBound>,
704                      methods: &Vec<ast::TraitItem>) {
705         let qualname = self.analysis.ty_cx.map.path_to_string(item.id);
706         let val = self.span.snippet(item.span);
707         let sub_span = self.span.sub_span_after_keyword(item.span, keywords::Trait);
708         self.fmt.trait_str(item.span,
709                            sub_span,
710                            item.id,
711                            &qualname[],
712                            self.cur_scope,
713                            &val[]);
714
715         // super-traits
716         for super_bound in trait_refs.iter() {
717             let trait_ref = match *super_bound {
718                 ast::TraitTyParamBound(ref trait_ref, _) => {
719                     trait_ref
720                 }
721                 ast::RegionTyParamBound(..) => {
722                     continue;
723                 }
724             };
725
726             let trait_ref = &trait_ref.trait_ref;
727             match self.lookup_type_ref(trait_ref.ref_id) {
728                 Some(id) => {
729                     let sub_span = self.span.sub_span_for_type_name(trait_ref.path.span);
730                     self.fmt.ref_str(recorder::TypeRef,
731                                      trait_ref.path.span,
732                                      sub_span,
733                                      id,
734                                      self.cur_scope);
735                     self.fmt.inherit_str(trait_ref.path.span,
736                                          sub_span,
737                                          id,
738                                          item.id);
739                 },
740                 None => ()
741             }
742         }
743
744         // walk generics and methods
745         self.process_generic_params(generics, item.span, &qualname[], item.id);
746         for method in methods.iter() {
747             self.visit_trait_item(method)
748         }
749     }
750
751     fn process_mod(&mut self,
752                    item: &ast::Item,  // The module in question, represented as an item.
753                    m: &ast::Mod) {
754         let qualname = self.analysis.ty_cx.map.path_to_string(item.id);
755
756         let cm = self.sess.codemap();
757         let filename = cm.span_to_filename(m.inner);
758
759         let sub_span = self.span.sub_span_after_keyword(item.span, keywords::Mod);
760         self.fmt.mod_str(item.span,
761                          sub_span,
762                          item.id,
763                          &qualname[],
764                          self.cur_scope,
765                          &filename[]);
766
767         self.nest(item.id, |v| visit::walk_mod(v, m));
768     }
769
770     fn process_path(&mut self,
771                     id: NodeId,
772                     span: Span,
773                     path: &ast::Path,
774                     ref_kind: Option<recorder::Row>) {
775         if generated_code(span) {
776             return
777         }
778
779         let def_map = self.analysis.ty_cx.def_map.borrow();
780         if !def_map.contains_key(&id) {
781             self.sess.span_bug(span,
782                                format!("def_map has no key for {} in visit_expr", id).as_slice());
783         }
784         let def = &(*def_map)[id];
785         let sub_span = self.span.span_for_last_ident(span);
786         match *def {
787             def::DefUpvar(..) |
788             def::DefLocal(..) |
789             def::DefStatic(..) |
790             def::DefConst(..) |
791             def::DefVariant(..) => self.fmt.ref_str(ref_kind.unwrap_or(recorder::VarRef),
792                                                     span,
793                                                     sub_span,
794                                                     def.def_id(),
795                                                     self.cur_scope),
796             def::DefStruct(def_id) => self.fmt.ref_str(recorder::StructRef,
797                                                        span,
798                                                        sub_span,
799                                                        def_id,
800                                                        self.cur_scope),
801             def::DefStaticMethod(declid, provenence) => {
802                 let sub_span = self.span.sub_span_for_meth_name(span);
803                 let defid = if declid.krate == ast::LOCAL_CRATE {
804                     let ti = ty::impl_or_trait_item(&self.analysis.ty_cx,
805                                                     declid);
806                     match provenence {
807                         def::FromTrait(def_id) => {
808                             Some(ty::trait_items(&self.analysis.ty_cx,
809                                                  def_id)
810                                     .iter()
811                                     .find(|mr| {
812                                         mr.name() == ti.name()
813                                     })
814                                     .unwrap()
815                                     .def_id())
816                         }
817                         def::FromImpl(def_id) => {
818                             let impl_items = self.analysis
819                                                  .ty_cx
820                                                  .impl_items
821                                                  .borrow();
822                             Some((*impl_items)[def_id]
823                                            .iter()
824                                            .find(|mr| {
825                                                 ty::impl_or_trait_item(
826                                                     &self.analysis.ty_cx,
827                                                     mr.def_id()
828                                                 ).name() == ti.name()
829                                             })
830                                            .unwrap()
831                                            .def_id())
832                         }
833                     }
834                 } else {
835                     None
836                 };
837                 self.fmt.meth_call_str(span,
838                                        sub_span,
839                                        defid,
840                                        Some(declid),
841                                        self.cur_scope);
842             },
843             def::DefFn(def_id, _) => self.fmt.fn_call_str(span,
844                                                           sub_span,
845                                                           def_id,
846                                                           self.cur_scope),
847             _ => self.sess.span_bug(span,
848                                     &format!("Unexpected def kind while looking up path in '{}'",
849                                             self.span.snippet(span))[]),
850         }
851         // modules or types in the path prefix
852         match *def {
853             def::DefStaticMethod(..) => self.write_sub_path_trait_truncated(path),
854             def::DefLocal(_) |
855             def::DefStatic(_,_) |
856             def::DefConst(..) |
857             def::DefStruct(_) |
858             def::DefVariant(..) |
859             def::DefFn(..) => self.write_sub_paths_truncated(path),
860             _ => {},
861         }
862     }
863
864     fn process_struct_lit(&mut self,
865                           ex: &ast::Expr,
866                           path: &ast::Path,
867                           fields: &Vec<ast::Field>,
868                           base: &Option<P<ast::Expr>>) {
869         if generated_code(path.span) {
870             return
871         }
872
873         let mut struct_def: Option<DefId> = None;
874         match self.lookup_type_ref(ex.id) {
875             Some(id) => {
876                 struct_def = Some(id);
877                 let sub_span = self.span.span_for_last_ident(path.span);
878                 self.fmt.ref_str(recorder::StructRef,
879                                  path.span,
880                                  sub_span,
881                                  id,
882                                  self.cur_scope);
883             },
884             None => ()
885         }
886
887         self.write_sub_paths_truncated(path);
888
889         for field in fields.iter() {
890             match struct_def {
891                 Some(struct_def) => {
892                     let fields = ty::lookup_struct_fields(&self.analysis.ty_cx, struct_def);
893                     for f in fields.iter() {
894                         if generated_code(field.ident.span) {
895                             continue;
896                         }
897                         if f.name == field.ident.node.name {
898                             // We don't really need a sub-span here, but no harm done
899                             let sub_span = self.span.span_for_last_ident(field.ident.span);
900                             self.fmt.ref_str(recorder::VarRef,
901                                              field.ident.span,
902                                              sub_span,
903                                              f.id,
904                                              self.cur_scope);
905                         }
906                     }
907                 }
908                 None => {}
909             }
910
911             self.visit_expr(&*field.expr)
912         }
913         visit::walk_expr_opt(self, base)
914     }
915
916     fn process_method_call(&mut self,
917                            ex: &ast::Expr,
918                            args: &Vec<P<ast::Expr>>) {
919         let method_map = self.analysis.ty_cx.method_map.borrow();
920         let method_callee = &(*method_map)[ty::MethodCall::expr(ex.id)];
921         let (def_id, decl_id) = match method_callee.origin {
922             ty::MethodStatic(def_id) |
923             ty::MethodStaticUnboxedClosure(def_id) => {
924                 // method invoked on an object with a concrete type (not a static method)
925                 let decl_id =
926                     match ty::trait_item_of_item(&self.analysis.ty_cx,
927                                                  def_id) {
928                         None => None,
929                         Some(decl_id) => Some(decl_id.def_id()),
930                     };
931
932                 // This incantation is required if the method referenced is a
933                 // trait's default implementation.
934                 let def_id = match ty::impl_or_trait_item(&self.analysis
935                                                                .ty_cx,
936                                                           def_id) {
937                     ty::MethodTraitItem(method) => {
938                         method.provided_source.unwrap_or(def_id)
939                     }
940                     ty::TypeTraitItem(_) => def_id,
941                 };
942                 (Some(def_id), decl_id)
943             }
944             ty::MethodTypeParam(ref mp) => {
945                 // method invoked on a type parameter
946                 let trait_item = ty::trait_item(&self.analysis.ty_cx,
947                                                 mp.trait_ref.def_id,
948                                                 mp.method_num);
949                 (None, Some(trait_item.def_id()))
950             }
951             ty::MethodTraitObject(ref mo) => {
952                 // method invoked on a trait instance
953                 let trait_item = ty::trait_item(&self.analysis.ty_cx,
954                                                 mo.trait_ref.def_id,
955                                                 mo.method_num);
956                 (None, Some(trait_item.def_id()))
957             }
958         };
959         let sub_span = self.span.sub_span_for_meth_name(ex.span);
960         self.fmt.meth_call_str(ex.span,
961                                sub_span,
962                                def_id,
963                                decl_id,
964                                self.cur_scope);
965
966         // walk receiver and args
967         visit::walk_exprs(self, &args[]);
968     }
969
970     fn process_pat(&mut self, p:&ast::Pat) {
971         if generated_code(p.span) {
972             return
973         }
974
975         match p.node {
976             ast::PatStruct(ref path, ref fields, _) => {
977                 self.collected_paths.push((p.id, path.clone(), false, recorder::StructRef));
978                 visit::walk_path(self, path);
979                 let struct_def = match self.lookup_type_ref(p.id) {
980                     Some(sd) => sd,
981                     None => {
982                         self.sess.span_bug(p.span,
983                                            &format!("Could not find struct_def for `{}`",
984                                                    self.span.snippet(p.span))[]);
985                     }
986                 };
987                 for &Spanned { node: ref field, span } in fields.iter() {
988                     let sub_span = self.span.span_for_first_ident(span);
989                     let fields = ty::lookup_struct_fields(&self.analysis.ty_cx, struct_def);
990                     for f in fields.iter() {
991                         if f.name == field.ident.name {
992                             self.fmt.ref_str(recorder::VarRef,
993                                              span,
994                                              sub_span,
995                                              f.id,
996                                              self.cur_scope);
997                             break;
998                         }
999                     }
1000                     self.visit_pat(&*field.pat);
1001                 }
1002             }
1003             ast::PatEnum(ref path, _) => {
1004                 self.collected_paths.push((p.id, path.clone(), false, recorder::VarRef));
1005                 visit::walk_pat(self, p);
1006             }
1007             ast::PatIdent(bm, ref path1, ref optional_subpattern) => {
1008                 let immut = match bm {
1009                     // Even if the ref is mut, you can't change the ref, only
1010                     // the data pointed at, so showing the initialising expression
1011                     // is still worthwhile.
1012                     ast::BindByRef(_) => true,
1013                     ast::BindByValue(mt) => {
1014                         match mt {
1015                             ast::MutMutable => false,
1016                             ast::MutImmutable => true,
1017                         }
1018                     }
1019                 };
1020                 // collect path for either visit_local or visit_arm
1021                 let path = ast_util::ident_to_path(path1.span,path1.node);
1022                 self.collected_paths.push((p.id, path, immut, recorder::VarRef));
1023                 match *optional_subpattern {
1024                     None => {}
1025                     Some(ref subpattern) => self.visit_pat(&**subpattern)
1026                 }
1027             }
1028             _ => visit::walk_pat(self, p)
1029         }
1030     }
1031 }
1032
1033 impl<'l, 'tcx, 'v> Visitor<'v> for DxrVisitor<'l, 'tcx> {
1034     fn visit_item(&mut self, item: &ast::Item) {
1035         if generated_code(item.span) {
1036             return
1037         }
1038
1039         match item.node {
1040             ast::ItemFn(ref decl, _, _, ref ty_params, ref body) =>
1041                 self.process_fn(item, &**decl, ty_params, &**body),
1042             ast::ItemStatic(ref typ, mt, ref expr) =>
1043                 self.process_static(item, &**typ, mt, &**expr),
1044             ast::ItemConst(ref typ, ref expr) =>
1045                 self.process_const(item, &**typ, &**expr),
1046             ast::ItemStruct(ref def, ref ty_params) => self.process_struct(item, &**def, ty_params),
1047             ast::ItemEnum(ref def, ref ty_params) => self.process_enum(item, def, ty_params),
1048             ast::ItemImpl(_, _,
1049                           ref ty_params,
1050                           ref trait_ref,
1051                           ref typ,
1052                           ref impl_items) => {
1053                 self.process_impl(item,
1054                                   ty_params,
1055                                   trait_ref,
1056                                   &**typ,
1057                                   impl_items)
1058             }
1059             ast::ItemTrait(_, ref generics, ref trait_refs, ref methods) =>
1060                 self.process_trait(item, generics, trait_refs, methods),
1061             ast::ItemMod(ref m) => self.process_mod(item, m),
1062             ast::ItemTy(ref ty, ref ty_params) => {
1063                 let qualname = self.analysis.ty_cx.map.path_to_string(item.id);
1064                 let value = ty_to_string(&**ty);
1065                 let sub_span = self.span.sub_span_after_keyword(item.span, keywords::Type);
1066                 self.fmt.typedef_str(item.span,
1067                                      sub_span,
1068                                      item.id,
1069                                      &qualname[],
1070                                      &value[]);
1071
1072                 self.visit_ty(&**ty);
1073                 self.process_generic_params(ty_params, item.span, qualname.as_slice(), item.id);
1074             },
1075             ast::ItemMac(_) => (),
1076             _ => visit::walk_item(self, item),
1077         }
1078     }
1079
1080     fn visit_generics(&mut self, generics: &ast::Generics) {
1081         for param in generics.ty_params.iter() {
1082             for bound in param.bounds.iter() {
1083                 if let ast::TraitTyParamBound(ref trait_ref, _) = *bound {
1084                     self.process_trait_ref(&trait_ref.trait_ref);
1085                 }
1086             }
1087             if let Some(ref ty) = param.default {
1088                 self.visit_ty(&**ty);
1089             }
1090         }
1091     }
1092
1093     // We don't actually index functions here, that is done in visit_item/ItemFn.
1094     // Here we just visit methods.
1095     fn visit_fn(&mut self,
1096                 fk: visit::FnKind<'v>,
1097                 fd: &'v ast::FnDecl,
1098                 b: &'v ast::Block,
1099                 s: Span,
1100                 _: ast::NodeId) {
1101         if generated_code(s) {
1102             return;
1103         }
1104
1105         match fk {
1106             visit::FkMethod(_, _, method) => self.process_method(method),
1107             _ => visit::walk_fn(self, fk, fd, b, s),
1108         }
1109     }
1110
1111     fn visit_trait_item(&mut self, tm: &ast::TraitItem) {
1112         match *tm {
1113             ast::RequiredMethod(ref method_type) => {
1114                 if generated_code(method_type.span) {
1115                     return;
1116                 }
1117
1118                 let mut scope_id;
1119                 let mut qualname = match ty::trait_of_item(&self.analysis.ty_cx,
1120                                                            ast_util::local_def(method_type.id)) {
1121                     Some(def_id) => {
1122                         scope_id = def_id.node;
1123                         let mut s = ty::item_path_str(&self.analysis.ty_cx, def_id);
1124                         s.push_str("::");
1125                         s
1126                     },
1127                     None => {
1128                         self.sess.span_bug(method_type.span,
1129                                            &format!("Could not find trait for method {}",
1130                                                    method_type.id)[]);
1131                     },
1132                 };
1133
1134                 qualname.push_str(get_ident(method_type.ident).get());
1135                 let qualname = &qualname[];
1136
1137                 let sub_span = self.span.sub_span_after_keyword(method_type.span, keywords::Fn);
1138                 self.fmt.method_decl_str(method_type.span,
1139                                          sub_span,
1140                                          method_type.id,
1141                                          qualname,
1142                                          scope_id);
1143
1144                 // walk arg and return types
1145                 for arg in method_type.decl.inputs.iter() {
1146                     self.visit_ty(&*arg.ty);
1147                 }
1148
1149                 if let ast::Return(ref ret_ty) = method_type.decl.output {
1150                     self.visit_ty(&**ret_ty);
1151                 }
1152
1153                 self.process_generic_params(&method_type.generics,
1154                                             method_type.span,
1155                                             qualname,
1156                                             method_type.id);
1157             }
1158             ast::ProvidedMethod(ref method) => self.process_method(&**method),
1159             ast::TypeTraitItem(_) => {}
1160         }
1161     }
1162
1163     fn visit_view_item(&mut self, i: &ast::ViewItem) {
1164         if generated_code(i.span) {
1165             return
1166         }
1167
1168         match i.node {
1169             ast::ViewItemUse(ref item) => {
1170                 match item.node {
1171                     ast::ViewPathSimple(ident, ref path, id) => {
1172                         let sub_span = self.span.span_for_last_ident(path.span);
1173                         let mod_id = match self.lookup_type_ref(id) {
1174                             Some(def_id) => {
1175                                 match self.lookup_def_kind(id, path.span) {
1176                                     Some(kind) => self.fmt.ref_str(kind,
1177                                                                    path.span,
1178                                                                    sub_span,
1179                                                                    def_id,
1180                                                                    self.cur_scope),
1181                                     None => {},
1182                                 }
1183                                 Some(def_id)
1184                             },
1185                             None => None,
1186                         };
1187
1188                         // 'use' always introduces an alias, if there is not an explicit
1189                         // one, there is an implicit one.
1190                         let sub_span =
1191                             match self.span.sub_span_after_keyword(item.span, keywords::As) {
1192                                 Some(sub_span) => Some(sub_span),
1193                                 None => sub_span,
1194                             };
1195
1196                         self.fmt.use_alias_str(path.span,
1197                                                sub_span,
1198                                                id,
1199                                                mod_id,
1200                                                get_ident(ident).get(),
1201                                                self.cur_scope);
1202                         self.write_sub_paths_truncated(path);
1203                     }
1204                     ast::ViewPathGlob(ref path, id) => {
1205                         // Make a comma-separated list of names of imported modules.
1206                         let mut name_string = String::new();
1207                         let glob_map = &self.analysis.glob_map;
1208                         let glob_map = glob_map.as_ref().unwrap();
1209                         if glob_map.contains_key(&id) {
1210                             for n in glob_map[id].iter() {
1211                                 if name_string.len() > 0 {
1212                                     name_string.push_str(", ");
1213                                 }
1214                                 name_string.push_str(n.as_str());
1215                             }
1216                         }
1217
1218                         let sub_span = self.span.sub_span_of_token(path.span,
1219                                                                    token::BinOp(token::Star));
1220                         self.fmt.use_glob_str(path.span,
1221                                               sub_span,
1222                                               id,
1223                                               name_string.as_slice(),
1224                                               self.cur_scope);
1225                         self.write_sub_paths(path);
1226                     }
1227                     ast::ViewPathList(ref path, ref list, _) => {
1228                         for plid in list.iter() {
1229                             match plid.node {
1230                                 ast::PathListIdent { id, .. } => {
1231                                     match self.lookup_type_ref(id) {
1232                                         Some(def_id) =>
1233                                             match self.lookup_def_kind(id, plid.span) {
1234                                                 Some(kind) => {
1235                                                     self.fmt.ref_str(
1236                                                         kind, plid.span,
1237                                                         Some(plid.span),
1238                                                         def_id, self.cur_scope);
1239                                                 }
1240                                                 None => ()
1241                                             },
1242                                         None => ()
1243                                     }
1244                                 },
1245                                 ast::PathListMod { .. } => ()
1246                             }
1247                         }
1248
1249                         self.write_sub_paths(path);
1250                     }
1251                 }
1252             },
1253             ast::ViewItemExternCrate(ident, ref s, id) => {
1254                 let name = get_ident(ident);
1255                 let name = name.get();
1256                 let s = match *s {
1257                     Some((ref s, _)) => s.get().to_string(),
1258                     None => name.to_string(),
1259                 };
1260                 let sub_span = self.span.sub_span_after_keyword(i.span, keywords::Crate);
1261                 let cnum = match self.sess.cstore.find_extern_mod_stmt_cnum(id) {
1262                     Some(cnum) => cnum,
1263                     None => 0,
1264                 };
1265                 self.fmt.extern_crate_str(i.span,
1266                                           sub_span,
1267                                           id,
1268                                           cnum,
1269                                           name,
1270                                           &s[],
1271                                           self.cur_scope);
1272             },
1273         }
1274     }
1275
1276     fn visit_ty(&mut self, t: &ast::Ty) {
1277         if generated_code(t.span) {
1278             return
1279         }
1280
1281         match t.node {
1282             ast::TyPath(ref path, id) => {
1283                 match self.lookup_type_ref(id) {
1284                     Some(id) => {
1285                         let sub_span = self.span.sub_span_for_type_name(t.span);
1286                         self.fmt.ref_str(recorder::TypeRef,
1287                                          t.span,
1288                                          sub_span,
1289                                          id,
1290                                          self.cur_scope);
1291                     },
1292                     None => ()
1293                 }
1294
1295                 self.write_sub_paths_truncated(path);
1296
1297                 visit::walk_path(self, path);
1298             },
1299             _ => visit::walk_ty(self, t),
1300         }
1301     }
1302
1303     fn visit_expr(&mut self, ex: &ast::Expr) {
1304         if generated_code(ex.span) {
1305             return
1306         }
1307
1308         match ex.node {
1309             ast::ExprCall(ref _f, ref _args) => {
1310                 // Don't need to do anything for function calls,
1311                 // because just walking the callee path does what we want.
1312                 visit::walk_expr(self, ex);
1313             },
1314             ast::ExprPath(ref path) => {
1315                 self.process_path(ex.id, path.span, path, None);
1316                 visit::walk_path(self, path);
1317             }
1318             ast::ExprQPath(ref qpath) => {
1319                 let mut path = qpath.trait_ref.path.clone();
1320                 path.segments.push(qpath.item_path.clone());
1321                 self.process_path(ex.id, ex.span, &path, None);
1322                 visit::walk_qpath(self, ex.span, &**qpath);
1323             }
1324             ast::ExprStruct(ref path, ref fields, ref base) =>
1325                 self.process_struct_lit(ex, path, fields, base),
1326             ast::ExprMethodCall(_, _, ref args) => self.process_method_call(ex, args),
1327             ast::ExprField(ref sub_ex, ident) => {
1328                 if generated_code(sub_ex.span) {
1329                     return
1330                 }
1331
1332                 self.visit_expr(&**sub_ex);
1333
1334                 match ty::expr_ty_adjusted(&self.analysis.ty_cx, &**sub_ex).sty {
1335                     ty::ty_struct(def_id, _) => {
1336                         let fields = ty::lookup_struct_fields(&self.analysis.ty_cx, def_id);
1337                         for f in fields.iter() {
1338                             if f.name == ident.node.name {
1339                                 let sub_span = self.span.span_for_last_ident(ex.span);
1340                                 self.fmt.ref_str(recorder::VarRef,
1341                                                  ex.span,
1342                                                  sub_span,
1343                                                  f.id,
1344                                                  self.cur_scope);
1345                                 break;
1346                             }
1347                         }
1348                     },
1349                     _ => self.sess.span_bug(ex.span,
1350                                             "Expected struct type, but not ty_struct"),
1351                 }
1352             },
1353             ast::ExprTupField(ref sub_ex, idx) => {
1354                 if generated_code(sub_ex.span) {
1355                     return
1356                 }
1357
1358                 self.visit_expr(&**sub_ex);
1359
1360                 match ty::expr_ty_adjusted(&self.analysis.ty_cx, &**sub_ex).sty {
1361                     ty::ty_struct(def_id, _) => {
1362                         let fields = ty::lookup_struct_fields(&self.analysis.ty_cx, def_id);
1363                         for (i, f) in fields.iter().enumerate() {
1364                             if i == idx.node {
1365                                 let sub_span = self.span.span_for_last_ident(ex.span);
1366                                 self.fmt.ref_str(recorder::VarRef,
1367                                                  ex.span,
1368                                                  sub_span,
1369                                                  f.id,
1370                                                  self.cur_scope);
1371                                 break;
1372                             }
1373                         }
1374                     },
1375                     _ => self.sess.span_bug(ex.span,
1376                                             "Expected struct type, but not ty_struct"),
1377                 }
1378             },
1379             ast::ExprClosure(_, _, ref decl, ref body) => {
1380                 if generated_code(body.span) {
1381                     return
1382                 }
1383
1384                 let mut id = String::from_str("$");
1385                 id.push_str(&ex.id.to_string()[]);
1386                 self.process_formals(&decl.inputs, &id[]);
1387
1388                 // walk arg and return types
1389                 for arg in decl.inputs.iter() {
1390                     self.visit_ty(&*arg.ty);
1391                 }
1392
1393                 if let ast::Return(ref ret_ty) = decl.output {
1394                     self.visit_ty(&**ret_ty);
1395                 }
1396
1397                 // walk the body
1398                 self.nest(ex.id, |v| v.visit_block(&**body));
1399             },
1400             _ => {
1401                 visit::walk_expr(self, ex)
1402             },
1403         }
1404     }
1405
1406     fn visit_mac(&mut self, _: &ast::Mac) {
1407         // Just stop, macros are poison to us.
1408     }
1409
1410     fn visit_pat(&mut self, p: &ast::Pat) {
1411         self.process_pat(p);
1412         if !self.collecting {
1413             self.collected_paths.clear();
1414         }
1415     }
1416
1417     fn visit_arm(&mut self, arm: &ast::Arm) {
1418         assert!(self.collected_paths.len() == 0 && !self.collecting);
1419         self.collecting = true;
1420         for pattern in arm.pats.iter() {
1421             // collect paths from the arm's patterns
1422             self.visit_pat(&**pattern);
1423         }
1424
1425         // This is to get around borrow checking, because we need mut self to call process_path.
1426         let mut paths_to_process = vec![];
1427         // process collected paths
1428         for &(id, ref p, ref immut, ref_kind) in self.collected_paths.iter() {
1429             let def_map = self.analysis.ty_cx.def_map.borrow();
1430             if !def_map.contains_key(&id) {
1431                 self.sess.span_bug(p.span,
1432                                    &format!("def_map has no key for {} in visit_arm",
1433                                            id)[]);
1434             }
1435             let def = &(*def_map)[id];
1436             match *def {
1437                 def::DefLocal(id)  => {
1438                     let value = if *immut {
1439                         self.span.snippet(p.span).to_string()
1440                     } else {
1441                         "<mutable>".to_string()
1442                     };
1443
1444                     assert!(p.segments.len() == 1, "qualified path for local variable def in arm");
1445                     self.fmt.variable_str(p.span,
1446                                           Some(p.span),
1447                                           id,
1448                                           &path_to_string(p)[],
1449                                           &value[],
1450                                           "")
1451                 }
1452                 def::DefVariant(..) => {
1453                     paths_to_process.push((id, p.clone(), Some(ref_kind)))
1454                 }
1455                 // FIXME(nrc) what are these doing here?
1456                 def::DefStatic(_, _) => {}
1457                 def::DefConst(..) => {}
1458                 _ => error!("unexpected definition kind when processing collected paths: {:?}",
1459                             *def)
1460             }
1461         }
1462         for &(id, ref path, ref_kind) in paths_to_process.iter() {
1463             self.process_path(id, path.span, path, ref_kind);
1464         }
1465         self.collecting = false;
1466         self.collected_paths.clear();
1467         visit::walk_expr_opt(self, &arm.guard);
1468         self.visit_expr(&*arm.body);
1469     }
1470
1471     fn visit_stmt(&mut self, s: &ast::Stmt) {
1472         if generated_code(s.span) {
1473             return
1474         }
1475
1476         visit::walk_stmt(self, s)
1477     }
1478
1479     fn visit_local(&mut self, l: &ast::Local) {
1480         if generated_code(l.span) {
1481             return
1482         }
1483
1484         // The local could declare multiple new vars, we must walk the
1485         // pattern and collect them all.
1486         assert!(self.collected_paths.len() == 0 && !self.collecting);
1487         self.collecting = true;
1488         self.visit_pat(&*l.pat);
1489         self.collecting = false;
1490
1491         let value = self.span.snippet(l.span);
1492
1493         for &(id, ref p, ref immut, _) in self.collected_paths.iter() {
1494             let value = if *immut { value.to_string() } else { "<mutable>".to_string() };
1495             let types = self.analysis.ty_cx.node_types.borrow();
1496             let typ = ppaux::ty_to_string(&self.analysis.ty_cx, (*types)[id]);
1497             // Get the span only for the name of the variable (I hope the path
1498             // is only ever a variable name, but who knows?).
1499             let sub_span = self.span.span_for_last_ident(p.span);
1500             // Rust uses the id of the pattern for var lookups, so we'll use it too.
1501             self.fmt.variable_str(p.span,
1502                                   sub_span,
1503                                   id,
1504                                   &path_to_string(p)[],
1505                                   &value[],
1506                                   &typ[]);
1507         }
1508         self.collected_paths.clear();
1509
1510         // Just walk the initialiser and type (don't want to walk the pattern again).
1511         visit::walk_ty_opt(self, &l.ty);
1512         visit::walk_expr_opt(self, &l.init);
1513     }
1514 }
1515
1516 pub fn process_crate(sess: &Session,
1517                      krate: &ast::Crate,
1518                      analysis: &ty::CrateAnalysis,
1519                      odir: Option<&Path>) {
1520     if generated_code(krate.span) {
1521         return;
1522     }
1523
1524     assert!(analysis.glob_map.is_some());
1525     let cratename = match attr::find_crate_name(&krate.attrs[]) {
1526         Some(name) => name.get().to_string(),
1527         None => {
1528             info!("Could not find crate name, using 'unknown_crate'");
1529             String::from_str("unknown_crate")
1530         },
1531     };
1532
1533     info!("Dumping crate {}", cratename);
1534
1535     // find a path to dump our data to
1536     let mut root_path = match os::getenv("DXR_RUST_TEMP_FOLDER") {
1537         Some(val) => Path::new(val),
1538         None => match odir {
1539             Some(val) => val.join("dxr"),
1540             None => Path::new("dxr-temp"),
1541         },
1542     };
1543
1544     match fs::mkdir_recursive(&root_path, io::USER_RWX) {
1545         Err(e) => sess.err(&format!("Could not create directory {}: {}",
1546                            root_path.display(), e)[]),
1547         _ => (),
1548     }
1549
1550     {
1551         let disp = root_path.display();
1552         info!("Writing output to {}", disp);
1553     }
1554
1555     // Create output file.
1556     let mut out_name = cratename.clone();
1557     out_name.push_str(".csv");
1558     root_path.push(out_name);
1559     let output_file = match File::create(&root_path) {
1560         Ok(f) => box f,
1561         Err(e) => {
1562             let disp = root_path.display();
1563             sess.fatal(&format!("Could not open {}: {}", disp, e)[]);
1564         }
1565     };
1566     root_path.pop();
1567
1568     let mut visitor = DxrVisitor {
1569         sess: sess,
1570         analysis: analysis,
1571         collected_paths: vec!(),
1572         collecting: false,
1573         fmt: FmtStrs::new(box Recorder {
1574                             out: output_file as Box<Writer+'static>,
1575                             dump_spans: false,
1576                         },
1577                         SpanUtils {
1578                             sess: sess,
1579                             err_count: Cell::new(0)
1580                         },
1581                         cratename.clone()),
1582         span: SpanUtils {
1583             sess: sess,
1584             err_count: Cell::new(0)
1585         },
1586         cur_scope: 0
1587     };
1588
1589     visitor.dump_crate_info(&cratename[], krate);
1590
1591     visit::walk_crate(&mut visitor, krate);
1592 }