]> git.lizzy.rs Git - rust.git/blob - src/librustc_trans/save/mod.rs
Autoderef in librustc_trans
[rust.git] / src / librustc_trans / save / mod.rs
1 // Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 use middle::ty;
12 use middle::def::Def;
13 use middle::def_id::DefId;
14
15 use std::env;
16 use std::fs::{self, File};
17 use std::path::{Path, PathBuf};
18
19 use rustc_front;
20 use rustc_front::{hir, lowering};
21 use rustc::front::map::NodeItem;
22 use rustc::session::config::CrateType::CrateTypeExecutable;
23
24 use syntax::ast::{self, NodeId};
25 use syntax::ast_util;
26 use syntax::codemap::*;
27 use syntax::parse::token::{self, keywords};
28 use syntax::visit::{self, Visitor};
29 use syntax::print::pprust::ty_to_string;
30
31 use self::span_utils::SpanUtils;
32
33 #[macro_use]
34 pub mod span_utils;
35 pub mod recorder;
36
37 mod dump_csv;
38
39 pub struct SaveContext<'l, 'tcx: 'l> {
40     tcx: &'l ty::ctxt<'tcx>,
41     lcx: &'l lowering::LoweringContext<'l>,
42     span_utils: SpanUtils<'l>,
43 }
44
45 pub struct CrateData {
46     pub name: String,
47     pub number: u32,
48 }
49
50 /// Data for any entity in the Rust language. The actual data contained varied
51 /// with the kind of entity being queried. See the nested structs for details.
52 #[derive(Debug)]
53 pub enum Data {
54     /// Data for all kinds of functions and methods.
55     FunctionData(FunctionData),
56     /// Data for local and global variables (consts and statics), and fields.
57     VariableData(VariableData),
58     /// Data for modules.
59     ModData(ModData),
60     /// Data for Enums.
61     EnumData(EnumData),
62     /// Data for impls.
63     ImplData(ImplData),
64
65     /// Data for the use of some variable (e.g., the use of a local variable, which
66     /// will refere to that variables declaration).
67     VariableRefData(VariableRefData),
68     /// Data for a reference to a type or trait.
69     TypeRefData(TypeRefData),
70     /// Data for a reference to a module.
71     ModRefData(ModRefData),
72     /// Data about a function call.
73     FunctionCallData(FunctionCallData),
74     /// Data about a method call.
75     MethodCallData(MethodCallData),
76     /// Data about a macro use.
77     MacroUseData(MacroUseData),
78 }
79
80 /// Data for all kinds of functions and methods.
81 #[derive(Debug)]
82 pub struct FunctionData {
83     pub id: NodeId,
84     pub name: String,
85     pub qualname: String,
86     pub declaration: Option<DefId>,
87     pub span: Span,
88     pub scope: NodeId,
89 }
90
91 /// Data for local and global variables (consts and statics).
92 #[derive(Debug)]
93 pub struct VariableData {
94     pub id: NodeId,
95     pub name: String,
96     pub qualname: String,
97     pub span: Span,
98     pub scope: NodeId,
99     pub value: String,
100     pub type_value: String,
101 }
102
103 /// Data for modules.
104 #[derive(Debug)]
105 pub struct ModData {
106     pub id: NodeId,
107     pub name: String,
108     pub qualname: String,
109     pub span: Span,
110     pub scope: NodeId,
111     pub filename: String,
112 }
113
114 /// Data for enum declarations.
115 #[derive(Debug)]
116 pub struct EnumData {
117     pub id: NodeId,
118     pub value: String,
119     pub qualname: String,
120     pub span: Span,
121     pub scope: NodeId,
122 }
123
124 #[derive(Debug)]
125 pub struct ImplData {
126     pub id: NodeId,
127     pub span: Span,
128     pub scope: NodeId,
129     // FIXME: I'm not really sure inline data is the best way to do this. Seems
130     // OK in this case, but generalising leads to returning chunks of AST, which
131     // feels wrong.
132     pub trait_ref: Option<TypeRefData>,
133     pub self_ref: Option<TypeRefData>,
134 }
135
136 /// Data for the use of some item (e.g., the use of a local variable, which
137 /// will refer to that variables declaration (by ref_id)).
138 #[derive(Debug)]
139 pub struct VariableRefData {
140     pub name: String,
141     pub span: Span,
142     pub scope: NodeId,
143     pub ref_id: DefId,
144 }
145
146 /// Data for a reference to a type or trait.
147 #[derive(Debug)]
148 pub struct TypeRefData {
149     pub span: Span,
150     pub scope: NodeId,
151     pub ref_id: DefId,
152 }
153
154 /// Data for a reference to a module.
155 #[derive(Debug)]
156 pub struct ModRefData {
157     pub span: Span,
158     pub scope: NodeId,
159     pub ref_id: DefId,
160 }
161
162 /// Data about a function call.
163 #[derive(Debug)]
164 pub struct FunctionCallData {
165     pub span: Span,
166     pub scope: NodeId,
167     pub ref_id: DefId,
168 }
169
170 /// Data about a method call.
171 #[derive(Debug)]
172 pub struct MethodCallData {
173     pub span: Span,
174     pub scope: NodeId,
175     pub ref_id: Option<DefId>,
176     pub decl_id: Option<DefId>,
177 }
178
179 /// Data about a macro use.
180 #[derive(Debug)]
181 pub struct MacroUseData {
182     pub span: Span,
183     pub name: String,
184     // Because macro expansion happens before ref-ids are determined,
185     // we use the callee span to reference the associated macro definition.
186     pub callee_span: Span,
187     pub scope: NodeId,
188     pub imported: bool,
189 }
190
191 macro_rules! option_try(
192     ($e:expr) => (match $e { Some(e) => e, None => return None })
193 );
194
195
196
197 impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
198     pub fn new(tcx: &'l ty::ctxt<'tcx>,
199                lcx: &'l lowering::LoweringContext<'l>)
200                -> SaveContext<'l, 'tcx> {
201         let span_utils = SpanUtils::new(&tcx.sess);
202         SaveContext::from_span_utils(tcx, lcx, span_utils)
203     }
204
205     pub fn from_span_utils(tcx: &'l ty::ctxt<'tcx>,
206                            lcx: &'l lowering::LoweringContext<'l>,
207                            span_utils: SpanUtils<'l>)
208                            -> SaveContext<'l, 'tcx> {
209         SaveContext {
210             tcx: tcx,
211             lcx: lcx,
212             span_utils: span_utils,
213         }
214     }
215
216     // List external crates used by the current crate.
217     pub fn get_external_crates(&self) -> Vec<CrateData> {
218         let mut result = Vec::new();
219
220         for n in self.tcx.sess.cstore.crates() {
221             result.push(CrateData {
222                 name: self.tcx.sess.cstore.crate_name(n),
223                 number: n,
224             });
225         }
226
227         result
228     }
229
230     pub fn get_item_data(&self, item: &ast::Item) -> Option<Data> {
231         match item.node {
232             ast::ItemKind::Fn(..) => {
233                 let name = self.tcx.map.path_to_string(item.id);
234                 let qualname = format!("::{}", name);
235                 let sub_span = self.span_utils.sub_span_after_keyword(item.span, keywords::Fn);
236                 filter!(self.span_utils, sub_span, item.span, None);
237                 Some(Data::FunctionData(FunctionData {
238                     id: item.id,
239                     name: name,
240                     qualname: qualname,
241                     declaration: None,
242                     span: sub_span.unwrap(),
243                     scope: self.enclosing_scope(item.id),
244                 }))
245             }
246             ast::ItemKind::Static(ref typ, mt, ref expr) => {
247                 let qualname = format!("::{}", self.tcx.map.path_to_string(item.id));
248
249                 // If the variable is immutable, save the initialising expression.
250                 let (value, keyword) = match mt {
251                     ast::Mutability::Mutable => (String::from("<mutable>"), keywords::Mut),
252                     ast::Mutability::Immutable => {
253                         (self.span_utils.snippet(expr.span), keywords::Static)
254                     },
255                 };
256
257                 let sub_span = self.span_utils.sub_span_after_keyword(item.span, keyword);
258                 filter!(self.span_utils, sub_span, item.span, None);
259                 Some(Data::VariableData(VariableData {
260                     id: item.id,
261                     name: item.ident.to_string(),
262                     qualname: qualname,
263                     span: sub_span.unwrap(),
264                     scope: self.enclosing_scope(item.id),
265                     value: value,
266                     type_value: ty_to_string(&typ),
267                 }))
268             }
269             ast::ItemKind::Const(ref typ, ref expr) => {
270                 let qualname = format!("::{}", self.tcx.map.path_to_string(item.id));
271                 let sub_span = self.span_utils.sub_span_after_keyword(item.span, keywords::Const);
272                 filter!(self.span_utils, sub_span, item.span, None);
273                 Some(Data::VariableData(VariableData {
274                     id: item.id,
275                     name: item.ident.to_string(),
276                     qualname: qualname,
277                     span: sub_span.unwrap(),
278                     scope: self.enclosing_scope(item.id),
279                     value: self.span_utils.snippet(expr.span),
280                     type_value: ty_to_string(&typ),
281                 }))
282             }
283             ast::ItemKind::Mod(ref m) => {
284                 let qualname = format!("::{}", self.tcx.map.path_to_string(item.id));
285
286                 let cm = self.tcx.sess.codemap();
287                 let filename = cm.span_to_filename(m.inner);
288
289                 let sub_span = self.span_utils.sub_span_after_keyword(item.span, keywords::Mod);
290                 filter!(self.span_utils, sub_span, item.span, None);
291                 Some(Data::ModData(ModData {
292                     id: item.id,
293                     name: item.ident.to_string(),
294                     qualname: qualname,
295                     span: sub_span.unwrap(),
296                     scope: self.enclosing_scope(item.id),
297                     filename: filename,
298                 }))
299             }
300             ast::ItemKind::Enum(..) => {
301                 let enum_name = format!("::{}", self.tcx.map.path_to_string(item.id));
302                 let val = self.span_utils.snippet(item.span);
303                 let sub_span = self.span_utils.sub_span_after_keyword(item.span, keywords::Enum);
304                 filter!(self.span_utils, sub_span, item.span, None);
305                 Some(Data::EnumData(EnumData {
306                     id: item.id,
307                     value: val,
308                     span: sub_span.unwrap(),
309                     qualname: enum_name,
310                     scope: self.enclosing_scope(item.id),
311                 }))
312             }
313             ast::ItemKind::Impl(_, _, _, ref trait_ref, ref typ, _) => {
314                 let mut type_data = None;
315                 let sub_span;
316
317                 let parent = self.enclosing_scope(item.id);
318
319                 match typ.node {
320                     // Common case impl for a struct or something basic.
321                     ast::TyKind::Path(None, ref path) => {
322                         sub_span = self.span_utils.sub_span_for_type_name(path.span);
323                         filter!(self.span_utils, sub_span, path.span, None);
324                         type_data = self.lookup_ref_id(typ.id).map(|id| {
325                             TypeRefData {
326                                 span: sub_span.unwrap(),
327                                 scope: parent,
328                                 ref_id: id,
329                             }
330                         });
331                     }
332                     _ => {
333                         // Less useful case, impl for a compound type.
334                         let span = typ.span;
335                         sub_span = self.span_utils.sub_span_for_type_name(span).or(Some(span));
336                     }
337                 }
338
339                 let trait_data = trait_ref.as_ref()
340                                           .and_then(|tr| self.get_trait_ref_data(tr, parent));
341
342                 filter!(self.span_utils, sub_span, typ.span, None);
343                 Some(Data::ImplData(ImplData {
344                     id: item.id,
345                     span: sub_span.unwrap(),
346                     scope: parent,
347                     trait_ref: trait_data,
348                     self_ref: type_data,
349                 }))
350             }
351             _ => {
352                 // FIXME
353                 unimplemented!();
354             }
355         }
356     }
357
358     pub fn get_field_data(&self, field: &ast::StructField,
359                           scope: NodeId) -> Option<VariableData> {
360         match field.node.kind {
361             ast::NamedField(ident, _) => {
362                 let qualname = format!("::{}::{}", self.tcx.map.path_to_string(scope), ident);
363                 let typ = self.tcx.node_types().get(&field.node.id).unwrap().to_string();
364                 let sub_span = self.span_utils.sub_span_before_token(field.span, token::Colon);
365                 filter!(self.span_utils, sub_span, field.span, None);
366                 Some(VariableData {
367                     id: field.node.id,
368                     name: ident.to_string(),
369                     qualname: qualname,
370                     span: sub_span.unwrap(),
371                     scope: scope,
372                     value: "".to_owned(),
373                     type_value: typ,
374                 })
375             }
376             _ => None,
377         }
378     }
379
380     // FIXME would be nice to take a MethodItem here, but the ast provides both
381     // trait and impl flavours, so the caller must do the disassembly.
382     pub fn get_method_data(&self, id: ast::NodeId,
383                            name: ast::Name, span: Span) -> Option<FunctionData> {
384         // The qualname for a method is the trait name or name of the struct in an impl in
385         // which the method is declared in, followed by the method's name.
386         let qualname = match self.tcx.impl_of_method(self.tcx.map.local_def_id(id)) {
387             Some(impl_id) => match self.tcx.map.get_if_local(impl_id) {
388                 Some(NodeItem(item)) => {
389                     match item.node {
390                         hir::ItemImpl(_, _, _, _, ref ty, _) => {
391                             let mut result = String::from("<");
392                             result.push_str(&rustc_front::print::pprust::ty_to_string(&ty));
393
394                             match self.tcx.trait_of_item(self.tcx.map.local_def_id(id)) {
395                                 Some(def_id) => {
396                                     result.push_str(" as ");
397                                     result.push_str(&self.tcx.item_path_str(def_id));
398                                 }
399                                 None => {}
400                             }
401                             result.push_str(">");
402                             result
403                         }
404                         _ => {
405                             self.tcx.sess.span_bug(span,
406                                                    &format!("Container {:?} for method {} not \
407                                                              an impl?",
408                                                             impl_id,
409                                                             id));
410                         }
411                     }
412                 }
413                 r => {
414                     self.tcx.sess.span_bug(span,
415                                            &format!("Container {:?} for method {} is not a node \
416                                                      item {:?}",
417                                                     impl_id,
418                                                     id,
419                                                     r));
420                 }
421             },
422             None => match self.tcx.trait_of_item(self.tcx.map.local_def_id(id)) {
423                 Some(def_id) => {
424                     match self.tcx.map.get_if_local(def_id) {
425                         Some(NodeItem(_)) => {
426                             format!("::{}", self.tcx.item_path_str(def_id))
427                         }
428                         r => {
429                             self.tcx.sess.span_bug(span,
430                                                    &format!("Could not find container {:?} for \
431                                                              method {}, got {:?}",
432                                                             def_id,
433                                                             id,
434                                                             r));
435                         }
436                     }
437                 }
438                 None => {
439                     self.tcx.sess.span_bug(span,
440                                            &format!("Could not find container for method {}", id));
441                 }
442             },
443         };
444
445         let qualname = format!("{}::{}", qualname, name);
446
447         let def_id = self.tcx.map.local_def_id(id);
448         let decl_id = self.tcx.trait_item_of_item(def_id).and_then(|new_id| {
449             let new_def_id = new_id.def_id();
450             if new_def_id != def_id {
451                 Some(new_def_id)
452             } else {
453                 None
454             }
455         });
456
457         let sub_span = self.span_utils.sub_span_after_keyword(span, keywords::Fn);
458         filter!(self.span_utils, sub_span, span, None);
459         Some(FunctionData {
460             id: id,
461             name: name.to_string(),
462             qualname: qualname,
463             declaration: decl_id,
464             span: sub_span.unwrap(),
465             scope: self.enclosing_scope(id),
466         })
467     }
468
469     pub fn get_trait_ref_data(&self,
470                               trait_ref: &ast::TraitRef,
471                               parent: NodeId)
472                               -> Option<TypeRefData> {
473         self.lookup_ref_id(trait_ref.ref_id).and_then(|def_id| {
474             let span = trait_ref.path.span;
475             let sub_span = self.span_utils.sub_span_for_type_name(span).or(Some(span));
476             filter!(self.span_utils, sub_span, span, None);
477             Some(TypeRefData {
478                 span: sub_span.unwrap(),
479                 scope: parent,
480                 ref_id: def_id,
481             })
482         })
483     }
484
485     pub fn get_expr_data(&self, expr: &ast::Expr) -> Option<Data> {
486         let hir_node = lowering::lower_expr(self.lcx, expr);
487         let ty = self.tcx.expr_ty_adjusted_opt(&hir_node);
488         if ty.is_none() || ty.unwrap().sty == ty::TyError {
489             return None;
490         }
491         match expr.node {
492             ast::ExprKind::Field(ref sub_ex, ident) => {
493                 let hir_node = lowering::lower_expr(self.lcx, sub_ex);
494                 match self.tcx.expr_ty_adjusted(&hir_node).sty {
495                     ty::TyStruct(def, _) => {
496                         let f = def.struct_variant().field_named(ident.node.name);
497                         let sub_span = self.span_utils.span_for_last_ident(expr.span);
498                         filter!(self.span_utils, sub_span, expr.span, None);
499                         return Some(Data::VariableRefData(VariableRefData {
500                             name: ident.node.to_string(),
501                             span: sub_span.unwrap(),
502                             scope: self.enclosing_scope(expr.id),
503                             ref_id: f.did,
504                         }));
505                     }
506                     _ => {
507                         debug!("Expected struct type, found {:?}", ty);
508                         None
509                     }
510                 }
511             }
512             ast::ExprKind::Struct(ref path, _, _) => {
513                 let hir_node = lowering::lower_expr(self.lcx, expr);
514                 match self.tcx.expr_ty_adjusted(&hir_node).sty {
515                     ty::TyStruct(def, _) => {
516                         let sub_span = self.span_utils.span_for_last_ident(path.span);
517                         filter!(self.span_utils, sub_span, path.span, None);
518                         Some(Data::TypeRefData(TypeRefData {
519                             span: sub_span.unwrap(),
520                             scope: self.enclosing_scope(expr.id),
521                             ref_id: def.did,
522                         }))
523                     }
524                     _ => {
525                         // FIXME ty could legitimately be a TyEnum, but then we will fail
526                         // later if we try to look up the fields.
527                         debug!("expected TyStruct, found {:?}", ty);
528                         None
529                     }
530                 }
531             }
532             ast::ExprKind::MethodCall(..) => {
533                 let method_call = ty::MethodCall::expr(expr.id);
534                 let method_id = self.tcx.tables.borrow().method_map[&method_call].def_id;
535                 let (def_id, decl_id) = match self.tcx.impl_or_trait_item(method_id).container() {
536                     ty::ImplContainer(_) => (Some(method_id), None),
537                     ty::TraitContainer(_) => (None, Some(method_id)),
538                 };
539                 let sub_span = self.span_utils.sub_span_for_meth_name(expr.span);
540                 filter!(self.span_utils, sub_span, expr.span, None);
541                 let parent = self.enclosing_scope(expr.id);
542                 Some(Data::MethodCallData(MethodCallData {
543                     span: sub_span.unwrap(),
544                     scope: parent,
545                     ref_id: def_id,
546                     decl_id: decl_id,
547                 }))
548             }
549             ast::ExprKind::Path(_, ref path) => {
550                 self.get_path_data(expr.id, path)
551             }
552             _ => {
553                 // FIXME
554                 unimplemented!();
555             }
556         }
557     }
558
559     pub fn get_path_data(&self, id: NodeId, path: &ast::Path) -> Option<Data> {
560         let def_map = self.tcx.def_map.borrow();
561         if !def_map.contains_key(&id) {
562             self.tcx.sess.span_bug(path.span,
563                                    &format!("def_map has no key for {} in visit_expr", id));
564         }
565         let def = def_map.get(&id).unwrap().full_def();
566         let sub_span = self.span_utils.span_for_last_ident(path.span);
567         filter!(self.span_utils, sub_span, path.span, None);
568         match def {
569             Def::Upvar(..) |
570             Def::Local(..) |
571             Def::Static(..) |
572             Def::Const(..) |
573             Def::AssociatedConst(..) |
574             Def::Variant(..) => {
575                 Some(Data::VariableRefData(VariableRefData {
576                     name: self.span_utils.snippet(sub_span.unwrap()),
577                     span: sub_span.unwrap(),
578                     scope: self.enclosing_scope(id),
579                     ref_id: def.def_id(),
580                 }))
581             }
582             Def::Struct(def_id) |
583             Def::Enum(def_id) |
584             Def::TyAlias(def_id) |
585             Def::Trait(def_id) |
586             Def::TyParam(_, _, def_id, _) => {
587                 Some(Data::TypeRefData(TypeRefData {
588                     span: sub_span.unwrap(),
589                     ref_id: def_id,
590                     scope: self.enclosing_scope(id),
591                 }))
592             }
593             Def::Method(decl_id) => {
594                 let sub_span = self.span_utils.sub_span_for_meth_name(path.span);
595                 filter!(self.span_utils, sub_span, path.span, None);
596                 let def_id = if decl_id.is_local() {
597                     let ti = self.tcx.impl_or_trait_item(decl_id);
598                     match ti.container() {
599                         ty::TraitContainer(def_id) => {
600                             self.tcx
601                                 .trait_items(def_id)
602                                 .iter()
603                                 .find(|mr| mr.name() == ti.name() && self.trait_method_has_body(mr))
604                                 .map(|mr| mr.def_id())
605                         }
606                         ty::ImplContainer(def_id) => {
607                             let impl_items = self.tcx.impl_items.borrow();
608                             Some(impl_items.get(&def_id)
609                                            .unwrap()
610                                            .iter()
611                                            .find(|mr| {
612                                                self.tcx.impl_or_trait_item(mr.def_id()).name() ==
613                                                ti.name()
614                                            })
615                                            .unwrap()
616                                            .def_id())
617                         }
618                     }
619                 } else {
620                     None
621                 };
622                 Some(Data::MethodCallData(MethodCallData {
623                     span: sub_span.unwrap(),
624                     scope: self.enclosing_scope(id),
625                     ref_id: def_id,
626                     decl_id: Some(decl_id),
627                 }))
628             }
629             Def::Fn(def_id) => {
630                 Some(Data::FunctionCallData(FunctionCallData {
631                     ref_id: def_id,
632                     span: sub_span.unwrap(),
633                     scope: self.enclosing_scope(id),
634                 }))
635             }
636             Def::Mod(def_id) => {
637                 Some(Data::ModRefData(ModRefData {
638                     ref_id: def_id,
639                     span: sub_span.unwrap(),
640                     scope: self.enclosing_scope(id),
641                 }))
642             }
643             _ => None,
644         }
645     }
646
647     fn trait_method_has_body(&self, mr: &ty::ImplOrTraitItem) -> bool {
648         let def_id = mr.def_id();
649         if let Some(node_id) = self.tcx.map.as_local_node_id(def_id) {
650             let trait_item = self.tcx.map.expect_trait_item(node_id);
651             if let hir::TraitItem_::MethodTraitItem(_, Some(_)) = trait_item.node {
652                 true
653             } else {
654                 false
655             }
656         } else {
657             false
658         }
659     }
660
661     pub fn get_field_ref_data(&self,
662                               field_ref: &ast::Field,
663                               variant: ty::VariantDef,
664                               parent: NodeId)
665                               -> Option<VariableRefData> {
666         let f = variant.field_named(field_ref.ident.node.name);
667         // We don't really need a sub-span here, but no harm done
668         let sub_span = self.span_utils.span_for_last_ident(field_ref.ident.span);
669         filter!(self.span_utils, sub_span, field_ref.ident.span, None);
670         Some(VariableRefData {
671             name: field_ref.ident.node.to_string(),
672             span: sub_span.unwrap(),
673             scope: parent,
674             ref_id: f.did,
675         })
676     }
677
678     /// Attempt to return MacroUseData for any AST node.
679     ///
680     /// For a given piece of AST defined by the supplied Span and NodeId,
681     /// returns None if the node is not macro-generated or the span is malformed,
682     /// else uses the expansion callsite and callee to return some MacroUseData.
683     pub fn get_macro_use_data(&self, span: Span, id: NodeId) -> Option<MacroUseData> {
684         if !generated_code(span) {
685             return None;
686         }
687         // Note we take care to use the source callsite/callee, to handle
688         // nested expansions and ensure we only generate data for source-visible
689         // macro uses.
690         let callsite = self.tcx.sess.codemap().source_callsite(span);
691         let callee = self.tcx.sess.codemap().source_callee(span);
692         let callee = option_try!(callee);
693         let callee_span = option_try!(callee.span);
694
695         // Ignore attribute macros, their spans are usually mangled
696         if let MacroAttribute(_) = callee.format {
697             return None;
698         }
699
700         // If the callee is an imported macro from an external crate, need to get
701         // the source span and name from the session, as their spans are localized
702         // when read in, and no longer correspond to the source.
703         if let Some(mac) = self.tcx.sess.imported_macro_spans.borrow().get(&callee_span) {
704             let &(ref mac_name, mac_span) = mac;
705             return Some(MacroUseData {
706                                         span: callsite,
707                                         name: mac_name.clone(),
708                                         callee_span: mac_span,
709                                         scope: self.enclosing_scope(id),
710                                         imported: true,
711                                     });
712         }
713
714         Some(MacroUseData {
715             span: callsite,
716             name: callee.name().to_string(),
717             callee_span: callee_span,
718             scope: self.enclosing_scope(id),
719             imported: false,
720         })
721     }
722
723     pub fn get_data_for_id(&self, _id: &NodeId) -> Data {
724         // FIXME
725         unimplemented!();
726     }
727
728     fn lookup_ref_id(&self, ref_id: NodeId) -> Option<DefId> {
729         if !self.tcx.def_map.borrow().contains_key(&ref_id) {
730             self.tcx.sess.bug(&format!("def_map has no key for {} in lookup_type_ref",
731                                        ref_id));
732         }
733         let def = self.tcx.def_map.borrow().get(&ref_id).unwrap().full_def();
734         match def {
735             Def::PrimTy(_) | Def::SelfTy(..) => None,
736             _ => Some(def.def_id()),
737         }
738     }
739
740     #[inline]
741     pub fn enclosing_scope(&self, id: NodeId) -> NodeId {
742         self.tcx.map.get_enclosing_scope(id).unwrap_or(0)
743     }
744 }
745
746 // An AST visitor for collecting paths from patterns.
747 struct PathCollector {
748     // The Row field identifies the kind of pattern.
749     collected_paths: Vec<(NodeId, ast::Path, ast::Mutability, recorder::Row)>,
750 }
751
752 impl PathCollector {
753     fn new() -> PathCollector {
754         PathCollector { collected_paths: vec![] }
755     }
756 }
757
758 impl<'v> Visitor<'v> for PathCollector {
759     fn visit_pat(&mut self, p: &ast::Pat) {
760         match p.node {
761             ast::PatStruct(ref path, _, _) => {
762                 self.collected_paths.push((p.id, path.clone(),
763                                            ast::Mutability::Mutable, recorder::TypeRef));
764             }
765             ast::PatEnum(ref path, _) |
766             ast::PatQPath(_, ref path) => {
767                 self.collected_paths.push((p.id, path.clone(),
768                                            ast::Mutability::Mutable, recorder::VarRef));
769             }
770             ast::PatIdent(bm, ref path1, _) => {
771                 debug!("PathCollector, visit ident in pat {}: {:?} {:?}",
772                        path1.node,
773                        p.span,
774                        path1.span);
775                 let immut = match bm {
776                     // Even if the ref is mut, you can't change the ref, only
777                     // the data pointed at, so showing the initialising expression
778                     // is still worthwhile.
779                     ast::BindingMode::ByRef(_) => ast::Mutability::Immutable,
780                     ast::BindingMode::ByValue(mt) => mt,
781                 };
782                 // collect path for either visit_local or visit_arm
783                 let path = ast_util::ident_to_path(path1.span, path1.node);
784                 self.collected_paths.push((p.id, path, immut, recorder::VarRef));
785             }
786             _ => {}
787         }
788         visit::walk_pat(self, p);
789     }
790 }
791
792 pub fn process_crate<'l, 'tcx>(tcx: &'l ty::ctxt<'tcx>,
793                                lcx: &'l lowering::LoweringContext<'l>,
794                                krate: &ast::Crate,
795                                analysis: &ty::CrateAnalysis,
796                                cratename: &str,
797                                odir: Option<&Path>) {
798     let _ignore = tcx.dep_graph.in_ignore();
799
800     assert!(analysis.glob_map.is_some());
801
802     info!("Dumping crate {}", cratename);
803
804     // find a path to dump our data to
805     let mut root_path = match env::var_os("DXR_RUST_TEMP_FOLDER") {
806         Some(val) => PathBuf::from(val),
807         None => match odir {
808             Some(val) => val.join("dxr"),
809             None => PathBuf::from("dxr-temp"),
810         },
811     };
812
813     if let Err(e) = fs::create_dir_all(&root_path) {
814         tcx.sess.err(&format!("Could not create directory {}: {}",
815                               root_path.display(),
816                               e));
817     }
818
819     {
820         let disp = root_path.display();
821         info!("Writing output to {}", disp);
822     }
823
824     // Create output file.
825     let executable = tcx.sess.crate_types.borrow().iter().any(|ct| *ct == CrateTypeExecutable);
826     let mut out_name = if executable {
827         "".to_owned()
828     } else {
829         "lib".to_owned()
830     };
831     out_name.push_str(&cratename);
832     out_name.push_str(&tcx.sess.opts.cg.extra_filename);
833     out_name.push_str(".csv");
834     root_path.push(&out_name);
835     let output_file = match File::create(&root_path) {
836         Ok(f) => box f,
837         Err(e) => {
838             let disp = root_path.display();
839             tcx.sess.fatal(&format!("Could not open {}: {}", disp, e));
840         }
841     };
842     root_path.pop();
843
844     let mut visitor = dump_csv::DumpCsvVisitor::new(tcx, lcx, analysis, output_file);
845
846     visitor.dump_crate_info(cratename, krate);
847     visit::walk_crate(&mut visitor, krate);
848 }
849
850 // Utility functions for the module.
851
852 // Helper function to escape quotes in a string
853 fn escape(s: String) -> String {
854     s.replace("\"", "\"\"")
855 }
856
857 // Helper function to determine if a span came from a
858 // macro expansion or syntax extension.
859 pub fn generated_code(span: Span) -> bool {
860     span.expn_id != NO_EXPANSION || span == DUMMY_SP
861 }