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 //! Write the output of rustc's analysis to an implementor of Dump.
13 //! Dumping the analysis is implemented by walking the AST and getting a bunch of
14 //! info out from all over the place. We use Def IDs to identify objects. The
15 //! tricky part is getting syntactic (span, source text) and semantic (reference
16 //! Def IDs) information for parts of expressions which the compiler has discarded.
17 //! E.g., in a path `foo::bar::baz`, the compiler only keeps a span for the whole
18 //! path and a reference to `baz`, but we want spans and references for all three
21 //! SpanUtils is used to manipulate spans. In particular, to extract sub-spans
22 //! from spans (e.g., the span for `bar` from the above example path).
23 //! DumpVisitor walks the AST and processes it, and an implementor of Dump
24 //! is used for recording the output in a format-agnostic way (see CsvDumper
27 use rustc
::hir
::def
::Def
as HirDef
;
28 use rustc
::hir
::def_id
::DefId
;
29 use rustc
::hir
::map
::Node
;
30 use rustc
::ty
::{self, TyCtxt}
;
31 use rustc_data_structures
::fx
::FxHashSet
;
35 use syntax
::ast
::{self, Attribute, NodeId, PatKind, CRATE_NODE_ID}
;
36 use syntax
::parse
::token
;
37 use syntax
::symbol
::keywords
;
38 use syntax
::visit
::{self, Visitor}
;
39 use syntax
::print
::pprust
::{
41 generic_params_to_string
,
46 use syntax
::codemap
::{Spanned, DUMMY_SP}
;
49 use {escape, generated_code, lower_attributes, PathCollector, SaveContext}
;
50 use json_dumper
::{Access, DumpOutput, JsonDumper}
;
51 use span_utils
::SpanUtils
;
54 use rls_data
::{CratePreludeData
, Def
, DefKind
, GlobalCrateId
, Import
, ImportKind
, Ref
, RefKind
,
55 Relation
, RelationKind
, SpanData
};
57 macro_rules
! down_cast_data
{
58 ($id
:ident
, $kind
:ident
, $sp
:expr
) => {
59 let $id
= if let super::Data
::$
kind(data
) = $id
{
62 span_bug
!($sp
, "unexpected data kind: {:?}", $id
);
67 macro_rules
! access_from
{
68 ($save_ctxt
:expr
, $item
:expr
) => {
70 public
: $item
.vis
== ast
::Visibility
::Public
,
71 reachable
: $save_ctxt
.analysis
.access_levels
.is_reachable($item
.id
),
76 pub struct DumpVisitor
<'l
, 'tcx
: 'l
, 'll
, O
: DumpOutput
+ 'll
> {
77 save_ctxt
: SaveContext
<'l
, 'tcx
>,
78 tcx
: TyCtxt
<'l
, 'tcx
, 'tcx
>,
79 dumper
: &'ll
mut JsonDumper
<O
>,
85 // Set of macro definition (callee) spans, and the set
86 // of macro use (callsite) spans. We store these to ensure
87 // we only write one macro def per unique macro definition, and
88 // one macro use per unique callsite span.
89 // mac_defs: HashSet<Span>,
90 macro_calls
: FxHashSet
<Span
>,
93 impl<'l
, 'tcx
: 'l
, 'll
, O
: DumpOutput
+ 'll
> DumpVisitor
<'l
, 'tcx
, 'll
, O
> {
95 save_ctxt
: SaveContext
<'l
, 'tcx
>,
96 dumper
: &'ll
mut JsonDumper
<O
>,
97 ) -> DumpVisitor
<'l
, 'tcx
, 'll
, O
> {
98 let span_utils
= SpanUtils
::new(&save_ctxt
.tcx
.sess
);
103 span
: span_utils
.clone(),
104 cur_scope
: CRATE_NODE_ID
,
105 // mac_defs: HashSet::new(),
106 macro_calls
: FxHashSet(),
110 fn nest_scope
<F
>(&mut self, scope_id
: NodeId
, f
: F
)
112 F
: FnOnce(&mut DumpVisitor
<'l
, 'tcx
, 'll
, O
>),
114 let parent_scope
= self.cur_scope
;
115 self.cur_scope
= scope_id
;
117 self.cur_scope
= parent_scope
;
120 fn nest_tables
<F
>(&mut self, item_id
: NodeId
, f
: F
)
122 F
: FnOnce(&mut DumpVisitor
<'l
, 'tcx
, 'll
, O
>),
124 let item_def_id
= self.tcx
.hir
.local_def_id(item_id
);
125 if self.tcx
.has_typeck_tables(item_def_id
) {
126 let tables
= self.tcx
.typeck_tables_of(item_def_id
);
127 let old_tables
= self.save_ctxt
.tables
;
128 self.save_ctxt
.tables
= tables
;
130 self.save_ctxt
.tables
= old_tables
;
136 fn span_from_span(&self, span
: Span
) -> SpanData
{
137 self.save_ctxt
.span_from_span(span
)
140 pub fn dump_crate_info(&mut self, name
: &str, krate
: &ast
::Crate
) {
141 let source_file
= self.tcx
.sess
.local_crate_source_file
.as_ref();
142 let crate_root
= source_file
.map(|source_file
| {
143 let source_file
= Path
::new(source_file
);
144 match source_file
.file_name() {
145 Some(_
) => source_file
.parent().unwrap().display().to_string(),
146 None
=> source_file
.display().to_string(),
150 let data
= CratePreludeData
{
151 crate_id
: GlobalCrateId
{
153 disambiguator
: self.tcx
155 .local_crate_disambiguator()
159 crate_root
: crate_root
.unwrap_or("<no source>".to_owned()),
160 external_crates
: self.save_ctxt
.get_external_crates(),
161 span
: self.span_from_span(krate
.span
),
164 self.dumper
.crate_prelude(data
);
167 // Return all non-empty prefixes of a path.
168 // For each prefix, we return the span for the last segment in the prefix and
169 // a str representation of the entire prefix.
170 fn process_path_prefixes(&self, path
: &ast
::Path
) -> Vec
<(Span
, String
)> {
171 let segments
= &path
.segments
[if path
.is_global() { 1 }
else { 0 }
..];
173 let mut result
= Vec
::with_capacity(segments
.len());
175 let mut segs
= vec
![];
176 for (i
, seg
) in segments
.iter().enumerate() {
177 segs
.push(seg
.clone());
178 let sub_path
= ast
::Path
{
179 span
: seg
.span
, // span for the last segment
182 let qualname
= if i
== 0 && path
.is_global() {
183 format
!("::{}", path_to_string(&sub_path
))
185 path_to_string(&sub_path
)
187 result
.push((seg
.span
, qualname
));
188 segs
= sub_path
.segments
;
194 fn write_sub_paths(&mut self, path
: &ast
::Path
) {
195 let sub_paths
= self.process_path_prefixes(path
);
196 for (span
, _
) in sub_paths
{
197 let span
= self.span_from_span(span
);
198 self.dumper
.dump_ref(Ref
{
206 // As write_sub_paths, but does not process the last ident in the path (assuming it
207 // will be processed elsewhere). See note on write_sub_paths about global.
208 fn write_sub_paths_truncated(&mut self, path
: &ast
::Path
) {
209 let sub_paths
= self.process_path_prefixes(path
);
210 let len
= sub_paths
.len();
215 for (span
, _
) in sub_paths
.into_iter().take(len
- 1) {
216 let span
= self.span_from_span(span
);
217 self.dumper
.dump_ref(Ref
{
225 // As write_sub_paths, but expects a path of the form module_path::trait::method
226 // Where trait could actually be a struct too.
227 fn write_sub_path_trait_truncated(&mut self, path
: &ast
::Path
) {
228 let sub_paths
= self.process_path_prefixes(path
);
229 let len
= sub_paths
.len();
233 let sub_paths
= &sub_paths
[..(len
- 1)];
235 // write the trait part of the sub-path
236 let (ref span
, _
) = sub_paths
[len
- 2];
237 let span
= self.span_from_span(*span
);
238 self.dumper
.dump_ref(Ref
{
244 // write the other sub-paths
248 let sub_paths
= &sub_paths
[..len
- 2];
249 for &(ref span
, _
) in sub_paths
{
250 let span
= self.span_from_span(*span
);
251 self.dumper
.dump_ref(Ref
{
259 fn lookup_def_id(&self, ref_id
: NodeId
) -> Option
<DefId
> {
260 match self.save_ctxt
.get_path_def(ref_id
) {
261 HirDef
::PrimTy(..) | HirDef
::SelfTy(..) | HirDef
::Err
=> None
,
262 def
=> Some(def
.def_id()),
270 sub_span
: Option
<Span
>,
273 if self.span
.filter_generated(sub_span
, span
) {
277 let def
= self.save_ctxt
.get_path_def(ref_id
);
280 let span
= self.span_from_span(sub_span
.expect("No span found for mod ref"));
281 self.dumper
.dump_ref(Ref
{
284 ref_id
: ::id_from_def_id(def_id
),
288 HirDef
::Variant(..) |
291 HirDef
::TyAlias(..) |
292 HirDef
::TyForeign(..) |
293 HirDef
::TraitAlias(..) |
294 HirDef
::Trait(_
) => {
295 let span
= self.span_from_span(sub_span
.expect("No span found for type ref"));
296 self.dumper
.dump_ref(Ref
{
299 ref_id
: ::id_from_def_id(def_id
),
304 HirDef
::StructCtor(..) |
305 HirDef
::VariantCtor(..) => {
306 let span
= self.span_from_span(sub_span
.expect("No span found for var ref"));
307 self.dumper
.dump_ref(Ref
{
308 kind
: RefKind
::Variable
,
310 ref_id
: ::id_from_def_id(def_id
),
314 let span
= self.span_from_span(sub_span
.expect("No span found for fn ref"));
315 self.dumper
.dump_ref(Ref
{
316 kind
: RefKind
::Function
,
318 ref_id
: ::id_from_def_id(def_id
),
321 // With macros 2.0, we can legitimately get a ref to a macro, but
322 // we don't handle it properly for now (FIXME).
323 HirDef
::Macro(..) => {}
328 HirDef
::TyParam(..) |
330 HirDef
::AssociatedTy(..) |
331 HirDef
::AssociatedConst(..) |
333 HirDef
::GlobalAsm(_
) |
335 span_bug
!(span
, "process_def_kind for unexpected item: {:?}", def
);
340 fn process_formals(&mut self, formals
: &'l
[ast
::Arg
], qualname
: &str) {
342 self.visit_pat(&arg
.pat
);
343 let mut collector
= PathCollector
::new();
344 collector
.visit_pat(&arg
.pat
);
345 let span_utils
= self.span
.clone();
347 for (id
, i
, sp
, ..) in collector
.collected_idents
{
348 let hir_id
= self.tcx
.hir
.node_to_hir_id(id
);
349 let typ
= match self.save_ctxt
.tables
.node_id_to_type_opt(hir_id
) {
350 Some(s
) => s
.to_string(),
353 let sub_span
= span_utils
.span_for_last_ident(sp
);
354 if !self.span
.filter_generated(sub_span
, sp
) {
355 let id
= ::id_from_node_id(id
, &self.save_ctxt
);
356 let span
= self.span_from_span(sub_span
.expect("No span found for variable"));
358 self.dumper
.dump_def(
364 kind
: DefKind
::Local
,
368 qualname
: format
!("{}::{}", qualname
, i
.to_string()),
385 sig
: &'l ast
::MethodSig
,
386 body
: Option
<&'l ast
::Block
>,
389 generics
: &'l ast
::Generics
,
390 vis
: ast
::Visibility
,
393 debug
!("process_method: {}:{}", id
, name
);
395 if let Some(mut method_data
) = self.save_ctxt
.get_method_data(id
, name
.name
, span
) {
396 let sig_str
= ::make_signature(&sig
.decl
, &generics
);
400 |v
| v
.process_formals(&sig
.decl
.inputs
, &method_data
.qualname
),
404 self.process_generic_params(&generics
, span
, &method_data
.qualname
, id
);
406 method_data
.value
= sig_str
;
407 method_data
.sig
= sig
::method_signature(id
, name
, generics
, sig
, &self.save_ctxt
);
408 self.dumper
.dump_def(
410 public
: vis
== ast
::Visibility
::Public
,
411 reachable
: self.save_ctxt
.analysis
.access_levels
.is_reachable(id
),
416 // walk arg and return types
417 for arg
in &sig
.decl
.inputs
{
418 self.visit_ty(&arg
.ty
);
421 if let ast
::FunctionRetTy
::Ty(ref ret_ty
) = sig
.decl
.output
{
422 self.visit_ty(ret_ty
);
426 if let Some(body
) = body
{
427 self.nest_tables(id
, |v
| v
.nest_scope(id
, |v
| v
.visit_block(body
)));
431 fn process_struct_field_def(&mut self, field
: &ast
::StructField
, parent_id
: NodeId
) {
432 let field_data
= self.save_ctxt
.get_field_data(field
, parent_id
);
433 if let Some(field_data
) = field_data
{
434 self.dumper
.dump_def(&access_from
!(self.save_ctxt
, field
), field_data
);
438 // Dump generic params bindings, then visit_generics
439 fn process_generic_params(
441 generics
: &'l ast
::Generics
,
446 for param
in &generics
.params
{
447 if let ast
::GenericParam
::Type(ref ty_param
) = *param
{
448 let param_ss
= ty_param
.span
;
449 let name
= escape(self.span
.snippet(param_ss
));
450 // Append $id to name to make sure each one is unique
451 let qualname
= format
!("{}::{}${}", prefix
, name
, id
);
452 if !self.span
.filter_generated(Some(param_ss
), full_span
) {
453 let id
= ::id_from_node_id(ty_param
.id
, &self.save_ctxt
);
454 let span
= self.span_from_span(param_ss
);
456 self.dumper
.dump_def(
467 value
: String
::new(),
479 self.visit_generics(generics
);
485 decl
: &'l ast
::FnDecl
,
486 ty_params
: &'l ast
::Generics
,
487 body
: &'l ast
::Block
,
489 if let Some(fn_data
) = self.save_ctxt
.get_item_data(item
) {
490 down_cast_data
!(fn_data
, DefData
, item
.span
);
493 |v
| v
.process_formals(&decl
.inputs
, &fn_data
.qualname
),
495 self.process_generic_params(ty_params
, item
.span
, &fn_data
.qualname
, item
.id
);
496 self.dumper
.dump_def(&access_from
!(self.save_ctxt
, item
), fn_data
);
499 for arg
in &decl
.inputs
{
500 self.visit_ty(&arg
.ty
);
503 if let ast
::FunctionRetTy
::Ty(ref ret_ty
) = decl
.output
{
504 self.visit_ty(&ret_ty
);
507 self.nest_tables(item
.id
, |v
| v
.nest_scope(item
.id
, |v
| v
.visit_block(&body
)));
510 fn process_static_or_const_item(
516 self.nest_tables(item
.id
, |v
| {
517 if let Some(var_data
) = v
.save_ctxt
.get_item_data(item
) {
518 down_cast_data
!(var_data
, DefData
, item
.span
);
519 v
.dumper
.dump_def(&access_from
!(v
.save_ctxt
, item
), var_data
);
526 fn process_assoc_const(
532 expr
: Option
<&'l ast
::Expr
>,
534 vis
: ast
::Visibility
,
535 attrs
: &'l
[Attribute
],
537 let qualname
= format
!("::{}", self.tcx
.node_path_str(id
));
539 let sub_span
= self.span
.sub_span_after_keyword(span
, keywords
::Const
);
541 if !self.span
.filter_generated(sub_span
, span
) {
542 let sig
= sig
::assoc_const_signature(id
, name
, typ
, expr
, &self.save_ctxt
);
543 let span
= self.span_from_span(sub_span
.expect("No span found for variable"));
545 self.dumper
.dump_def(
547 public
: vis
== ast
::Visibility
::Public
,
548 reachable
: self.save_ctxt
.analysis
.access_levels
.is_reachable(id
),
551 kind
: DefKind
::Const
,
552 id
: ::id_from_node_id(id
, &self.save_ctxt
),
554 name
: name
.to_string(),
556 value
: ty_to_string(&typ
),
557 parent
: Some(::id_from_def_id(parent_id
)),
560 docs
: self.save_ctxt
.docs_for_attrs(attrs
),
562 attributes
: lower_attributes(attrs
.to_owned(), &self.save_ctxt
),
567 // walk type and init value
569 if let Some(expr
) = expr
{
570 self.visit_expr(expr
);
574 // FIXME tuple structs should generate tuple-specific data.
578 def
: &'l ast
::VariantData
,
579 ty_params
: &'l ast
::Generics
,
581 debug
!("process_struct {:?} {:?}", item
, item
.span
);
582 let name
= item
.ident
.to_string();
583 let qualname
= format
!("::{}", self.tcx
.node_path_str(item
.id
));
585 let (kind
, keyword
) = match item
.node
{
586 ast
::ItemKind
::Struct(_
, _
) => (DefKind
::Struct
, keywords
::Struct
),
587 ast
::ItemKind
::Union(_
, _
) => (DefKind
::Union
, keywords
::Union
),
591 let sub_span
= self.span
.sub_span_after_keyword(item
.span
, keyword
);
592 let (value
, fields
) = match item
.node
{
593 ast
::ItemKind
::Struct(ast
::VariantData
::Struct(ref fields
, _
), _
) |
594 ast
::ItemKind
::Union(ast
::VariantData
::Struct(ref fields
, _
), _
) => {
595 let include_priv_fields
= !self.save_ctxt
.config
.pub_only
;
596 let fields_str
= fields
599 .filter_map(|(i
, f
)| {
600 if include_priv_fields
|| f
.vis
== ast
::Visibility
::Public
{
602 .map(|i
| i
.to_string())
603 .or_else(|| Some(i
.to_string()))
610 let value
= format
!("{} {{ {} }}", name
, fields_str
);
615 .map(|f
| ::id_from_node_id(f
.id
, &self.save_ctxt
))
619 _
=> (String
::new(), vec
![]),
622 if !self.span
.filter_generated(sub_span
, item
.span
) {
623 let span
= self.span_from_span(sub_span
.expect("No span found for struct"));
624 self.dumper
.dump_def(
625 &access_from
!(self.save_ctxt
, item
),
628 id
: ::id_from_node_id(item
.id
, &self.save_ctxt
),
631 qualname
: qualname
.clone(),
636 docs
: self.save_ctxt
.docs_for_attrs(&item
.attrs
),
637 sig
: sig
::item_signature(item
, &self.save_ctxt
),
638 attributes
: lower_attributes(item
.attrs
.clone(), &self.save_ctxt
),
643 for field
in def
.fields() {
644 self.process_struct_field_def(field
, item
.id
);
645 self.visit_ty(&field
.ty
);
648 self.process_generic_params(ty_params
, item
.span
, &qualname
, item
.id
);
654 enum_definition
: &'l ast
::EnumDef
,
655 ty_params
: &'l ast
::Generics
,
657 let enum_data
= self.save_ctxt
.get_item_data(item
);
658 let enum_data
= match enum_data
{
662 down_cast_data
!(enum_data
, DefData
, item
.span
);
664 let access
= access_from
!(self.save_ctxt
, item
);
666 for variant
in &enum_definition
.variants
{
667 let name
= variant
.node
.name
.name
.to_string();
668 let mut qualname
= enum_data
.qualname
.clone();
669 qualname
.push_str("::");
670 qualname
.push_str(&name
);
672 match variant
.node
.data
{
673 ast
::VariantData
::Struct(ref fields
, _
) => {
674 let sub_span
= self.span
.span_for_first_ident(variant
.span
);
675 let fields_str
= fields
679 f
.ident
.map(|i
| i
.to_string()).unwrap_or(i
.to_string())
683 let value
= format
!("{}::{} {{ {} }}", enum_data
.name
, name
, fields_str
);
684 if !self.span
.filter_generated(sub_span
, variant
.span
) {
686 .span_from_span(sub_span
.expect("No span found for struct variant"));
687 let id
= ::id_from_node_id(variant
.node
.data
.id(), &self.save_ctxt
);
688 let parent
= Some(::id_from_node_id(item
.id
, &self.save_ctxt
));
690 self.dumper
.dump_def(
693 kind
: DefKind
::StructVariant
,
702 docs
: self.save_ctxt
.docs_for_attrs(&variant
.node
.attrs
),
703 sig
: sig
::variant_signature(variant
, &self.save_ctxt
),
704 attributes
: lower_attributes(
705 variant
.node
.attrs
.clone(),
713 let sub_span
= self.span
.span_for_first_ident(variant
.span
);
714 let mut value
= format
!("{}::{}", enum_data
.name
, name
);
715 if let &ast
::VariantData
::Tuple(ref fields
, _
) = v
{
717 value
.push_str(&fields
719 .map(|f
| ty_to_string(&f
.ty
))
724 if !self.span
.filter_generated(sub_span
, variant
.span
) {
726 self.span_from_span(sub_span
.expect("No span found for tuple variant"));
727 let id
= ::id_from_node_id(variant
.node
.data
.id(), &self.save_ctxt
);
728 let parent
= Some(::id_from_node_id(item
.id
, &self.save_ctxt
));
730 self.dumper
.dump_def(
733 kind
: DefKind
::TupleVariant
,
742 docs
: self.save_ctxt
.docs_for_attrs(&variant
.node
.attrs
),
743 sig
: sig
::variant_signature(variant
, &self.save_ctxt
),
744 attributes
: lower_attributes(
745 variant
.node
.attrs
.clone(),
755 for field
in variant
.node
.data
.fields() {
756 self.process_struct_field_def(field
, variant
.node
.data
.id());
757 self.visit_ty(&field
.ty
);
760 self.process_generic_params(ty_params
, item
.span
, &enum_data
.qualname
, item
.id
);
761 self.dumper
.dump_def(&access
, enum_data
);
767 type_parameters
: &'l ast
::Generics
,
768 trait_ref
: &'l Option
<ast
::TraitRef
>,
770 impl_items
: &'l
[ast
::ImplItem
],
772 if let Some(impl_data
) = self.save_ctxt
.get_item_data(item
) {
773 if let super::Data
::RelationData(rel
, imp
) = impl_data
{
774 self.dumper
.dump_relation(rel
);
775 self.dumper
.dump_impl(imp
);
777 span_bug
!(item
.span
, "unexpected data kind: {:?}", impl_data
);
781 if let &Some(ref trait_ref
) = trait_ref
{
782 self.process_path(trait_ref
.ref_id
, &trait_ref
.path
);
784 self.process_generic_params(type_parameters
, item
.span
, "", item
.id
);
785 for impl_item
in impl_items
{
786 let map
= &self.tcx
.hir
;
787 self.process_impl_item(impl_item
, map
.local_def_id(item
.id
));
794 generics
: &'l ast
::Generics
,
795 trait_refs
: &'l ast
::TyParamBounds
,
796 methods
: &'l
[ast
::TraitItem
],
798 let name
= item
.ident
.to_string();
799 let qualname
= format
!("::{}", self.tcx
.node_path_str(item
.id
));
800 let mut val
= name
.clone();
801 if !generics
.params
.is_empty() {
802 val
.push_str(&generic_params_to_string(&generics
.params
));
804 if !trait_refs
.is_empty() {
806 val
.push_str(&bounds_to_string(trait_refs
));
808 let sub_span
= self.span
.sub_span_after_keyword(item
.span
, keywords
::Trait
);
809 if !self.span
.filter_generated(sub_span
, item
.span
) {
810 let id
= ::id_from_node_id(item
.id
, &self.save_ctxt
);
811 let span
= self.span_from_span(sub_span
.expect("No span found for trait"));
812 let children
= methods
814 .map(|i
| ::id_from_node_id(i
.id
, &self.save_ctxt
))
816 self.dumper
.dump_def(
817 &access_from
!(self.save_ctxt
, item
),
819 kind
: DefKind
::Trait
,
823 qualname
: qualname
.clone(),
828 docs
: self.save_ctxt
.docs_for_attrs(&item
.attrs
),
829 sig
: sig
::item_signature(item
, &self.save_ctxt
),
830 attributes
: lower_attributes(item
.attrs
.clone(), &self.save_ctxt
),
836 for super_bound
in trait_refs
.iter() {
837 let trait_ref
= match *super_bound
{
838 ast
::TraitTyParamBound(ref trait_ref
, _
) => trait_ref
,
839 ast
::RegionTyParamBound(..) => {
844 let trait_ref
= &trait_ref
.trait_ref
;
845 if let Some(id
) = self.lookup_def_id(trait_ref
.ref_id
) {
846 let sub_span
= self.span
.sub_span_for_type_name(trait_ref
.path
.span
);
847 if !self.span
.filter_generated(sub_span
, trait_ref
.path
.span
) {
848 let span
= self.span_from_span(sub_span
.expect("No span found for trait ref"));
849 self.dumper
.dump_ref(Ref
{
852 ref_id
: ::id_from_def_id(id
),
856 if !self.span
.filter_generated(sub_span
, trait_ref
.path
.span
) {
857 let sub_span
= self.span_from_span(sub_span
.expect("No span for inheritance"));
858 self.dumper
.dump_relation(Relation
{
859 kind
: RelationKind
::SuperTrait
,
861 from
: ::id_from_def_id(id
),
862 to
: ::id_from_node_id(item
.id
, &self.save_ctxt
),
868 // walk generics and methods
869 self.process_generic_params(generics
, item
.span
, &qualname
, item
.id
);
870 for method
in methods
{
871 let map
= &self.tcx
.hir
;
872 self.process_trait_item(method
, map
.local_def_id(item
.id
))
876 // `item` is the module in question, represented as an item.
877 fn process_mod(&mut self, item
: &ast
::Item
) {
878 if let Some(mod_data
) = self.save_ctxt
.get_item_data(item
) {
879 down_cast_data
!(mod_data
, DefData
, item
.span
);
880 self.dumper
.dump_def(&access_from
!(self.save_ctxt
, item
), mod_data
);
884 fn dump_path_ref(&mut self, id
: NodeId
, path
: &ast
::Path
) {
885 let path_data
= self.save_ctxt
.get_path_data(id
, path
);
886 if let Some(path_data
) = path_data
{
887 self.dumper
.dump_ref(path_data
);
891 fn process_path(&mut self, id
: NodeId
, path
: &'l ast
::Path
) {
892 debug
!("process_path {:?}", path
);
893 if generated_code(path
.span
) {
896 self.dump_path_ref(id
, path
);
899 for seg
in &path
.segments
{
900 if let Some(ref params
) = seg
.parameters
{
902 ast
::PathParameters
::AngleBracketed(ref data
) => for t
in &data
.types
{
905 ast
::PathParameters
::Parenthesized(ref data
) => {
906 for t
in &data
.inputs
{
909 if let Some(ref t
) = data
.output
{
917 // Modules or types in the path prefix.
918 match self.save_ctxt
.get_path_def(id
) {
919 HirDef
::Method(did
) => {
920 let ti
= self.tcx
.associated_item(did
);
921 if ti
.kind
== ty
::AssociatedKind
::Method
&& ti
.method_has_self_argument
{
922 self.write_sub_path_trait_truncated(path
);
928 HirDef
::StructCtor(..) |
929 HirDef
::VariantCtor(..) |
930 HirDef
::AssociatedConst(..) |
935 HirDef
::Variant(..) |
936 HirDef
::TyAlias(..) |
937 HirDef
::AssociatedTy(..) => self.write_sub_paths_truncated(path
),
942 fn process_struct_lit(
946 fields
: &'l
[ast
::Field
],
947 variant
: &'l ty
::VariantDef
,
948 base
: &'l Option
<P
<ast
::Expr
>>,
950 self.write_sub_paths_truncated(path
);
952 if let Some(struct_lit_data
) = self.save_ctxt
.get_expr_data(ex
) {
953 down_cast_data
!(struct_lit_data
, RefData
, ex
.span
);
954 if !generated_code(ex
.span
) {
955 self.dumper
.dump_ref(struct_lit_data
);
958 for field
in fields
{
959 if let Some(field_data
) = self.save_ctxt
.get_field_ref_data(field
, variant
) {
960 self.dumper
.dump_ref(field_data
);
963 self.visit_expr(&field
.expr
)
967 walk_list
!(self, visit_expr
, base
);
970 fn process_method_call(
973 seg
: &'l ast
::PathSegment
,
974 args
: &'l
[P
<ast
::Expr
>],
976 debug
!("process_method_call {:?} {:?}", ex
, ex
.span
);
977 if let Some(mcd
) = self.save_ctxt
.get_expr_data(ex
) {
978 down_cast_data
!(mcd
, RefData
, ex
.span
);
979 if !generated_code(ex
.span
) {
980 self.dumper
.dump_ref(mcd
);
984 // Explicit types in the turbo-fish.
985 if let Some(ref params
) = seg
.parameters
{
986 if let ast
::PathParameters
::AngleBracketed(ref data
) = **params
{
987 for t
in &data
.types
{
993 // walk receiver and args
994 walk_list
!(self, visit_expr
, args
);
997 fn process_pat(&mut self, p
: &'l ast
::Pat
) {
999 PatKind
::Struct(ref _path
, ref fields
, _
) => {
1000 // FIXME do something with _path?
1001 let hir_id
= self.tcx
.hir
.node_to_hir_id(p
.id
);
1002 let adt
= match self.save_ctxt
.tables
.node_id_to_type_opt(hir_id
) {
1003 Some(ty
) => ty
.ty_adt_def().unwrap(),
1005 visit
::walk_pat(self, p
);
1009 let variant
= adt
.variant_of_def(self.save_ctxt
.get_path_def(p
.id
));
1016 let sub_span
= self.span
.span_for_first_ident(span
);
1017 if let Some(f
) = variant
.find_field_named(field
.ident
.name
) {
1018 if !self.span
.filter_generated(sub_span
, span
) {
1020 self.span_from_span(sub_span
.expect("No span fund for var ref"));
1021 self.dumper
.dump_ref(Ref
{
1022 kind
: RefKind
::Variable
,
1024 ref_id
: ::id_from_def_id(f
.did
),
1028 self.visit_pat(&field
.pat
);
1031 _
=> visit
::walk_pat(self, p
),
1036 fn process_var_decl(&mut self, p
: &'l ast
::Pat
, value
: String
) {
1037 // The local could declare multiple new vars, we must walk the
1038 // pattern and collect them all.
1039 let mut collector
= PathCollector
::new();
1040 collector
.visit_pat(&p
);
1043 for (id
, i
, sp
, immut
) in collector
.collected_idents
{
1044 let mut value
= match immut
{
1045 ast
::Mutability
::Immutable
=> value
.to_string(),
1048 let hir_id
= self.tcx
.hir
.node_to_hir_id(id
);
1049 let typ
= match self.save_ctxt
.tables
.node_id_to_type_opt(hir_id
) {
1051 let typ
= typ
.to_string();
1052 if !value
.is_empty() {
1053 value
.push_str(": ");
1055 value
.push_str(&typ
);
1058 None
=> String
::new(),
1061 // Get the span only for the name of the variable (I hope the path
1062 // is only ever a variable name, but who knows?).
1063 let sub_span
= self.span
.span_for_last_ident(sp
);
1064 // Rust uses the id of the pattern for var lookups, so we'll use it too.
1065 if !self.span
.filter_generated(sub_span
, sp
) {
1066 let qualname
= format
!("{}${}", i
.to_string(), id
);
1067 let id
= ::id_from_node_id(id
, &self.save_ctxt
);
1068 let span
= self.span_from_span(sub_span
.expect("No span found for variable"));
1070 self.dumper
.dump_def(
1076 kind
: DefKind
::Local
,
1079 name
: i
.to_string(),
1085 docs
: String
::new(),
1094 /// Extract macro use and definition information from the AST node defined
1095 /// by the given NodeId, using the expansion information from the node's
1098 /// If the span is not macro-generated, do nothing, else use callee and
1099 /// callsite spans to record macro definition and use data, using the
1100 /// mac_uses and mac_defs sets to prevent multiples.
1101 fn process_macro_use(&mut self, span
: Span
) {
1102 let source_span
= span
.source_callsite();
1103 if self.macro_calls
.contains(&source_span
) {
1106 self.macro_calls
.insert(source_span
);
1108 let data
= match self.save_ctxt
.get_macro_use_data(span
) {
1113 self.dumper
.macro_use(data
);
1115 // FIXME write the macro def
1116 // let mut hasher = DefaultHasher::new();
1117 // data.callee_span.hash(&mut hasher);
1118 // let hash = hasher.finish();
1119 // let qualname = format!("{}::{}", data.name, hash);
1120 // Don't write macro definition for imported macros
1121 // if !self.mac_defs.contains(&data.callee_span)
1122 // && !data.imported {
1123 // self.mac_defs.insert(data.callee_span);
1124 // if let Some(sub_span) = self.span.span_for_macro_def_name(data.callee_span) {
1125 // self.dumper.macro_data(MacroData {
1127 // name: data.name.clone(),
1128 // qualname: qualname.clone(),
1129 // // FIXME where do macro docs come from?
1130 // docs: String::new(),
1131 // }.lower(self.tcx));
1136 fn process_trait_item(&mut self, trait_item
: &'l ast
::TraitItem
, trait_id
: DefId
) {
1137 self.process_macro_use(trait_item
.span
);
1138 match trait_item
.node
{
1139 ast
::TraitItemKind
::Const(ref ty
, ref expr
) => {
1140 self.process_assoc_const(
1142 trait_item
.ident
.name
,
1145 expr
.as_ref().map(|e
| &**e
),
1147 ast
::Visibility
::Public
,
1151 ast
::TraitItemKind
::Method(ref sig
, ref body
) => {
1152 self.process_method(
1154 body
.as_ref().map(|x
| &**x
),
1157 &trait_item
.generics
,
1158 ast
::Visibility
::Public
,
1162 ast
::TraitItemKind
::Type(ref bounds
, ref default_ty
) => {
1163 // FIXME do something with _bounds (for type refs)
1164 let name
= trait_item
.ident
.name
.to_string();
1165 let qualname
= format
!("::{}", self.tcx
.node_path_str(trait_item
.id
));
1166 let sub_span
= self.span
1167 .sub_span_after_keyword(trait_item
.span
, keywords
::Type
);
1169 if !self.span
.filter_generated(sub_span
, trait_item
.span
) {
1170 let span
= self.span_from_span(sub_span
.expect("No span found for assoc type"));
1171 let id
= ::id_from_node_id(trait_item
.id
, &self.save_ctxt
);
1173 self.dumper
.dump_def(
1179 kind
: DefKind
::Type
,
1184 value
: self.span
.snippet(trait_item
.span
),
1185 parent
: Some(::id_from_def_id(trait_id
)),
1188 docs
: self.save_ctxt
.docs_for_attrs(&trait_item
.attrs
),
1189 sig
: sig
::assoc_type_signature(
1193 default_ty
.as_ref().map(|ty
| &**ty
),
1196 attributes
: lower_attributes(trait_item
.attrs
.clone(), &self.save_ctxt
),
1201 if let &Some(ref default_ty
) = default_ty
{
1202 self.visit_ty(default_ty
)
1205 ast
::TraitItemKind
::Macro(_
) => {}
1209 fn process_impl_item(&mut self, impl_item
: &'l ast
::ImplItem
, impl_id
: DefId
) {
1210 self.process_macro_use(impl_item
.span
);
1211 match impl_item
.node
{
1212 ast
::ImplItemKind
::Const(ref ty
, ref expr
) => {
1213 self.process_assoc_const(
1215 impl_item
.ident
.name
,
1220 impl_item
.vis
.clone(),
1224 ast
::ImplItemKind
::Method(ref sig
, ref body
) => {
1225 self.process_method(
1230 &impl_item
.generics
,
1231 impl_item
.vis
.clone(),
1235 ast
::ImplItemKind
::Type(ref ty
) => {
1236 // FIXME uses of the assoc type should ideally point to this
1237 // 'def' and the name here should be a ref to the def in the
1241 ast
::ImplItemKind
::Macro(_
) => {}
1245 /// Dumps imports in a use tree recursively.
1247 /// A use tree is an import that may contain nested braces (RFC 2128). The `use_tree` parameter
1248 /// is the current use tree under scrutiny, while `id` and `prefix` are its corresponding node
1249 /// id and path. `root_item` is the topmost use tree in the hierarchy.
1251 /// If `use_tree` is a simple or glob import, it is dumped into the analysis data. Otherwise,
1252 /// each child use tree is dumped recursively.
1253 fn process_use_tree(&mut self,
1254 use_tree
: &'l ast
::UseTree
,
1256 root_item
: &'l ast
::Item
,
1257 prefix
: &ast
::Path
) {
1258 let path
= &use_tree
.prefix
;
1260 // The access is calculated using the current tree ID, but with the root tree's visibility
1261 // (since nested trees don't have their own visibility).
1262 let access
= Access
{
1263 public
: root_item
.vis
== ast
::Visibility
::Public
,
1264 reachable
: self.save_ctxt
.analysis
.access_levels
.is_reachable(id
),
1267 // The parent def id of a given use tree is always the enclosing item.
1268 let parent
= self.save_ctxt
.tcx
.hir
.opt_local_def_id(id
)
1269 .and_then(|id
| self.save_ctxt
.tcx
.parent_def_id(id
))
1270 .map(::id_from_def_id
);
1272 match use_tree
.kind
{
1273 ast
::UseTreeKind
::Simple(ident
) => {
1274 let path
= ast
::Path
{
1275 segments
: prefix
.segments
1277 .chain(path
.segments
.iter())
1283 let sub_span
= self.span
.span_for_last_ident(path
.span
);
1284 let mod_id
= match self.lookup_def_id(id
) {
1286 self.process_def_kind(id
, path
.span
, sub_span
, def_id
);
1292 // 'use' always introduces an alias, if there is not an explicit
1293 // one, there is an implicit one.
1294 let sub_span
= match self.span
.sub_span_after_keyword(use_tree
.span
,
1296 Some(sub_span
) => Some(sub_span
),
1300 if !self.span
.filter_generated(sub_span
, path
.span
) {
1302 self.span_from_span(sub_span
.expect("No span found for use"));
1303 self.dumper
.import(&access
, Import
{
1304 kind
: ImportKind
::Use
,
1305 ref_id
: mod_id
.map(|id
| ::id_from_def_id(id
)),
1307 name
: ident
.to_string(),
1308 value
: String
::new(),
1312 self.write_sub_paths_truncated(&path
);
1314 ast
::UseTreeKind
::Glob
=> {
1315 let path
= ast
::Path
{
1316 segments
: prefix
.segments
1318 .chain(path
.segments
.iter())
1324 // Make a comma-separated list of names of imported modules.
1325 let mut names
= vec
![];
1326 let glob_map
= &self.save_ctxt
.analysis
.glob_map
;
1327 let glob_map
= glob_map
.as_ref().unwrap();
1328 if glob_map
.contains_key(&id
) {
1329 for n
in glob_map
.get(&id
).unwrap() {
1330 names
.push(n
.to_string());
1334 let sub_span
= self.span
.sub_span_of_token(use_tree
.span
,
1335 token
::BinOp(token
::Star
));
1336 if !self.span
.filter_generated(sub_span
, use_tree
.span
) {
1338 self.span_from_span(sub_span
.expect("No span found for use glob"));
1339 self.dumper
.import(&access
, Import
{
1340 kind
: ImportKind
::GlobUse
,
1343 name
: "*".to_owned(),
1344 value
: names
.join(", "),
1348 self.write_sub_paths(&path
);
1350 ast
::UseTreeKind
::Nested(ref nested_items
) => {
1351 let prefix
= ast
::Path
{
1352 segments
: prefix
.segments
1354 .chain(path
.segments
.iter())
1359 for &(ref tree
, id
) in nested_items
{
1360 self.process_use_tree(tree
, id
, root_item
, &prefix
);
1367 impl<'l
, 'tcx
: 'l
, 'll
, O
: DumpOutput
+ 'll
> Visitor
<'l
> for DumpVisitor
<'l
, 'tcx
, 'll
, O
> {
1368 fn visit_mod(&mut self, m
: &'l ast
::Mod
, span
: Span
, attrs
: &[ast
::Attribute
], id
: NodeId
) {
1369 // Since we handle explicit modules ourselves in visit_item, this should
1370 // only get called for the root module of a crate.
1371 assert_eq
!(id
, ast
::CRATE_NODE_ID
);
1373 let qualname
= format
!("::{}", self.tcx
.node_path_str(id
));
1375 let cm
= self.tcx
.sess
.codemap();
1376 let filename
= cm
.span_to_filename(span
);
1377 let data_id
= ::id_from_node_id(id
, &self.save_ctxt
);
1378 let children
= m
.items
1380 .map(|i
| ::id_from_node_id(i
.id
, &self.save_ctxt
))
1382 let span
= self.span_from_span(span
);
1384 self.dumper
.dump_def(
1392 name
: String
::new(),
1395 value
: filename
.to_string(),
1399 docs
: self.save_ctxt
.docs_for_attrs(attrs
),
1401 attributes
: lower_attributes(attrs
.to_owned(), &self.save_ctxt
),
1404 self.nest_scope(id
, |v
| visit
::walk_mod(v
, m
));
1407 fn visit_item(&mut self, item
: &'l ast
::Item
) {
1408 use syntax
::ast
::ItemKind
::*;
1409 self.process_macro_use(item
.span
);
1411 Use(ref use_tree
) => {
1412 let prefix
= ast
::Path
{
1416 self.process_use_tree(use_tree
, item
.id
, item
, &prefix
);
1419 let alias_span
= self.span
.span_for_last_ident(item
.span
);
1421 if !self.span
.filter_generated(alias_span
, item
.span
) {
1423 self.span_from_span(alias_span
.expect("No span found for extern crate"));
1424 let parent
= self.save_ctxt
.tcx
.hir
.opt_local_def_id(item
.id
)
1425 .and_then(|id
| self.save_ctxt
.tcx
.parent_def_id(id
))
1426 .map(::id_from_def_id
);
1433 kind
: ImportKind
::ExternCrate
,
1436 name
: item
.ident
.to_string(),
1437 value
: String
::new(),
1443 Fn(ref decl
, .., ref ty_params
, ref body
) => {
1444 self.process_fn(item
, &decl
, ty_params
, &body
)
1446 Static(ref typ
, _
, ref expr
) => self.process_static_or_const_item(item
, typ
, expr
),
1447 Const(ref typ
, ref expr
) => self.process_static_or_const_item(item
, &typ
, &expr
),
1448 Struct(ref def
, ref ty_params
) | Union(ref def
, ref ty_params
) => {
1449 self.process_struct(item
, def
, ty_params
)
1451 Enum(ref def
, ref ty_params
) => self.process_enum(item
, def
, ty_params
),
1452 Impl(.., ref ty_params
, ref trait_ref
, ref typ
, ref impl_items
) => {
1453 self.process_impl(item
, ty_params
, trait_ref
, &typ
, impl_items
)
1455 Trait(_
, _
, ref generics
, ref trait_refs
, ref methods
) => {
1456 self.process_trait(item
, generics
, trait_refs
, methods
)
1459 self.process_mod(item
);
1460 self.nest_scope(item
.id
, |v
| visit
::walk_mod(v
, m
));
1462 Ty(ref ty
, ref ty_params
) => {
1463 let qualname
= format
!("::{}", self.tcx
.node_path_str(item
.id
));
1464 let value
= ty_to_string(&ty
);
1465 let sub_span
= self.span
.sub_span_after_keyword(item
.span
, keywords
::Type
);
1466 if !self.span
.filter_generated(sub_span
, item
.span
) {
1467 let span
= self.span_from_span(sub_span
.expect("No span found for typedef"));
1468 let id
= ::id_from_node_id(item
.id
, &self.save_ctxt
);
1470 self.dumper
.dump_def(
1471 &access_from
!(self.save_ctxt
, item
),
1473 kind
: DefKind
::Type
,
1476 name
: item
.ident
.to_string(),
1477 qualname
: qualname
.clone(),
1482 docs
: self.save_ctxt
.docs_for_attrs(&item
.attrs
),
1483 sig
: sig
::item_signature(item
, &self.save_ctxt
),
1484 attributes
: lower_attributes(item
.attrs
.clone(), &self.save_ctxt
),
1490 self.process_generic_params(ty_params
, item
.span
, &qualname
, item
.id
);
1493 _
=> visit
::walk_item(self, item
),
1497 fn visit_generics(&mut self, generics
: &'l ast
::Generics
) {
1498 for param
in &generics
.params
{
1499 if let ast
::GenericParam
::Type(ref ty_param
) = *param
{
1500 for bound
in ty_param
.bounds
.iter() {
1501 if let ast
::TraitTyParamBound(ref trait_ref
, _
) = *bound
{
1502 self.process_path(trait_ref
.trait_ref
.ref_id
, &trait_ref
.trait_ref
.path
)
1505 if let Some(ref ty
) = ty_param
.default {
1512 fn visit_ty(&mut self, t
: &'l ast
::Ty
) {
1513 self.process_macro_use(t
.span
);
1515 ast
::TyKind
::Path(_
, ref path
) => {
1516 if generated_code(t
.span
) {
1520 if let Some(id
) = self.lookup_def_id(t
.id
) {
1521 if let Some(sub_span
) = self.span
.sub_span_for_type_name(t
.span
) {
1522 let span
= self.span_from_span(sub_span
);
1523 self.dumper
.dump_ref(Ref
{
1524 kind
: RefKind
::Type
,
1526 ref_id
: ::id_from_def_id(id
),
1531 self.write_sub_paths_truncated(path
);
1532 visit
::walk_path(self, path
);
1534 ast
::TyKind
::Array(ref element
, ref length
) => {
1535 self.visit_ty(element
);
1536 self.nest_tables(length
.id
, |v
| v
.visit_expr(length
));
1538 _
=> visit
::walk_ty(self, t
),
1542 fn visit_expr(&mut self, ex
: &'l ast
::Expr
) {
1543 debug
!("visit_expr {:?}", ex
.node
);
1544 self.process_macro_use(ex
.span
);
1546 ast
::ExprKind
::Struct(ref path
, ref fields
, ref base
) => {
1547 let hir_expr
= self.save_ctxt
.tcx
.hir
.expect_expr(ex
.id
);
1548 let adt
= match self.save_ctxt
.tables
.expr_ty_opt(&hir_expr
) {
1549 Some(ty
) if ty
.ty_adt_def().is_some() => ty
.ty_adt_def().unwrap(),
1551 visit
::walk_expr(self, ex
);
1555 let def
= self.save_ctxt
.get_path_def(hir_expr
.id
);
1556 self.process_struct_lit(ex
, path
, fields
, adt
.variant_of_def(def
), base
)
1558 ast
::ExprKind
::MethodCall(ref seg
, ref args
) => self.process_method_call(ex
, seg
, args
),
1559 ast
::ExprKind
::Field(ref sub_ex
, _
) => {
1560 self.visit_expr(&sub_ex
);
1562 if let Some(field_data
) = self.save_ctxt
.get_expr_data(ex
) {
1563 down_cast_data
!(field_data
, RefData
, ex
.span
);
1564 if !generated_code(ex
.span
) {
1565 self.dumper
.dump_ref(field_data
);
1569 ast
::ExprKind
::TupField(ref sub_ex
, idx
) => {
1570 self.visit_expr(&sub_ex
);
1572 let hir_node
= match self.save_ctxt
.tcx
.hir
.find(sub_ex
.id
) {
1573 Some(Node
::NodeExpr(expr
)) => expr
,
1576 "Missing or weird node for sub-expression {} in {:?}",
1583 let ty
= match self.save_ctxt
.tables
.expr_ty_adjusted_opt(&hir_node
) {
1584 Some(ty
) => &ty
.sty
,
1586 visit
::walk_expr(self, ex
);
1591 ty
::TyAdt(def
, _
) => {
1592 let sub_span
= self.span
.sub_span_after_token(ex
.span
, token
::Dot
);
1593 if !self.span
.filter_generated(sub_span
, ex
.span
) {
1595 self.span_from_span(sub_span
.expect("No span found for var ref"));
1597 ::id_from_def_id(def
.non_enum_variant().fields
[idx
.node
].did
);
1598 self.dumper
.dump_ref(Ref
{
1599 kind
: RefKind
::Variable
,
1605 ty
::TyTuple(..) => {}
1606 _
=> span_bug
!(ex
.span
, "Expected struct or tuple type, found {:?}", ty
),
1609 ast
::ExprKind
::Closure(_
, _
, ref decl
, ref body
, _fn_decl_span
) => {
1610 let mut id
= String
::from("$");
1611 id
.push_str(&ex
.id
.to_string());
1613 // walk arg and return types
1614 for arg
in &decl
.inputs
{
1615 self.visit_ty(&arg
.ty
);
1618 if let ast
::FunctionRetTy
::Ty(ref ret_ty
) = decl
.output
{
1619 self.visit_ty(&ret_ty
);
1623 self.nest_tables(ex
.id
, |v
| {
1624 v
.process_formals(&decl
.inputs
, &id
);
1625 v
.nest_scope(ex
.id
, |v
| v
.visit_expr(body
))
1628 ast
::ExprKind
::ForLoop(ref pattern
, ref subexpression
, ref block
, _
) |
1629 ast
::ExprKind
::WhileLet(ref pattern
, ref subexpression
, ref block
, _
) => {
1630 let value
= self.span
.snippet(subexpression
.span
);
1631 self.process_var_decl(pattern
, value
);
1632 debug
!("for loop, walk sub-expr: {:?}", subexpression
.node
);
1633 self.visit_expr(subexpression
);
1634 visit
::walk_block(self, block
);
1636 ast
::ExprKind
::IfLet(ref pattern
, ref subexpression
, ref block
, ref opt_else
) => {
1637 let value
= self.span
.snippet(subexpression
.span
);
1638 self.process_var_decl(pattern
, value
);
1639 self.visit_expr(subexpression
);
1640 visit
::walk_block(self, block
);
1641 opt_else
.as_ref().map(|el
| self.visit_expr(el
));
1643 ast
::ExprKind
::Repeat(ref element
, ref count
) => {
1644 self.visit_expr(element
);
1645 self.nest_tables(count
.id
, |v
| v
.visit_expr(count
));
1647 // In particular, we take this branch for call and path expressions,
1648 // where we'll index the idents involved just by continuing to walk.
1649 _
=> visit
::walk_expr(self, ex
),
1653 fn visit_mac(&mut self, mac
: &'l ast
::Mac
) {
1654 // These shouldn't exist in the AST at this point, log a span bug.
1657 "macro invocation should have been expanded out of AST"
1661 fn visit_pat(&mut self, p
: &'l ast
::Pat
) {
1662 self.process_macro_use(p
.span
);
1663 self.process_pat(p
);
1666 fn visit_arm(&mut self, arm
: &'l ast
::Arm
) {
1667 let mut collector
= PathCollector
::new();
1668 for pattern
in &arm
.pats
{
1669 // collect paths from the arm's patterns
1670 collector
.visit_pat(&pattern
);
1671 self.visit_pat(&pattern
);
1674 // process collected paths
1675 for (id
, i
, sp
, immut
) in collector
.collected_idents
{
1676 match self.save_ctxt
.get_path_def(id
) {
1677 HirDef
::Local(id
) => {
1678 let mut value
= if immut
== ast
::Mutability
::Immutable
{
1679 self.span
.snippet(sp
).to_string()
1681 "<mutable>".to_string()
1683 let hir_id
= self.tcx
.hir
.node_to_hir_id(id
);
1684 let typ
= self.save_ctxt
1686 .node_id_to_type_opt(hir_id
)
1687 .map(|t
| t
.to_string())
1688 .unwrap_or(String
::new());
1689 value
.push_str(": ");
1690 value
.push_str(&typ
);
1692 if !self.span
.filter_generated(Some(sp
), sp
) {
1693 let qualname
= format
!("{}${}", i
.to_string(), id
);
1694 let id
= ::id_from_node_id(id
, &self.save_ctxt
);
1695 let span
= self.span_from_span(sp
);
1697 self.dumper
.dump_def(
1703 kind
: DefKind
::Local
,
1706 name
: i
.to_string(),
1712 docs
: String
::new(),
1719 HirDef
::StructCtor(..) |
1720 HirDef
::VariantCtor(..) |
1722 HirDef
::AssociatedConst(..) |
1723 HirDef
::Struct(..) |
1724 HirDef
::Variant(..) |
1725 HirDef
::TyAlias(..) |
1726 HirDef
::AssociatedTy(..) |
1727 HirDef
::SelfTy(..) => {
1728 self.dump_path_ref(id
, &ast
::Path
::from_ident(sp
, i
));
1731 "unexpected definition kind when processing collected idents: {:?}",
1737 for (id
, ref path
) in collector
.collected_paths
{
1738 self.process_path(id
, path
);
1740 walk_list
!(self, visit_expr
, &arm
.guard
);
1741 self.visit_expr(&arm
.body
);
1744 fn visit_path(&mut self, p
: &'l ast
::Path
, id
: NodeId
) {
1745 self.process_path(id
, p
);
1748 fn visit_stmt(&mut self, s
: &'l ast
::Stmt
) {
1749 self.process_macro_use(s
.span
);
1750 visit
::walk_stmt(self, s
)
1753 fn visit_local(&mut self, l
: &'l ast
::Local
) {
1754 self.process_macro_use(l
.span
);
1757 .map(|i
| self.span
.snippet(i
.span
))
1758 .unwrap_or(String
::new());
1759 self.process_var_decl(&l
.pat
, value
);
1761 // Just walk the initialiser and type (don't want to walk the pattern again).
1762 walk_list
!(self, visit_ty
, &l
.ty
);
1763 walk_list
!(self, visit_expr
, &l
.init
);
1766 fn visit_foreign_item(&mut self, item
: &'l ast
::ForeignItem
) {
1767 let access
= access_from
!(self.save_ctxt
, item
);
1770 ast
::ForeignItemKind
::Fn(ref decl
, ref generics
) => {
1771 if let Some(fn_data
) = self.save_ctxt
.get_extern_item_data(item
) {
1772 down_cast_data
!(fn_data
, DefData
, item
.span
);
1776 |v
| v
.process_formals(&decl
.inputs
, &fn_data
.qualname
),
1778 self.process_generic_params(generics
, item
.span
, &fn_data
.qualname
, item
.id
);
1779 self.dumper
.dump_def(&access
, fn_data
);
1782 for arg
in &decl
.inputs
{
1783 self.visit_ty(&arg
.ty
);
1786 if let ast
::FunctionRetTy
::Ty(ref ret_ty
) = decl
.output
{
1787 self.visit_ty(&ret_ty
);
1790 ast
::ForeignItemKind
::Static(ref ty
, _
) => {
1791 if let Some(var_data
) = self.save_ctxt
.get_extern_item_data(item
) {
1792 down_cast_data
!(var_data
, DefData
, item
.span
);
1793 self.dumper
.dump_def(&access
, var_data
);
1798 ast
::ForeignItemKind
::Ty
=> {
1799 if let Some(var_data
) = self.save_ctxt
.get_extern_item_data(item
) {
1800 down_cast_data
!(var_data
, DefData
, item
.span
);
1801 self.dumper
.dump_def(&access
, var_data
);