1 //! Write the output of rustc's analysis to an implementor of Dump.
3 //! Dumping the analysis is implemented by walking the AST and getting a bunch of
4 //! info out from all over the place. We use `DefId`s to identify objects. The
5 //! tricky part is getting syntactic (span, source text) and semantic (reference
6 //! `DefId`s) information for parts of expressions which the compiler has discarded.
7 //! E.g., in a path `foo::bar::baz`, the compiler only keeps a span for the whole
8 //! path and a reference to `baz`, but we want spans and references for all three
11 //! SpanUtils is used to manipulate spans. In particular, to extract sub-spans
12 //! from spans (e.g., the span for `bar` from the above example path).
13 //! DumpVisitor walks the AST and processes it, and Dumper is used for
14 //! recording the output.
17 use rustc_ast
::walk_list
;
18 use rustc_data_structures
::fx
::FxHashSet
;
20 use rustc_hir
::def
::{DefKind as HirDefKind, Res}
;
21 use rustc_hir
::def_id
::{DefId, LocalDefId}
;
22 use rustc_hir
::intravisit
::{self, Visitor}
;
23 use rustc_hir_pretty
::{bounds_to_string, fn_to_string, generic_params_to_string, ty_to_string}
;
24 use rustc_middle
::hir
::map
::Map
;
25 use rustc_middle
::span_bug
;
26 use rustc_middle
::ty
::{self, DefIdTree, TyCtxt}
;
27 use rustc_session
::config
::Input
;
28 use rustc_span
::source_map
::respan
;
29 use rustc_span
::symbol
::Ident
;
35 use crate::dumper
::{Access, Dumper}
;
37 use crate::span_utils
::SpanUtils
;
39 escape
, generated_code
, id_from_def_id
, id_from_hir_id
, lower_attributes
, PathCollector
,
44 CompilationOptions
, CratePreludeData
, Def
, DefKind
, GlobalCrateId
, Import
, ImportKind
, Ref
,
45 RefKind
, Relation
, RelationKind
, SpanData
,
48 use tracing
::{debug, error}
;
50 macro_rules
! down_cast_data
{
51 ($id
:ident
, $kind
:ident
, $sp
:expr
) => {
52 let $id
= if let super::Data
::$
kind(data
) = $id
{
55 span_bug
!($sp
, "unexpected data kind: {:?}", $id
);
60 macro_rules
! access_from
{
61 ($save_ctxt
:expr
, $item
:expr
, $id
:expr
) => {
63 public
: $item
.vis
.node
.is_pub(),
64 reachable
: $save_ctxt
.access_levels
.is_reachable($id
),
69 macro_rules
! access_from_vis
{
70 ($save_ctxt
:expr
, $vis
:expr
, $id
:expr
) => {
71 Access { public: $vis.node.is_pub(), reachable: $save_ctxt.access_levels.is_reachable($id) }
75 pub struct DumpVisitor
<'tcx
> {
76 pub save_ctxt
: SaveContext
<'tcx
>,
80 span
: SpanUtils
<'tcx
>,
81 // Set of macro definition (callee) spans, and the set
82 // of macro use (callsite) spans. We store these to ensure
83 // we only write one macro def per unique macro definition, and
84 // one macro use per unique callsite span.
85 // mac_defs: FxHashSet<Span>,
86 // macro_calls: FxHashSet<Span>,
89 impl<'tcx
> DumpVisitor
<'tcx
> {
90 pub fn new(save_ctxt
: SaveContext
<'tcx
>) -> DumpVisitor
<'tcx
> {
91 let span_utils
= SpanUtils
::new(&save_ctxt
.tcx
.sess
);
92 let dumper
= Dumper
::new(save_ctxt
.config
.clone());
98 // mac_defs: FxHashSet::default(),
99 // macro_calls: FxHashSet::default(),
103 pub fn analysis(&self) -> &rls_data
::Analysis
{
104 self.dumper
.analysis()
107 fn nest_typeck_results
<F
>(&mut self, item_def_id
: LocalDefId
, f
: F
)
109 F
: FnOnce(&mut Self),
111 let typeck_results
= if self.tcx
.has_typeck_results(item_def_id
) {
112 Some(self.tcx
.typeck(item_def_id
))
117 let old_maybe_typeck_results
= self.save_ctxt
.maybe_typeck_results
;
118 self.save_ctxt
.maybe_typeck_results
= typeck_results
;
120 self.save_ctxt
.maybe_typeck_results
= old_maybe_typeck_results
;
123 fn span_from_span(&self, span
: Span
) -> SpanData
{
124 self.save_ctxt
.span_from_span(span
)
127 fn lookup_def_id(&self, ref_id
: hir
::HirId
) -> Option
<DefId
> {
128 self.save_ctxt
.lookup_def_id(ref_id
)
131 pub fn dump_crate_info(&mut self, name
: &str, krate
: &hir
::Crate
<'_
>) {
132 let source_file
= self.tcx
.sess
.local_crate_source_file
.as_ref();
133 let crate_root
= source_file
.map(|source_file
| {
134 let source_file
= Path
::new(source_file
);
135 match source_file
.file_name() {
136 Some(_
) => source_file
.parent().unwrap().display(),
137 None
=> source_file
.display(),
142 let data
= CratePreludeData
{
143 crate_id
: GlobalCrateId
{
148 .local_crate_disambiguator()
152 crate_root
: crate_root
.unwrap_or_else(|| "<no source>".to_owned()),
153 external_crates
: self.save_ctxt
.get_external_crates(),
154 span
: self.span_from_span(krate
.item
.span
),
157 self.dumper
.crate_prelude(data
);
160 pub fn dump_compilation_options(&mut self, input
: &Input
, crate_name
: &str) {
161 // Apply possible `remap-path-prefix` remapping to the input source file
162 // (and don't include remapping args anymore)
163 let (program
, arguments
) = {
164 let remap_arg_indices
= {
165 let mut indices
= FxHashSet
::default();
166 // Args are guaranteed to be valid UTF-8 (checked early)
167 for (i
, e
) in env
::args().enumerate() {
168 if e
.starts_with("--remap-path-prefix=") {
170 } else if e
== "--remap-path-prefix" {
172 indices
.insert(i
+ 1);
178 let mut args
= env
::args()
180 .filter(|(i
, _
)| !remap_arg_indices
.contains(i
))
181 .map(|(_
, arg
)| match input
{
182 Input
::File(ref path
) if path
== Path
::new(&arg
) => {
183 let mapped
= &self.tcx
.sess
.local_crate_source_file
;
184 mapped
.as_ref().unwrap().to_string_lossy().into()
189 (args
.next().unwrap(), args
.collect())
192 let data
= CompilationOptions
{
193 directory
: self.tcx
.sess
.working_dir
.0.clone(),
196 output
: self.save_ctxt
.compilation_output(crate_name
),
199 self.dumper
.compilation_opts(data
);
202 fn write_segments(&mut self, segments
: impl IntoIterator
<Item
= &'tcx hir
::PathSegment
<'tcx
>>) {
203 for seg
in segments
{
204 if let Some(data
) = self.save_ctxt
.get_path_segment_data(seg
) {
205 self.dumper
.dump_ref(data
);
210 fn write_sub_paths(&mut self, path
: &'tcx hir
::Path
<'tcx
>) {
211 self.write_segments(path
.segments
)
214 // As write_sub_paths, but does not process the last ident in the path (assuming it
215 // will be processed elsewhere). See note on write_sub_paths about global.
216 fn write_sub_paths_truncated(&mut self, path
: &'tcx hir
::Path
<'tcx
>) {
217 if let [segments @
.., _
] = path
.segments
{
218 self.write_segments(segments
)
222 fn process_formals(&mut self, formals
: &'tcx
[hir
::Param
<'tcx
>], qualname
: &str) {
224 self.visit_pat(&arg
.pat
);
225 let mut collector
= PathCollector
::new(self.tcx
);
226 collector
.visit_pat(&arg
.pat
);
228 for (hir_id
, ident
, ..) in collector
.collected_idents
{
229 let typ
= match self.save_ctxt
.typeck_results().node_type_opt(hir_id
) {
230 Some(s
) => s
.to_string(),
233 if !self.span
.filter_generated(ident
.span
) {
234 let id
= id_from_hir_id(hir_id
, &self.save_ctxt
);
235 let span
= self.span_from_span(ident
.span
);
237 self.dumper
.dump_def(
238 &Access { public: false, reachable: false }
,
240 kind
: DefKind
::Local
,
243 name
: ident
.to_string(),
244 qualname
: format
!("{}::{}", qualname
, ident
.to_string()),
261 sig
: &'tcx hir
::FnSig
<'tcx
>,
262 body
: Option
<hir
::BodyId
>,
265 generics
: &'tcx hir
::Generics
<'tcx
>,
266 vis
: &hir
::Visibility
<'tcx
>,
269 debug
!("process_method: {}:{}", hir_id
, ident
);
271 let map
= &self.tcx
.hir();
272 self.nest_typeck_results(map
.local_def_id(hir_id
), |v
| {
273 if let Some(mut method_data
) = v
.save_ctxt
.get_method_data(hir_id
, ident
, span
) {
274 if let Some(body
) = body
{
275 v
.process_formals(map
.body(body
).params
, &method_data
.qualname
);
277 v
.process_generic_params(&generics
, &method_data
.qualname
, hir_id
);
280 fn_to_string(sig
.decl
, sig
.header
, Some(ident
.name
), generics
, vis
, &[], None
);
281 method_data
.sig
= sig
::method_signature(hir_id
, ident
, generics
, sig
, &v
.save_ctxt
);
283 v
.dumper
.dump_def(&access_from_vis
!(v
.save_ctxt
, vis
, hir_id
), method_data
);
286 // walk arg and return types
287 for arg
in sig
.decl
.inputs
{
291 if let hir
::FnRetTy
::Return(ref ret_ty
) = sig
.decl
.output
{
296 if let Some(body
) = body
{
297 v
.visit_expr(&map
.body(body
).value
);
302 fn process_struct_field_def(
304 field
: &'tcx hir
::FieldDef
<'tcx
>,
305 parent_id
: hir
::HirId
,
307 let field_data
= self.save_ctxt
.get_field_data(field
, parent_id
);
308 if let Some(field_data
) = field_data
{
309 self.dumper
.dump_def(&access_from
!(self.save_ctxt
, field
, field
.hir_id
), field_data
);
313 // Dump generic params bindings, then visit_generics
314 fn process_generic_params(
316 generics
: &'tcx hir
::Generics
<'tcx
>,
320 for param
in generics
.params
{
322 hir
::GenericParamKind
::Lifetime { .. }
=> {}
323 hir
::GenericParamKind
::Type
{
324 synthetic
: Some(hir
::SyntheticTyParamKind
::ImplTrait
),
328 .nest_typeck_results(self.tcx
.hir().local_def_id(param
.hir_id
), |this
| {
329 this
.visit_generics(generics
)
332 hir
::GenericParamKind
::Type { .. }
=> {
333 let param_ss
= param
.name
.ident().span
;
334 let name
= escape(self.span
.snippet(param_ss
));
335 // Append $id to name to make sure each one is unique.
336 let qualname
= format
!("{}::{}${}", prefix
, name
, id
);
337 if !self.span
.filter_generated(param_ss
) {
338 let id
= id_from_hir_id(param
.hir_id
, &self.save_ctxt
);
339 let span
= self.span_from_span(param_ss
);
341 self.dumper
.dump_def(
342 &Access { public: false, reachable: false }
,
349 value
: String
::new(),
360 hir
::GenericParamKind
::Const { .. }
=> {}
364 self.visit_generics(generics
)
369 item
: &'tcx hir
::Item
<'tcx
>,
370 decl
: &'tcx hir
::FnDecl
<'tcx
>,
371 _header
: &'tcx hir
::FnHeader
,
372 ty_params
: &'tcx hir
::Generics
<'tcx
>,
375 let map
= &self.tcx
.hir();
376 self.nest_typeck_results(item
.def_id
, |v
| {
377 let body
= map
.body(body
);
378 if let Some(fn_data
) = v
.save_ctxt
.get_item_data(item
) {
379 down_cast_data
!(fn_data
, DefData
, item
.span
);
380 v
.process_formals(body
.params
, &fn_data
.qualname
);
381 v
.process_generic_params(ty_params
, &fn_data
.qualname
, item
.hir_id());
383 v
.dumper
.dump_def(&access_from
!(v
.save_ctxt
, item
, item
.hir_id()), fn_data
);
386 for arg
in decl
.inputs
{
390 if let hir
::FnRetTy
::Return(ref ret_ty
) = decl
.output
{
394 v
.visit_expr(&body
.value
);
398 fn process_static_or_const_item(
400 item
: &'tcx hir
::Item
<'tcx
>,
401 typ
: &'tcx hir
::Ty
<'tcx
>,
402 expr
: &'tcx hir
::Expr
<'tcx
>,
404 self.nest_typeck_results(item
.def_id
, |v
| {
405 if let Some(var_data
) = v
.save_ctxt
.get_item_data(item
) {
406 down_cast_data
!(var_data
, DefData
, item
.span
);
407 v
.dumper
.dump_def(&access_from
!(v
.save_ctxt
, item
, item
.hir_id()), var_data
);
414 fn process_assoc_const(
418 typ
: &'tcx hir
::Ty
<'tcx
>,
419 expr
: Option
<&'tcx hir
::Expr
<'tcx
>>,
421 vis
: &hir
::Visibility
<'tcx
>,
422 attrs
: &'tcx
[ast
::Attribute
],
425 format
!("::{}", self.tcx
.def_path_str(self.tcx
.hir().local_def_id(hir_id
).to_def_id()));
427 if !self.span
.filter_generated(ident
.span
) {
428 let sig
= sig
::assoc_const_signature(hir_id
, ident
.name
, typ
, expr
, &self.save_ctxt
);
429 let span
= self.span_from_span(ident
.span
);
431 self.dumper
.dump_def(
432 &access_from_vis
!(self.save_ctxt
, vis
, hir_id
),
434 kind
: DefKind
::Const
,
435 id
: id_from_hir_id(hir_id
, &self.save_ctxt
),
437 name
: ident
.name
.to_string(),
439 value
: ty_to_string(&typ
),
440 parent
: Some(id_from_def_id(parent_id
)),
443 docs
: self.save_ctxt
.docs_for_attrs(attrs
),
445 attributes
: lower_attributes(attrs
.to_owned(), &self.save_ctxt
),
450 // walk type and init value
451 self.nest_typeck_results(self.tcx
.hir().local_def_id(hir_id
), |v
| {
453 if let Some(expr
) = expr
{
459 // FIXME tuple structs should generate tuple-specific data.
462 item
: &'tcx hir
::Item
<'tcx
>,
463 def
: &'tcx hir
::VariantData
<'tcx
>,
464 ty_params
: &'tcx hir
::Generics
<'tcx
>,
466 debug
!("process_struct {:?} {:?}", item
, item
.span
);
467 let name
= item
.ident
.to_string();
468 let qualname
= format
!("::{}", self.tcx
.def_path_str(item
.def_id
.to_def_id()));
470 let kind
= match item
.kind
{
471 hir
::ItemKind
::Struct(_
, _
) => DefKind
::Struct
,
472 hir
::ItemKind
::Union(_
, _
) => DefKind
::Union
,
476 let (value
, fields
) = match item
.kind
{
477 hir
::ItemKind
::Struct(hir
::VariantData
::Struct(ref fields
, ..), ..)
478 | hir
::ItemKind
::Union(hir
::VariantData
::Struct(ref fields
, ..), ..) => {
479 let include_priv_fields
= !self.save_ctxt
.config
.pub_only
;
480 let fields_str
= fields
483 if include_priv_fields
|| f
.vis
.node
.is_pub() {
484 Some(f
.ident
.to_string())
491 let value
= format
!("{} {{ {} }}", name
, fields_str
);
492 (value
, fields
.iter().map(|f
| id_from_hir_id(f
.hir_id
, &self.save_ctxt
)).collect())
494 _
=> (String
::new(), vec
![]),
497 if !self.span
.filter_generated(item
.ident
.span
) {
498 let span
= self.span_from_span(item
.ident
.span
);
499 let attrs
= self.tcx
.hir().attrs(item
.hir_id());
500 self.dumper
.dump_def(
501 &access_from
!(self.save_ctxt
, item
, item
.hir_id()),
504 id
: id_from_def_id(item
.def_id
.to_def_id()),
507 qualname
: qualname
.clone(),
512 docs
: self.save_ctxt
.docs_for_attrs(attrs
),
513 sig
: sig
::item_signature(item
, &self.save_ctxt
),
514 attributes
: lower_attributes(attrs
.to_vec(), &self.save_ctxt
),
519 self.nest_typeck_results(item
.def_id
, |v
| {
520 for field
in def
.fields() {
521 v
.process_struct_field_def(field
, item
.hir_id());
522 v
.visit_ty(&field
.ty
);
525 v
.process_generic_params(ty_params
, &qualname
, item
.hir_id());
531 item
: &'tcx hir
::Item
<'tcx
>,
532 enum_definition
: &'tcx hir
::EnumDef
<'tcx
>,
533 ty_params
: &'tcx hir
::Generics
<'tcx
>,
535 let enum_data
= self.save_ctxt
.get_item_data(item
);
536 let enum_data
= match enum_data
{
540 down_cast_data
!(enum_data
, DefData
, item
.span
);
542 let access
= access_from
!(self.save_ctxt
, item
, item
.hir_id());
544 for variant
in enum_definition
.variants
{
545 let name
= variant
.ident
.name
.to_string();
546 let qualname
= format
!("{}::{}", enum_data
.qualname
, name
);
547 let name_span
= variant
.ident
.span
;
550 hir
::VariantData
::Struct(ref fields
, ..) => {
552 fields
.iter().map(|f
| f
.ident
.to_string()).collect
::<Vec
<_
>>().join(", ");
553 let value
= format
!("{}::{} {{ {} }}", enum_data
.name
, name
, fields_str
);
554 if !self.span
.filter_generated(name_span
) {
555 let span
= self.span_from_span(name_span
);
556 let id
= id_from_hir_id(variant
.id
, &self.save_ctxt
);
557 let parent
= Some(id_from_def_id(item
.def_id
.to_def_id()));
558 let attrs
= self.tcx
.hir().attrs(variant
.id
);
560 self.dumper
.dump_def(
563 kind
: DefKind
::StructVariant
,
572 docs
: self.save_ctxt
.docs_for_attrs(attrs
),
573 sig
: sig
::variant_signature(variant
, &self.save_ctxt
),
574 attributes
: lower_attributes(attrs
.to_vec(), &self.save_ctxt
),
580 let mut value
= format
!("{}::{}", enum_data
.name
, name
);
581 if let hir
::VariantData
::Tuple(fields
, _
) = v
{
586 .map(|f
| ty_to_string(&f
.ty
))
592 if !self.span
.filter_generated(name_span
) {
593 let span
= self.span_from_span(name_span
);
594 let id
= id_from_hir_id(variant
.id
, &self.save_ctxt
);
595 let parent
= Some(id_from_def_id(item
.def_id
.to_def_id()));
596 let attrs
= self.tcx
.hir().attrs(variant
.id
);
598 self.dumper
.dump_def(
601 kind
: DefKind
::TupleVariant
,
610 docs
: self.save_ctxt
.docs_for_attrs(attrs
),
611 sig
: sig
::variant_signature(variant
, &self.save_ctxt
),
612 attributes
: lower_attributes(attrs
.to_vec(), &self.save_ctxt
),
619 for field
in variant
.data
.fields() {
620 self.process_struct_field_def(field
, variant
.id
);
621 self.visit_ty(field
.ty
);
624 self.process_generic_params(ty_params
, &enum_data
.qualname
, item
.hir_id());
625 self.dumper
.dump_def(&access
, enum_data
);
628 fn process_impl(&mut self, item
: &'tcx hir
::Item
<'tcx
>, impl_
: &'tcx hir
::Impl
<'tcx
>) {
629 if let Some(impl_data
) = self.save_ctxt
.get_item_data(item
) {
630 if !self.span
.filter_generated(item
.span
) {
631 if let super::Data
::RelationData(rel
, imp
) = impl_data
{
632 self.dumper
.dump_relation(rel
);
633 self.dumper
.dump_impl(imp
);
635 span_bug
!(item
.span
, "unexpected data kind: {:?}", impl_data
);
640 let map
= &self.tcx
.hir();
641 self.nest_typeck_results(item
.def_id
, |v
| {
642 v
.visit_ty(&impl_
.self_ty
);
643 if let Some(trait_ref
) = &impl_
.of_trait
{
644 v
.process_path(trait_ref
.hir_ref_id
, &hir
::QPath
::Resolved(None
, &trait_ref
.path
));
646 v
.process_generic_params(&impl_
.generics
, "", item
.hir_id());
647 for impl_item
in impl_
.items
{
648 v
.process_impl_item(map
.impl_item(impl_item
.id
), item
.def_id
.to_def_id());
655 item
: &'tcx hir
::Item
<'tcx
>,
656 generics
: &'tcx hir
::Generics
<'tcx
>,
657 trait_refs
: hir
::GenericBounds
<'tcx
>,
658 methods
: &'tcx
[hir
::TraitItemRef
],
660 let name
= item
.ident
.to_string();
661 let qualname
= format
!("::{}", self.tcx
.def_path_str(item
.def_id
.to_def_id()));
662 let mut val
= name
.clone();
663 if !generics
.params
.is_empty() {
664 val
.push_str(&generic_params_to_string(generics
.params
));
666 if !trait_refs
.is_empty() {
668 val
.push_str(&bounds_to_string(trait_refs
));
670 if !self.span
.filter_generated(item
.ident
.span
) {
671 let id
= id_from_def_id(item
.def_id
.to_def_id());
672 let span
= self.span_from_span(item
.ident
.span
);
674 methods
.iter().map(|i
| id_from_def_id(i
.id
.def_id
.to_def_id())).collect();
675 let attrs
= self.tcx
.hir().attrs(item
.hir_id());
676 self.dumper
.dump_def(
677 &access_from
!(self.save_ctxt
, item
, item
.hir_id()),
679 kind
: DefKind
::Trait
,
683 qualname
: qualname
.clone(),
688 docs
: self.save_ctxt
.docs_for_attrs(attrs
),
689 sig
: sig
::item_signature(item
, &self.save_ctxt
),
690 attributes
: lower_attributes(attrs
.to_vec(), &self.save_ctxt
),
696 for super_bound
in trait_refs
.iter() {
697 let (def_id
, sub_span
) = match *super_bound
{
698 hir
::GenericBound
::Trait(ref trait_ref
, _
) => (
699 self.lookup_def_id(trait_ref
.trait_ref
.hir_ref_id
),
700 trait_ref
.trait_ref
.path
.segments
.last().unwrap().ident
.span
,
702 hir
::GenericBound
::LangItemTrait(lang_item
, span
, _
, _
) => {
703 (Some(self.tcx
.require_lang_item(lang_item
, Some(span
))), span
)
705 hir
::GenericBound
::Outlives(..) => continue,
708 if let Some(id
) = def_id
{
709 if !self.span
.filter_generated(sub_span
) {
710 let span
= self.span_from_span(sub_span
);
711 self.dumper
.dump_ref(Ref
{
714 ref_id
: id_from_def_id(id
),
717 self.dumper
.dump_relation(Relation
{
718 kind
: RelationKind
::SuperTrait
,
720 from
: id_from_def_id(id
),
721 to
: id_from_def_id(item
.def_id
.to_def_id()),
727 // walk generics and methods
728 self.process_generic_params(generics
, &qualname
, item
.hir_id());
729 for method
in methods
{
730 let map
= &self.tcx
.hir();
731 self.process_trait_item(map
.trait_item(method
.id
), item
.def_id
.to_def_id())
735 // `item` is the module in question, represented as an( item.
736 fn process_mod(&mut self, item
: &'tcx hir
::Item
<'tcx
>) {
737 if let Some(mod_data
) = self.save_ctxt
.get_item_data(item
) {
738 down_cast_data
!(mod_data
, DefData
, item
.span
);
739 self.dumper
.dump_def(&access_from
!(self.save_ctxt
, item
, item
.hir_id()), mod_data
);
743 fn dump_path_ref(&mut self, id
: hir
::HirId
, path
: &hir
::QPath
<'tcx
>) {
744 let path_data
= self.save_ctxt
.get_path_data(id
, path
);
745 if let Some(path_data
) = path_data
{
746 self.dumper
.dump_ref(path_data
);
750 fn dump_path_segment_ref(&mut self, id
: hir
::HirId
, segment
: &hir
::PathSegment
<'tcx
>) {
751 let segment_data
= self.save_ctxt
.get_path_segment_data_with_id(segment
, id
);
752 if let Some(segment_data
) = segment_data
{
753 self.dumper
.dump_ref(segment_data
);
757 fn process_path(&mut self, id
: hir
::HirId
, path
: &hir
::QPath
<'tcx
>) {
758 if self.span
.filter_generated(path
.span()) {
761 self.dump_path_ref(id
, path
);
764 let segments
= match path
{
765 hir
::QPath
::Resolved(ty
, path
) => {
766 if let Some(ty
) = ty
{
771 hir
::QPath
::TypeRelative(ty
, segment
) => {
773 std
::slice
::from_ref(*segment
)
775 hir
::QPath
::LangItem(..) => return,
777 for seg
in segments
{
778 if let Some(ref generic_args
) = seg
.args
{
779 for arg
in generic_args
.args
{
780 if let hir
::GenericArg
::Type(ref ty
) = arg
{
787 if let hir
::QPath
::Resolved(_
, path
) = path
{
788 self.write_sub_paths_truncated(path
);
792 fn process_struct_lit(
794 ex
: &'tcx hir
::Expr
<'tcx
>,
795 path
: &'tcx hir
::QPath
<'tcx
>,
796 fields
: &'tcx
[hir
::ExprField
<'tcx
>],
797 variant
: &'tcx ty
::VariantDef
,
798 rest
: Option
<&'tcx hir
::Expr
<'tcx
>>,
800 if let Some(struct_lit_data
) = self.save_ctxt
.get_expr_data(ex
) {
801 if let hir
::QPath
::Resolved(_
, path
) = path
{
802 self.write_sub_paths_truncated(path
);
804 down_cast_data
!(struct_lit_data
, RefData
, ex
.span
);
805 if !generated_code(ex
.span
) {
806 self.dumper
.dump_ref(struct_lit_data
);
809 for field
in fields
{
810 if let Some(field_data
) = self.save_ctxt
.get_field_ref_data(field
, variant
) {
811 self.dumper
.dump_ref(field_data
);
814 self.visit_expr(&field
.expr
)
818 if let Some(base
) = rest
{
819 self.visit_expr(&base
);
823 fn process_method_call(
825 ex
: &'tcx hir
::Expr
<'tcx
>,
826 seg
: &'tcx hir
::PathSegment
<'tcx
>,
827 args
: &'tcx
[hir
::Expr
<'tcx
>],
829 debug
!("process_method_call {:?} {:?}", ex
, ex
.span
);
830 if let Some(mcd
) = self.save_ctxt
.get_expr_data(ex
) {
831 down_cast_data
!(mcd
, RefData
, ex
.span
);
832 if !generated_code(ex
.span
) {
833 self.dumper
.dump_ref(mcd
);
837 // Explicit types in the turbo-fish.
838 if let Some(generic_args
) = seg
.args
{
839 for arg
in generic_args
.args
{
840 if let hir
::GenericArg
::Type(ty
) = arg
{
846 // walk receiver and args
847 walk_list
!(self, visit_expr
, args
);
850 fn process_pat(&mut self, p
: &'tcx hir
::Pat
<'tcx
>) {
852 hir
::PatKind
::Struct(ref _path
, fields
, _
) => {
853 // FIXME do something with _path?
854 let adt
= match self.save_ctxt
.typeck_results().node_type_opt(p
.hir_id
) {
855 Some(ty
) if ty
.ty_adt_def().is_some() => ty
.ty_adt_def().unwrap(),
857 intravisit
::walk_pat(self, p
);
861 let variant
= adt
.variant_of_res(self.save_ctxt
.get_path_res(p
.hir_id
));
863 for field
in fields
{
864 if let Some(index
) = self.tcx
.find_field_index(field
.ident
, variant
) {
865 if !self.span
.filter_generated(field
.ident
.span
) {
866 let span
= self.span_from_span(field
.ident
.span
);
867 self.dumper
.dump_ref(Ref
{
868 kind
: RefKind
::Variable
,
870 ref_id
: id_from_def_id(variant
.fields
[index
].did
),
874 self.visit_pat(&field
.pat
);
877 _
=> intravisit
::walk_pat(self, p
),
881 fn process_var_decl(&mut self, pat
: &'tcx hir
::Pat
<'tcx
>) {
882 // The pattern could declare multiple new vars,
883 // we must walk the pattern and collect them all.
884 let mut collector
= PathCollector
::new(self.tcx
);
885 collector
.visit_pat(&pat
);
886 self.visit_pat(&pat
);
888 // Process collected paths.
889 for (id
, ident
, _
) in collector
.collected_idents
{
890 let res
= self.save_ctxt
.get_path_res(id
);
892 Res
::Local(hir_id
) => {
896 .node_type_opt(hir_id
)
897 .map(|t
| t
.to_string())
898 .unwrap_or_default();
900 // Rust uses the id of the pattern for var lookups, so we'll use it too.
901 if !self.span
.filter_generated(ident
.span
) {
902 let qualname
= format
!("{}${}", ident
.to_string(), hir_id
);
903 let id
= id_from_hir_id(hir_id
, &self.save_ctxt
);
904 let span
= self.span_from_span(ident
.span
);
906 self.dumper
.dump_def(
907 &Access { public: false, reachable: false }
,
909 kind
: DefKind
::Local
,
912 name
: ident
.to_string(),
928 | HirDefKind
::AssocConst
930 | HirDefKind
::Variant
931 | HirDefKind
::TyAlias
932 | HirDefKind
::AssocTy
,
935 | Res
::SelfTy(..) => {
936 self.dump_path_segment_ref(id
, &hir
::PathSegment
::from_ident(ident
));
939 error
!("unexpected definition kind when processing collected idents: {:?}", def
)
944 for (id
, ref path
) in collector
.collected_paths
{
945 self.process_path(id
, path
);
949 /// Extracts macro use and definition information from the AST node defined
950 /// by the given NodeId, using the expansion information from the node's
953 /// If the span is not macro-generated, do nothing, else use callee and
954 /// callsite spans to record macro definition and use data, using the
955 /// mac_uses and mac_defs sets to prevent multiples.
956 fn process_macro_use(&mut self, _span
: Span
) {
957 // FIXME if we're not dumping the defs (see below), there is no point
958 // dumping refs either.
959 // let source_span = span.source_callsite();
960 // if !self.macro_calls.insert(source_span) {
964 // let data = match self.save_ctxt.get_macro_use_data(span) {
966 // Some(data) => data,
969 // self.dumper.macro_use(data);
971 // FIXME write the macro def
972 // let mut hasher = DefaultHasher::new();
973 // data.callee_span.hash(&mut hasher);
974 // let hash = hasher.finish();
975 // let qualname = format!("{}::{}", data.name, hash);
976 // Don't write macro definition for imported macros
977 // if !self.mac_defs.contains(&data.callee_span)
978 // && !data.imported {
979 // self.mac_defs.insert(data.callee_span);
980 // if let Some(sub_span) = self.span.span_for_macro_def_name(data.callee_span) {
981 // self.dumper.macro_data(MacroData {
983 // name: data.name.clone(),
984 // qualname: qualname.clone(),
985 // // FIXME where do macro docs come from?
986 // docs: String::new(),
987 // }.lower(self.tcx));
992 fn process_trait_item(&mut self, trait_item
: &'tcx hir
::TraitItem
<'tcx
>, trait_id
: DefId
) {
993 self.process_macro_use(trait_item
.span
);
994 let vis_span
= trait_item
.span
.shrink_to_lo();
995 match trait_item
.kind
{
996 hir
::TraitItemKind
::Const(ref ty
, body
) => {
997 let body
= body
.map(|b
| &self.tcx
.hir().body(b
).value
);
998 let respan
= respan(vis_span
, hir
::VisibilityKind
::Public
);
999 let attrs
= self.tcx
.hir().attrs(trait_item
.hir_id());
1000 self.process_assoc_const(
1001 trait_item
.hir_id(),
1010 hir
::TraitItemKind
::Fn(ref sig
, ref trait_fn
) => {
1012 if let hir
::TraitFn
::Provided(body
) = trait_fn { Some(*body) }
else { None }
;
1013 let respan
= respan(vis_span
, hir
::VisibilityKind
::Public
);
1014 self.process_method(
1017 trait_item
.hir_id(),
1019 &trait_item
.generics
,
1024 hir
::TraitItemKind
::Type(ref bounds
, ref default_ty
) => {
1025 // FIXME do something with _bounds (for type refs)
1026 let name
= trait_item
.ident
.name
.to_string();
1028 format
!("::{}", self.tcx
.def_path_str(trait_item
.def_id
.to_def_id()));
1030 if !self.span
.filter_generated(trait_item
.ident
.span
) {
1031 let span
= self.span_from_span(trait_item
.ident
.span
);
1032 let id
= id_from_def_id(trait_item
.def_id
.to_def_id());
1033 let attrs
= self.tcx
.hir().attrs(trait_item
.hir_id());
1035 self.dumper
.dump_def(
1036 &Access { public: true, reachable: true }
,
1038 kind
: DefKind
::Type
,
1043 value
: self.span
.snippet(trait_item
.span
),
1044 parent
: Some(id_from_def_id(trait_id
)),
1047 docs
: self.save_ctxt
.docs_for_attrs(attrs
),
1048 sig
: sig
::assoc_type_signature(
1049 trait_item
.hir_id(),
1052 default_ty
.as_ref().map(|ty
| &**ty
),
1055 attributes
: lower_attributes(attrs
.to_vec(), &self.save_ctxt
),
1060 if let Some(default_ty
) = default_ty
{
1061 self.visit_ty(default_ty
)
1067 fn process_impl_item(&mut self, impl_item
: &'tcx hir
::ImplItem
<'tcx
>, impl_id
: DefId
) {
1068 self.process_macro_use(impl_item
.span
);
1069 match impl_item
.kind
{
1070 hir
::ImplItemKind
::Const(ref ty
, body
) => {
1071 let body
= self.tcx
.hir().body(body
);
1072 let attrs
= self.tcx
.hir().attrs(impl_item
.hir_id());
1073 self.process_assoc_const(
1083 hir
::ImplItemKind
::Fn(ref sig
, body
) => {
1084 self.process_method(
1089 &impl_item
.generics
,
1094 hir
::ImplItemKind
::TyAlias(ref ty
) => {
1095 // FIXME: uses of the assoc type should ideally point to this
1096 // 'def' and the name here should be a ref to the def in the
1103 pub(crate) fn process_crate(&mut self, krate
: &'tcx hir
::Crate
<'tcx
>) {
1104 let id
= hir
::CRATE_HIR_ID
;
1106 format
!("::{}", self.tcx
.def_path_str(self.tcx
.hir().local_def_id(id
).to_def_id()));
1108 let sm
= self.tcx
.sess
.source_map();
1109 let filename
= sm
.span_to_filename(krate
.item
.span
);
1110 let data_id
= id_from_hir_id(id
, &self.save_ctxt
);
1111 let children
= krate
1116 .map(|i
| id_from_def_id(i
.def_id
.to_def_id()))
1118 let span
= self.span_from_span(krate
.item
.span
);
1119 let attrs
= self.tcx
.hir().attrs(id
);
1121 self.dumper
.dump_def(
1122 &Access { public: true, reachable: true }
,
1126 name
: String
::new(),
1129 value
: filename
.to_string(),
1133 docs
: self.save_ctxt
.docs_for_attrs(attrs
),
1135 attributes
: lower_attributes(attrs
.to_owned(), &self.save_ctxt
),
1138 intravisit
::walk_crate(self, krate
);
1141 fn process_bounds(&mut self, bounds
: hir
::GenericBounds
<'tcx
>) {
1142 for bound
in bounds
{
1143 if let hir
::GenericBound
::Trait(ref trait_ref
, _
) = *bound
{
1145 trait_ref
.trait_ref
.hir_ref_id
,
1146 &hir
::QPath
::Resolved(None
, &trait_ref
.trait_ref
.path
),
1153 impl<'tcx
> Visitor
<'tcx
> for DumpVisitor
<'tcx
> {
1154 type Map
= Map
<'tcx
>;
1156 fn nested_visit_map(&mut self) -> intravisit
::NestedVisitorMap
<Self::Map
> {
1157 intravisit
::NestedVisitorMap
::All(self.tcx
.hir())
1160 fn visit_item(&mut self, item
: &'tcx hir
::Item
<'tcx
>) {
1161 self.process_macro_use(item
.span
);
1163 hir
::ItemKind
::Use(path
, hir
::UseKind
::Single
) => {
1164 let sub_span
= path
.segments
.last().unwrap().ident
.span
;
1165 if !self.span
.filter_generated(sub_span
) {
1166 let access
= access_from
!(self.save_ctxt
, item
, item
.hir_id());
1167 let ref_id
= self.lookup_def_id(item
.hir_id()).map(id_from_def_id
);
1168 let span
= self.span_from_span(sub_span
);
1170 self.save_ctxt
.tcx
.parent(item
.def_id
.to_def_id()).map(id_from_def_id
);
1174 kind
: ImportKind
::Use
,
1178 name
: item
.ident
.to_string(),
1179 value
: String
::new(),
1183 self.write_sub_paths_truncated(&path
);
1186 hir
::ItemKind
::Use(path
, hir
::UseKind
::Glob
) => {
1187 // Make a comma-separated list of names of imported modules.
1188 let names
= self.tcx
.names_imported_by_glob_use(item
.def_id
);
1189 let names
: Vec
<_
> = names
.iter().map(|n
| n
.to_string()).collect();
1191 // Otherwise it's a span with wrong macro expansion info, which
1192 // we don't want to track anyway, since it's probably macro-internal `use`
1193 if let Some(sub_span
) = self.span
.sub_span_of_star(item
.span
) {
1194 if !self.span
.filter_generated(item
.span
) {
1195 let access
= access_from
!(self.save_ctxt
, item
, item
.hir_id());
1196 let span
= self.span_from_span(sub_span
);
1198 self.save_ctxt
.tcx
.parent(item
.def_id
.to_def_id()).map(id_from_def_id
);
1202 kind
: ImportKind
::GlobUse
,
1206 name
: "*".to_owned(),
1207 value
: names
.join(", "),
1211 self.write_sub_paths(&path
);
1215 hir
::ItemKind
::ExternCrate(_
) => {
1216 let name_span
= item
.ident
.span
;
1217 if !self.span
.filter_generated(name_span
) {
1218 let span
= self.span_from_span(name_span
);
1220 self.save_ctxt
.tcx
.parent(item
.def_id
.to_def_id()).map(id_from_def_id
);
1222 &Access { public: false, reachable: false }
,
1224 kind
: ImportKind
::ExternCrate
,
1228 name
: item
.ident
.to_string(),
1229 value
: String
::new(),
1235 hir
::ItemKind
::Fn(ref sig
, ref ty_params
, body
) => {
1236 self.process_fn(item
, sig
.decl
, &sig
.header
, ty_params
, body
)
1238 hir
::ItemKind
::Static(ref typ
, _
, body
) => {
1239 let body
= self.tcx
.hir().body(body
);
1240 self.process_static_or_const_item(item
, typ
, &body
.value
)
1242 hir
::ItemKind
::Const(ref typ
, body
) => {
1243 let body
= self.tcx
.hir().body(body
);
1244 self.process_static_or_const_item(item
, typ
, &body
.value
)
1246 hir
::ItemKind
::Struct(ref def
, ref ty_params
)
1247 | hir
::ItemKind
::Union(ref def
, ref ty_params
) => {
1248 self.process_struct(item
, def
, ty_params
)
1250 hir
::ItemKind
::Enum(ref def
, ref ty_params
) => self.process_enum(item
, def
, ty_params
),
1251 hir
::ItemKind
::Impl(ref impl_
) => self.process_impl(item
, impl_
),
1252 hir
::ItemKind
::Trait(_
, _
, ref generics
, ref trait_refs
, methods
) => {
1253 self.process_trait(item
, generics
, trait_refs
, methods
)
1255 hir
::ItemKind
::Mod(ref m
) => {
1256 self.process_mod(item
);
1257 intravisit
::walk_mod(self, m
, item
.hir_id());
1259 hir
::ItemKind
::TyAlias(ty
, ref generics
) => {
1260 let qualname
= format
!("::{}", self.tcx
.def_path_str(item
.def_id
.to_def_id()));
1261 let value
= ty_to_string(&ty
);
1262 if !self.span
.filter_generated(item
.ident
.span
) {
1263 let span
= self.span_from_span(item
.ident
.span
);
1264 let id
= id_from_def_id(item
.def_id
.to_def_id());
1265 let attrs
= self.tcx
.hir().attrs(item
.hir_id());
1267 self.dumper
.dump_def(
1268 &access_from
!(self.save_ctxt
, item
, item
.hir_id()),
1270 kind
: DefKind
::Type
,
1273 name
: item
.ident
.to_string(),
1274 qualname
: qualname
.clone(),
1279 docs
: self.save_ctxt
.docs_for_attrs(attrs
),
1280 sig
: sig
::item_signature(item
, &self.save_ctxt
),
1281 attributes
: lower_attributes(attrs
.to_vec(), &self.save_ctxt
),
1287 self.process_generic_params(generics
, &qualname
, item
.hir_id());
1289 _
=> intravisit
::walk_item(self, item
),
1293 fn visit_generics(&mut self, generics
: &'tcx hir
::Generics
<'tcx
>) {
1294 for param
in generics
.params
{
1296 hir
::GenericParamKind
::Lifetime { .. }
=> {}
1297 hir
::GenericParamKind
::Type { ref default, .. }
=> {
1298 self.process_bounds(param
.bounds
);
1299 if let Some(ref ty
) = default {
1303 hir
::GenericParamKind
::Const { ref ty, ref default }
=> {
1304 self.process_bounds(param
.bounds
);
1306 if let Some(default) = default {
1307 self.visit_anon_const(default);
1312 for pred
in generics
.where_clause
.predicates
{
1313 if let hir
::WherePredicate
::BoundPredicate(ref wbp
) = *pred
{
1314 self.process_bounds(wbp
.bounds
);
1315 self.visit_ty(wbp
.bounded_ty
);
1320 fn visit_ty(&mut self, t
: &'tcx hir
::Ty
<'tcx
>) {
1321 self.process_macro_use(t
.span
);
1323 hir
::TyKind
::Path(ref path
) => {
1324 if generated_code(t
.span
) {
1328 if let Some(id
) = self.lookup_def_id(t
.hir_id
) {
1329 let sub_span
= path
.last_segment_span();
1330 let span
= self.span_from_span(sub_span
);
1331 self.dumper
.dump_ref(Ref
{
1332 kind
: RefKind
::Type
,
1334 ref_id
: id_from_def_id(id
),
1338 if let hir
::QPath
::Resolved(_
, path
) = path
{
1339 self.write_sub_paths_truncated(path
);
1341 intravisit
::walk_qpath(self, path
, t
.hir_id
, t
.span
);
1343 hir
::TyKind
::Array(ref ty
, ref anon_const
) => {
1345 let map
= self.tcx
.hir();
1346 self.nest_typeck_results(self.tcx
.hir().local_def_id(anon_const
.hir_id
), |v
| {
1347 v
.visit_expr(&map
.body(anon_const
.body
).value
)
1350 hir
::TyKind
::OpaqueDef(item_id
, _
) => {
1351 let item
= self.tcx
.hir().item(item_id
);
1352 self.nest_typeck_results(item_id
.def_id
, |v
| v
.visit_item(item
));
1354 _
=> intravisit
::walk_ty(self, t
),
1358 fn visit_expr(&mut self, ex
: &'tcx hir
::Expr
<'tcx
>) {
1359 debug
!("visit_expr {:?}", ex
.kind
);
1360 self.process_macro_use(ex
.span
);
1362 hir
::ExprKind
::Struct(ref path
, ref fields
, ref rest
) => {
1363 let hir_expr
= self.save_ctxt
.tcx
.hir().expect_expr(ex
.hir_id
);
1364 let adt
= match self.save_ctxt
.typeck_results().expr_ty_opt(&hir_expr
) {
1365 Some(ty
) if ty
.ty_adt_def().is_some() => ty
.ty_adt_def().unwrap(),
1367 intravisit
::walk_expr(self, ex
);
1371 let res
= self.save_ctxt
.get_path_res(hir_expr
.hir_id
);
1372 self.process_struct_lit(ex
, path
, fields
, adt
.variant_of_res(res
), *rest
)
1374 hir
::ExprKind
::MethodCall(ref seg
, _
, args
, _
) => {
1375 self.process_method_call(ex
, seg
, args
)
1377 hir
::ExprKind
::Field(ref sub_ex
, _
) => {
1378 self.visit_expr(&sub_ex
);
1380 if let Some(field_data
) = self.save_ctxt
.get_expr_data(ex
) {
1381 down_cast_data
!(field_data
, RefData
, ex
.span
);
1382 if !generated_code(ex
.span
) {
1383 self.dumper
.dump_ref(field_data
);
1387 hir
::ExprKind
::Closure(_
, ref decl
, body
, _fn_decl_span
, _
) => {
1388 let id
= format
!("${}", ex
.hir_id
);
1390 // walk arg and return types
1391 for ty
in decl
.inputs
{
1395 if let hir
::FnRetTy
::Return(ref ret_ty
) = decl
.output
{
1396 self.visit_ty(ret_ty
);
1400 let map
= self.tcx
.hir();
1401 self.nest_typeck_results(self.tcx
.hir().local_def_id(ex
.hir_id
), |v
| {
1402 let body
= map
.body(body
);
1403 v
.process_formals(body
.params
, &id
);
1404 v
.visit_expr(&body
.value
)
1407 hir
::ExprKind
::Repeat(ref expr
, ref anon_const
) => {
1408 self.visit_expr(expr
);
1409 let map
= self.tcx
.hir();
1410 self.nest_typeck_results(self.tcx
.hir().local_def_id(anon_const
.hir_id
), |v
| {
1411 v
.visit_expr(&map
.body(anon_const
.body
).value
)
1414 // In particular, we take this branch for call and path expressions,
1415 // where we'll index the idents involved just by continuing to walk.
1416 _
=> intravisit
::walk_expr(self, ex
),
1420 fn visit_pat(&mut self, p
: &'tcx hir
::Pat
<'tcx
>) {
1421 self.process_macro_use(p
.span
);
1422 self.process_pat(p
);
1425 fn visit_arm(&mut self, arm
: &'tcx hir
::Arm
<'tcx
>) {
1426 self.process_var_decl(&arm
.pat
);
1427 if let Some(hir
::Guard
::If(expr
)) = &arm
.guard
{
1428 self.visit_expr(expr
);
1430 self.visit_expr(&arm
.body
);
1433 fn visit_qpath(&mut self, path
: &'tcx hir
::QPath
<'tcx
>, id
: hir
::HirId
, _
: Span
) {
1434 self.process_path(id
, path
);
1437 fn visit_stmt(&mut self, s
: &'tcx hir
::Stmt
<'tcx
>) {
1438 self.process_macro_use(s
.span
);
1439 intravisit
::walk_stmt(self, s
)
1442 fn visit_local(&mut self, l
: &'tcx hir
::Local
<'tcx
>) {
1443 self.process_macro_use(l
.span
);
1444 self.process_var_decl(&l
.pat
);
1446 // Just walk the initialiser and type (don't want to walk the pattern again).
1447 walk_list
!(self, visit_ty
, &l
.ty
);
1448 walk_list
!(self, visit_expr
, &l
.init
);
1451 fn visit_foreign_item(&mut self, item
: &'tcx hir
::ForeignItem
<'tcx
>) {
1452 let access
= access_from
!(self.save_ctxt
, item
, item
.hir_id());
1455 hir
::ForeignItemKind
::Fn(decl
, _
, ref generics
) => {
1456 if let Some(fn_data
) = self.save_ctxt
.get_extern_item_data(item
) {
1457 down_cast_data
!(fn_data
, DefData
, item
.span
);
1459 self.process_generic_params(generics
, &fn_data
.qualname
, item
.hir_id());
1460 self.dumper
.dump_def(&access
, fn_data
);
1463 for ty
in decl
.inputs
{
1467 if let hir
::FnRetTy
::Return(ref ret_ty
) = decl
.output
{
1468 self.visit_ty(ret_ty
);
1471 hir
::ForeignItemKind
::Static(ref ty
, _
) => {
1472 if let Some(var_data
) = self.save_ctxt
.get_extern_item_data(item
) {
1473 down_cast_data
!(var_data
, DefData
, item
.span
);
1474 self.dumper
.dump_def(&access
, var_data
);
1479 hir
::ForeignItemKind
::Type
=> {
1480 if let Some(var_data
) = self.save_ctxt
.get_extern_item_data(item
) {
1481 down_cast_data
!(var_data
, DefData
, item
.span
);
1482 self.dumper
.dump_def(&access
, var_data
);