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.
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.
13 use middle
::def_id
::DefId
;
16 use std
::fs
::{self, File}
;
17 use std
::path
::{Path, PathBuf}
;
20 use rustc_front
::{hir, lowering}
;
21 use rustc
::front
::map
::NodeItem
;
22 use rustc
::session
::config
::CrateType
::CrateTypeExecutable
;
24 use syntax
::ast
::{self, NodeId, PatKind}
;
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
;
31 use self::span_utils
::SpanUtils
;
39 pub struct SaveContext
<'l
, 'tcx
: 'l
> {
40 tcx
: &'l ty
::ctxt
<'tcx
>,
41 lcx
: &'l lowering
::LoweringContext
<'l
>,
42 span_utils
: SpanUtils
<'l
>,
45 pub struct CrateData
{
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.
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
),
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
),
80 /// Data for all kinds of functions and methods.
82 pub struct FunctionData
{
86 pub declaration
: Option
<DefId
>,
91 /// Data for local and global variables (consts and statics).
93 pub struct VariableData
{
100 pub type_value
: String
,
103 /// Data for modules.
108 pub qualname
: String
,
111 pub filename
: String
,
114 /// Data for enum declarations.
116 pub struct EnumData
{
119 pub qualname
: String
,
125 pub struct ImplData
{
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
132 pub trait_ref
: Option
<TypeRefData
>,
133 pub self_ref
: Option
<TypeRefData
>,
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)).
139 pub struct VariableRefData
{
146 /// Data for a reference to a type or trait.
148 pub struct TypeRefData
{
154 /// Data for a reference to a module.
156 pub struct ModRefData
{
162 /// Data about a function call.
164 pub struct FunctionCallData
{
170 /// Data about a method call.
172 pub struct MethodCallData
{
175 pub ref_id
: Option
<DefId
>,
176 pub decl_id
: Option
<DefId
>,
179 /// Data about a macro use.
181 pub struct MacroUseData
{
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
,
191 macro_rules
! option_try(
192 ($e
:expr
) => (match $e { Some(e) => e, None => return None }
)
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
)
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
> {
212 span_utils
: span_utils
,
216 // List external crates used by the current crate.
217 pub fn get_external_crates(&self) -> Vec
<CrateData
> {
218 let mut result
= Vec
::new();
220 for n
in self.tcx
.sess
.cstore
.crates() {
221 result
.push(CrateData
{
222 name
: self.tcx
.sess
.cstore
.crate_name(n
),
230 pub fn get_item_data(&self, item
: &ast
::Item
) -> Option
<Data
> {
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
{
242 span
: sub_span
.unwrap(),
243 scope
: self.enclosing_scope(item
.id
),
246 ast
::ItemKind
::Static(ref typ
, mt
, ref expr
) => {
247 let qualname
= format
!("::{}", self.tcx
.map
.path_to_string(item
.id
));
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
)
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
{
261 name
: item
.ident
.to_string(),
263 span
: sub_span
.unwrap(),
264 scope
: self.enclosing_scope(item
.id
),
266 type_value
: ty_to_string(&typ
),
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
{
275 name
: item
.ident
.to_string(),
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
),
283 ast
::ItemKind
::Mod(ref m
) => {
284 let qualname
= format
!("::{}", self.tcx
.map
.path_to_string(item
.id
));
286 let cm
= self.tcx
.sess
.codemap();
287 let filename
= cm
.span_to_filename(m
.inner
);
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
{
293 name
: item
.ident
.to_string(),
295 span
: sub_span
.unwrap(),
296 scope
: self.enclosing_scope(item
.id
),
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
{
308 span
: sub_span
.unwrap(),
310 scope
: self.enclosing_scope(item
.id
),
313 ast
::ItemKind
::Impl(_
, _
, _
, ref trait_ref
, ref typ
, _
) => {
314 let mut type_data
= None
;
317 let parent
= self.enclosing_scope(item
.id
);
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
| {
326 span
: sub_span
.unwrap(),
333 // Less useful case, impl for a compound type.
335 sub_span
= self.span_utils
.sub_span_for_type_name(span
).or(Some(span
));
339 let trait_data
= trait_ref
.as_ref()
340 .and_then(|tr
| self.get_trait_ref_data(tr
, parent
));
342 filter
!(self.span_utils
, sub_span
, typ
.span
, None
);
343 Some(Data
::ImplData(ImplData
{
345 span
: sub_span
.unwrap(),
347 trait_ref
: trait_data
,
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
);
368 name
: ident
.to_string(),
370 span
: sub_span
.unwrap(),
372 value
: "".to_owned(),
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
)) => {
390 hir
::ItemImpl(_
, _
, _
, _
, ref ty
, _
) => {
391 let mut result
= String
::from("<");
392 result
.push_str(&rustc_front
::print
::pprust
::ty_to_string(&ty
));
394 match self.tcx
.trait_of_item(self.tcx
.map
.local_def_id(id
)) {
396 result
.push_str(" as ");
397 result
.push_str(&self.tcx
.item_path_str(def_id
));
401 result
.push_str(">");
405 self.tcx
.sess
.span_bug(span
,
406 &format
!("Container {:?} for method {} not \
414 self.tcx
.sess
.span_bug(span
,
415 &format
!("Container {:?} for method {} is not a node \
422 None
=> match self.tcx
.trait_of_item(self.tcx
.map
.local_def_id(id
)) {
424 match self.tcx
.map
.get_if_local(def_id
) {
425 Some(NodeItem(_
)) => {
426 format
!("::{}", self.tcx
.item_path_str(def_id
))
429 self.tcx
.sess
.span_bug(span
,
430 &format
!("Could not find container {:?} for \
431 method {}, got {:?}",
439 self.tcx
.sess
.span_bug(span
,
440 &format
!("Could not find container for method {}", id
));
445 let qualname
= format
!("{}::{}", qualname
, name
);
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
{
457 let sub_span
= self.span_utils
.sub_span_after_keyword(span
, keywords
::Fn
);
458 filter
!(self.span_utils
, sub_span
, span
, None
);
461 name
: name
.to_string(),
463 declaration
: decl_id
,
464 span
: sub_span
.unwrap(),
465 scope
: self.enclosing_scope(id
),
469 pub fn get_trait_ref_data(&self,
470 trait_ref
: &ast
::TraitRef
,
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
);
478 span
: sub_span
.unwrap(),
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
{
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
),
507 debug
!("Expected struct type, found {:?}", ty
);
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
),
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
);
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
)),
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(),
549 ast
::ExprKind
::Path(_
, ref path
) => {
550 self.get_path_data(expr
.id
, path
)
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
));
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
);
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(),
582 Def
::Struct(def_id
) |
584 Def
::TyAlias(def_id
) |
586 Def
::TyParam(_
, _
, def_id
, _
) => {
587 Some(Data
::TypeRefData(TypeRefData
{
588 span
: sub_span
.unwrap(),
590 scope
: self.enclosing_scope(id
),
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
) => {
603 .find(|mr
| mr
.name() == ti
.name() && self.trait_method_has_body(mr
))
604 .map(|mr
| mr
.def_id())
606 ty
::ImplContainer(def_id
) => {
607 let impl_items
= self.tcx
.impl_items
.borrow();
608 Some(impl_items
.get(&def_id
)
612 self.tcx
.impl_or_trait_item(mr
.def_id()).name() ==
622 Some(Data
::MethodCallData(MethodCallData
{
623 span
: sub_span
.unwrap(),
624 scope
: self.enclosing_scope(id
),
626 decl_id
: Some(decl_id
),
630 Some(Data
::FunctionCallData(FunctionCallData
{
632 span
: sub_span
.unwrap(),
633 scope
: self.enclosing_scope(id
),
636 Def
::Mod(def_id
) => {
637 Some(Data
::ModRefData(ModRefData
{
639 span
: sub_span
.unwrap(),
640 scope
: self.enclosing_scope(id
),
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
{
661 pub fn get_field_ref_data(&self,
662 field_ref
: &ast
::Field
,
663 variant
: ty
::VariantDef
,
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(),
678 /// Attempt to return MacroUseData for any AST node.
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
) {
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
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
);
695 // Ignore attribute macros, their spans are usually mangled
696 if let MacroAttribute(_
) = callee
.format
{
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
{
707 name
: mac_name
.clone(),
708 callee_span
: mac_span
,
709 scope
: self.enclosing_scope(id
),
716 name
: callee
.name().to_string(),
717 callee_span
: callee_span
,
718 scope
: self.enclosing_scope(id
),
723 pub fn get_data_for_id(&self, _id
: &NodeId
) -> Data
{
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",
733 let def
= self.tcx
.def_map
.borrow().get(&ref_id
).unwrap().full_def();
735 Def
::PrimTy(_
) | Def
::SelfTy(..) => None
,
736 _
=> Some(def
.def_id()),
741 pub fn enclosing_scope(&self, id
: NodeId
) -> NodeId
{
742 self.tcx
.map
.get_enclosing_scope(id
).unwrap_or(0)
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
)>,
753 fn new() -> PathCollector
{
754 PathCollector { collected_paths: vec![] }
758 impl<'v
> Visitor
<'v
> for PathCollector
{
759 fn visit_pat(&mut self, p
: &ast
::Pat
) {
761 PatKind
::Struct(ref path
, _
, _
) => {
762 self.collected_paths
.push((p
.id
, path
.clone(),
763 ast
::Mutability
::Mutable
, recorder
::TypeRef
));
765 PatKind
::TupleStruct(ref path
, _
) |
766 PatKind
::Path(ref path
) |
767 PatKind
::QPath(_
, ref path
) => {
768 self.collected_paths
.push((p
.id
, path
.clone(),
769 ast
::Mutability
::Mutable
, recorder
::VarRef
));
771 PatKind
::Ident(bm
, ref path1
, _
) => {
772 debug
!("PathCollector, visit ident in pat {}: {:?} {:?}",
776 let immut
= match bm
{
777 // Even if the ref is mut, you can't change the ref, only
778 // the data pointed at, so showing the initialising expression
779 // is still worthwhile.
780 ast
::BindingMode
::ByRef(_
) => ast
::Mutability
::Immutable
,
781 ast
::BindingMode
::ByValue(mt
) => mt
,
783 // collect path for either visit_local or visit_arm
784 let path
= ast_util
::ident_to_path(path1
.span
, path1
.node
);
785 self.collected_paths
.push((p
.id
, path
, immut
, recorder
::VarRef
));
789 visit
::walk_pat(self, p
);
793 pub fn process_crate
<'l
, 'tcx
>(tcx
: &'l ty
::ctxt
<'tcx
>,
794 lcx
: &'l lowering
::LoweringContext
<'l
>,
796 analysis
: &ty
::CrateAnalysis
,
798 odir
: Option
<&Path
>) {
799 let _ignore
= tcx
.dep_graph
.in_ignore();
801 assert
!(analysis
.glob_map
.is_some());
803 info
!("Dumping crate {}", cratename
);
805 // find a path to dump our data to
806 let mut root_path
= match env
::var_os("DXR_RUST_TEMP_FOLDER") {
807 Some(val
) => PathBuf
::from(val
),
809 Some(val
) => val
.join("dxr"),
810 None
=> PathBuf
::from("dxr-temp"),
814 if let Err(e
) = fs
::create_dir_all(&root_path
) {
815 tcx
.sess
.err(&format
!("Could not create directory {}: {}",
821 let disp
= root_path
.display();
822 info
!("Writing output to {}", disp
);
825 // Create output file.
826 let executable
= tcx
.sess
.crate_types
.borrow().iter().any(|ct
| *ct
== CrateTypeExecutable
);
827 let mut out_name
= if executable
{
832 out_name
.push_str(&cratename
);
833 out_name
.push_str(&tcx
.sess
.opts
.cg
.extra_filename
);
834 out_name
.push_str(".csv");
835 root_path
.push(&out_name
);
836 let output_file
= match File
::create(&root_path
) {
839 let disp
= root_path
.display();
840 tcx
.sess
.fatal(&format
!("Could not open {}: {}", disp
, e
));
845 let mut visitor
= dump_csv
::DumpCsvVisitor
::new(tcx
, lcx
, analysis
, output_file
);
847 visitor
.dump_crate_info(cratename
, krate
);
848 visit
::walk_crate(&mut visitor
, krate
);
851 // Utility functions for the module.
853 // Helper function to escape quotes in a string
854 fn escape(s
: String
) -> String
{
855 s
.replace("\"", "\"\"")
858 // Helper function to determine if a span came from a
859 // macro expansion or syntax extension.
860 pub fn generated_code(span
: Span
) -> bool
{
861 span
.expn_id
!= NO_EXPANSION
|| span
== DUMMY_SP