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