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