1 // Copyright 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.
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.
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
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 //! DumpCsvVisitor walks the AST and processes it.
31 use super::{escape, generated_code, recorder, SaveContext, PathCollector}
;
36 use middle
::ty
::{self, Ty}
;
43 use syntax
::ast
::{self, NodeId, DefId}
;
44 use syntax
::ast_map
::NodeItem
;
45 use syntax
::codemap
::*;
46 use syntax
::parse
::token
::{self, get_ident, keywords}
;
47 use syntax
::owned_slice
::OwnedSlice
;
48 use syntax
::visit
::{self, Visitor}
;
49 use syntax
::print
::pprust
::{path_to_string, ty_to_string}
;
52 use super::span_utils
::SpanUtils
;
53 use super::recorder
::{Recorder, FmtStrs}
;
58 pub struct DumpCsvVisitor
<'l
, 'tcx
: 'l
> {
59 save_ctxt
: SaveContext
<'l
, 'tcx
>,
61 analysis
: &'l ty
::CrateAnalysis
<'tcx
>,
69 impl <'l
, 'tcx
> DumpCsvVisitor
<'l
, 'tcx
> {
70 pub fn new(sess
: &'l Session
,
71 analysis
: &'l ty
::CrateAnalysis
<'tcx
>,
72 output_file
: Box
<File
>) -> DumpCsvVisitor
<'l
, 'tcx
> {
75 save_ctxt
: SaveContext
::new(sess
, analysis
, SpanUtils
{
77 err_count
: Cell
::new(0)
82 err_count
: Cell
::new(0)
84 fmt
: FmtStrs
::new(box Recorder
{
90 err_count
: Cell
::new(0)
96 fn nest
<F
>(&mut self, scope_id
: NodeId
, f
: F
) where
97 F
: FnOnce(&mut DumpCsvVisitor
<'l
, 'tcx
>),
99 let parent_scope
= self.cur_scope
;
100 self.cur_scope
= scope_id
;
102 self.cur_scope
= parent_scope
;
105 pub fn dump_crate_info(&mut self, name
: &str, krate
: &ast
::Crate
) {
106 // The current crate.
107 self.fmt
.crate_str(krate
.span
, name
);
109 // Dump info about all the external crates referenced from this crate.
110 for c
in &self.save_ctxt
.get_external_crates() {
111 self.fmt
.external_crate_str(krate
.span
, &c
.name
, c
.number
);
113 self.fmt
.recorder
.record("end_external_crates\n");
116 // Return all non-empty prefixes of a path.
117 // For each prefix, we return the span for the last segment in the prefix and
118 // a str representation of the entire prefix.
119 fn process_path_prefixes(&self, path
: &ast
::Path
) -> Vec
<(Span
, String
)> {
120 let spans
= self.span
.spans_for_path_segments(path
);
122 // Paths to enums seem to not match their spans - the span includes all the
123 // variants too. But they seem to always be at the end, so I hope we can cope with
124 // always using the first ones. So, only error out if we don't have enough spans.
125 // What could go wrong...?
126 if spans
.len() < path
.segments
.len() {
127 error
!("Mis-calculated spans for path '{}'. \
128 Found {} spans, expected {}. Found spans:",
129 path_to_string(path
), spans
.len(), path
.segments
.len());
131 let loc
= self.sess
.codemap().lookup_char_pos(s
.lo
);
132 error
!(" '{}' in {}, line {}",
133 self.span
.snippet(*s
), loc
.file
.name
, loc
.line
);
138 let mut result
: Vec
<(Span
, String
)> = vec
!();
140 let mut segs
= vec
!();
141 for (i
, (seg
, span
)) in path
.segments
.iter().zip(spans
.iter()).enumerate() {
142 segs
.push(seg
.clone());
143 let sub_path
= ast
::Path
{span
: *span
, // span for the last segment
146 let qualname
= if i
== 0 && path
.global
{
147 format
!("::{}", path_to_string(&sub_path
))
149 path_to_string(&sub_path
)
151 result
.push((*span
, qualname
));
152 segs
= sub_path
.segments
;
158 // The global arg allows us to override the global-ness of the path (which
159 // actually means 'does the path start with `::`', rather than 'is the path
160 // semantically global). We use the override for `use` imports (etc.) where
161 // the syntax is non-global, but the semantics are global.
162 fn write_sub_paths(&mut self, path
: &ast
::Path
, global
: bool
) {
163 let sub_paths
= self.process_path_prefixes(path
);
164 for (i
, &(ref span
, ref qualname
)) in sub_paths
.iter().enumerate() {
165 let qualname
= if i
== 0 && global
&& !path
.global
{
166 format
!("::{}", qualname
)
170 self.fmt
.sub_mod_ref_str(path
.span
,
177 // As write_sub_paths, but does not process the last ident in the path (assuming it
178 // will be processed elsewhere). See note on write_sub_paths about global.
179 fn write_sub_paths_truncated(&mut self, path
: &ast
::Path
, global
: bool
) {
180 let sub_paths
= self.process_path_prefixes(path
);
181 let len
= sub_paths
.len();
186 let sub_paths
= &sub_paths
[..len
-1];
187 for (i
, &(ref span
, ref qualname
)) in sub_paths
.iter().enumerate() {
188 let qualname
= if i
== 0 && global
&& !path
.global
{
189 format
!("::{}", qualname
)
193 self.fmt
.sub_mod_ref_str(path
.span
,
200 // As write_sub_paths, but expects a path of the form module_path::trait::method
201 // Where trait could actually be a struct too.
202 fn write_sub_path_trait_truncated(&mut self, path
: &ast
::Path
) {
203 let sub_paths
= self.process_path_prefixes(path
);
204 let len
= sub_paths
.len();
208 let sub_paths
= &sub_paths
[.. (len
-1)];
210 // write the trait part of the sub-path
211 let (ref span
, ref qualname
) = sub_paths
[len
-2];
212 self.fmt
.sub_type_ref_str(path
.span
,
216 // write the other sub-paths
220 let sub_paths
= &sub_paths
[..len
-2];
221 for &(ref span
, ref qualname
) in sub_paths
{
222 self.fmt
.sub_mod_ref_str(path
.span
,
229 // looks up anything, not just a type
230 fn lookup_type_ref(&self, ref_id
: NodeId
) -> Option
<DefId
> {
231 if !self.analysis
.ty_cx
.def_map
.borrow().contains_key(&ref_id
) {
232 self.sess
.bug(&format
!("def_map has no key for {} in lookup_type_ref",
235 let def
= self.analysis
.ty_cx
.def_map
.borrow().get(&ref_id
).unwrap().full_def();
237 def
::DefPrimTy(_
) => None
,
238 _
=> Some(def
.def_id()),
242 fn lookup_def_kind(&self, ref_id
: NodeId
, span
: Span
) -> Option
<recorder
::Row
> {
243 let def_map
= self.analysis
.ty_cx
.def_map
.borrow();
244 if !def_map
.contains_key(&ref_id
) {
245 self.sess
.span_bug(span
, &format
!("def_map has no key for {} in lookup_def_kind",
248 let def
= def_map
.get(&ref_id
).unwrap().full_def();
251 def
::DefForeignMod(_
) => Some(recorder
::ModRef
),
252 def
::DefStruct(_
) => Some(recorder
::StructRef
),
254 def
::DefAssociatedTy(..) |
255 def
::DefTrait(_
) => Some(recorder
::TypeRef
),
256 def
::DefStatic(_
, _
) |
258 def
::DefAssociatedConst(..) |
260 def
::DefVariant(_
, _
, _
) |
261 def
::DefUpvar(..) => Some(recorder
::VarRef
),
263 def
::DefFn(..) => Some(recorder
::FnRef
),
268 def
::DefTyParam(..) |
271 def
::DefPrimTy(_
) => {
272 self.sess
.span_bug(span
, &format
!("lookup_def_kind for unexpected item: {:?}",
278 fn process_formals(&mut self, formals
: &Vec
<ast
::Arg
>, qualname
: &str) {
280 self.visit_pat(&arg
.pat
);
281 let mut collector
= PathCollector
::new();
282 collector
.visit_pat(&arg
.pat
);
283 let span_utils
= self.span
.clone();
284 for &(id
, ref p
, _
, _
) in &collector
.collected_paths
{
287 &self.analysis
.ty_cx
,
288 *self.analysis
.ty_cx
.node_types().get(&id
).unwrap());
289 // get the span only for the name of the variable (I hope the path is only ever a
290 // variable name, but who knows?)
291 self.fmt
.formal_str(p
.span
,
292 span_utils
.span_for_last_ident(p
.span
),
301 fn process_method(&mut self, sig
: &ast
::MethodSig
,
302 body
: Option
<&ast
::Block
>,
303 id
: ast
::NodeId
, name
: ast
::Name
,
305 if generated_code(span
) {
309 debug
!("process_method: {}:{}", id
, token
::get_name(name
));
312 // The qualname for a method is the trait name or name of the struct in an impl in
313 // which the method is declared in, followed by the method's name.
314 let qualname
= match ty
::impl_of_method(&self.analysis
.ty_cx
,
315 ast_util
::local_def(id
)) {
316 Some(impl_id
) => match self.analysis
.ty_cx
.map
.get(impl_id
.node
) {
320 ast
::ItemImpl(_
, _
, _
, _
, ref ty
, _
) => {
321 let mut result
= String
::from_str("<");
322 result
.push_str(&ty_to_string(&**ty
));
324 match ty
::trait_of_item(&self.analysis
.ty_cx
,
325 ast_util
::local_def(id
)) {
327 result
.push_str(" as ");
329 &ty
::item_path_str(&self.analysis
.ty_cx
, def_id
));
333 result
.push_str(">");
337 self.sess
.span_bug(span
,
338 &format
!("Container {} for method {} not an impl?",
344 self.sess
.span_bug(span
,
345 &format
!("Container {} for method {} is not a node item {:?}",
346 impl_id
.node
, id
, self.analysis
.ty_cx
.map
.get(impl_id
.node
)));
349 None
=> match ty
::trait_of_item(&self.analysis
.ty_cx
,
350 ast_util
::local_def(id
)) {
352 scope_id
= def_id
.node
;
353 match self.analysis
.ty_cx
.map
.get(def_id
.node
) {
355 format
!("::{}", ty
::item_path_str(&self.analysis
.ty_cx
, def_id
))
358 self.sess
.span_bug(span
,
359 &format
!("Could not find container {} for method {}",
365 self.sess
.span_bug(span
,
366 &format
!("Could not find container for method {}", id
));
371 let qualname
= &format
!("{}::{}", qualname
, &token
::get_name(name
));
373 // record the decl for this def (if it has one)
374 let decl_id
= ty
::trait_item_of_item(&self.analysis
.ty_cx
,
375 ast_util
::local_def(id
))
377 let def_id
= new_id
.def_id();
378 if def_id
.node
!= 0 && def_id
!= ast_util
::local_def(id
) {
385 let sub_span
= self.span
.sub_span_after_keyword(span
, keywords
::Fn
);
387 self.fmt
.method_str(span
,
393 self.process_formals(&sig
.decl
.inputs
, qualname
);
395 self.fmt
.method_decl_str(span
,
402 // walk arg and return types
403 for arg
in &sig
.decl
.inputs
{
404 self.visit_ty(&arg
.ty
);
407 if let ast
::Return(ref ret_ty
) = sig
.decl
.output
{
408 self.visit_ty(ret_ty
);
412 if let Some(body
) = body
{
413 self.nest(id
, |v
| v
.visit_block(body
));
416 self.process_generic_params(&sig
.generics
,
422 fn process_trait_ref(&mut self,
423 trait_ref
: &ast
::TraitRef
) {
424 match self.lookup_type_ref(trait_ref
.ref_id
) {
426 let sub_span
= self.span
.sub_span_for_type_name(trait_ref
.path
.span
);
427 self.fmt
.ref_str(recorder
::TypeRef
,
432 visit
::walk_path(self, &trait_ref
.path
);
438 fn process_struct_field_def(&mut self,
439 field
: &ast
::StructField
,
442 match field
.node
.kind
{
443 ast
::NamedField(ident
, _
) => {
444 let name
= get_ident(ident
);
445 let qualname
= format
!("{}::{}", qualname
, name
);
448 &self.analysis
.ty_cx
,
449 *self.analysis
.ty_cx
.node_types().get(&field
.node
.id
).unwrap());
450 match self.span
.sub_span_before_token(field
.span
, token
::Colon
) {
451 Some(sub_span
) => self.fmt
.field_str(field
.span
,
458 None
=> self.sess
.span_bug(field
.span
,
459 &format
!("Could not find sub-span for field {}",
467 // Dump generic params bindings, then visit_generics
468 fn process_generic_params(&mut self,
469 generics
:&ast
::Generics
,
473 // We can't only use visit_generics since we don't have spans for param
474 // bindings, so we reparse the full_span to get those sub spans.
475 // However full span is the entire enum/fn/struct block, so we only want
476 // the first few to match the number of generics we're looking for.
477 let param_sub_spans
= self.span
.spans_for_ty_params(full_span
,
478 (generics
.ty_params
.len() as isize));
479 for (param
, param_ss
) in generics
.ty_params
.iter().zip(param_sub_spans
.iter()) {
480 // Append $id to name to make sure each one is unique
481 let name
= format
!("{}::{}${}",
483 escape(self.span
.snippet(*param_ss
)),
485 self.fmt
.typedef_str(full_span
,
491 self.visit_generics(generics
);
494 fn process_fn(&mut self,
497 ty_params
: &ast
::Generics
,
499 let fn_data
= self.save_ctxt
.get_item_data(item
);
500 if let super::Data
::FunctionData(fn_data
) = fn_data
{
501 self.fmt
.fn_str(item
.span
,
508 self.process_formals(&decl
.inputs
, &fn_data
.qualname
);
509 self.process_generic_params(ty_params
, item
.span
, &fn_data
.qualname
, item
.id
);
514 for arg
in &decl
.inputs
{
515 self.visit_ty(&arg
.ty
);
518 if let ast
::Return(ref ret_ty
) = decl
.output
{
519 self.visit_ty(&ret_ty
);
522 self.nest(item
.id
, |v
| v
.visit_block(&body
));
525 fn process_static_or_const_item(&mut self,
530 let var_data
= self.save_ctxt
.get_item_data(item
);
531 if let super::Data
::VariableData(var_data
) = var_data
{
532 self.fmt
.static_str(item
.span
,
538 &var_data
.type_value
,
545 self.visit_expr(expr
);
548 fn process_const(&mut self,
555 let qualname
= format
!("::{}", self.analysis
.ty_cx
.map
.path_to_string(id
));
557 let sub_span
= self.span
.sub_span_after_keyword(span
,
560 self.fmt
.static_str(span
,
563 &get_ident((*ident
).clone()),
565 &self.span
.snippet(expr
.span
),
566 &ty_to_string(&*typ
),
569 // walk type and init value
571 self.visit_expr(expr
);
574 fn process_struct(&mut self,
576 def
: &ast
::StructDef
,
577 ty_params
: &ast
::Generics
) {
578 let qualname
= format
!("::{}", self.analysis
.ty_cx
.map
.path_to_string(item
.id
));
580 let ctor_id
= match def
.ctor_id
{
581 Some(node_id
) => node_id
,
584 let val
= self.span
.snippet(item
.span
);
585 let sub_span
= self.span
.sub_span_after_keyword(item
.span
, keywords
::Struct
);
586 self.fmt
.struct_str(item
.span
,
595 for field
in &def
.fields
{
596 self.process_struct_field_def(field
, &qualname
[..], item
.id
);
597 self.visit_ty(&*field
.node
.ty
);
600 self.process_generic_params(ty_params
, item
.span
, &qualname
[..], item
.id
);
603 fn process_enum(&mut self,
605 enum_definition
: &ast
::EnumDef
,
606 ty_params
: &ast
::Generics
) {
607 let enum_name
= format
!("::{}", self.analysis
.ty_cx
.map
.path_to_string(item
.id
));
608 let val
= self.span
.snippet(item
.span
);
609 match self.span
.sub_span_after_keyword(item
.span
, keywords
::Enum
) {
610 Some(sub_span
) => self.fmt
.enum_str(item
.span
,
616 None
=> self.sess
.span_bug(item
.span
,
617 &format
!("Could not find subspan for enum {}",
620 for variant
in &enum_definition
.variants
{
621 let name
= get_ident(variant
.node
.name
);
623 let mut qualname
= enum_name
.clone();
624 qualname
.push_str("::");
625 qualname
.push_str(name
);
626 let val
= self.span
.snippet(variant
.span
);
627 match variant
.node
.kind
{
628 ast
::TupleVariantKind(ref args
) => {
629 // first ident in span is the variant's name
630 self.fmt
.tuple_variant_str(variant
.span
,
631 self.span
.span_for_first_ident(variant
.span
),
639 self.visit_ty(&*arg
.ty
);
642 ast
::StructVariantKind(ref struct_def
) => {
643 let ctor_id
= match struct_def
.ctor_id
{
644 Some(node_id
) => node_id
,
647 self.fmt
.struct_variant_str(
649 self.span
.span_for_first_ident(variant
.span
),
657 for field
in &struct_def
.fields
{
658 self.process_struct_field_def(field
, &qualname
, variant
.node
.id
);
659 self.visit_ty(&*field
.node
.ty
);
665 self.process_generic_params(ty_params
, item
.span
, &enum_name
[..], item
.id
);
668 fn process_impl(&mut self,
670 type_parameters
: &ast
::Generics
,
671 trait_ref
: &Option
<ast
::TraitRef
>,
673 impl_items
: &[P
<ast
::ImplItem
>]) {
674 let trait_id
= trait_ref
.as_ref().and_then(|tr
| self.lookup_type_ref(tr
.ref_id
));
676 // Common case impl for a struct or something basic.
677 ast
::TyPath(None
, ref path
) => {
678 let sub_span
= self.span
.sub_span_for_type_name(path
.span
);
679 let self_id
= self.lookup_type_ref(typ
.id
).map(|id
| {
680 self.fmt
.ref_str(recorder
::TypeRef
,
687 self.fmt
.impl_str(path
.span
,
695 // Less useful case, impl for a compound type.
696 self.visit_ty(&*typ
);
698 let sub_span
= self.span
.sub_span_for_type_name(typ
.span
);
699 self.fmt
.impl_str(typ
.span
,
709 Some(ref trait_ref
) => self.process_trait_ref(trait_ref
),
713 self.process_generic_params(type_parameters
, item
.span
, "", item
.id
);
714 for impl_item
in impl_items
{
715 self.visit_impl_item(impl_item
);
719 fn process_trait(&mut self,
721 generics
: &ast
::Generics
,
722 trait_refs
: &OwnedSlice
<ast
::TyParamBound
>,
723 methods
: &[P
<ast
::TraitItem
>]) {
724 let qualname
= format
!("::{}", self.analysis
.ty_cx
.map
.path_to_string(item
.id
));
725 let val
= self.span
.snippet(item
.span
);
726 let sub_span
= self.span
.sub_span_after_keyword(item
.span
, keywords
::Trait
);
727 self.fmt
.trait_str(item
.span
,
735 for super_bound
in &**trait_refs
{
736 let trait_ref
= match *super_bound
{
737 ast
::TraitTyParamBound(ref trait_ref
, _
) => {
740 ast
::RegionTyParamBound(..) => {
745 let trait_ref
= &trait_ref
.trait_ref
;
746 match self.lookup_type_ref(trait_ref
.ref_id
) {
748 let sub_span
= self.span
.sub_span_for_type_name(trait_ref
.path
.span
);
749 self.fmt
.ref_str(recorder
::TypeRef
,
754 self.fmt
.inherit_str(trait_ref
.path
.span
,
763 // walk generics and methods
764 self.process_generic_params(generics
, item
.span
, &qualname
[..], item
.id
);
765 for method
in methods
{
766 self.visit_trait_item(method
)
770 fn process_mod(&mut self,
771 item
: &ast
::Item
, // The module in question, represented as an item.
773 let qualname
= format
!("::{}", self.analysis
.ty_cx
.map
.path_to_string(item
.id
));
775 let cm
= self.sess
.codemap();
776 let filename
= cm
.span_to_filename(m
.inner
);
778 let sub_span
= self.span
.sub_span_after_keyword(item
.span
, keywords
::Mod
);
779 self.fmt
.mod_str(item
.span
,
786 self.nest(item
.id
, |v
| visit
::walk_mod(v
, m
));
789 fn process_path(&mut self,
793 ref_kind
: Option
<recorder
::Row
>) {
794 if generated_code(span
) {
798 let def_map
= self.analysis
.ty_cx
.def_map
.borrow();
799 if !def_map
.contains_key(&id
) {
800 self.sess
.span_bug(span
,
801 &format
!("def_map has no key for {} in visit_expr", id
));
803 let def
= def_map
.get(&id
).unwrap().full_def();
804 let sub_span
= self.span
.span_for_last_ident(span
);
810 def
::DefAssociatedConst(..) |
811 def
::DefVariant(..) => self.fmt
.ref_str(ref_kind
.unwrap_or(recorder
::VarRef
),
816 def
::DefStruct(def_id
) => self.fmt
.ref_str(recorder
::StructRef
,
821 def
::DefTy(def_id
, _
) => self.fmt
.ref_str(recorder
::TypeRef
,
826 def
::DefMethod(declid
, provenence
) => {
827 let sub_span
= self.span
.sub_span_for_meth_name(span
);
828 let defid
= if declid
.krate
== ast
::LOCAL_CRATE
{
829 let ti
= ty
::impl_or_trait_item(&self.analysis
.ty_cx
,
832 def
::FromTrait(def_id
) => {
833 Some(ty
::trait_items(&self.analysis
.ty_cx
,
837 mr
.name() == ti
.name()
842 def
::FromImpl(def_id
) => {
843 let impl_items
= self.analysis
847 Some(impl_items
.get(&def_id
)
851 ty
::impl_or_trait_item(
852 &self.analysis
.ty_cx
,
854 ).name() == ti
.name()
863 self.fmt
.meth_call_str(span
,
869 def
::DefFn(def_id
, _
) => {
870 self.fmt
.fn_call_str(span
,
875 _
=> self.sess
.span_bug(span
,
876 &format
!("Unexpected def kind while looking \
877 up path in `{}`: `{:?}`",
878 self.span
.snippet(span
),
881 // modules or types in the path prefix
883 def
::DefMethod(did
, _
) => {
884 let ti
= ty
::impl_or_trait_item(&self.analysis
.ty_cx
, did
);
885 if let ty
::MethodTraitItem(m
) = ti
{
886 if m
.explicit_self
== ty
::StaticExplicitSelfCategory
{
887 self.write_sub_path_trait_truncated(path
);
892 def
::DefStatic(_
,_
) |
894 def
::DefAssociatedConst(..) |
896 def
::DefVariant(..) |
897 def
::DefFn(..) => self.write_sub_paths_truncated(path
, false),
902 fn process_struct_lit(&mut self,
905 fields
: &Vec
<ast
::Field
>,
906 base
: &Option
<P
<ast
::Expr
>>) {
907 if generated_code(path
.span
) {
911 self.write_sub_paths_truncated(path
, false);
913 let ty
= &ty
::expr_ty_adjusted(&self.analysis
.ty_cx
, ex
).sty
;
914 let struct_def
= match *ty
{
915 ty
::ty_struct(def_id
, _
) => {
916 let sub_span
= self.span
.span_for_last_ident(path
.span
);
917 self.fmt
.ref_str(recorder
::StructRef
,
927 for field
in fields
{
929 Some(struct_def
) => {
930 let fields
= ty
::lookup_struct_fields(&self.analysis
.ty_cx
, struct_def
);
932 if generated_code(field
.ident
.span
) {
935 if f
.name
== field
.ident
.node
.name
{
936 // We don't really need a sub-span here, but no harm done
937 let sub_span
= self.span
.span_for_last_ident(field
.ident
.span
);
938 self.fmt
.ref_str(recorder
::VarRef
,
949 self.visit_expr(&*field
.expr
)
951 visit
::walk_expr_opt(self, base
)
954 fn process_method_call(&mut self,
956 args
: &Vec
<P
<ast
::Expr
>>) {
957 let method_map
= self.analysis
.ty_cx
.method_map
.borrow();
958 let method_callee
= method_map
.get(&ty
::MethodCall
::expr(ex
.id
)).unwrap();
959 let (def_id
, decl_id
) = match method_callee
.origin
{
960 ty
::MethodStatic(def_id
) |
961 ty
::MethodStaticClosure(def_id
) => {
962 // method invoked on an object with a concrete type (not a static method)
964 match ty
::trait_item_of_item(&self.analysis
.ty_cx
,
967 Some(decl_id
) => Some(decl_id
.def_id()),
970 // This incantation is required if the method referenced is a
971 // trait's default implementation.
972 let def_id
= match ty
::impl_or_trait_item(&self.analysis
975 ty
::MethodTraitItem(method
) => {
976 method
.provided_source
.unwrap_or(def_id
)
980 "save::process_method_call: non-method \
981 DefId in MethodStatic or MethodStaticClosure"),
983 (Some(def_id
), decl_id
)
985 ty
::MethodTypeParam(ref mp
) => {
986 // method invoked on a type parameter
987 let trait_item
= ty
::trait_item(&self.analysis
.ty_cx
,
990 (None
, Some(trait_item
.def_id()))
992 ty
::MethodTraitObject(ref mo
) => {
993 // method invoked on a trait instance
994 let trait_item
= ty
::trait_item(&self.analysis
.ty_cx
,
997 (None
, Some(trait_item
.def_id()))
1000 let sub_span
= self.span
.sub_span_for_meth_name(ex
.span
);
1001 self.fmt
.meth_call_str(ex
.span
,
1007 // walk receiver and args
1008 visit
::walk_exprs(self, &args
[..]);
1011 fn process_pat(&mut self, p
:&ast
::Pat
) {
1012 if generated_code(p
.span
) {
1017 ast
::PatStruct(ref path
, ref fields
, _
) => {
1018 visit
::walk_path(self, path
);
1020 let def
= self.analysis
.ty_cx
.def_map
.borrow().get(&p
.id
).unwrap().full_def();
1021 let struct_def
= match def
{
1022 def
::DefConst(..) | def
::DefAssociatedConst(..) => None
,
1023 def
::DefVariant(_
, variant_id
, _
) => Some(variant_id
),
1025 match ty
::ty_to_def_id(ty
::node_id_to_type(&self.analysis
.ty_cx
, p
.id
)) {
1027 self.sess
.span_bug(p
.span
,
1028 &format
!("Could not find struct_def for `{}`",
1029 self.span
.snippet(p
.span
)));
1031 Some(def_id
) => Some(def_id
),
1036 if let Some(struct_def
) = struct_def
{
1037 let struct_fields
= ty
::lookup_struct_fields(&self.analysis
.ty_cx
, struct_def
);
1038 for &Spanned { node: ref field, span }
in fields
{
1039 let sub_span
= self.span
.span_for_first_ident(span
);
1040 for f
in &struct_fields
{
1041 if f
.name
== field
.ident
.name
{
1042 self.fmt
.ref_str(recorder
::VarRef
,
1050 self.visit_pat(&*field
.pat
);
1054 _
=> visit
::walk_pat(self, p
)
1059 impl<'l
, 'tcx
, 'v
> Visitor
<'v
> for DumpCsvVisitor
<'l
, 'tcx
> {
1060 fn visit_item(&mut self, item
: &ast
::Item
) {
1061 if generated_code(item
.span
) {
1066 ast
::ItemUse(ref use_item
) => {
1067 match use_item
.node
{
1068 ast
::ViewPathSimple(ident
, ref path
) => {
1069 let sub_span
= self.span
.span_for_last_ident(path
.span
);
1070 let mod_id
= match self.lookup_type_ref(item
.id
) {
1072 match self.lookup_def_kind(item
.id
, path
.span
) {
1073 Some(kind
) => self.fmt
.ref_str(kind
,
1085 // 'use' always introduces an alias, if there is not an explicit
1086 // one, there is an implicit one.
1088 match self.span
.sub_span_after_keyword(use_item
.span
, keywords
::As
) {
1089 Some(sub_span
) => Some(sub_span
),
1093 self.fmt
.use_alias_str(path
.span
,
1099 self.write_sub_paths_truncated(path
, true);
1101 ast
::ViewPathGlob(ref path
) => {
1102 // Make a comma-separated list of names of imported modules.
1103 let mut name_string
= String
::new();
1104 let glob_map
= &self.analysis
.glob_map
;
1105 let glob_map
= glob_map
.as_ref().unwrap();
1106 if glob_map
.contains_key(&item
.id
) {
1107 for n
in glob_map
.get(&item
.id
).unwrap() {
1108 if !name_string
.is_empty() {
1109 name_string
.push_str(", ");
1111 name_string
.push_str(n
.as_str());
1115 let sub_span
= self.span
.sub_span_of_token(path
.span
,
1116 token
::BinOp(token
::Star
));
1117 self.fmt
.use_glob_str(path
.span
,
1122 self.write_sub_paths(path
, true);
1124 ast
::ViewPathList(ref path
, ref list
) => {
1127 ast
::PathListIdent { id, .. }
=> {
1128 match self.lookup_type_ref(id
) {
1130 match self.lookup_def_kind(id
, plid
.span
) {
1135 def_id
, self.cur_scope
);
1142 ast
::PathListMod { .. }
=> ()
1146 self.write_sub_paths(path
, true);
1150 ast
::ItemExternCrate(ref s
) => {
1151 let name
= get_ident(item
.ident
);
1153 let location
= match *s
{
1154 Some(s
) => s
.to_string(),
1155 None
=> name
.to_string(),
1157 let alias_span
= self.span
.span_for_last_ident(item
.span
);
1158 let cnum
= match self.sess
.cstore
.find_extern_mod_stmt_cnum(item
.id
) {
1162 self.fmt
.extern_crate_str(item
.span
,
1170 ast
::ItemFn(ref decl
, _
, _
, ref ty_params
, ref body
) =>
1171 self.process_fn(item
, &**decl
, ty_params
, &**body
),
1172 ast
::ItemStatic(ref typ
, _
, ref expr
) =>
1173 self.process_static_or_const_item(item
, typ
, expr
),
1174 ast
::ItemConst(ref typ
, ref expr
) =>
1175 self.process_static_or_const_item(item
, &typ
, &expr
),
1176 ast
::ItemStruct(ref def
, ref ty_params
) => self.process_struct(item
, &**def
, ty_params
),
1177 ast
::ItemEnum(ref def
, ref ty_params
) => self.process_enum(item
, def
, ty_params
),
1182 ref impl_items
) => {
1183 self.process_impl(item
,
1189 ast
::ItemTrait(_
, ref generics
, ref trait_refs
, ref methods
) =>
1190 self.process_trait(item
, generics
, trait_refs
, methods
),
1191 ast
::ItemMod(ref m
) => self.process_mod(item
, m
),
1192 ast
::ItemTy(ref ty
, ref ty_params
) => {
1193 let qualname
= format
!("::{}", self.analysis
.ty_cx
.map
.path_to_string(item
.id
));
1194 let value
= ty_to_string(&**ty
);
1195 let sub_span
= self.span
.sub_span_after_keyword(item
.span
, keywords
::Type
);
1196 self.fmt
.typedef_str(item
.span
,
1202 self.visit_ty(&**ty
);
1203 self.process_generic_params(ty_params
, item
.span
, &qualname
, item
.id
);
1205 ast
::ItemMac(_
) => (),
1206 _
=> visit
::walk_item(self, item
),
1210 fn visit_generics(&mut self, generics
: &ast
::Generics
) {
1211 for param
in &*generics
.ty_params
{
1212 for bound
in &*param
.bounds
{
1213 if let ast
::TraitTyParamBound(ref trait_ref
, _
) = *bound
{
1214 self.process_trait_ref(&trait_ref
.trait_ref
);
1217 if let Some(ref ty
) = param
.default {
1218 self.visit_ty(&**ty
);
1223 fn visit_trait_item(&mut self, trait_item
: &ast
::TraitItem
) {
1224 match trait_item
.node
{
1225 ast
::ConstTraitItem(ref ty
, Some(ref expr
)) => {
1226 self.process_const(trait_item
.id
, &trait_item
.ident
,
1227 trait_item
.span
, &*ty
, &*expr
);
1229 ast
::MethodTraitItem(ref sig
, ref body
) => {
1230 self.process_method(sig
, body
.as_ref().map(|x
| &**x
),
1231 trait_item
.id
, trait_item
.ident
.name
, trait_item
.span
);
1233 ast
::ConstTraitItem(_
, None
) |
1234 ast
::TypeTraitItem(..) => {}
1238 fn visit_impl_item(&mut self, impl_item
: &ast
::ImplItem
) {
1239 match impl_item
.node
{
1240 ast
::ConstImplItem(ref ty
, ref expr
) => {
1241 self.process_const(impl_item
.id
, &impl_item
.ident
,
1242 impl_item
.span
, &ty
, &expr
);
1244 ast
::MethodImplItem(ref sig
, ref body
) => {
1245 self.process_method(sig
, Some(body
), impl_item
.id
,
1246 impl_item
.ident
.name
, impl_item
.span
);
1248 ast
::TypeImplItem(_
) |
1249 ast
::MacImplItem(_
) => {}
1253 fn visit_ty(&mut self, t
: &ast
::Ty
) {
1254 if generated_code(t
.span
) {
1259 ast
::TyPath(_
, ref path
) => {
1260 match self.lookup_type_ref(t
.id
) {
1262 let sub_span
= self.span
.sub_span_for_type_name(t
.span
);
1263 self.fmt
.ref_str(recorder
::TypeRef
,
1272 self.write_sub_paths_truncated(path
, false);
1274 visit
::walk_path(self, path
);
1276 _
=> visit
::walk_ty(self, t
),
1280 fn visit_expr(&mut self, ex
: &ast
::Expr
) {
1281 if generated_code(ex
.span
) {
1286 ast
::ExprCall(ref _f
, ref _args
) => {
1287 // Don't need to do anything for function calls,
1288 // because just walking the callee path does what we want.
1289 visit
::walk_expr(self, ex
);
1291 ast
::ExprPath(_
, ref path
) => {
1292 self.process_path(ex
.id
, path
.span
, path
, None
);
1293 visit
::walk_expr(self, ex
);
1295 ast
::ExprStruct(ref path
, ref fields
, ref base
) =>
1296 self.process_struct_lit(ex
, path
, fields
, base
),
1297 ast
::ExprMethodCall(_
, _
, ref args
) => self.process_method_call(ex
, args
),
1298 ast
::ExprField(ref sub_ex
, ident
) => {
1299 if generated_code(sub_ex
.span
) {
1303 self.visit_expr(&**sub_ex
);
1304 let ty
= &ty
::expr_ty_adjusted(&self.analysis
.ty_cx
, &**sub_ex
).sty
;
1306 ty
::ty_struct(def_id
, _
) => {
1307 let fields
= ty
::lookup_struct_fields(&self.analysis
.ty_cx
, def_id
);
1309 if f
.name
== ident
.node
.name
{
1310 let sub_span
= self.span
.span_for_last_ident(ex
.span
);
1311 self.fmt
.ref_str(recorder
::VarRef
,
1320 _
=> self.sess
.span_bug(ex
.span
,
1321 &format
!("Expected struct type, found {:?}", ty
)),
1324 ast
::ExprTupField(ref sub_ex
, idx
) => {
1325 if generated_code(sub_ex
.span
) {
1329 self.visit_expr(&**sub_ex
);
1331 let ty
= &ty
::expr_ty_adjusted(&self.analysis
.ty_cx
, &**sub_ex
).sty
;
1333 ty
::ty_struct(def_id
, _
) => {
1334 let fields
= ty
::lookup_struct_fields(&self.analysis
.ty_cx
, def_id
);
1335 for (i
, f
) in fields
.iter().enumerate() {
1337 let sub_span
= self.span
.sub_span_after_token(ex
.span
, token
::Dot
);
1338 self.fmt
.ref_str(recorder
::VarRef
,
1348 _
=> self.sess
.span_bug(ex
.span
,
1349 &format
!("Expected struct or tuple \
1350 type, found {:?}", ty
)),
1353 ast
::ExprClosure(_
, ref decl
, ref body
) => {
1354 if generated_code(body
.span
) {
1358 let mut id
= String
::from_str("$");
1359 id
.push_str(&ex
.id
.to_string());
1360 self.process_formals(&decl
.inputs
, &id
[..]);
1362 // walk arg and return types
1363 for arg
in &decl
.inputs
{
1364 self.visit_ty(&*arg
.ty
);
1367 if let ast
::Return(ref ret_ty
) = decl
.output
{
1368 self.visit_ty(&**ret_ty
);
1372 self.nest(ex
.id
, |v
| v
.visit_block(&**body
));
1375 visit
::walk_expr(self, ex
)
1380 fn visit_mac(&mut self, _
: &ast
::Mac
) {
1381 // Just stop, macros are poison to us.
1384 fn visit_pat(&mut self, p
: &ast
::Pat
) {
1385 self.process_pat(p
);
1388 fn visit_arm(&mut self, arm
: &ast
::Arm
) {
1389 let mut collector
= PathCollector
::new();
1390 for pattern
in &arm
.pats
{
1391 // collect paths from the arm's patterns
1392 collector
.visit_pat(&pattern
);
1393 self.visit_pat(&pattern
);
1396 // This is to get around borrow checking, because we need mut self to call process_path.
1397 let mut paths_to_process
= vec
![];
1398 // process collected paths
1399 for &(id
, ref p
, immut
, ref_kind
) in &collector
.collected_paths
{
1400 let def_map
= self.analysis
.ty_cx
.def_map
.borrow();
1401 if !def_map
.contains_key(&id
) {
1402 self.sess
.span_bug(p
.span
,
1403 &format
!("def_map has no key for {} in visit_arm",
1406 let def
= def_map
.get(&id
).unwrap().full_def();
1408 def
::DefLocal(id
) => {
1409 let value
= if immut
== ast
::MutImmutable
{
1410 self.span
.snippet(p
.span
).to_string()
1412 "<mutable>".to_string()
1415 assert
!(p
.segments
.len() == 1, "qualified path for local variable def in arm");
1416 self.fmt
.variable_str(p
.span
,
1423 def
::DefVariant(..) | def
::DefTy(..) | def
::DefStruct(..) => {
1424 paths_to_process
.push((id
, p
.clone(), Some(ref_kind
)))
1426 // FIXME(nrc) what are these doing here?
1427 def
::DefStatic(_
, _
) |
1429 def
::DefAssociatedConst(..) => {}
1430 _
=> error
!("unexpected definition kind when processing collected paths: {:?}",
1434 for &(id
, ref path
, ref_kind
) in &paths_to_process
{
1435 self.process_path(id
, path
.span
, path
, ref_kind
);
1437 visit
::walk_expr_opt(self, &arm
.guard
);
1438 self.visit_expr(&*arm
.body
);
1441 fn visit_stmt(&mut self, s
: &ast
::Stmt
) {
1442 if generated_code(s
.span
) {
1446 visit
::walk_stmt(self, s
)
1449 fn visit_local(&mut self, l
: &ast
::Local
) {
1450 if generated_code(l
.span
) {
1454 // The local could declare multiple new vars, we must walk the
1455 // pattern and collect them all.
1456 let mut collector
= PathCollector
::new();
1457 collector
.visit_pat(&l
.pat
);
1458 self.visit_pat(&l
.pat
);
1460 let value
= self.span
.snippet(l
.span
);
1462 for &(id
, ref p
, immut
, _
) in &collector
.collected_paths
{
1463 let value
= if immut
== ast
::MutImmutable
{
1466 "<mutable>".to_string()
1468 let types
= self.analysis
.ty_cx
.node_types();
1469 let typ
= ppaux
::ty_to_string(&self.analysis
.ty_cx
, *types
.get(&id
).unwrap());
1470 // Get the span only for the name of the variable (I hope the path
1471 // is only ever a variable name, but who knows?).
1472 let sub_span
= self.span
.span_for_last_ident(p
.span
);
1473 // Rust uses the id of the pattern for var lookups, so we'll use it too.
1474 self.fmt
.variable_str(p
.span
,
1482 // Just walk the initialiser and type (don't want to walk the pattern again).
1483 visit
::walk_ty_opt(self, &l
.ty
);
1484 visit
::walk_expr_opt(self, &l
.init
);