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, CRATE_DEF_ID}
;
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
::nested_filter
;
25 use rustc_middle
::span_bug
;
26 use rustc_middle
::ty
::{self, DefIdTree, TyCtxt}
;
27 use rustc_session
::config
::Input
;
28 use rustc_span
::symbol
::Ident
;
34 use crate::dumper
::{Access, Dumper}
;
36 use crate::span_utils
::SpanUtils
;
38 escape
, generated_code
, id_from_def_id
, id_from_hir_id
, lower_attributes
, PathCollector
,
43 CompilationOptions
, CratePreludeData
, Def
, DefKind
, GlobalCrateId
, Import
, ImportKind
, Ref
,
44 RefKind
, Relation
, RelationKind
, SpanData
,
47 #[rustfmt::skip] // https://github.com/rust-lang/rustfmt/issues/5213
48 macro_rules
! down_cast_data
{
49 ($id
:ident
, $kind
:ident
, $sp
:expr
) => {
50 let super::Data
::$
kind($id
) = $id
else {
51 span_bug
!($sp
, "unexpected data kind: {:?}", $id
);
56 macro_rules
! access_from
{
57 ($save_ctxt
:expr
, $id
:expr
) => {
59 public
: $save_ctxt
.tcx
.visibility($id
).is_public(),
60 reachable
: $save_ctxt
.access_levels
.is_reachable($id
),
65 pub struct DumpVisitor
<'tcx
> {
66 pub save_ctxt
: SaveContext
<'tcx
>,
70 span
: SpanUtils
<'tcx
>,
71 // Set of macro definition (callee) spans, and the set
72 // of macro use (callsite) spans. We store these to ensure
73 // we only write one macro def per unique macro definition, and
74 // one macro use per unique callsite span.
75 // mac_defs: FxHashSet<Span>,
76 // macro_calls: FxHashSet<Span>,
79 impl<'tcx
> DumpVisitor
<'tcx
> {
80 pub fn new(save_ctxt
: SaveContext
<'tcx
>) -> DumpVisitor
<'tcx
> {
81 let span_utils
= SpanUtils
::new(&save_ctxt
.tcx
.sess
);
82 let dumper
= Dumper
::new(save_ctxt
.config
.clone());
83 DumpVisitor { tcx: save_ctxt.tcx, save_ctxt, dumper, span: span_utils }
86 pub fn analysis(&self) -> &rls_data
::Analysis
{
87 self.dumper
.analysis()
90 fn nest_typeck_results
<F
>(&mut self, item_def_id
: LocalDefId
, f
: F
)
94 let typeck_results
= if self.tcx
.has_typeck_results(item_def_id
) {
95 Some(self.tcx
.typeck(item_def_id
))
100 let old_maybe_typeck_results
= self.save_ctxt
.maybe_typeck_results
;
101 self.save_ctxt
.maybe_typeck_results
= typeck_results
;
103 self.save_ctxt
.maybe_typeck_results
= old_maybe_typeck_results
;
106 fn span_from_span(&self, span
: Span
) -> SpanData
{
107 self.save_ctxt
.span_from_span(span
)
110 fn lookup_def_id(&self, ref_id
: hir
::HirId
) -> Option
<DefId
> {
111 self.save_ctxt
.lookup_def_id(ref_id
)
114 pub fn dump_crate_info(&mut self, name
: &str) {
115 let source_file
= self.tcx
.sess
.local_crate_source_file
.as_ref();
116 let crate_root
= source_file
.map(|source_file
| {
117 let source_file
= Path
::new(source_file
);
118 match source_file
.file_name() {
119 Some(_
) => source_file
.parent().unwrap().display(),
120 None
=> source_file
.display(),
125 let data
= CratePreludeData
{
126 crate_id
: GlobalCrateId
{
128 disambiguator
: (self.tcx
.sess
.local_stable_crate_id().to_u64(), 0),
130 crate_root
: crate_root
.unwrap_or_else(|| "<no source>".to_owned()),
131 external_crates
: self.save_ctxt
.get_external_crates(),
132 span
: self.span_from_span(self.tcx
.def_span(CRATE_DEF_ID
)),
135 self.dumper
.crate_prelude(data
);
138 pub fn dump_compilation_options(&mut self, input
: &Input
, crate_name
: &str) {
139 // Apply possible `remap-path-prefix` remapping to the input source file
140 // (and don't include remapping args anymore)
141 let (program
, arguments
) = {
142 let remap_arg_indices
= {
143 let mut indices
= FxHashSet
::default();
144 // Args are guaranteed to be valid UTF-8 (checked early)
145 for (i
, e
) in env
::args().enumerate() {
146 if e
.starts_with("--remap-path-prefix=") {
148 } else if e
== "--remap-path-prefix" {
150 indices
.insert(i
+ 1);
156 let mut args
= env
::args()
158 .filter(|(i
, _
)| !remap_arg_indices
.contains(i
))
159 .map(|(_
, arg
)| match input
{
160 Input
::File(ref path
) if path
== Path
::new(&arg
) => {
161 let mapped
= &self.tcx
.sess
.local_crate_source_file
;
162 mapped
.as_ref().unwrap().to_string_lossy().into()
167 (args
.next().unwrap(), args
.collect())
170 let data
= CompilationOptions
{
171 directory
: self.tcx
.sess
.opts
.working_dir
.remapped_path_if_available().into(),
174 output
: self.save_ctxt
.compilation_output(crate_name
),
177 self.dumper
.compilation_opts(data
);
180 fn write_segments(&mut self, segments
: impl IntoIterator
<Item
= &'tcx hir
::PathSegment
<'tcx
>>) {
181 for seg
in segments
{
182 if let Some(data
) = self.save_ctxt
.get_path_segment_data(seg
) {
183 self.dumper
.dump_ref(data
);
188 fn write_sub_paths(&mut self, path
: &'tcx hir
::Path
<'tcx
>) {
189 self.write_segments(path
.segments
)
192 // As write_sub_paths, but does not process the last ident in the path (assuming it
193 // will be processed elsewhere). See note on write_sub_paths about global.
194 fn write_sub_paths_truncated(&mut self, path
: &'tcx hir
::Path
<'tcx
>) {
195 if let [segments @
.., _
] = path
.segments
{
196 self.write_segments(segments
)
200 fn process_formals(&mut self, formals
: &'tcx
[hir
::Param
<'tcx
>], qualname
: &str) {
202 self.visit_pat(&arg
.pat
);
203 let mut collector
= PathCollector
::new(self.tcx
);
204 collector
.visit_pat(&arg
.pat
);
206 for (hir_id
, ident
, ..) in collector
.collected_idents
{
207 let typ
= match self.save_ctxt
.typeck_results().node_type_opt(hir_id
) {
208 Some(s
) => s
.to_string(),
211 if !self.span
.filter_generated(ident
.span
) {
212 let id
= id_from_hir_id(hir_id
, &self.save_ctxt
);
213 let span
= self.span_from_span(ident
.span
);
215 self.dumper
.dump_def(
216 &Access { public: false, reachable: false }
,
218 kind
: DefKind
::Local
,
221 name
: ident
.to_string(),
222 qualname
: format
!("{}::{}", qualname
, ident
),
239 sig
: &'tcx hir
::FnSig
<'tcx
>,
240 body
: Option
<hir
::BodyId
>,
243 generics
: &'tcx hir
::Generics
<'tcx
>,
246 debug
!("process_method: {:?}:{}", def_id
, ident
);
248 let map
= self.tcx
.hir();
249 let hir_id
= map
.local_def_id_to_hir_id(def_id
);
250 self.nest_typeck_results(def_id
, |v
| {
251 if let Some(mut method_data
) = v
.save_ctxt
.get_method_data(hir_id
, ident
, span
) {
252 if let Some(body
) = body
{
253 v
.process_formals(map
.body(body
).params
, &method_data
.qualname
);
255 v
.process_generic_params(&generics
, &method_data
.qualname
, hir_id
);
258 fn_to_string(sig
.decl
, sig
.header
, Some(ident
.name
), generics
, &[], None
);
259 method_data
.sig
= sig
::method_signature(hir_id
, ident
, generics
, sig
, &v
.save_ctxt
);
261 v
.dumper
.dump_def(&access_from
!(v
.save_ctxt
, def_id
), method_data
);
264 // walk arg and return types
265 for arg
in sig
.decl
.inputs
{
269 if let hir
::FnRetTy
::Return(ref ret_ty
) = sig
.decl
.output
{
274 if let Some(body
) = body
{
275 v
.visit_expr(&map
.body(body
).value
);
280 fn process_struct_field_def(
282 field
: &'tcx hir
::FieldDef
<'tcx
>,
283 parent_id
: hir
::HirId
,
285 let field_data
= self.save_ctxt
.get_field_data(field
, parent_id
);
286 if let Some(field_data
) = field_data
{
287 self.dumper
.dump_def(
288 &access_from
!(self.save_ctxt
, self.tcx
.hir().local_def_id(field
.hir_id
)),
294 // Dump generic params bindings, then visit_generics
295 fn process_generic_params(
297 generics
: &'tcx hir
::Generics
<'tcx
>,
301 for param
in generics
.params
{
303 hir
::GenericParamKind
::Lifetime { .. }
=> {}
304 hir
::GenericParamKind
::Type { .. }
=> {
305 let param_ss
= param
.name
.ident().span
;
306 let name
= escape(self.span
.snippet(param_ss
));
307 // Append $id to name to make sure each one is unique.
308 let qualname
= format
!("{}::{}${}", prefix
, name
, id
);
309 if !self.span
.filter_generated(param_ss
) {
310 let id
= id_from_hir_id(param
.hir_id
, &self.save_ctxt
);
311 let span
= self.span_from_span(param_ss
);
313 self.dumper
.dump_def(
314 &Access { public: false, reachable: false }
,
321 value
: String
::new(),
332 hir
::GenericParamKind
::Const { .. }
=> {}
336 self.visit_generics(generics
)
341 item
: &'tcx hir
::Item
<'tcx
>,
342 decl
: &'tcx hir
::FnDecl
<'tcx
>,
343 _header
: &'tcx hir
::FnHeader
,
344 ty_params
: &'tcx hir
::Generics
<'tcx
>,
347 let map
= self.tcx
.hir();
348 self.nest_typeck_results(item
.def_id
, |v
| {
349 let body
= map
.body(body
);
350 if let Some(fn_data
) = v
.save_ctxt
.get_item_data(item
) {
351 down_cast_data
!(fn_data
, DefData
, item
.span
);
352 v
.process_formals(body
.params
, &fn_data
.qualname
);
353 v
.process_generic_params(ty_params
, &fn_data
.qualname
, item
.hir_id());
355 v
.dumper
.dump_def(&access_from
!(v
.save_ctxt
, item
.def_id
), fn_data
);
358 for arg
in decl
.inputs
{
362 if let hir
::FnRetTy
::Return(ref ret_ty
) = decl
.output
{
366 v
.visit_expr(&body
.value
);
370 fn process_static_or_const_item(
372 item
: &'tcx hir
::Item
<'tcx
>,
373 typ
: &'tcx hir
::Ty
<'tcx
>,
374 expr
: &'tcx hir
::Expr
<'tcx
>,
376 self.nest_typeck_results(item
.def_id
, |v
| {
377 if let Some(var_data
) = v
.save_ctxt
.get_item_data(item
) {
378 down_cast_data
!(var_data
, DefData
, item
.span
);
379 v
.dumper
.dump_def(&access_from
!(v
.save_ctxt
, item
.def_id
), var_data
);
386 fn process_assoc_const(
390 typ
: &'tcx hir
::Ty
<'tcx
>,
391 expr
: Option
<&'tcx hir
::Expr
<'tcx
>>,
393 attrs
: &'tcx
[ast
::Attribute
],
395 let qualname
= format
!("::{}", self.tcx
.def_path_str(def_id
.to_def_id()));
397 if !self.span
.filter_generated(ident
.span
) {
398 let hir_id
= self.tcx
.hir().local_def_id_to_hir_id(def_id
);
399 let sig
= sig
::assoc_const_signature(hir_id
, ident
.name
, typ
, expr
, &self.save_ctxt
);
400 let span
= self.span_from_span(ident
.span
);
402 self.dumper
.dump_def(
403 &access_from
!(self.save_ctxt
, def_id
),
405 kind
: DefKind
::Const
,
406 id
: id_from_hir_id(hir_id
, &self.save_ctxt
),
408 name
: ident
.name
.to_string(),
410 value
: ty_to_string(&typ
),
411 parent
: Some(id_from_def_id(parent_id
)),
414 docs
: self.save_ctxt
.docs_for_attrs(attrs
),
416 attributes
: lower_attributes(attrs
.to_owned(), &self.save_ctxt
),
421 // walk type and init value
422 self.nest_typeck_results(def_id
, |v
| {
424 if let Some(expr
) = expr
{
430 // FIXME tuple structs should generate tuple-specific data.
433 item
: &'tcx hir
::Item
<'tcx
>,
434 def
: &'tcx hir
::VariantData
<'tcx
>,
435 ty_params
: &'tcx hir
::Generics
<'tcx
>,
437 debug
!("process_struct {:?} {:?}", item
, item
.span
);
438 let name
= item
.ident
.to_string();
439 let qualname
= format
!("::{}", self.tcx
.def_path_str(item
.def_id
.to_def_id()));
441 let kind
= match item
.kind
{
442 hir
::ItemKind
::Struct(_
, _
) => DefKind
::Struct
,
443 hir
::ItemKind
::Union(_
, _
) => DefKind
::Union
,
447 let (value
, fields
) = match item
.kind
{
448 hir
::ItemKind
::Struct(hir
::VariantData
::Struct(ref fields
, ..), ..)
449 | hir
::ItemKind
::Union(hir
::VariantData
::Struct(ref fields
, ..), ..) => {
450 let include_priv_fields
= !self.save_ctxt
.config
.pub_only
;
451 let fields_str
= fields
454 if include_priv_fields
{
455 return Some(f
.ident
.to_string());
457 let def_id
= self.save_ctxt
.tcx
.hir().local_def_id(f
.hir_id
);
458 if self.save_ctxt
.tcx
.visibility(def_id
).is_public() {
459 Some(f
.ident
.to_string())
466 let value
= format
!("{} {{ {} }}", name
, fields_str
);
467 (value
, fields
.iter().map(|f
| id_from_hir_id(f
.hir_id
, &self.save_ctxt
)).collect())
469 _
=> (String
::new(), vec
![]),
472 if !self.span
.filter_generated(item
.ident
.span
) {
473 let span
= self.span_from_span(item
.ident
.span
);
474 let attrs
= self.tcx
.hir().attrs(item
.hir_id());
475 self.dumper
.dump_def(
476 &access_from
!(self.save_ctxt
, item
.def_id
),
479 id
: id_from_def_id(item
.def_id
.to_def_id()),
482 qualname
: qualname
.clone(),
487 docs
: self.save_ctxt
.docs_for_attrs(attrs
),
488 sig
: sig
::item_signature(item
, &self.save_ctxt
),
489 attributes
: lower_attributes(attrs
.to_vec(), &self.save_ctxt
),
494 self.nest_typeck_results(item
.def_id
, |v
| {
495 for field
in def
.fields() {
496 v
.process_struct_field_def(field
, item
.hir_id());
497 v
.visit_ty(&field
.ty
);
500 v
.process_generic_params(ty_params
, &qualname
, item
.hir_id());
506 item
: &'tcx hir
::Item
<'tcx
>,
507 enum_definition
: &'tcx hir
::EnumDef
<'tcx
>,
508 ty_params
: &'tcx hir
::Generics
<'tcx
>,
510 let enum_data
= self.save_ctxt
.get_item_data(item
);
511 let Some(enum_data
) = enum_data
else {
514 down_cast_data
!(enum_data
, DefData
, item
.span
);
516 let access
= access_from
!(self.save_ctxt
, item
.def_id
);
518 for variant
in enum_definition
.variants
{
519 let name
= variant
.ident
.name
.to_string();
520 let qualname
= format
!("{}::{}", enum_data
.qualname
, name
);
521 let name_span
= variant
.ident
.span
;
524 hir
::VariantData
::Struct(ref fields
, ..) => {
526 fields
.iter().map(|f
| f
.ident
.to_string()).collect
::<Vec
<_
>>().join(", ");
527 let value
= format
!("{}::{} {{ {} }}", enum_data
.name
, name
, fields_str
);
528 if !self.span
.filter_generated(name_span
) {
529 let span
= self.span_from_span(name_span
);
530 let id
= id_from_hir_id(variant
.id
, &self.save_ctxt
);
531 let parent
= Some(id_from_def_id(item
.def_id
.to_def_id()));
532 let attrs
= self.tcx
.hir().attrs(variant
.id
);
534 self.dumper
.dump_def(
537 kind
: DefKind
::StructVariant
,
546 docs
: self.save_ctxt
.docs_for_attrs(attrs
),
547 sig
: sig
::variant_signature(variant
, &self.save_ctxt
),
548 attributes
: lower_attributes(attrs
.to_vec(), &self.save_ctxt
),
554 let mut value
= format
!("{}::{}", enum_data
.name
, name
);
555 if let hir
::VariantData
::Tuple(fields
, _
) = v
{
560 .map(|f
| ty_to_string(&f
.ty
))
566 if !self.span
.filter_generated(name_span
) {
567 let span
= self.span_from_span(name_span
);
568 let id
= id_from_hir_id(variant
.id
, &self.save_ctxt
);
569 let parent
= Some(id_from_def_id(item
.def_id
.to_def_id()));
570 let attrs
= self.tcx
.hir().attrs(variant
.id
);
572 self.dumper
.dump_def(
575 kind
: DefKind
::TupleVariant
,
584 docs
: self.save_ctxt
.docs_for_attrs(attrs
),
585 sig
: sig
::variant_signature(variant
, &self.save_ctxt
),
586 attributes
: lower_attributes(attrs
.to_vec(), &self.save_ctxt
),
593 for field
in variant
.data
.fields() {
594 self.process_struct_field_def(field
, variant
.id
);
595 self.visit_ty(field
.ty
);
598 self.process_generic_params(ty_params
, &enum_data
.qualname
, item
.hir_id());
599 self.dumper
.dump_def(&access
, enum_data
);
602 fn process_impl(&mut self, item
: &'tcx hir
::Item
<'tcx
>, impl_
: &'tcx hir
::Impl
<'tcx
>) {
603 if let Some(impl_data
) = self.save_ctxt
.get_item_data(item
) {
604 if !self.span
.filter_generated(item
.span
) {
605 if let super::Data
::RelationData(rel
, imp
) = impl_data
{
606 self.dumper
.dump_relation(rel
);
607 self.dumper
.dump_impl(imp
);
609 span_bug
!(item
.span
, "unexpected data kind: {:?}", impl_data
);
614 let map
= self.tcx
.hir();
615 self.nest_typeck_results(item
.def_id
, |v
| {
616 v
.visit_ty(&impl_
.self_ty
);
617 if let Some(trait_ref
) = &impl_
.of_trait
{
618 v
.process_path(trait_ref
.hir_ref_id
, &hir
::QPath
::Resolved(None
, &trait_ref
.path
));
620 v
.process_generic_params(&impl_
.generics
, "", item
.hir_id());
621 for impl_item
in impl_
.items
{
622 v
.process_impl_item(map
.impl_item(impl_item
.id
), item
.def_id
.to_def_id());
629 item
: &'tcx hir
::Item
<'tcx
>,
630 generics
: &'tcx hir
::Generics
<'tcx
>,
631 trait_refs
: hir
::GenericBounds
<'tcx
>,
632 methods
: &'tcx
[hir
::TraitItemRef
],
634 let name
= item
.ident
.to_string();
635 let qualname
= format
!("::{}", self.tcx
.def_path_str(item
.def_id
.to_def_id()));
636 let mut val
= name
.clone();
637 if !generics
.params
.is_empty() {
638 val
.push_str(&generic_params_to_string(generics
.params
));
640 if !trait_refs
.is_empty() {
642 val
.push_str(&bounds_to_string(trait_refs
));
644 if !self.span
.filter_generated(item
.ident
.span
) {
645 let id
= id_from_def_id(item
.def_id
.to_def_id());
646 let span
= self.span_from_span(item
.ident
.span
);
648 methods
.iter().map(|i
| id_from_def_id(i
.id
.def_id
.to_def_id())).collect();
649 let attrs
= self.tcx
.hir().attrs(item
.hir_id());
650 self.dumper
.dump_def(
651 &access_from
!(self.save_ctxt
, item
.def_id
),
653 kind
: DefKind
::Trait
,
657 qualname
: qualname
.clone(),
662 docs
: self.save_ctxt
.docs_for_attrs(attrs
),
663 sig
: sig
::item_signature(item
, &self.save_ctxt
),
664 attributes
: lower_attributes(attrs
.to_vec(), &self.save_ctxt
),
670 for super_bound
in trait_refs
.iter() {
671 let (def_id
, sub_span
) = match *super_bound
{
672 hir
::GenericBound
::Trait(ref trait_ref
, _
) => (
673 self.lookup_def_id(trait_ref
.trait_ref
.hir_ref_id
),
674 trait_ref
.trait_ref
.path
.segments
.last().unwrap().ident
.span
,
676 hir
::GenericBound
::LangItemTrait(lang_item
, span
, _
, _
) => {
677 (Some(self.tcx
.require_lang_item(lang_item
, Some(span
))), span
)
679 hir
::GenericBound
::Outlives(..) => continue,
682 if let Some(id
) = def_id
{
683 if !self.span
.filter_generated(sub_span
) {
684 let span
= self.span_from_span(sub_span
);
685 self.dumper
.dump_ref(Ref
{
688 ref_id
: id_from_def_id(id
),
691 self.dumper
.dump_relation(Relation
{
692 kind
: RelationKind
::SuperTrait
,
694 from
: id_from_def_id(id
),
695 to
: id_from_def_id(item
.def_id
.to_def_id()),
701 // walk generics and methods
702 self.process_generic_params(generics
, &qualname
, item
.hir_id());
703 for method
in methods
{
704 let map
= self.tcx
.hir();
705 self.process_trait_item(map
.trait_item(method
.id
), item
.def_id
.to_def_id())
709 // `item` is the module in question, represented as an( item.
710 fn process_mod(&mut self, item
: &'tcx hir
::Item
<'tcx
>) {
711 if let Some(mod_data
) = self.save_ctxt
.get_item_data(item
) {
712 down_cast_data
!(mod_data
, DefData
, item
.span
);
713 self.dumper
.dump_def(&access_from
!(self.save_ctxt
, item
.def_id
), mod_data
);
717 fn dump_path_ref(&mut self, id
: hir
::HirId
, path
: &hir
::QPath
<'tcx
>) {
718 let path_data
= self.save_ctxt
.get_path_data(id
, path
);
719 if let Some(path_data
) = path_data
{
720 self.dumper
.dump_ref(path_data
);
724 fn dump_path_segment_ref(&mut self, id
: hir
::HirId
, segment
: &hir
::PathSegment
<'tcx
>) {
725 let segment_data
= self.save_ctxt
.get_path_segment_data_with_id(segment
, id
);
726 if let Some(segment_data
) = segment_data
{
727 self.dumper
.dump_ref(segment_data
);
731 fn process_path(&mut self, id
: hir
::HirId
, path
: &hir
::QPath
<'tcx
>) {
732 if self.span
.filter_generated(path
.span()) {
735 self.dump_path_ref(id
, path
);
738 let segments
= match path
{
739 hir
::QPath
::Resolved(ty
, path
) => {
740 if let Some(ty
) = ty
{
745 hir
::QPath
::TypeRelative(ty
, segment
) => {
747 std
::slice
::from_ref(*segment
)
749 hir
::QPath
::LangItem(..) => return,
751 for seg
in segments
{
752 if let Some(ref generic_args
) = seg
.args
{
753 for arg
in generic_args
.args
{
754 if let hir
::GenericArg
::Type(ref ty
) = arg
{
761 if let hir
::QPath
::Resolved(_
, path
) = path
{
762 self.write_sub_paths_truncated(path
);
766 fn process_struct_lit(
768 ex
: &'tcx hir
::Expr
<'tcx
>,
769 path
: &'tcx hir
::QPath
<'tcx
>,
770 fields
: &'tcx
[hir
::ExprField
<'tcx
>],
771 variant
: &'tcx ty
::VariantDef
,
772 rest
: Option
<&'tcx hir
::Expr
<'tcx
>>,
774 if let Some(_ex_res_data
) = self.save_ctxt
.get_expr_data(ex
) {
775 if let hir
::QPath
::Resolved(_
, path
) = path
{
776 self.write_sub_paths_truncated(path
);
778 // For MyEnum::MyVariant, get_expr_data gives us MyEnum, not MyVariant.
779 // For recording the span's ref id, we want MyVariant.
780 if !generated_code(ex
.span
) {
781 let sub_span
= path
.last_segment_span();
782 let span
= self.save_ctxt
.span_from_span(sub_span
);
784 Ref { kind: RefKind::Type, span, ref_id: id_from_def_id(variant.def_id) }
;
785 self.dumper
.dump_ref(reff
);
788 for field
in fields
{
789 if let Some(field_data
) = self.save_ctxt
.get_field_ref_data(field
, variant
) {
790 self.dumper
.dump_ref(field_data
);
793 self.visit_expr(&field
.expr
)
797 if let Some(base
) = rest
{
798 self.visit_expr(&base
);
802 fn process_method_call(
804 ex
: &'tcx hir
::Expr
<'tcx
>,
805 seg
: &'tcx hir
::PathSegment
<'tcx
>,
806 receiver
: &'tcx hir
::Expr
<'tcx
>,
807 args
: &'tcx
[hir
::Expr
<'tcx
>],
809 debug
!("process_method_call {:?} {:?}", ex
, ex
.span
);
810 if let Some(mcd
) = self.save_ctxt
.get_expr_data(ex
) {
811 down_cast_data
!(mcd
, RefData
, ex
.span
);
812 if !generated_code(ex
.span
) {
813 self.dumper
.dump_ref(mcd
);
817 // Explicit types in the turbo-fish.
818 if let Some(generic_args
) = seg
.args
{
819 for arg
in generic_args
.args
{
820 if let hir
::GenericArg
::Type(ty
) = arg
{
826 // walk receiver and args
827 self.visit_expr(receiver
);
828 walk_list
!(self, visit_expr
, args
);
831 fn process_pat(&mut self, p
: &'tcx hir
::Pat
<'tcx
>) {
833 hir
::PatKind
::Struct(ref _path
, fields
, _
) => {
834 // FIXME do something with _path?
835 let adt
= match self.save_ctxt
.typeck_results().node_type_opt(p
.hir_id
) {
836 Some(ty
) if ty
.ty_adt_def().is_some() => ty
.ty_adt_def().unwrap(),
838 intravisit
::walk_pat(self, p
);
842 let variant
= adt
.variant_of_res(self.save_ctxt
.get_path_res(p
.hir_id
));
844 for field
in fields
{
845 if let Some(index
) = self.tcx
.find_field_index(field
.ident
, variant
) {
846 if !self.span
.filter_generated(field
.ident
.span
) {
847 let span
= self.span_from_span(field
.ident
.span
);
848 self.dumper
.dump_ref(Ref
{
849 kind
: RefKind
::Variable
,
851 ref_id
: id_from_def_id(variant
.fields
[index
].did
),
855 self.visit_pat(&field
.pat
);
858 _
=> intravisit
::walk_pat(self, p
),
862 fn process_var_decl(&mut self, pat
: &'tcx hir
::Pat
<'tcx
>) {
863 // The pattern could declare multiple new vars,
864 // we must walk the pattern and collect them all.
865 let mut collector
= PathCollector
::new(self.tcx
);
866 collector
.visit_pat(&pat
);
867 self.visit_pat(&pat
);
869 // Process collected paths.
870 for (id
, ident
, _
) in collector
.collected_idents
{
871 let res
= self.save_ctxt
.get_path_res(id
);
873 Res
::Local(hir_id
) => {
877 .node_type_opt(hir_id
)
878 .map(|t
| t
.to_string())
879 .unwrap_or_default();
881 // Rust uses the id of the pattern for var lookups, so we'll use it too.
882 if !self.span
.filter_generated(ident
.span
) {
883 let qualname
= format
!("{}${}", ident
, hir_id
);
884 let id
= id_from_hir_id(hir_id
, &self.save_ctxt
);
885 let span
= self.span_from_span(ident
.span
);
887 self.dumper
.dump_def(
888 &Access { public: false, reachable: false }
,
890 kind
: DefKind
::Local
,
893 name
: ident
.to_string(),
909 | HirDefKind
::AssocConst
911 | HirDefKind
::Variant
912 | HirDefKind
::TyAlias
913 | HirDefKind
::AssocTy
,
916 | Res
::SelfTy { .. }
=> {
917 self.dump_path_segment_ref(
919 &hir
::PathSegment
::new(ident
, hir
::HirId
::INVALID
, Res
::Err
),
923 error
!("unexpected definition kind when processing collected idents: {:?}", def
)
928 for (id
, ref path
) in collector
.collected_paths
{
929 self.process_path(id
, path
);
933 /// Extracts macro use and definition information from the AST node defined
934 /// by the given NodeId, using the expansion information from the node's
937 /// If the span is not macro-generated, do nothing, else use callee and
938 /// callsite spans to record macro definition and use data, using the
939 /// mac_uses and mac_defs sets to prevent multiples.
940 fn process_macro_use(&mut self, _span
: Span
) {
941 // FIXME if we're not dumping the defs (see below), there is no point
942 // dumping refs either.
943 // let source_span = span.source_callsite();
944 // if !self.macro_calls.insert(source_span) {
948 // let data = match self.save_ctxt.get_macro_use_data(span) {
950 // Some(data) => data,
953 // self.dumper.macro_use(data);
955 // FIXME write the macro def
956 // let mut hasher = DefaultHasher::new();
957 // data.callee_span.hash(&mut hasher);
958 // let hash = hasher.finish();
959 // let qualname = format!("{}::{}", data.name, hash);
960 // Don't write macro definition for imported macros
961 // if !self.mac_defs.contains(&data.callee_span)
962 // && !data.imported {
963 // self.mac_defs.insert(data.callee_span);
964 // if let Some(sub_span) = self.span.span_for_macro_def_name(data.callee_span) {
965 // self.dumper.macro_data(MacroData {
967 // name: data.name.clone(),
968 // qualname: qualname.clone(),
969 // // FIXME where do macro docs come from?
970 // docs: String::new(),
971 // }.lower(self.tcx));
976 fn process_trait_item(&mut self, trait_item
: &'tcx hir
::TraitItem
<'tcx
>, trait_id
: DefId
) {
977 self.process_macro_use(trait_item
.span
);
978 match trait_item
.kind
{
979 hir
::TraitItemKind
::Const(ref ty
, body
) => {
980 let body
= body
.map(|b
| self.tcx
.hir().body(b
).value
);
981 let attrs
= self.tcx
.hir().attrs(trait_item
.hir_id());
982 self.process_assoc_const(
991 hir
::TraitItemKind
::Fn(ref sig
, ref trait_fn
) => {
993 if let hir
::TraitFn
::Provided(body
) = trait_fn { Some(*body) }
else { None }
;
999 &trait_item
.generics
,
1003 hir
::TraitItemKind
::Type(ref bounds
, ref default_ty
) => {
1004 // FIXME do something with _bounds (for type refs)
1005 let name
= trait_item
.ident
.name
.to_string();
1007 format
!("::{}", self.tcx
.def_path_str(trait_item
.def_id
.to_def_id()));
1009 if !self.span
.filter_generated(trait_item
.ident
.span
) {
1010 let span
= self.span_from_span(trait_item
.ident
.span
);
1011 let id
= id_from_def_id(trait_item
.def_id
.to_def_id());
1012 let attrs
= self.tcx
.hir().attrs(trait_item
.hir_id());
1014 self.dumper
.dump_def(
1015 &Access { public: true, reachable: true }
,
1017 kind
: DefKind
::Type
,
1022 value
: self.span
.snippet(trait_item
.span
),
1023 parent
: Some(id_from_def_id(trait_id
)),
1026 docs
: self.save_ctxt
.docs_for_attrs(attrs
),
1027 sig
: sig
::assoc_type_signature(
1028 trait_item
.hir_id(),
1031 default_ty
.as_ref().map(|ty
| &**ty
),
1034 attributes
: lower_attributes(attrs
.to_vec(), &self.save_ctxt
),
1039 if let Some(default_ty
) = default_ty
{
1040 self.visit_ty(default_ty
)
1046 fn process_impl_item(&mut self, impl_item
: &'tcx hir
::ImplItem
<'tcx
>, impl_id
: DefId
) {
1047 self.process_macro_use(impl_item
.span
);
1048 match impl_item
.kind
{
1049 hir
::ImplItemKind
::Const(ref ty
, body
) => {
1050 let body
= self.tcx
.hir().body(body
);
1051 let attrs
= self.tcx
.hir().attrs(impl_item
.hir_id());
1052 self.process_assoc_const(
1061 hir
::ImplItemKind
::Fn(ref sig
, body
) => {
1062 self.process_method(
1067 &impl_item
.generics
,
1071 hir
::ImplItemKind
::TyAlias(ref ty
) => {
1072 // FIXME: uses of the assoc type should ideally point to this
1073 // 'def' and the name here should be a ref to the def in the
1080 pub(crate) fn process_crate(&mut self) {
1081 let id
= hir
::CRATE_HIR_ID
;
1083 format
!("::{}", self.tcx
.def_path_str(self.tcx
.hir().local_def_id(id
).to_def_id()));
1085 let sm
= self.tcx
.sess
.source_map();
1086 let krate_mod
= self.tcx
.hir().root_module();
1087 let filename
= sm
.span_to_filename(krate_mod
.spans
.inner_span
);
1088 let data_id
= id_from_hir_id(id
, &self.save_ctxt
);
1090 krate_mod
.item_ids
.iter().map(|i
| id_from_def_id(i
.def_id
.to_def_id())).collect();
1091 let span
= self.span_from_span(krate_mod
.spans
.inner_span
);
1092 let attrs
= self.tcx
.hir().attrs(id
);
1094 self.dumper
.dump_def(
1095 &Access { public: true, reachable: true }
,
1099 name
: String
::new(),
1102 value
: filename
.prefer_remapped().to_string(),
1106 docs
: self.save_ctxt
.docs_for_attrs(attrs
),
1108 attributes
: lower_attributes(attrs
.to_owned(), &self.save_ctxt
),
1111 self.tcx
.hir().walk_toplevel_module(self);
1114 fn process_bounds(&mut self, bounds
: hir
::GenericBounds
<'tcx
>) {
1115 for bound
in bounds
{
1116 if let hir
::GenericBound
::Trait(ref trait_ref
, _
) = *bound
{
1118 trait_ref
.trait_ref
.hir_ref_id
,
1119 &hir
::QPath
::Resolved(None
, &trait_ref
.trait_ref
.path
),
1126 impl<'tcx
> Visitor
<'tcx
> for DumpVisitor
<'tcx
> {
1127 type NestedFilter
= nested_filter
::All
;
1129 fn nested_visit_map(&mut self) -> Self::Map
{
1133 fn visit_item(&mut self, item
: &'tcx hir
::Item
<'tcx
>) {
1134 self.process_macro_use(item
.span
);
1136 hir
::ItemKind
::Use(path
, hir
::UseKind
::Single
) => {
1137 let sub_span
= path
.segments
.last().unwrap().ident
.span
;
1138 if !self.span
.filter_generated(sub_span
) {
1139 let access
= access_from
!(self.save_ctxt
, item
.def_id
);
1140 let ref_id
= self.lookup_def_id(item
.hir_id()).map(id_from_def_id
);
1141 let span
= self.span_from_span(sub_span
);
1142 let parent
= self.save_ctxt
.tcx
.local_parent(item
.def_id
);
1146 kind
: ImportKind
::Use
,
1150 name
: item
.ident
.to_string(),
1151 value
: String
::new(),
1152 parent
: Some(id_from_def_id(parent
.to_def_id())),
1155 self.write_sub_paths_truncated(&path
);
1158 hir
::ItemKind
::Use(path
, hir
::UseKind
::Glob
) => {
1159 // Make a comma-separated list of names of imported modules.
1160 let names
= self.tcx
.names_imported_by_glob_use(item
.def_id
);
1161 let names
: Vec
<_
> = names
.iter().map(|n
| n
.to_string()).collect();
1163 // Otherwise it's a span with wrong macro expansion info, which
1164 // we don't want to track anyway, since it's probably macro-internal `use`
1165 if let Some(sub_span
) = self.span
.sub_span_of_star(item
.span
) {
1166 if !self.span
.filter_generated(item
.span
) {
1167 let access
= access_from
!(self.save_ctxt
, item
.def_id
);
1168 let span
= self.span_from_span(sub_span
);
1169 let parent
= self.save_ctxt
.tcx
.local_parent(item
.def_id
);
1173 kind
: ImportKind
::GlobUse
,
1177 name
: "*".to_owned(),
1178 value
: names
.join(", "),
1179 parent
: Some(id_from_def_id(parent
.to_def_id())),
1182 self.write_sub_paths(&path
);
1186 hir
::ItemKind
::ExternCrate(_
) => {
1187 let name_span
= item
.ident
.span
;
1188 if !self.span
.filter_generated(name_span
) {
1189 let span
= self.span_from_span(name_span
);
1190 let parent
= self.save_ctxt
.tcx
.local_parent(item
.def_id
);
1192 &Access { public: false, reachable: false }
,
1194 kind
: ImportKind
::ExternCrate
,
1198 name
: item
.ident
.to_string(),
1199 value
: String
::new(),
1200 parent
: Some(id_from_def_id(parent
.to_def_id())),
1205 hir
::ItemKind
::Fn(ref sig
, ref ty_params
, body
) => {
1206 self.process_fn(item
, sig
.decl
, &sig
.header
, ty_params
, body
)
1208 hir
::ItemKind
::Static(ref typ
, _
, body
) => {
1209 let body
= self.tcx
.hir().body(body
);
1210 self.process_static_or_const_item(item
, typ
, &body
.value
)
1212 hir
::ItemKind
::Const(ref typ
, body
) => {
1213 let body
= self.tcx
.hir().body(body
);
1214 self.process_static_or_const_item(item
, typ
, &body
.value
)
1216 hir
::ItemKind
::Struct(ref def
, ref ty_params
)
1217 | hir
::ItemKind
::Union(ref def
, ref ty_params
) => {
1218 self.process_struct(item
, def
, ty_params
)
1220 hir
::ItemKind
::Enum(ref def
, ref ty_params
) => self.process_enum(item
, def
, ty_params
),
1221 hir
::ItemKind
::Impl(ref impl_
) => self.process_impl(item
, impl_
),
1222 hir
::ItemKind
::Trait(_
, _
, ref generics
, ref trait_refs
, methods
) => {
1223 self.process_trait(item
, generics
, trait_refs
, methods
)
1225 hir
::ItemKind
::Mod(ref m
) => {
1226 self.process_mod(item
);
1227 intravisit
::walk_mod(self, m
, item
.hir_id());
1229 hir
::ItemKind
::TyAlias(ty
, ref generics
) => {
1230 let qualname
= format
!("::{}", self.tcx
.def_path_str(item
.def_id
.to_def_id()));
1231 let value
= ty_to_string(&ty
);
1232 if !self.span
.filter_generated(item
.ident
.span
) {
1233 let span
= self.span_from_span(item
.ident
.span
);
1234 let id
= id_from_def_id(item
.def_id
.to_def_id());
1235 let attrs
= self.tcx
.hir().attrs(item
.hir_id());
1237 self.dumper
.dump_def(
1238 &access_from
!(self.save_ctxt
, item
.def_id
),
1240 kind
: DefKind
::Type
,
1243 name
: item
.ident
.to_string(),
1244 qualname
: qualname
.clone(),
1249 docs
: self.save_ctxt
.docs_for_attrs(attrs
),
1250 sig
: sig
::item_signature(item
, &self.save_ctxt
),
1251 attributes
: lower_attributes(attrs
.to_vec(), &self.save_ctxt
),
1257 self.process_generic_params(generics
, &qualname
, item
.hir_id());
1259 _
=> intravisit
::walk_item(self, item
),
1263 fn visit_generics(&mut self, generics
: &'tcx hir
::Generics
<'tcx
>) {
1264 for param
in generics
.params
{
1266 hir
::GenericParamKind
::Lifetime { .. }
=> {}
1267 hir
::GenericParamKind
::Type { ref default, .. }
=> {
1268 if let Some(ref ty
) = default {
1272 hir
::GenericParamKind
::Const { ref ty, ref default }
=> {
1274 if let Some(default) = default {
1275 self.visit_anon_const(default);
1280 for pred
in generics
.predicates
{
1281 if let hir
::WherePredicate
::BoundPredicate(ref wbp
) = *pred
{
1282 self.process_bounds(wbp
.bounds
);
1283 self.visit_ty(wbp
.bounded_ty
);
1288 fn visit_ty(&mut self, t
: &'tcx hir
::Ty
<'tcx
>) {
1289 self.process_macro_use(t
.span
);
1291 hir
::TyKind
::Path(ref path
) => {
1292 if generated_code(t
.span
) {
1296 if let Some(id
) = self.lookup_def_id(t
.hir_id
) {
1297 let sub_span
= path
.last_segment_span();
1298 let span
= self.span_from_span(sub_span
);
1299 self.dumper
.dump_ref(Ref
{
1300 kind
: RefKind
::Type
,
1302 ref_id
: id_from_def_id(id
),
1306 if let hir
::QPath
::Resolved(_
, path
) = path
{
1307 self.write_sub_paths_truncated(path
);
1309 intravisit
::walk_qpath(self, path
, t
.hir_id
);
1311 hir
::TyKind
::Array(ref ty
, ref length
) => {
1313 let map
= self.tcx
.hir();
1315 // FIXME(generic_arg_infer): We probably want to
1316 // output the inferred type here? :shrug:
1317 hir
::ArrayLen
::Infer(..) => {}
1318 hir
::ArrayLen
::Body(anon_const
) => self
1319 .nest_typeck_results(self.tcx
.hir().local_def_id(anon_const
.hir_id
), |v
| {
1320 v
.visit_expr(&map
.body(anon_const
.body
).value
)
1324 hir
::TyKind
::OpaqueDef(item_id
, _
, _
) => {
1325 let item
= self.tcx
.hir().item(item_id
);
1326 self.nest_typeck_results(item_id
.def_id
, |v
| v
.visit_item(item
));
1328 _
=> intravisit
::walk_ty(self, t
),
1332 fn visit_expr(&mut self, ex
: &'tcx hir
::Expr
<'tcx
>) {
1333 debug
!("visit_expr {:?}", ex
.kind
);
1334 self.process_macro_use(ex
.span
);
1336 hir
::ExprKind
::Struct(ref path
, ref fields
, ref rest
) => {
1337 let hir_expr
= self.save_ctxt
.tcx
.hir().expect_expr(ex
.hir_id
);
1338 let adt
= match self.save_ctxt
.typeck_results().expr_ty_opt(&hir_expr
) {
1339 Some(ty
) if ty
.ty_adt_def().is_some() => ty
.ty_adt_def().unwrap(),
1341 intravisit
::walk_expr(self, ex
);
1345 let res
= self.save_ctxt
.get_path_res(hir_expr
.hir_id
);
1346 self.process_struct_lit(ex
, path
, fields
, adt
.variant_of_res(res
), *rest
)
1348 hir
::ExprKind
::MethodCall(ref seg
, receiver
, args
, _
) => {
1349 self.process_method_call(ex
, seg
, receiver
, args
)
1351 hir
::ExprKind
::Field(ref sub_ex
, _
) => {
1352 self.visit_expr(&sub_ex
);
1354 if let Some(field_data
) = self.save_ctxt
.get_expr_data(ex
) {
1355 down_cast_data
!(field_data
, RefData
, ex
.span
);
1356 if !generated_code(ex
.span
) {
1357 self.dumper
.dump_ref(field_data
);
1361 hir
::ExprKind
::Closure(&hir
::Closure { ref fn_decl, body, .. }
) => {
1362 let id
= format
!("${}", ex
.hir_id
);
1364 // walk arg and return types
1365 for ty
in fn_decl
.inputs
{
1369 if let hir
::FnRetTy
::Return(ref ret_ty
) = fn_decl
.output
{
1370 self.visit_ty(ret_ty
);
1374 let map
= self.tcx
.hir();
1375 self.nest_typeck_results(self.tcx
.hir().local_def_id(ex
.hir_id
), |v
| {
1376 let body
= map
.body(body
);
1377 v
.process_formals(body
.params
, &id
);
1378 v
.visit_expr(&body
.value
)
1381 hir
::ExprKind
::Repeat(ref expr
, ref length
) => {
1382 self.visit_expr(expr
);
1383 let map
= self.tcx
.hir();
1385 // FIXME(generic_arg_infer): We probably want to
1386 // output the inferred type here? :shrug:
1387 hir
::ArrayLen
::Infer(..) => {}
1388 hir
::ArrayLen
::Body(anon_const
) => self
1389 .nest_typeck_results(self.tcx
.hir().local_def_id(anon_const
.hir_id
), |v
| {
1390 v
.visit_expr(&map
.body(anon_const
.body
).value
)
1394 // In particular, we take this branch for call and path expressions,
1395 // where we'll index the idents involved just by continuing to walk.
1396 _
=> intravisit
::walk_expr(self, ex
),
1400 fn visit_pat(&mut self, p
: &'tcx hir
::Pat
<'tcx
>) {
1401 self.process_macro_use(p
.span
);
1402 self.process_pat(p
);
1405 fn visit_arm(&mut self, arm
: &'tcx hir
::Arm
<'tcx
>) {
1406 self.process_var_decl(&arm
.pat
);
1407 if let Some(hir
::Guard
::If(expr
)) = &arm
.guard
{
1408 self.visit_expr(expr
);
1410 self.visit_expr(&arm
.body
);
1413 fn visit_qpath(&mut self, path
: &'tcx hir
::QPath
<'tcx
>, id
: hir
::HirId
, _
: Span
) {
1414 self.process_path(id
, path
);
1417 fn visit_stmt(&mut self, s
: &'tcx hir
::Stmt
<'tcx
>) {
1418 self.process_macro_use(s
.span
);
1419 intravisit
::walk_stmt(self, s
)
1422 fn visit_local(&mut self, l
: &'tcx hir
::Local
<'tcx
>) {
1423 self.process_macro_use(l
.span
);
1424 self.process_var_decl(&l
.pat
);
1426 // Just walk the initializer, the else branch and type (don't want to walk the pattern again).
1427 walk_list
!(self, visit_ty
, &l
.ty
);
1428 walk_list
!(self, visit_expr
, &l
.init
);
1429 walk_list
!(self, visit_block
, l
.els
);
1432 fn visit_foreign_item(&mut self, item
: &'tcx hir
::ForeignItem
<'tcx
>) {
1433 let access
= access_from
!(self.save_ctxt
, item
.def_id
);
1436 hir
::ForeignItemKind
::Fn(decl
, _
, ref generics
) => {
1437 if let Some(fn_data
) = self.save_ctxt
.get_extern_item_data(item
) {
1438 down_cast_data
!(fn_data
, DefData
, item
.span
);
1440 self.process_generic_params(generics
, &fn_data
.qualname
, item
.hir_id());
1441 self.dumper
.dump_def(&access
, fn_data
);
1444 for ty
in decl
.inputs
{
1448 if let hir
::FnRetTy
::Return(ref ret_ty
) = decl
.output
{
1449 self.visit_ty(ret_ty
);
1452 hir
::ForeignItemKind
::Static(ref ty
, _
) => {
1453 if let Some(var_data
) = self.save_ctxt
.get_extern_item_data(item
) {
1454 down_cast_data
!(var_data
, DefData
, item
.span
);
1455 self.dumper
.dump_def(&access
, var_data
);
1460 hir
::ForeignItemKind
::Type
=> {
1461 if let Some(var_data
) = self.save_ctxt
.get_extern_item_data(item
) {
1462 down_cast_data
!(var_data
, DefData
, item
.span
);
1463 self.dumper
.dump_def(&access
, var_data
);