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 JsonDumper is used for
24 //! recording the output.
26 use rustc
::hir
::def
::Def
as HirDef
;
27 use rustc
::hir
::def_id
::DefId
;
28 use rustc
::session
::config
::Input
;
29 use rustc
::ty
::{self, TyCtxt}
;
30 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
::source_map
::{Spanned, DUMMY_SP, respan}
;
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
::{CompilationOptions
, CratePreludeData
, Def
, DefKind
, GlobalCrateId
, Import
,
55 ImportKind
, Ref
, RefKind
, 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
, $vis
:expr
, $id
:expr
) => {
70 public
: $vis
.node
.is_pub(),
71 reachable
: $save_ctxt
.analysis
.access_levels
.is_reachable($id
),
75 ($save_ctxt
:expr
, $item
:expr
) => {
77 public
: $item
.vis
.node
.is_pub(),
78 reachable
: $save_ctxt
.analysis
.access_levels
.is_reachable($item
.id
),
83 pub struct DumpVisitor
<'l
, 'tcx
: 'l
, 'll
, O
: DumpOutput
+ 'll
> {
84 save_ctxt
: SaveContext
<'l
, 'tcx
>,
85 tcx
: TyCtxt
<'l
, 'tcx
, 'tcx
>,
86 dumper
: &'ll
mut JsonDumper
<O
>,
92 // Set of macro definition (callee) spans, and the set
93 // of macro use (callsite) spans. We store these to ensure
94 // we only write one macro def per unique macro definition, and
95 // one macro use per unique callsite span.
96 // mac_defs: FxHashSet<Span>,
97 macro_calls
: FxHashSet
<Span
>,
100 impl<'l
, 'tcx
: 'l
, 'll
, O
: DumpOutput
+ 'll
> DumpVisitor
<'l
, 'tcx
, 'll
, O
> {
102 save_ctxt
: SaveContext
<'l
, 'tcx
>,
103 dumper
: &'ll
mut JsonDumper
<O
>,
104 ) -> DumpVisitor
<'l
, 'tcx
, 'll
, O
> {
105 let span_utils
= SpanUtils
::new(&save_ctxt
.tcx
.sess
);
111 cur_scope
: CRATE_NODE_ID
,
112 // mac_defs: FxHashSet::default(),
113 macro_calls
: FxHashSet
::default(),
117 fn nest_scope
<F
>(&mut self, scope_id
: NodeId
, f
: F
)
119 F
: FnOnce(&mut DumpVisitor
<'l
, 'tcx
, 'll
, O
>),
121 let parent_scope
= self.cur_scope
;
122 self.cur_scope
= scope_id
;
124 self.cur_scope
= parent_scope
;
127 fn nest_tables
<F
>(&mut self, item_id
: NodeId
, f
: F
)
129 F
: FnOnce(&mut DumpVisitor
<'l
, 'tcx
, 'll
, O
>),
131 let item_def_id
= self.tcx
.hir
.local_def_id(item_id
);
132 if self.tcx
.has_typeck_tables(item_def_id
) {
133 let tables
= self.tcx
.typeck_tables_of(item_def_id
);
134 let old_tables
= self.save_ctxt
.tables
;
135 self.save_ctxt
.tables
= tables
;
137 self.save_ctxt
.tables
= old_tables
;
143 fn span_from_span(&self, span
: Span
) -> SpanData
{
144 self.save_ctxt
.span_from_span(span
)
147 pub fn dump_crate_info(&mut self, name
: &str, krate
: &ast
::Crate
) {
148 let source_file
= self.tcx
.sess
.local_crate_source_file
.as_ref();
149 let crate_root
= source_file
.map(|source_file
| {
150 let source_file
= Path
::new(source_file
);
151 match source_file
.file_name() {
152 Some(_
) => source_file
.parent().unwrap().display(),
153 None
=> source_file
.display(),
157 let data
= CratePreludeData
{
158 crate_id
: GlobalCrateId
{
160 disambiguator
: self.tcx
162 .local_crate_disambiguator()
166 crate_root
: crate_root
.unwrap_or_else(|| "<no source>".to_owned()),
167 external_crates
: self.save_ctxt
.get_external_crates(),
168 span
: self.span_from_span(krate
.span
),
171 self.dumper
.crate_prelude(data
);
174 pub fn dump_compilation_options(&mut self, input
: &Input
, crate_name
: &str) {
175 // Apply possible `remap-path-prefix` remapping to the input source file
176 // (and don't include remapping args anymore)
177 let (program
, arguments
) = {
178 let remap_arg_indices
= {
179 let mut indices
= FxHashSet
::default();
180 // Args are guaranteed to be valid UTF-8 (checked early)
181 for (i
, e
) in env
::args().enumerate() {
182 if e
.starts_with("--remap-path-prefix=") {
184 } else if e
== "--remap-path-prefix" {
186 indices
.insert(i
+ 1);
192 let mut args
= env
::args()
194 .filter(|(i
, _
)| !remap_arg_indices
.contains(i
))
197 Input
::File(ref path
) if path
== Path
::new(&arg
) => {
198 let mapped
= &self.tcx
.sess
.local_crate_source_file
;
209 (args
.next().unwrap(), args
.collect())
212 let data
= CompilationOptions
{
213 directory
: self.tcx
.sess
.working_dir
.0.clone(),
216 output
: self.save_ctxt
.compilation_output(crate_name
),
219 self.dumper
.compilation_opts(data
);
222 // Return all non-empty prefixes of a path.
223 // For each prefix, we return the span for the last segment in the prefix and
224 // a str representation of the entire prefix.
225 fn process_path_prefixes(&self, path
: &ast
::Path
) -> Vec
<(Span
, String
)> {
226 let segments
= &path
.segments
[if path
.is_global() { 1 }
else { 0 }
..];
228 let mut result
= Vec
::with_capacity(segments
.len());
229 let mut segs
= Vec
::with_capacity(segments
.len());
231 for (i
, seg
) in segments
.iter().enumerate() {
232 segs
.push(seg
.clone());
233 let sub_path
= ast
::Path
{
234 span
: seg
.ident
.span
, // span for the last segment
237 let qualname
= if i
== 0 && path
.is_global() {
238 format
!("::{}", path_to_string(&sub_path
))
240 path_to_string(&sub_path
)
242 result
.push((seg
.ident
.span
, qualname
));
243 segs
= sub_path
.segments
;
249 fn write_sub_paths(&mut self, path
: &ast
::Path
) {
250 let sub_paths
= self.process_path_prefixes(path
);
251 for (span
, _
) in sub_paths
{
252 let span
= self.span_from_span(span
);
253 self.dumper
.dump_ref(Ref
{
261 // As write_sub_paths, but does not process the last ident in the path (assuming it
262 // will be processed elsewhere). See note on write_sub_paths about global.
263 fn write_sub_paths_truncated(&mut self, path
: &ast
::Path
) {
264 let sub_paths
= self.process_path_prefixes(path
);
265 let len
= sub_paths
.len();
270 for (span
, _
) in sub_paths
.into_iter().take(len
- 1) {
271 let span
= self.span_from_span(span
);
272 self.dumper
.dump_ref(Ref
{
280 // As write_sub_paths, but expects a path of the form module_path::trait::method
281 // Where trait could actually be a struct too.
282 fn write_sub_path_trait_truncated(&mut self, path
: &ast
::Path
) {
283 let sub_paths
= self.process_path_prefixes(path
);
284 let len
= sub_paths
.len();
288 let sub_paths
= &sub_paths
[..(len
- 1)];
290 // write the trait part of the sub-path
291 let (ref span
, _
) = sub_paths
[len
- 2];
292 let span
= self.span_from_span(*span
);
293 self.dumper
.dump_ref(Ref
{
299 // write the other sub-paths
303 let sub_paths
= &sub_paths
[..len
- 2];
304 for &(ref span
, _
) in sub_paths
{
305 let span
= self.span_from_span(*span
);
306 self.dumper
.dump_ref(Ref
{
314 fn lookup_def_id(&self, ref_id
: NodeId
) -> Option
<DefId
> {
315 match self.save_ctxt
.get_path_def(ref_id
) {
316 HirDef
::PrimTy(..) | HirDef
::SelfTy(..) | HirDef
::Err
=> None
,
317 def
=> Some(def
.def_id()),
321 fn process_formals(&mut self, formals
: &'l
[ast
::Arg
], qualname
: &str) {
323 self.visit_pat(&arg
.pat
);
324 let mut collector
= PathCollector
::new();
325 collector
.visit_pat(&arg
.pat
);
326 let span_utils
= self.span
.clone();
328 for (id
, ident
, ..) in collector
.collected_idents
{
329 let hir_id
= self.tcx
.hir
.node_to_hir_id(id
);
330 let typ
= match self.save_ctxt
.tables
.node_id_to_type_opt(hir_id
) {
331 Some(s
) => s
.to_string(),
334 let sub_span
= span_utils
.span_for_last_ident(ident
.span
);
335 if !self.span
.filter_generated(sub_span
, ident
.span
) {
336 let id
= ::id_from_node_id(id
, &self.save_ctxt
);
337 let span
= self.span_from_span(sub_span
.expect("No span found for variable"));
339 self.dumper
.dump_def(
345 kind
: DefKind
::Local
,
348 name
: ident
.to_string(),
349 qualname
: format
!("{}::{}", qualname
, ident
.to_string()),
366 sig
: &'l ast
::MethodSig
,
367 body
: Option
<&'l ast
::Block
>,
370 generics
: &'l ast
::Generics
,
371 vis
: ast
::Visibility
,
374 debug
!("process_method: {}:{}", id
, ident
);
376 if let Some(mut method_data
) = self.save_ctxt
.get_method_data(id
, ident
.name
, span
) {
377 let sig_str
= ::make_signature(&sig
.decl
, &generics
);
381 |v
| v
.process_formals(&sig
.decl
.inputs
, &method_data
.qualname
),
385 self.process_generic_params(&generics
, span
, &method_data
.qualname
, id
);
387 method_data
.value
= sig_str
;
388 method_data
.sig
= sig
::method_signature(id
, ident
, generics
, sig
, &self.save_ctxt
);
389 self.dumper
.dump_def(&access_from
!(self.save_ctxt
, vis
, id
), method_data
);
392 // walk arg and return types
393 for arg
in &sig
.decl
.inputs
{
394 self.visit_ty(&arg
.ty
);
397 if let ast
::FunctionRetTy
::Ty(ref ret_ty
) = sig
.decl
.output
{
398 self.visit_ty(ret_ty
);
402 if let Some(body
) = body
{
403 self.nest_tables(id
, |v
| v
.nest_scope(id
, |v
| v
.visit_block(body
)));
407 fn process_struct_field_def(&mut self, field
: &ast
::StructField
, parent_id
: NodeId
) {
408 let field_data
= self.save_ctxt
.get_field_data(field
, parent_id
);
409 if let Some(field_data
) = field_data
{
410 self.dumper
.dump_def(&access_from
!(self.save_ctxt
, field
), field_data
);
414 // Dump generic params bindings, then visit_generics
415 fn process_generic_params(
417 generics
: &'l ast
::Generics
,
422 for param
in &generics
.params
{
424 ast
::GenericParamKind
::Lifetime { .. }
=> {}
425 ast
::GenericParamKind
::Type { .. }
=> {
426 let param_ss
= param
.ident
.span
;
427 let name
= escape(self.span
.snippet(param_ss
));
428 // Append $id to name to make sure each one is unique.
429 let qualname
= format
!("{}::{}${}", prefix
, name
, id
);
430 if !self.span
.filter_generated(Some(param_ss
), full_span
) {
431 let id
= ::id_from_node_id(param
.id
, &self.save_ctxt
);
432 let span
= self.span_from_span(param_ss
);
434 self.dumper
.dump_def(
445 value
: String
::new(),
458 self.visit_generics(generics
);
464 decl
: &'l ast
::FnDecl
,
465 ty_params
: &'l ast
::Generics
,
466 body
: &'l ast
::Block
,
468 if let Some(fn_data
) = self.save_ctxt
.get_item_data(item
) {
469 down_cast_data
!(fn_data
, DefData
, item
.span
);
472 |v
| v
.process_formals(&decl
.inputs
, &fn_data
.qualname
),
474 self.process_generic_params(ty_params
, item
.span
, &fn_data
.qualname
, item
.id
);
475 self.dumper
.dump_def(&access_from
!(self.save_ctxt
, item
), fn_data
);
478 for arg
in &decl
.inputs
{
479 self.visit_ty(&arg
.ty
);
482 if let ast
::FunctionRetTy
::Ty(ref ret_ty
) = decl
.output
{
483 self.visit_ty(&ret_ty
);
486 self.nest_tables(item
.id
, |v
| v
.nest_scope(item
.id
, |v
| v
.visit_block(&body
)));
489 fn process_static_or_const_item(
495 self.nest_tables(item
.id
, |v
| {
496 if let Some(var_data
) = v
.save_ctxt
.get_item_data(item
) {
497 down_cast_data
!(var_data
, DefData
, item
.span
);
498 v
.dumper
.dump_def(&access_from
!(v
.save_ctxt
, item
), var_data
);
505 fn process_assoc_const(
511 expr
: Option
<&'l ast
::Expr
>,
513 vis
: ast
::Visibility
,
514 attrs
: &'l
[Attribute
],
516 let qualname
= format
!("::{}", self.tcx
.node_path_str(id
));
518 let sub_span
= self.span
.sub_span_after_keyword(span
, keywords
::Const
);
520 if !self.span
.filter_generated(sub_span
, span
) {
521 let sig
= sig
::assoc_const_signature(id
, name
, typ
, expr
, &self.save_ctxt
);
522 let span
= self.span_from_span(sub_span
.expect("No span found for variable"));
524 self.dumper
.dump_def(
525 &access_from
!(self.save_ctxt
, vis
, id
),
527 kind
: DefKind
::Const
,
528 id
: ::id_from_node_id(id
, &self.save_ctxt
),
530 name
: name
.to_string(),
532 value
: ty_to_string(&typ
),
533 parent
: Some(::id_from_def_id(parent_id
)),
536 docs
: self.save_ctxt
.docs_for_attrs(attrs
),
538 attributes
: lower_attributes(attrs
.to_owned(), &self.save_ctxt
),
543 // walk type and init value
545 if let Some(expr
) = expr
{
546 self.visit_expr(expr
);
550 // FIXME tuple structs should generate tuple-specific data.
554 def
: &'l ast
::VariantData
,
555 ty_params
: &'l ast
::Generics
,
557 debug
!("process_struct {:?} {:?}", item
, item
.span
);
558 let name
= item
.ident
.to_string();
559 let qualname
= format
!("::{}", self.tcx
.node_path_str(item
.id
));
561 let (kind
, keyword
) = match item
.node
{
562 ast
::ItemKind
::Struct(_
, _
) => (DefKind
::Struct
, keywords
::Struct
),
563 ast
::ItemKind
::Union(_
, _
) => (DefKind
::Union
, keywords
::Union
),
567 let sub_span
= self.span
.sub_span_after_keyword(item
.span
, keyword
);
568 let (value
, fields
) = match item
.node
{
569 ast
::ItemKind
::Struct(ast
::VariantData
::Struct(ref fields
, _
), _
) |
570 ast
::ItemKind
::Union(ast
::VariantData
::Struct(ref fields
, _
), _
) => {
571 let include_priv_fields
= !self.save_ctxt
.config
.pub_only
;
572 let fields_str
= fields
575 .filter_map(|(i
, f
)| {
576 if include_priv_fields
|| f
.vis
.node
.is_pub() {
578 .map(|i
| i
.to_string())
579 .or_else(|| Some(i
.to_string()))
586 let value
= format
!("{} {{ {} }}", name
, fields_str
);
591 .map(|f
| ::id_from_node_id(f
.id
, &self.save_ctxt
))
595 _
=> (String
::new(), vec
![]),
598 if !self.span
.filter_generated(sub_span
, item
.span
) {
599 let span
= self.span_from_span(sub_span
.expect("No span found for struct"));
600 self.dumper
.dump_def(
601 &access_from
!(self.save_ctxt
, item
),
604 id
: ::id_from_node_id(item
.id
, &self.save_ctxt
),
607 qualname
: qualname
.clone(),
612 docs
: self.save_ctxt
.docs_for_attrs(&item
.attrs
),
613 sig
: sig
::item_signature(item
, &self.save_ctxt
),
614 attributes
: lower_attributes(item
.attrs
.clone(), &self.save_ctxt
),
619 for field
in def
.fields() {
620 self.process_struct_field_def(field
, item
.id
);
621 self.visit_ty(&field
.ty
);
624 self.process_generic_params(ty_params
, item
.span
, &qualname
, item
.id
);
630 enum_definition
: &'l ast
::EnumDef
,
631 ty_params
: &'l ast
::Generics
,
633 let enum_data
= self.save_ctxt
.get_item_data(item
);
634 let enum_data
= match enum_data
{
638 down_cast_data
!(enum_data
, DefData
, item
.span
);
640 let access
= access_from
!(self.save_ctxt
, item
);
642 for variant
in &enum_definition
.variants
{
643 let name
= variant
.node
.ident
.name
.to_string();
644 let qualname
= format
!("{}::{}", enum_data
.qualname
, name
);
646 match variant
.node
.data
{
647 ast
::VariantData
::Struct(ref fields
, _
) => {
648 let sub_span
= self.span
.span_for_first_ident(variant
.span
);
649 let fields_str
= fields
653 f
.ident
.map(|i
| i
.to_string()).unwrap_or_else(|| i
.to_string())
657 let value
= format
!("{}::{} {{ {} }}", enum_data
.name
, name
, fields_str
);
658 if !self.span
.filter_generated(sub_span
, variant
.span
) {
660 .span_from_span(sub_span
.expect("No span found for struct variant"));
661 let id
= ::id_from_node_id(variant
.node
.data
.id(), &self.save_ctxt
);
662 let parent
= Some(::id_from_node_id(item
.id
, &self.save_ctxt
));
664 self.dumper
.dump_def(
667 kind
: DefKind
::StructVariant
,
676 docs
: self.save_ctxt
.docs_for_attrs(&variant
.node
.attrs
),
677 sig
: sig
::variant_signature(variant
, &self.save_ctxt
),
678 attributes
: lower_attributes(
679 variant
.node
.attrs
.clone(),
687 let sub_span
= self.span
.span_for_first_ident(variant
.span
);
688 let mut value
= format
!("{}::{}", enum_data
.name
, name
);
689 if let &ast
::VariantData
::Tuple(ref fields
, _
) = v
{
691 value
.push_str(&fields
693 .map(|f
| ty_to_string(&f
.ty
))
698 if !self.span
.filter_generated(sub_span
, variant
.span
) {
700 self.span_from_span(sub_span
.expect("No span found for tuple variant"));
701 let id
= ::id_from_node_id(variant
.node
.data
.id(), &self.save_ctxt
);
702 let parent
= Some(::id_from_node_id(item
.id
, &self.save_ctxt
));
704 self.dumper
.dump_def(
707 kind
: DefKind
::TupleVariant
,
716 docs
: self.save_ctxt
.docs_for_attrs(&variant
.node
.attrs
),
717 sig
: sig
::variant_signature(variant
, &self.save_ctxt
),
718 attributes
: lower_attributes(
719 variant
.node
.attrs
.clone(),
729 for field
in variant
.node
.data
.fields() {
730 self.process_struct_field_def(field
, variant
.node
.data
.id());
731 self.visit_ty(&field
.ty
);
734 self.process_generic_params(ty_params
, item
.span
, &enum_data
.qualname
, item
.id
);
735 self.dumper
.dump_def(&access
, enum_data
);
741 type_parameters
: &'l ast
::Generics
,
742 trait_ref
: &'l Option
<ast
::TraitRef
>,
744 impl_items
: &'l
[ast
::ImplItem
],
746 if let Some(impl_data
) = self.save_ctxt
.get_item_data(item
) {
747 if let super::Data
::RelationData(rel
, imp
) = impl_data
{
748 self.dumper
.dump_relation(rel
);
749 self.dumper
.dump_impl(imp
);
751 span_bug
!(item
.span
, "unexpected data kind: {:?}", impl_data
);
755 if let &Some(ref trait_ref
) = trait_ref
{
756 self.process_path(trait_ref
.ref_id
, &trait_ref
.path
);
758 self.process_generic_params(type_parameters
, item
.span
, "", item
.id
);
759 for impl_item
in impl_items
{
760 let map
= &self.tcx
.hir
;
761 self.process_impl_item(impl_item
, map
.local_def_id(item
.id
));
768 generics
: &'l ast
::Generics
,
769 trait_refs
: &'l ast
::GenericBounds
,
770 methods
: &'l
[ast
::TraitItem
],
772 let name
= item
.ident
.to_string();
773 let qualname
= format
!("::{}", self.tcx
.node_path_str(item
.id
));
774 let mut val
= name
.clone();
775 if !generics
.params
.is_empty() {
776 val
.push_str(&generic_params_to_string(&generics
.params
));
778 if !trait_refs
.is_empty() {
780 val
.push_str(&bounds_to_string(trait_refs
));
782 let sub_span
= self.span
.sub_span_after_keyword(item
.span
, keywords
::Trait
);
783 if !self.span
.filter_generated(sub_span
, item
.span
) {
784 let id
= ::id_from_node_id(item
.id
, &self.save_ctxt
);
785 let span
= self.span_from_span(sub_span
.expect("No span found for trait"));
786 let children
= methods
788 .map(|i
| ::id_from_node_id(i
.id
, &self.save_ctxt
))
790 self.dumper
.dump_def(
791 &access_from
!(self.save_ctxt
, item
),
793 kind
: DefKind
::Trait
,
797 qualname
: qualname
.clone(),
802 docs
: self.save_ctxt
.docs_for_attrs(&item
.attrs
),
803 sig
: sig
::item_signature(item
, &self.save_ctxt
),
804 attributes
: lower_attributes(item
.attrs
.clone(), &self.save_ctxt
),
810 for super_bound
in trait_refs
.iter() {
811 let trait_ref
= match *super_bound
{
812 ast
::GenericBound
::Trait(ref trait_ref
, _
) => trait_ref
,
813 ast
::GenericBound
::Outlives(..) => continue,
816 let trait_ref
= &trait_ref
.trait_ref
;
817 if let Some(id
) = self.lookup_def_id(trait_ref
.ref_id
) {
818 let sub_span
= self.span
.sub_span_for_type_name(trait_ref
.path
.span
);
819 if !self.span
.filter_generated(sub_span
, trait_ref
.path
.span
) {
820 let span
= self.span_from_span(sub_span
.expect("No span found for trait ref"));
821 self.dumper
.dump_ref(Ref
{
824 ref_id
: ::id_from_def_id(id
),
828 if !self.span
.filter_generated(sub_span
, trait_ref
.path
.span
) {
829 let sub_span
= self.span_from_span(sub_span
.expect("No span for inheritance"));
830 self.dumper
.dump_relation(Relation
{
831 kind
: RelationKind
::SuperTrait
,
833 from
: ::id_from_def_id(id
),
834 to
: ::id_from_node_id(item
.id
, &self.save_ctxt
),
840 // walk generics and methods
841 self.process_generic_params(generics
, item
.span
, &qualname
, item
.id
);
842 for method
in methods
{
843 let map
= &self.tcx
.hir
;
844 self.process_trait_item(method
, map
.local_def_id(item
.id
))
848 // `item` is the module in question, represented as an item.
849 fn process_mod(&mut self, item
: &ast
::Item
) {
850 if let Some(mod_data
) = self.save_ctxt
.get_item_data(item
) {
851 down_cast_data
!(mod_data
, DefData
, item
.span
);
852 self.dumper
.dump_def(&access_from
!(self.save_ctxt
, item
), mod_data
);
856 fn dump_path_ref(&mut self, id
: NodeId
, path
: &ast
::Path
) {
857 let path_data
= self.save_ctxt
.get_path_data(id
, path
);
858 if let Some(path_data
) = path_data
{
859 self.dumper
.dump_ref(path_data
);
863 fn process_path(&mut self, id
: NodeId
, path
: &'l ast
::Path
) {
864 debug
!("process_path {:?}", path
);
865 if generated_code(path
.span
) {
868 self.dump_path_ref(id
, path
);
871 for seg
in &path
.segments
{
872 if let Some(ref generic_args
) = seg
.args
{
873 match **generic_args
{
874 ast
::GenericArgs
::AngleBracketed(ref data
) => {
875 for arg
in &data
.args
{
877 ast
::GenericArg
::Type(ty
) => self.visit_ty(ty
),
882 ast
::GenericArgs
::Parenthesized(ref data
) => {
883 for t
in &data
.inputs
{
886 if let Some(ref t
) = data
.output
{
894 // Modules or types in the path prefix.
895 match self.save_ctxt
.get_path_def(id
) {
896 HirDef
::Method(did
) => {
897 let ti
= self.tcx
.associated_item(did
);
898 if ti
.kind
== ty
::AssociatedKind
::Method
&& ti
.method_has_self_argument
{
899 self.write_sub_path_trait_truncated(path
);
905 HirDef
::StructCtor(..) |
906 HirDef
::VariantCtor(..) |
907 HirDef
::AssociatedConst(..) |
912 HirDef
::Variant(..) |
913 HirDef
::TyAlias(..) |
914 HirDef
::AssociatedTy(..) => self.write_sub_paths_truncated(path
),
919 fn process_struct_lit(
923 fields
: &'l
[ast
::Field
],
924 variant
: &'l ty
::VariantDef
,
925 base
: &'l Option
<P
<ast
::Expr
>>,
927 self.write_sub_paths_truncated(path
);
929 if let Some(struct_lit_data
) = self.save_ctxt
.get_expr_data(ex
) {
930 down_cast_data
!(struct_lit_data
, RefData
, ex
.span
);
931 if !generated_code(ex
.span
) {
932 self.dumper
.dump_ref(struct_lit_data
);
935 for field
in fields
{
936 if let Some(field_data
) = self.save_ctxt
.get_field_ref_data(field
, variant
) {
937 self.dumper
.dump_ref(field_data
);
940 self.visit_expr(&field
.expr
)
944 walk_list
!(self, visit_expr
, base
);
947 fn process_method_call(
950 seg
: &'l ast
::PathSegment
,
951 args
: &'l
[P
<ast
::Expr
>],
953 debug
!("process_method_call {:?} {:?}", ex
, ex
.span
);
954 if let Some(mcd
) = self.save_ctxt
.get_expr_data(ex
) {
955 down_cast_data
!(mcd
, RefData
, ex
.span
);
956 if !generated_code(ex
.span
) {
957 self.dumper
.dump_ref(mcd
);
961 // Explicit types in the turbo-fish.
962 if let Some(ref generic_args
) = seg
.args
{
963 if let ast
::GenericArgs
::AngleBracketed(ref data
) = **generic_args
{
964 for arg
in &data
.args
{
966 ast
::GenericArg
::Type(ty
) => self.visit_ty(ty
),
973 // walk receiver and args
974 walk_list
!(self, visit_expr
, args
);
977 fn process_pat(&mut self, p
: &'l ast
::Pat
) {
979 PatKind
::Struct(ref _path
, ref fields
, _
) => {
980 // FIXME do something with _path?
981 let hir_id
= self.tcx
.hir
.node_to_hir_id(p
.id
);
982 let adt
= match self.save_ctxt
.tables
.node_id_to_type_opt(hir_id
) {
983 Some(ty
) => ty
.ty_adt_def().unwrap(),
985 visit
::walk_pat(self, p
);
989 let variant
= adt
.variant_of_def(self.save_ctxt
.get_path_def(p
.id
));
991 for &Spanned { node: ref field, span }
in fields
{
992 let sub_span
= self.span
.span_for_first_ident(span
);
993 if let Some(index
) = self.tcx
.find_field_index(field
.ident
, variant
) {
994 if !self.span
.filter_generated(sub_span
, span
) {
996 self.span_from_span(sub_span
.expect("No span fund for var ref"));
997 self.dumper
.dump_ref(Ref
{
998 kind
: RefKind
::Variable
,
1000 ref_id
: ::id_from_def_id(variant
.fields
[index
].did
),
1004 self.visit_pat(&field
.pat
);
1007 _
=> visit
::walk_pat(self, p
),
1011 fn process_var_decl_multi(&mut self, pats
: &'l
[P
<ast
::Pat
>]) {
1012 let mut collector
= PathCollector
::new();
1013 for pattern
in pats
{
1014 // collect paths from the arm's patterns
1015 collector
.visit_pat(&pattern
);
1016 self.visit_pat(&pattern
);
1019 // process collected paths
1020 for (id
, ident
, immut
) in collector
.collected_idents
{
1021 match self.save_ctxt
.get_path_def(id
) {
1022 HirDef
::Local(id
) => {
1023 let mut value
= if immut
== ast
::Mutability
::Immutable
{
1024 self.span
.snippet(ident
.span
)
1026 "<mutable>".to_owned()
1028 let hir_id
= self.tcx
.hir
.node_to_hir_id(id
);
1029 let typ
= self.save_ctxt
1031 .node_id_to_type_opt(hir_id
)
1032 .map(|t
| t
.to_string())
1033 .unwrap_or_default();
1034 value
.push_str(": ");
1035 value
.push_str(&typ
);
1037 if !self.span
.filter_generated(Some(ident
.span
), ident
.span
) {
1038 let qualname
= format
!("{}${}", ident
.to_string(), id
);
1039 let id
= ::id_from_node_id(id
, &self.save_ctxt
);
1040 let span
= self.span_from_span(ident
.span
);
1042 self.dumper
.dump_def(
1048 kind
: DefKind
::Local
,
1051 name
: ident
.to_string(),
1057 docs
: String
::new(),
1064 HirDef
::StructCtor(..) |
1065 HirDef
::VariantCtor(..) |
1067 HirDef
::AssociatedConst(..) |
1068 HirDef
::Struct(..) |
1069 HirDef
::Variant(..) |
1070 HirDef
::TyAlias(..) |
1071 HirDef
::AssociatedTy(..) |
1072 HirDef
::SelfTy(..) => {
1073 self.dump_path_ref(id
, &ast
::Path
::from_ident(ident
));
1076 "unexpected definition kind when processing collected idents: {:?}",
1082 for (id
, ref path
) in collector
.collected_paths
{
1083 self.process_path(id
, path
);
1087 fn process_var_decl(&mut self, p
: &'l ast
::Pat
, value
: String
) {
1088 // The local could declare multiple new vars, we must walk the
1089 // pattern and collect them all.
1090 let mut collector
= PathCollector
::new();
1091 collector
.visit_pat(&p
);
1094 for (id
, ident
, immut
) in collector
.collected_idents
{
1095 let mut value
= match immut
{
1096 ast
::Mutability
::Immutable
=> value
.to_string(),
1099 let hir_id
= self.tcx
.hir
.node_to_hir_id(id
);
1100 let typ
= match self.save_ctxt
.tables
.node_id_to_type_opt(hir_id
) {
1102 let typ
= typ
.to_string();
1103 if !value
.is_empty() {
1104 value
.push_str(": ");
1106 value
.push_str(&typ
);
1109 None
=> String
::new(),
1112 // Get the span only for the name of the variable (I hope the path
1113 // is only ever a variable name, but who knows?).
1114 let sub_span
= self.span
.span_for_last_ident(ident
.span
);
1115 // Rust uses the id of the pattern for var lookups, so we'll use it too.
1116 if !self.span
.filter_generated(sub_span
, ident
.span
) {
1117 let qualname
= format
!("{}${}", ident
.to_string(), id
);
1118 let id
= ::id_from_node_id(id
, &self.save_ctxt
);
1119 let span
= self.span_from_span(sub_span
.expect("No span found for variable"));
1121 self.dumper
.dump_def(
1127 kind
: DefKind
::Local
,
1130 name
: ident
.to_string(),
1136 docs
: String
::new(),
1145 /// Extract macro use and definition information from the AST node defined
1146 /// by the given NodeId, using the expansion information from the node's
1149 /// If the span is not macro-generated, do nothing, else use callee and
1150 /// callsite spans to record macro definition and use data, using the
1151 /// mac_uses and mac_defs sets to prevent multiples.
1152 fn process_macro_use(&mut self, span
: Span
) {
1153 let source_span
= span
.source_callsite();
1154 if !self.macro_calls
.insert(source_span
) {
1158 let data
= match self.save_ctxt
.get_macro_use_data(span
) {
1163 self.dumper
.macro_use(data
);
1165 // FIXME write the macro def
1166 // let mut hasher = DefaultHasher::new();
1167 // data.callee_span.hash(&mut hasher);
1168 // let hash = hasher.finish();
1169 // let qualname = format!("{}::{}", data.name, hash);
1170 // Don't write macro definition for imported macros
1171 // if !self.mac_defs.contains(&data.callee_span)
1172 // && !data.imported {
1173 // self.mac_defs.insert(data.callee_span);
1174 // if let Some(sub_span) = self.span.span_for_macro_def_name(data.callee_span) {
1175 // self.dumper.macro_data(MacroData {
1177 // name: data.name.clone(),
1178 // qualname: qualname.clone(),
1179 // // FIXME where do macro docs come from?
1180 // docs: String::new(),
1181 // }.lower(self.tcx));
1186 fn process_trait_item(&mut self, trait_item
: &'l ast
::TraitItem
, trait_id
: DefId
) {
1187 self.process_macro_use(trait_item
.span
);
1188 let vis_span
= trait_item
.span
.shrink_to_lo();
1189 match trait_item
.node
{
1190 ast
::TraitItemKind
::Const(ref ty
, ref expr
) => {
1191 self.process_assoc_const(
1193 trait_item
.ident
.name
,
1196 expr
.as_ref().map(|e
| &**e
),
1198 respan(vis_span
, ast
::VisibilityKind
::Public
),
1202 ast
::TraitItemKind
::Method(ref sig
, ref body
) => {
1203 self.process_method(
1205 body
.as_ref().map(|x
| &**x
),
1208 &trait_item
.generics
,
1209 respan(vis_span
, ast
::VisibilityKind
::Public
),
1213 ast
::TraitItemKind
::Type(ref bounds
, ref default_ty
) => {
1214 // FIXME do something with _bounds (for type refs)
1215 let name
= trait_item
.ident
.name
.to_string();
1216 let qualname
= format
!("::{}", self.tcx
.node_path_str(trait_item
.id
));
1217 let sub_span
= self.span
1218 .sub_span_after_keyword(trait_item
.span
, keywords
::Type
);
1220 if !self.span
.filter_generated(sub_span
, trait_item
.span
) {
1221 let span
= self.span_from_span(sub_span
.expect("No span found for assoc type"));
1222 let id
= ::id_from_node_id(trait_item
.id
, &self.save_ctxt
);
1224 self.dumper
.dump_def(
1230 kind
: DefKind
::Type
,
1235 value
: self.span
.snippet(trait_item
.span
),
1236 parent
: Some(::id_from_def_id(trait_id
)),
1239 docs
: self.save_ctxt
.docs_for_attrs(&trait_item
.attrs
),
1240 sig
: sig
::assoc_type_signature(
1244 default_ty
.as_ref().map(|ty
| &**ty
),
1247 attributes
: lower_attributes(trait_item
.attrs
.clone(), &self.save_ctxt
),
1252 if let &Some(ref default_ty
) = default_ty
{
1253 self.visit_ty(default_ty
)
1256 ast
::TraitItemKind
::Macro(_
) => {}
1260 fn process_impl_item(&mut self, impl_item
: &'l ast
::ImplItem
, impl_id
: DefId
) {
1261 self.process_macro_use(impl_item
.span
);
1262 match impl_item
.node
{
1263 ast
::ImplItemKind
::Const(ref ty
, ref expr
) => {
1264 self.process_assoc_const(
1266 impl_item
.ident
.name
,
1271 impl_item
.vis
.clone(),
1275 ast
::ImplItemKind
::Method(ref sig
, ref body
) => {
1276 self.process_method(
1281 &impl_item
.generics
,
1282 impl_item
.vis
.clone(),
1286 ast
::ImplItemKind
::Type(ref ty
) => {
1287 // FIXME uses of the assoc type should ideally point to this
1288 // 'def' and the name here should be a ref to the def in the
1292 ast
::ImplItemKind
::Existential(ref bounds
) => {
1293 // FIXME uses of the assoc type should ideally point to this
1294 // 'def' and the name here should be a ref to the def in the
1296 for bound
in bounds
.iter() {
1297 if let ast
::GenericBound
::Trait(trait_ref
, _
) = bound
{
1298 self.process_path(trait_ref
.trait_ref
.ref_id
, &trait_ref
.trait_ref
.path
)
1302 ast
::ImplItemKind
::Macro(_
) => {}
1306 /// Dumps imports in a use tree recursively.
1308 /// A use tree is an import that may contain nested braces (RFC 2128). The `use_tree` parameter
1309 /// is the current use tree under scrutiny, while `id` and `prefix` are its corresponding node
1310 /// id and path. `root_item` is the topmost use tree in the hierarchy.
1312 /// If `use_tree` is a simple or glob import, it is dumped into the analysis data. Otherwise,
1313 /// each child use tree is dumped recursively.
1314 fn process_use_tree(&mut self,
1315 use_tree
: &'l ast
::UseTree
,
1317 root_item
: &'l ast
::Item
,
1318 prefix
: &ast
::Path
) {
1319 let path
= &use_tree
.prefix
;
1321 // The access is calculated using the current tree ID, but with the root tree's visibility
1322 // (since nested trees don't have their own visibility).
1323 let access
= access_from
!(self.save_ctxt
, root_item
.vis
, id
);
1325 // The parent def id of a given use tree is always the enclosing item.
1326 let parent
= self.save_ctxt
.tcx
.hir
.opt_local_def_id(id
)
1327 .and_then(|id
| self.save_ctxt
.tcx
.parent_def_id(id
))
1328 .map(::id_from_def_id
);
1330 match use_tree
.kind
{
1331 ast
::UseTreeKind
::Simple(..) => {
1332 let ident
= use_tree
.ident();
1333 let path
= ast
::Path
{
1334 segments
: prefix
.segments
1336 .chain(path
.segments
.iter())
1342 let sub_span
= self.span
.span_for_last_ident(path
.span
);
1343 let alias_span
= self.span
.sub_span_after_keyword(use_tree
.span
, keywords
::As
);
1344 let ref_id
= self.lookup_def_id(id
);
1346 if !self.span
.filter_generated(sub_span
, path
.span
) {
1347 let span
= self.span_from_span(sub_span
.expect("No span found for use"));
1348 let alias_span
= alias_span
.map(|sp
| self.span_from_span(sp
));
1349 self.dumper
.import(&access
, Import
{
1350 kind
: ImportKind
::Use
,
1351 ref_id
: ref_id
.map(|id
| ::id_from_def_id(id
)),
1354 name
: ident
.to_string(),
1355 value
: String
::new(),
1359 self.write_sub_paths_truncated(&path
);
1361 ast
::UseTreeKind
::Glob
=> {
1362 let path
= ast
::Path
{
1363 segments
: prefix
.segments
1365 .chain(path
.segments
.iter())
1371 // Make a comma-separated list of names of imported modules.
1372 let glob_map
= &self.save_ctxt
.analysis
.glob_map
;
1373 let glob_map
= glob_map
.as_ref().unwrap();
1374 let names
= if glob_map
.contains_key(&id
) {
1375 glob_map
.get(&id
).unwrap().iter().map(|n
| n
.to_string()).collect()
1380 let sub_span
= self.span
.sub_span_of_token(use_tree
.span
,
1381 token
::BinOp(token
::Star
));
1382 if !self.span
.filter_generated(sub_span
, use_tree
.span
) {
1384 self.span_from_span(sub_span
.expect("No span found for use glob"));
1385 self.dumper
.import(&access
, Import
{
1386 kind
: ImportKind
::GlobUse
,
1390 name
: "*".to_owned(),
1391 value
: names
.join(", "),
1395 self.write_sub_paths(&path
);
1397 ast
::UseTreeKind
::Nested(ref nested_items
) => {
1398 let prefix
= ast
::Path
{
1399 segments
: prefix
.segments
1401 .chain(path
.segments
.iter())
1406 for &(ref tree
, id
) in nested_items
{
1407 self.process_use_tree(tree
, id
, root_item
, &prefix
);
1413 fn process_bounds(&mut self, bounds
: &'l ast
::GenericBounds
) {
1414 for bound
in bounds
{
1415 if let ast
::GenericBound
::Trait(ref trait_ref
, _
) = *bound
{
1416 self.process_path(trait_ref
.trait_ref
.ref_id
, &trait_ref
.trait_ref
.path
)
1422 impl<'l
, 'tcx
: 'l
, 'll
, O
: DumpOutput
+ 'll
> Visitor
<'l
> for DumpVisitor
<'l
, 'tcx
, 'll
, O
> {
1423 fn visit_mod(&mut self, m
: &'l ast
::Mod
, span
: Span
, attrs
: &[ast
::Attribute
], id
: NodeId
) {
1424 // Since we handle explicit modules ourselves in visit_item, this should
1425 // only get called for the root module of a crate.
1426 assert_eq
!(id
, ast
::CRATE_NODE_ID
);
1428 let qualname
= format
!("::{}", self.tcx
.node_path_str(id
));
1430 let cm
= self.tcx
.sess
.source_map();
1431 let filename
= cm
.span_to_filename(span
);
1432 let data_id
= ::id_from_node_id(id
, &self.save_ctxt
);
1433 let children
= m
.items
1435 .map(|i
| ::id_from_node_id(i
.id
, &self.save_ctxt
))
1437 let span
= self.span_from_span(span
);
1439 self.dumper
.dump_def(
1447 name
: String
::new(),
1450 value
: filename
.to_string(),
1454 docs
: self.save_ctxt
.docs_for_attrs(attrs
),
1456 attributes
: lower_attributes(attrs
.to_owned(), &self.save_ctxt
),
1459 self.nest_scope(id
, |v
| visit
::walk_mod(v
, m
));
1462 fn visit_item(&mut self, item
: &'l ast
::Item
) {
1463 use syntax
::ast
::ItemKind
::*;
1464 self.process_macro_use(item
.span
);
1466 Use(ref use_tree
) => {
1467 let prefix
= ast
::Path
{
1471 self.process_use_tree(use_tree
, item
.id
, item
, &prefix
);
1474 let alias_span
= self.span
.span_for_last_ident(item
.span
);
1476 if !self.span
.filter_generated(alias_span
, item
.span
) {
1478 self.span_from_span(alias_span
.expect("No span found for extern crate"));
1479 let parent
= self.save_ctxt
.tcx
.hir
.opt_local_def_id(item
.id
)
1480 .and_then(|id
| self.save_ctxt
.tcx
.parent_def_id(id
))
1481 .map(::id_from_def_id
);
1488 kind
: ImportKind
::ExternCrate
,
1492 name
: item
.ident
.to_string(),
1493 value
: String
::new(),
1499 Fn(ref decl
, .., ref ty_params
, ref body
) => {
1500 self.process_fn(item
, &decl
, ty_params
, &body
)
1502 Static(ref typ
, _
, ref expr
) => self.process_static_or_const_item(item
, typ
, expr
),
1503 Const(ref typ
, ref expr
) => self.process_static_or_const_item(item
, &typ
, &expr
),
1504 Struct(ref def
, ref ty_params
) | Union(ref def
, ref ty_params
) => {
1505 self.process_struct(item
, def
, ty_params
)
1507 Enum(ref def
, ref ty_params
) => self.process_enum(item
, def
, ty_params
),
1508 Impl(.., ref ty_params
, ref trait_ref
, ref typ
, ref impl_items
) => {
1509 self.process_impl(item
, ty_params
, trait_ref
, &typ
, impl_items
)
1511 Trait(_
, _
, ref generics
, ref trait_refs
, ref methods
) => {
1512 self.process_trait(item
, generics
, trait_refs
, methods
)
1515 self.process_mod(item
);
1516 self.nest_scope(item
.id
, |v
| visit
::walk_mod(v
, m
));
1518 Ty(ref ty
, ref ty_params
) => {
1519 let qualname
= format
!("::{}", self.tcx
.node_path_str(item
.id
));
1520 let value
= ty_to_string(&ty
);
1521 let sub_span
= self.span
.sub_span_after_keyword(item
.span
, keywords
::Type
);
1522 if !self.span
.filter_generated(sub_span
, item
.span
) {
1523 let span
= self.span_from_span(sub_span
.expect("No span found for typedef"));
1524 let id
= ::id_from_node_id(item
.id
, &self.save_ctxt
);
1526 self.dumper
.dump_def(
1527 &access_from
!(self.save_ctxt
, item
),
1529 kind
: DefKind
::Type
,
1532 name
: item
.ident
.to_string(),
1533 qualname
: qualname
.clone(),
1538 docs
: self.save_ctxt
.docs_for_attrs(&item
.attrs
),
1539 sig
: sig
::item_signature(item
, &self.save_ctxt
),
1540 attributes
: lower_attributes(item
.attrs
.clone(), &self.save_ctxt
),
1546 self.process_generic_params(ty_params
, item
.span
, &qualname
, item
.id
);
1548 Existential(ref _bounds
, ref ty_params
) => {
1549 let qualname
= format
!("::{}", self.tcx
.node_path_str(item
.id
));
1550 // FIXME do something with _bounds
1551 let value
= String
::new();
1552 let sub_span
= self.span
.sub_span_after_keyword(item
.span
, keywords
::Type
);
1553 if !self.span
.filter_generated(sub_span
, item
.span
) {
1554 let span
= self.span_from_span(sub_span
.expect("No span found for typedef"));
1555 let id
= ::id_from_node_id(item
.id
, &self.save_ctxt
);
1557 self.dumper
.dump_def(
1558 &access_from
!(self.save_ctxt
, item
),
1560 kind
: DefKind
::Type
,
1563 name
: item
.ident
.to_string(),
1564 qualname
: qualname
.clone(),
1569 docs
: self.save_ctxt
.docs_for_attrs(&item
.attrs
),
1570 sig
: sig
::item_signature(item
, &self.save_ctxt
),
1571 attributes
: lower_attributes(item
.attrs
.clone(), &self.save_ctxt
),
1576 self.process_generic_params(ty_params
, item
.span
, &qualname
, item
.id
);
1579 _
=> visit
::walk_item(self, item
),
1583 fn visit_generics(&mut self, generics
: &'l ast
::Generics
) {
1584 for param
in &generics
.params
{
1585 if let ast
::GenericParamKind
::Type { ref default, .. }
= param
.kind
{
1586 self.process_bounds(¶m
.bounds
);
1587 if let Some(ref ty
) = default {
1592 for pred
in &generics
.where_clause
.predicates
{
1593 if let ast
::WherePredicate
::BoundPredicate(ref wbp
) = *pred
{
1594 self.process_bounds(&wbp
.bounds
);
1595 self.visit_ty(&wbp
.bounded_ty
);
1600 fn visit_ty(&mut self, t
: &'l ast
::Ty
) {
1601 self.process_macro_use(t
.span
);
1603 ast
::TyKind
::Path(_
, ref path
) => {
1604 if generated_code(t
.span
) {
1608 if let Some(id
) = self.lookup_def_id(t
.id
) {
1609 if let Some(sub_span
) = self.span
.sub_span_for_type_name(t
.span
) {
1610 let span
= self.span_from_span(sub_span
);
1611 self.dumper
.dump_ref(Ref
{
1612 kind
: RefKind
::Type
,
1614 ref_id
: ::id_from_def_id(id
),
1619 self.write_sub_paths_truncated(path
);
1620 visit
::walk_path(self, path
);
1622 ast
::TyKind
::Array(ref element
, ref length
) => {
1623 self.visit_ty(element
);
1624 self.nest_tables(length
.id
, |v
| v
.visit_expr(&length
.value
));
1626 _
=> visit
::walk_ty(self, t
),
1630 fn visit_expr(&mut self, ex
: &'l ast
::Expr
) {
1631 debug
!("visit_expr {:?}", ex
.node
);
1632 self.process_macro_use(ex
.span
);
1634 ast
::ExprKind
::Struct(ref path
, ref fields
, ref base
) => {
1635 let hir_expr
= self.save_ctxt
.tcx
.hir
.expect_expr(ex
.id
);
1636 let adt
= match self.save_ctxt
.tables
.expr_ty_opt(&hir_expr
) {
1637 Some(ty
) if ty
.ty_adt_def().is_some() => ty
.ty_adt_def().unwrap(),
1639 visit
::walk_expr(self, ex
);
1643 let def
= self.save_ctxt
.get_path_def(hir_expr
.id
);
1644 self.process_struct_lit(ex
, path
, fields
, adt
.variant_of_def(def
), base
)
1646 ast
::ExprKind
::MethodCall(ref seg
, ref args
) => self.process_method_call(ex
, seg
, args
),
1647 ast
::ExprKind
::Field(ref sub_ex
, _
) => {
1648 self.visit_expr(&sub_ex
);
1650 if let Some(field_data
) = self.save_ctxt
.get_expr_data(ex
) {
1651 down_cast_data
!(field_data
, RefData
, ex
.span
);
1652 if !generated_code(ex
.span
) {
1653 self.dumper
.dump_ref(field_data
);
1657 ast
::ExprKind
::Closure(_
, _
, _
, ref decl
, ref body
, _fn_decl_span
) => {
1658 let id
= format
!("${}", ex
.id
);
1660 // walk arg and return types
1661 for arg
in &decl
.inputs
{
1662 self.visit_ty(&arg
.ty
);
1665 if let ast
::FunctionRetTy
::Ty(ref ret_ty
) = decl
.output
{
1666 self.visit_ty(&ret_ty
);
1670 self.nest_tables(ex
.id
, |v
| {
1671 v
.process_formals(&decl
.inputs
, &id
);
1672 v
.nest_scope(ex
.id
, |v
| v
.visit_expr(body
))
1675 ast
::ExprKind
::ForLoop(ref pattern
, ref subexpression
, ref block
, _
) => {
1676 let value
= self.span
.snippet(subexpression
.span
);
1677 self.process_var_decl(pattern
, value
);
1678 debug
!("for loop, walk sub-expr: {:?}", subexpression
.node
);
1679 self.visit_expr(subexpression
);
1680 visit
::walk_block(self, block
);
1682 ast
::ExprKind
::WhileLet(ref pats
, ref subexpression
, ref block
, _
) => {
1683 self.process_var_decl_multi(pats
);
1684 debug
!("for loop, walk sub-expr: {:?}", subexpression
.node
);
1685 self.visit_expr(subexpression
);
1686 visit
::walk_block(self, block
);
1688 ast
::ExprKind
::IfLet(ref pats
, ref subexpression
, ref block
, ref opt_else
) => {
1689 self.process_var_decl_multi(pats
);
1690 self.visit_expr(subexpression
);
1691 visit
::walk_block(self, block
);
1692 opt_else
.as_ref().map(|el
| self.visit_expr(el
));
1694 ast
::ExprKind
::Repeat(ref element
, ref count
) => {
1695 self.visit_expr(element
);
1696 self.nest_tables(count
.id
, |v
| v
.visit_expr(&count
.value
));
1698 // In particular, we take this branch for call and path expressions,
1699 // where we'll index the idents involved just by continuing to walk.
1700 _
=> visit
::walk_expr(self, ex
),
1704 fn visit_mac(&mut self, mac
: &'l ast
::Mac
) {
1705 // These shouldn't exist in the AST at this point, log a span bug.
1708 "macro invocation should have been expanded out of AST"
1712 fn visit_pat(&mut self, p
: &'l ast
::Pat
) {
1713 self.process_macro_use(p
.span
);
1714 self.process_pat(p
);
1717 fn visit_arm(&mut self, arm
: &'l ast
::Arm
) {
1718 self.process_var_decl_multi(&arm
.pats
);
1720 Some(ast
::Guard
::If(ref expr
)) => self.visit_expr(expr
),
1723 self.visit_expr(&arm
.body
);
1726 fn visit_path(&mut self, p
: &'l ast
::Path
, id
: NodeId
) {
1727 self.process_path(id
, p
);
1730 fn visit_stmt(&mut self, s
: &'l ast
::Stmt
) {
1731 self.process_macro_use(s
.span
);
1732 visit
::walk_stmt(self, s
)
1735 fn visit_local(&mut self, l
: &'l ast
::Local
) {
1736 self.process_macro_use(l
.span
);
1739 .map(|i
| self.span
.snippet(i
.span
))
1740 .unwrap_or_default();
1741 self.process_var_decl(&l
.pat
, value
);
1743 // Just walk the initialiser and type (don't want to walk the pattern again).
1744 walk_list
!(self, visit_ty
, &l
.ty
);
1745 walk_list
!(self, visit_expr
, &l
.init
);
1748 fn visit_foreign_item(&mut self, item
: &'l ast
::ForeignItem
) {
1749 let access
= access_from
!(self.save_ctxt
, item
);
1752 ast
::ForeignItemKind
::Fn(ref decl
, ref generics
) => {
1753 if let Some(fn_data
) = self.save_ctxt
.get_extern_item_data(item
) {
1754 down_cast_data
!(fn_data
, DefData
, item
.span
);
1758 |v
| v
.process_formals(&decl
.inputs
, &fn_data
.qualname
),
1760 self.process_generic_params(generics
, item
.span
, &fn_data
.qualname
, item
.id
);
1761 self.dumper
.dump_def(&access
, fn_data
);
1764 for arg
in &decl
.inputs
{
1765 self.visit_ty(&arg
.ty
);
1768 if let ast
::FunctionRetTy
::Ty(ref ret_ty
) = decl
.output
{
1769 self.visit_ty(&ret_ty
);
1772 ast
::ForeignItemKind
::Static(ref ty
, _
) => {
1773 if let Some(var_data
) = self.save_ctxt
.get_extern_item_data(item
) {
1774 down_cast_data
!(var_data
, DefData
, item
.span
);
1775 self.dumper
.dump_def(&access
, var_data
);
1780 ast
::ForeignItemKind
::Ty
=> {
1781 if let Some(var_data
) = self.save_ctxt
.get_extern_item_data(item
) {
1782 down_cast_data
!(var_data
, DefData
, item
.span
);
1783 self.dumper
.dump_def(&access
, var_data
);
1786 ast
::ForeignItemKind
::Macro(..) => {}