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 use tracing
::{debug, error}
;
49 #[rustfmt::skip] // https://github.com/rust-lang/rustfmt/issues/5213
50 macro_rules
! down_cast_data
{
51 ($id
:ident
, $kind
:ident
, $sp
:expr
) => {
52 let super::Data
::$
kind($id
) = $id
else {
53 span_bug
!($sp
, "unexpected data kind: {:?}", $id
);
58 macro_rules
! access_from
{
59 ($save_ctxt
:expr
, $id
:expr
) => {
61 public
: $save_ctxt
.tcx
.visibility($id
).is_public(),
62 reachable
: $save_ctxt
.access_levels
.is_reachable($id
),
67 pub struct DumpVisitor
<'tcx
> {
68 pub save_ctxt
: SaveContext
<'tcx
>,
72 span
: SpanUtils
<'tcx
>,
73 // Set of macro definition (callee) spans, and the set
74 // of macro use (callsite) spans. We store these to ensure
75 // we only write one macro def per unique macro definition, and
76 // one macro use per unique callsite span.
77 // mac_defs: FxHashSet<Span>,
78 // macro_calls: FxHashSet<Span>,
81 impl<'tcx
> DumpVisitor
<'tcx
> {
82 pub fn new(save_ctxt
: SaveContext
<'tcx
>) -> DumpVisitor
<'tcx
> {
83 let span_utils
= SpanUtils
::new(&save_ctxt
.tcx
.sess
);
84 let dumper
= Dumper
::new(save_ctxt
.config
.clone());
90 // mac_defs: FxHashSet::default(),
91 // macro_calls: FxHashSet::default(),
95 pub fn analysis(&self) -> &rls_data
::Analysis
{
96 self.dumper
.analysis()
99 fn nest_typeck_results
<F
>(&mut self, item_def_id
: LocalDefId
, f
: F
)
101 F
: FnOnce(&mut Self),
103 let typeck_results
= if self.tcx
.has_typeck_results(item_def_id
) {
104 Some(self.tcx
.typeck(item_def_id
))
109 let old_maybe_typeck_results
= self.save_ctxt
.maybe_typeck_results
;
110 self.save_ctxt
.maybe_typeck_results
= typeck_results
;
112 self.save_ctxt
.maybe_typeck_results
= old_maybe_typeck_results
;
115 fn span_from_span(&self, span
: Span
) -> SpanData
{
116 self.save_ctxt
.span_from_span(span
)
119 fn lookup_def_id(&self, ref_id
: hir
::HirId
) -> Option
<DefId
> {
120 self.save_ctxt
.lookup_def_id(ref_id
)
123 pub fn dump_crate_info(&mut self, name
: &str) {
124 let source_file
= self.tcx
.sess
.local_crate_source_file
.as_ref();
125 let crate_root
= source_file
.map(|source_file
| {
126 let source_file
= Path
::new(source_file
);
127 match source_file
.file_name() {
128 Some(_
) => source_file
.parent().unwrap().display(),
129 None
=> source_file
.display(),
134 let data
= CratePreludeData
{
135 crate_id
: GlobalCrateId
{
137 disambiguator
: (self.tcx
.sess
.local_stable_crate_id().to_u64(), 0),
139 crate_root
: crate_root
.unwrap_or_else(|| "<no source>".to_owned()),
140 external_crates
: self.save_ctxt
.get_external_crates(),
141 span
: self.span_from_span(self.tcx
.def_span(CRATE_DEF_ID
)),
144 self.dumper
.crate_prelude(data
);
147 pub fn dump_compilation_options(&mut self, input
: &Input
, crate_name
: &str) {
148 // Apply possible `remap-path-prefix` remapping to the input source file
149 // (and don't include remapping args anymore)
150 let (program
, arguments
) = {
151 let remap_arg_indices
= {
152 let mut indices
= FxHashSet
::default();
153 // Args are guaranteed to be valid UTF-8 (checked early)
154 for (i
, e
) in env
::args().enumerate() {
155 if e
.starts_with("--remap-path-prefix=") {
157 } else if e
== "--remap-path-prefix" {
159 indices
.insert(i
+ 1);
165 let mut args
= env
::args()
167 .filter(|(i
, _
)| !remap_arg_indices
.contains(i
))
168 .map(|(_
, arg
)| match input
{
169 Input
::File(ref path
) if path
== Path
::new(&arg
) => {
170 let mapped
= &self.tcx
.sess
.local_crate_source_file
;
171 mapped
.as_ref().unwrap().to_string_lossy().into()
176 (args
.next().unwrap(), args
.collect())
179 let data
= CompilationOptions
{
180 directory
: self.tcx
.sess
.opts
.working_dir
.remapped_path_if_available().into(),
183 output
: self.save_ctxt
.compilation_output(crate_name
),
186 self.dumper
.compilation_opts(data
);
189 fn write_segments(&mut self, segments
: impl IntoIterator
<Item
= &'tcx hir
::PathSegment
<'tcx
>>) {
190 for seg
in segments
{
191 if let Some(data
) = self.save_ctxt
.get_path_segment_data(seg
) {
192 self.dumper
.dump_ref(data
);
197 fn write_sub_paths(&mut self, path
: &'tcx hir
::Path
<'tcx
>) {
198 self.write_segments(path
.segments
)
201 // As write_sub_paths, but does not process the last ident in the path (assuming it
202 // will be processed elsewhere). See note on write_sub_paths about global.
203 fn write_sub_paths_truncated(&mut self, path
: &'tcx hir
::Path
<'tcx
>) {
204 if let [segments @
.., _
] = path
.segments
{
205 self.write_segments(segments
)
209 fn process_formals(&mut self, formals
: &'tcx
[hir
::Param
<'tcx
>], qualname
: &str) {
211 self.visit_pat(&arg
.pat
);
212 let mut collector
= PathCollector
::new(self.tcx
);
213 collector
.visit_pat(&arg
.pat
);
215 for (hir_id
, ident
, ..) in collector
.collected_idents
{
216 let typ
= match self.save_ctxt
.typeck_results().node_type_opt(hir_id
) {
217 Some(s
) => s
.to_string(),
220 if !self.span
.filter_generated(ident
.span
) {
221 let id
= id_from_hir_id(hir_id
, &self.save_ctxt
);
222 let span
= self.span_from_span(ident
.span
);
224 self.dumper
.dump_def(
225 &Access { public: false, reachable: false }
,
227 kind
: DefKind
::Local
,
230 name
: ident
.to_string(),
231 qualname
: format
!("{}::{}", qualname
, ident
),
248 sig
: &'tcx hir
::FnSig
<'tcx
>,
249 body
: Option
<hir
::BodyId
>,
252 generics
: &'tcx hir
::Generics
<'tcx
>,
255 debug
!("process_method: {:?}:{}", def_id
, ident
);
257 let map
= self.tcx
.hir();
258 let hir_id
= map
.local_def_id_to_hir_id(def_id
);
259 self.nest_typeck_results(def_id
, |v
| {
260 if let Some(mut method_data
) = v
.save_ctxt
.get_method_data(hir_id
, ident
, span
) {
261 if let Some(body
) = body
{
262 v
.process_formals(map
.body(body
).params
, &method_data
.qualname
);
264 v
.process_generic_params(&generics
, &method_data
.qualname
, hir_id
);
267 fn_to_string(sig
.decl
, sig
.header
, Some(ident
.name
), generics
, &[], None
);
268 method_data
.sig
= sig
::method_signature(hir_id
, ident
, generics
, sig
, &v
.save_ctxt
);
270 v
.dumper
.dump_def(&access_from
!(v
.save_ctxt
, def_id
), method_data
);
273 // walk arg and return types
274 for arg
in sig
.decl
.inputs
{
278 if let hir
::FnRetTy
::Return(ref ret_ty
) = sig
.decl
.output
{
283 if let Some(body
) = body
{
284 v
.visit_expr(&map
.body(body
).value
);
289 fn process_struct_field_def(
291 field
: &'tcx hir
::FieldDef
<'tcx
>,
292 parent_id
: hir
::HirId
,
294 let field_data
= self.save_ctxt
.get_field_data(field
, parent_id
);
295 if let Some(field_data
) = field_data
{
296 self.dumper
.dump_def(
297 &access_from
!(self.save_ctxt
, self.tcx
.hir().local_def_id(field
.hir_id
)),
303 // Dump generic params bindings, then visit_generics
304 fn process_generic_params(
306 generics
: &'tcx hir
::Generics
<'tcx
>,
310 for param
in generics
.params
{
312 hir
::GenericParamKind
::Lifetime { .. }
=> {}
313 hir
::GenericParamKind
::Type { .. }
=> {
314 let param_ss
= param
.name
.ident().span
;
315 let name
= escape(self.span
.snippet(param_ss
));
316 // Append $id to name to make sure each one is unique.
317 let qualname
= format
!("{}::{}${}", prefix
, name
, id
);
318 if !self.span
.filter_generated(param_ss
) {
319 let id
= id_from_hir_id(param
.hir_id
, &self.save_ctxt
);
320 let span
= self.span_from_span(param_ss
);
322 self.dumper
.dump_def(
323 &Access { public: false, reachable: false }
,
330 value
: String
::new(),
341 hir
::GenericParamKind
::Const { .. }
=> {}
345 self.visit_generics(generics
)
350 item
: &'tcx hir
::Item
<'tcx
>,
351 decl
: &'tcx hir
::FnDecl
<'tcx
>,
352 _header
: &'tcx hir
::FnHeader
,
353 ty_params
: &'tcx hir
::Generics
<'tcx
>,
356 let map
= self.tcx
.hir();
357 self.nest_typeck_results(item
.def_id
, |v
| {
358 let body
= map
.body(body
);
359 if let Some(fn_data
) = v
.save_ctxt
.get_item_data(item
) {
360 down_cast_data
!(fn_data
, DefData
, item
.span
);
361 v
.process_formals(body
.params
, &fn_data
.qualname
);
362 v
.process_generic_params(ty_params
, &fn_data
.qualname
, item
.hir_id());
364 v
.dumper
.dump_def(&access_from
!(v
.save_ctxt
, item
.def_id
), fn_data
);
367 for arg
in decl
.inputs
{
371 if let hir
::FnRetTy
::Return(ref ret_ty
) = decl
.output
{
375 v
.visit_expr(&body
.value
);
379 fn process_static_or_const_item(
381 item
: &'tcx hir
::Item
<'tcx
>,
382 typ
: &'tcx hir
::Ty
<'tcx
>,
383 expr
: &'tcx hir
::Expr
<'tcx
>,
385 self.nest_typeck_results(item
.def_id
, |v
| {
386 if let Some(var_data
) = v
.save_ctxt
.get_item_data(item
) {
387 down_cast_data
!(var_data
, DefData
, item
.span
);
388 v
.dumper
.dump_def(&access_from
!(v
.save_ctxt
, item
.def_id
), var_data
);
395 fn process_assoc_const(
399 typ
: &'tcx hir
::Ty
<'tcx
>,
400 expr
: Option
<&'tcx hir
::Expr
<'tcx
>>,
402 attrs
: &'tcx
[ast
::Attribute
],
404 let qualname
= format
!("::{}", self.tcx
.def_path_str(def_id
.to_def_id()));
406 if !self.span
.filter_generated(ident
.span
) {
407 let hir_id
= self.tcx
.hir().local_def_id_to_hir_id(def_id
);
408 let sig
= sig
::assoc_const_signature(hir_id
, ident
.name
, typ
, expr
, &self.save_ctxt
);
409 let span
= self.span_from_span(ident
.span
);
411 self.dumper
.dump_def(
412 &access_from
!(self.save_ctxt
, def_id
),
414 kind
: DefKind
::Const
,
415 id
: id_from_hir_id(hir_id
, &self.save_ctxt
),
417 name
: ident
.name
.to_string(),
419 value
: ty_to_string(&typ
),
420 parent
: Some(id_from_def_id(parent_id
)),
423 docs
: self.save_ctxt
.docs_for_attrs(attrs
),
425 attributes
: lower_attributes(attrs
.to_owned(), &self.save_ctxt
),
430 // walk type and init value
431 self.nest_typeck_results(def_id
, |v
| {
433 if let Some(expr
) = expr
{
439 // FIXME tuple structs should generate tuple-specific data.
442 item
: &'tcx hir
::Item
<'tcx
>,
443 def
: &'tcx hir
::VariantData
<'tcx
>,
444 ty_params
: &'tcx hir
::Generics
<'tcx
>,
446 debug
!("process_struct {:?} {:?}", item
, item
.span
);
447 let name
= item
.ident
.to_string();
448 let qualname
= format
!("::{}", self.tcx
.def_path_str(item
.def_id
.to_def_id()));
450 let kind
= match item
.kind
{
451 hir
::ItemKind
::Struct(_
, _
) => DefKind
::Struct
,
452 hir
::ItemKind
::Union(_
, _
) => DefKind
::Union
,
456 let (value
, fields
) = match item
.kind
{
457 hir
::ItemKind
::Struct(hir
::VariantData
::Struct(ref fields
, ..), ..)
458 | hir
::ItemKind
::Union(hir
::VariantData
::Struct(ref fields
, ..), ..) => {
459 let include_priv_fields
= !self.save_ctxt
.config
.pub_only
;
460 let fields_str
= fields
463 if include_priv_fields
{
464 return Some(f
.ident
.to_string());
466 let def_id
= self.save_ctxt
.tcx
.hir().local_def_id(f
.hir_id
);
467 if self.save_ctxt
.tcx
.visibility(def_id
).is_public() {
468 Some(f
.ident
.to_string())
475 let value
= format
!("{} {{ {} }}", name
, fields_str
);
476 (value
, fields
.iter().map(|f
| id_from_hir_id(f
.hir_id
, &self.save_ctxt
)).collect())
478 _
=> (String
::new(), vec
![]),
481 if !self.span
.filter_generated(item
.ident
.span
) {
482 let span
= self.span_from_span(item
.ident
.span
);
483 let attrs
= self.tcx
.hir().attrs(item
.hir_id());
484 self.dumper
.dump_def(
485 &access_from
!(self.save_ctxt
, item
.def_id
),
488 id
: id_from_def_id(item
.def_id
.to_def_id()),
491 qualname
: qualname
.clone(),
496 docs
: self.save_ctxt
.docs_for_attrs(attrs
),
497 sig
: sig
::item_signature(item
, &self.save_ctxt
),
498 attributes
: lower_attributes(attrs
.to_vec(), &self.save_ctxt
),
503 self.nest_typeck_results(item
.def_id
, |v
| {
504 for field
in def
.fields() {
505 v
.process_struct_field_def(field
, item
.hir_id());
506 v
.visit_ty(&field
.ty
);
509 v
.process_generic_params(ty_params
, &qualname
, item
.hir_id());
515 item
: &'tcx hir
::Item
<'tcx
>,
516 enum_definition
: &'tcx hir
::EnumDef
<'tcx
>,
517 ty_params
: &'tcx hir
::Generics
<'tcx
>,
519 let enum_data
= self.save_ctxt
.get_item_data(item
);
520 let Some(enum_data
) = enum_data
else {
523 down_cast_data
!(enum_data
, DefData
, item
.span
);
525 let access
= access_from
!(self.save_ctxt
, item
.def_id
);
527 for variant
in enum_definition
.variants
{
528 let name
= variant
.ident
.name
.to_string();
529 let qualname
= format
!("{}::{}", enum_data
.qualname
, name
);
530 let name_span
= variant
.ident
.span
;
533 hir
::VariantData
::Struct(ref fields
, ..) => {
535 fields
.iter().map(|f
| f
.ident
.to_string()).collect
::<Vec
<_
>>().join(", ");
536 let value
= format
!("{}::{} {{ {} }}", enum_data
.name
, name
, fields_str
);
537 if !self.span
.filter_generated(name_span
) {
538 let span
= self.span_from_span(name_span
);
539 let id
= id_from_hir_id(variant
.id
, &self.save_ctxt
);
540 let parent
= Some(id_from_def_id(item
.def_id
.to_def_id()));
541 let attrs
= self.tcx
.hir().attrs(variant
.id
);
543 self.dumper
.dump_def(
546 kind
: DefKind
::StructVariant
,
555 docs
: self.save_ctxt
.docs_for_attrs(attrs
),
556 sig
: sig
::variant_signature(variant
, &self.save_ctxt
),
557 attributes
: lower_attributes(attrs
.to_vec(), &self.save_ctxt
),
563 let mut value
= format
!("{}::{}", enum_data
.name
, name
);
564 if let hir
::VariantData
::Tuple(fields
, _
) = v
{
569 .map(|f
| ty_to_string(&f
.ty
))
575 if !self.span
.filter_generated(name_span
) {
576 let span
= self.span_from_span(name_span
);
577 let id
= id_from_hir_id(variant
.id
, &self.save_ctxt
);
578 let parent
= Some(id_from_def_id(item
.def_id
.to_def_id()));
579 let attrs
= self.tcx
.hir().attrs(variant
.id
);
581 self.dumper
.dump_def(
584 kind
: DefKind
::TupleVariant
,
593 docs
: self.save_ctxt
.docs_for_attrs(attrs
),
594 sig
: sig
::variant_signature(variant
, &self.save_ctxt
),
595 attributes
: lower_attributes(attrs
.to_vec(), &self.save_ctxt
),
602 for field
in variant
.data
.fields() {
603 self.process_struct_field_def(field
, variant
.id
);
604 self.visit_ty(field
.ty
);
607 self.process_generic_params(ty_params
, &enum_data
.qualname
, item
.hir_id());
608 self.dumper
.dump_def(&access
, enum_data
);
611 fn process_impl(&mut self, item
: &'tcx hir
::Item
<'tcx
>, impl_
: &'tcx hir
::Impl
<'tcx
>) {
612 if let Some(impl_data
) = self.save_ctxt
.get_item_data(item
) {
613 if !self.span
.filter_generated(item
.span
) {
614 if let super::Data
::RelationData(rel
, imp
) = impl_data
{
615 self.dumper
.dump_relation(rel
);
616 self.dumper
.dump_impl(imp
);
618 span_bug
!(item
.span
, "unexpected data kind: {:?}", impl_data
);
623 let map
= self.tcx
.hir();
624 self.nest_typeck_results(item
.def_id
, |v
| {
625 v
.visit_ty(&impl_
.self_ty
);
626 if let Some(trait_ref
) = &impl_
.of_trait
{
627 v
.process_path(trait_ref
.hir_ref_id
, &hir
::QPath
::Resolved(None
, &trait_ref
.path
));
629 v
.process_generic_params(&impl_
.generics
, "", item
.hir_id());
630 for impl_item
in impl_
.items
{
631 v
.process_impl_item(map
.impl_item(impl_item
.id
), item
.def_id
.to_def_id());
638 item
: &'tcx hir
::Item
<'tcx
>,
639 generics
: &'tcx hir
::Generics
<'tcx
>,
640 trait_refs
: hir
::GenericBounds
<'tcx
>,
641 methods
: &'tcx
[hir
::TraitItemRef
],
643 let name
= item
.ident
.to_string();
644 let qualname
= format
!("::{}", self.tcx
.def_path_str(item
.def_id
.to_def_id()));
645 let mut val
= name
.clone();
646 if !generics
.params
.is_empty() {
647 val
.push_str(&generic_params_to_string(generics
.params
));
649 if !trait_refs
.is_empty() {
651 val
.push_str(&bounds_to_string(trait_refs
));
653 if !self.span
.filter_generated(item
.ident
.span
) {
654 let id
= id_from_def_id(item
.def_id
.to_def_id());
655 let span
= self.span_from_span(item
.ident
.span
);
657 methods
.iter().map(|i
| id_from_def_id(i
.id
.def_id
.to_def_id())).collect();
658 let attrs
= self.tcx
.hir().attrs(item
.hir_id());
659 self.dumper
.dump_def(
660 &access_from
!(self.save_ctxt
, item
.def_id
),
662 kind
: DefKind
::Trait
,
666 qualname
: qualname
.clone(),
671 docs
: self.save_ctxt
.docs_for_attrs(attrs
),
672 sig
: sig
::item_signature(item
, &self.save_ctxt
),
673 attributes
: lower_attributes(attrs
.to_vec(), &self.save_ctxt
),
679 for super_bound
in trait_refs
.iter() {
680 let (def_id
, sub_span
) = match *super_bound
{
681 hir
::GenericBound
::Trait(ref trait_ref
, _
) => (
682 self.lookup_def_id(trait_ref
.trait_ref
.hir_ref_id
),
683 trait_ref
.trait_ref
.path
.segments
.last().unwrap().ident
.span
,
685 hir
::GenericBound
::LangItemTrait(lang_item
, span
, _
, _
) => {
686 (Some(self.tcx
.require_lang_item(lang_item
, Some(span
))), span
)
688 hir
::GenericBound
::Outlives(..) => continue,
691 if let Some(id
) = def_id
{
692 if !self.span
.filter_generated(sub_span
) {
693 let span
= self.span_from_span(sub_span
);
694 self.dumper
.dump_ref(Ref
{
697 ref_id
: id_from_def_id(id
),
700 self.dumper
.dump_relation(Relation
{
701 kind
: RelationKind
::SuperTrait
,
703 from
: id_from_def_id(id
),
704 to
: id_from_def_id(item
.def_id
.to_def_id()),
710 // walk generics and methods
711 self.process_generic_params(generics
, &qualname
, item
.hir_id());
712 for method
in methods
{
713 let map
= self.tcx
.hir();
714 self.process_trait_item(map
.trait_item(method
.id
), item
.def_id
.to_def_id())
718 // `item` is the module in question, represented as an( item.
719 fn process_mod(&mut self, item
: &'tcx hir
::Item
<'tcx
>) {
720 if let Some(mod_data
) = self.save_ctxt
.get_item_data(item
) {
721 down_cast_data
!(mod_data
, DefData
, item
.span
);
722 self.dumper
.dump_def(&access_from
!(self.save_ctxt
, item
.def_id
), mod_data
);
726 fn dump_path_ref(&mut self, id
: hir
::HirId
, path
: &hir
::QPath
<'tcx
>) {
727 let path_data
= self.save_ctxt
.get_path_data(id
, path
);
728 if let Some(path_data
) = path_data
{
729 self.dumper
.dump_ref(path_data
);
733 fn dump_path_segment_ref(&mut self, id
: hir
::HirId
, segment
: &hir
::PathSegment
<'tcx
>) {
734 let segment_data
= self.save_ctxt
.get_path_segment_data_with_id(segment
, id
);
735 if let Some(segment_data
) = segment_data
{
736 self.dumper
.dump_ref(segment_data
);
740 fn process_path(&mut self, id
: hir
::HirId
, path
: &hir
::QPath
<'tcx
>) {
741 if self.span
.filter_generated(path
.span()) {
744 self.dump_path_ref(id
, path
);
747 let segments
= match path
{
748 hir
::QPath
::Resolved(ty
, path
) => {
749 if let Some(ty
) = ty
{
754 hir
::QPath
::TypeRelative(ty
, segment
) => {
756 std
::slice
::from_ref(*segment
)
758 hir
::QPath
::LangItem(..) => return,
760 for seg
in segments
{
761 if let Some(ref generic_args
) = seg
.args
{
762 for arg
in generic_args
.args
{
763 if let hir
::GenericArg
::Type(ref ty
) = arg
{
770 if let hir
::QPath
::Resolved(_
, path
) = path
{
771 self.write_sub_paths_truncated(path
);
775 fn process_struct_lit(
777 ex
: &'tcx hir
::Expr
<'tcx
>,
778 path
: &'tcx hir
::QPath
<'tcx
>,
779 fields
: &'tcx
[hir
::ExprField
<'tcx
>],
780 variant
: &'tcx ty
::VariantDef
,
781 rest
: Option
<&'tcx hir
::Expr
<'tcx
>>,
783 if let Some(_ex_res_data
) = self.save_ctxt
.get_expr_data(ex
) {
784 if let hir
::QPath
::Resolved(_
, path
) = path
{
785 self.write_sub_paths_truncated(path
);
787 // For MyEnum::MyVariant, get_expr_data gives us MyEnum, not MyVariant.
788 // For recording the span's ref id, we want MyVariant.
789 if !generated_code(ex
.span
) {
790 let sub_span
= path
.last_segment_span();
791 let span
= self.save_ctxt
.span_from_span(sub_span
);
793 Ref { kind: RefKind::Type, span, ref_id: id_from_def_id(variant.def_id) }
;
794 self.dumper
.dump_ref(reff
);
797 for field
in fields
{
798 if let Some(field_data
) = self.save_ctxt
.get_field_ref_data(field
, variant
) {
799 self.dumper
.dump_ref(field_data
);
802 self.visit_expr(&field
.expr
)
806 if let Some(base
) = rest
{
807 self.visit_expr(&base
);
811 fn process_method_call(
813 ex
: &'tcx hir
::Expr
<'tcx
>,
814 seg
: &'tcx hir
::PathSegment
<'tcx
>,
815 args
: &'tcx
[hir
::Expr
<'tcx
>],
817 debug
!("process_method_call {:?} {:?}", ex
, ex
.span
);
818 if let Some(mcd
) = self.save_ctxt
.get_expr_data(ex
) {
819 down_cast_data
!(mcd
, RefData
, ex
.span
);
820 if !generated_code(ex
.span
) {
821 self.dumper
.dump_ref(mcd
);
825 // Explicit types in the turbo-fish.
826 if let Some(generic_args
) = seg
.args
{
827 for arg
in generic_args
.args
{
828 if let hir
::GenericArg
::Type(ty
) = arg
{
834 // walk receiver and args
835 walk_list
!(self, visit_expr
, args
);
838 fn process_pat(&mut self, p
: &'tcx hir
::Pat
<'tcx
>) {
840 hir
::PatKind
::Struct(ref _path
, fields
, _
) => {
841 // FIXME do something with _path?
842 let adt
= match self.save_ctxt
.typeck_results().node_type_opt(p
.hir_id
) {
843 Some(ty
) if ty
.ty_adt_def().is_some() => ty
.ty_adt_def().unwrap(),
845 intravisit
::walk_pat(self, p
);
849 let variant
= adt
.variant_of_res(self.save_ctxt
.get_path_res(p
.hir_id
));
851 for field
in fields
{
852 if let Some(index
) = self.tcx
.find_field_index(field
.ident
, variant
) {
853 if !self.span
.filter_generated(field
.ident
.span
) {
854 let span
= self.span_from_span(field
.ident
.span
);
855 self.dumper
.dump_ref(Ref
{
856 kind
: RefKind
::Variable
,
858 ref_id
: id_from_def_id(variant
.fields
[index
].did
),
862 self.visit_pat(&field
.pat
);
865 _
=> intravisit
::walk_pat(self, p
),
869 fn process_var_decl(&mut self, pat
: &'tcx hir
::Pat
<'tcx
>) {
870 // The pattern could declare multiple new vars,
871 // we must walk the pattern and collect them all.
872 let mut collector
= PathCollector
::new(self.tcx
);
873 collector
.visit_pat(&pat
);
874 self.visit_pat(&pat
);
876 // Process collected paths.
877 for (id
, ident
, _
) in collector
.collected_idents
{
878 let res
= self.save_ctxt
.get_path_res(id
);
880 Res
::Local(hir_id
) => {
884 .node_type_opt(hir_id
)
885 .map(|t
| t
.to_string())
886 .unwrap_or_default();
888 // Rust uses the id of the pattern for var lookups, so we'll use it too.
889 if !self.span
.filter_generated(ident
.span
) {
890 let qualname
= format
!("{}${}", ident
, hir_id
);
891 let id
= id_from_hir_id(hir_id
, &self.save_ctxt
);
892 let span
= self.span_from_span(ident
.span
);
894 self.dumper
.dump_def(
895 &Access { public: false, reachable: false }
,
897 kind
: DefKind
::Local
,
900 name
: ident
.to_string(),
916 | HirDefKind
::AssocConst
918 | HirDefKind
::Variant
919 | HirDefKind
::TyAlias
920 | HirDefKind
::AssocTy
,
923 | Res
::SelfTy { .. }
=> {
924 self.dump_path_segment_ref(id
, &hir
::PathSegment
::from_ident(ident
));
927 error
!("unexpected definition kind when processing collected idents: {:?}", def
)
932 for (id
, ref path
) in collector
.collected_paths
{
933 self.process_path(id
, path
);
937 /// Extracts macro use and definition information from the AST node defined
938 /// by the given NodeId, using the expansion information from the node's
941 /// If the span is not macro-generated, do nothing, else use callee and
942 /// callsite spans to record macro definition and use data, using the
943 /// mac_uses and mac_defs sets to prevent multiples.
944 fn process_macro_use(&mut self, _span
: Span
) {
945 // FIXME if we're not dumping the defs (see below), there is no point
946 // dumping refs either.
947 // let source_span = span.source_callsite();
948 // if !self.macro_calls.insert(source_span) {
952 // let data = match self.save_ctxt.get_macro_use_data(span) {
954 // Some(data) => data,
957 // self.dumper.macro_use(data);
959 // FIXME write the macro def
960 // let mut hasher = DefaultHasher::new();
961 // data.callee_span.hash(&mut hasher);
962 // let hash = hasher.finish();
963 // let qualname = format!("{}::{}", data.name, hash);
964 // Don't write macro definition for imported macros
965 // if !self.mac_defs.contains(&data.callee_span)
966 // && !data.imported {
967 // self.mac_defs.insert(data.callee_span);
968 // if let Some(sub_span) = self.span.span_for_macro_def_name(data.callee_span) {
969 // self.dumper.macro_data(MacroData {
971 // name: data.name.clone(),
972 // qualname: qualname.clone(),
973 // // FIXME where do macro docs come from?
974 // docs: String::new(),
975 // }.lower(self.tcx));
980 fn process_trait_item(&mut self, trait_item
: &'tcx hir
::TraitItem
<'tcx
>, trait_id
: DefId
) {
981 self.process_macro_use(trait_item
.span
);
982 match trait_item
.kind
{
983 hir
::TraitItemKind
::Const(ref ty
, body
) => {
984 let body
= body
.map(|b
| &self.tcx
.hir().body(b
).value
);
985 let attrs
= self.tcx
.hir().attrs(trait_item
.hir_id());
986 self.process_assoc_const(
995 hir
::TraitItemKind
::Fn(ref sig
, ref trait_fn
) => {
997 if let hir
::TraitFn
::Provided(body
) = trait_fn { Some(*body) }
else { None }
;
1003 &trait_item
.generics
,
1007 hir
::TraitItemKind
::Type(ref bounds
, ref default_ty
) => {
1008 // FIXME do something with _bounds (for type refs)
1009 let name
= trait_item
.ident
.name
.to_string();
1011 format
!("::{}", self.tcx
.def_path_str(trait_item
.def_id
.to_def_id()));
1013 if !self.span
.filter_generated(trait_item
.ident
.span
) {
1014 let span
= self.span_from_span(trait_item
.ident
.span
);
1015 let id
= id_from_def_id(trait_item
.def_id
.to_def_id());
1016 let attrs
= self.tcx
.hir().attrs(trait_item
.hir_id());
1018 self.dumper
.dump_def(
1019 &Access { public: true, reachable: true }
,
1021 kind
: DefKind
::Type
,
1026 value
: self.span
.snippet(trait_item
.span
),
1027 parent
: Some(id_from_def_id(trait_id
)),
1030 docs
: self.save_ctxt
.docs_for_attrs(attrs
),
1031 sig
: sig
::assoc_type_signature(
1032 trait_item
.hir_id(),
1035 default_ty
.as_ref().map(|ty
| &**ty
),
1038 attributes
: lower_attributes(attrs
.to_vec(), &self.save_ctxt
),
1043 if let Some(default_ty
) = default_ty
{
1044 self.visit_ty(default_ty
)
1050 fn process_impl_item(&mut self, impl_item
: &'tcx hir
::ImplItem
<'tcx
>, impl_id
: DefId
) {
1051 self.process_macro_use(impl_item
.span
);
1052 match impl_item
.kind
{
1053 hir
::ImplItemKind
::Const(ref ty
, body
) => {
1054 let body
= self.tcx
.hir().body(body
);
1055 let attrs
= self.tcx
.hir().attrs(impl_item
.hir_id());
1056 self.process_assoc_const(
1065 hir
::ImplItemKind
::Fn(ref sig
, body
) => {
1066 self.process_method(
1071 &impl_item
.generics
,
1075 hir
::ImplItemKind
::TyAlias(ref ty
) => {
1076 // FIXME: uses of the assoc type should ideally point to this
1077 // 'def' and the name here should be a ref to the def in the
1084 pub(crate) fn process_crate(&mut self) {
1085 let id
= hir
::CRATE_HIR_ID
;
1087 format
!("::{}", self.tcx
.def_path_str(self.tcx
.hir().local_def_id(id
).to_def_id()));
1089 let sm
= self.tcx
.sess
.source_map();
1090 let krate_mod
= self.tcx
.hir().root_module();
1091 let filename
= sm
.span_to_filename(krate_mod
.spans
.inner_span
);
1092 let data_id
= id_from_hir_id(id
, &self.save_ctxt
);
1094 krate_mod
.item_ids
.iter().map(|i
| id_from_def_id(i
.def_id
.to_def_id())).collect();
1095 let span
= self.span_from_span(krate_mod
.spans
.inner_span
);
1096 let attrs
= self.tcx
.hir().attrs(id
);
1098 self.dumper
.dump_def(
1099 &Access { public: true, reachable: true }
,
1103 name
: String
::new(),
1106 value
: filename
.prefer_remapped().to_string(),
1110 docs
: self.save_ctxt
.docs_for_attrs(attrs
),
1112 attributes
: lower_attributes(attrs
.to_owned(), &self.save_ctxt
),
1115 self.tcx
.hir().walk_toplevel_module(self);
1118 fn process_bounds(&mut self, bounds
: hir
::GenericBounds
<'tcx
>) {
1119 for bound
in bounds
{
1120 if let hir
::GenericBound
::Trait(ref trait_ref
, _
) = *bound
{
1122 trait_ref
.trait_ref
.hir_ref_id
,
1123 &hir
::QPath
::Resolved(None
, &trait_ref
.trait_ref
.path
),
1130 impl<'tcx
> Visitor
<'tcx
> for DumpVisitor
<'tcx
> {
1131 type NestedFilter
= nested_filter
::All
;
1133 fn nested_visit_map(&mut self) -> Self::Map
{
1137 fn visit_item(&mut self, item
: &'tcx hir
::Item
<'tcx
>) {
1138 self.process_macro_use(item
.span
);
1140 hir
::ItemKind
::Use(path
, hir
::UseKind
::Single
) => {
1141 let sub_span
= path
.segments
.last().unwrap().ident
.span
;
1142 if !self.span
.filter_generated(sub_span
) {
1143 let access
= access_from
!(self.save_ctxt
, item
.def_id
);
1144 let ref_id
= self.lookup_def_id(item
.hir_id()).map(id_from_def_id
);
1145 let span
= self.span_from_span(sub_span
);
1146 let parent
= self.save_ctxt
.tcx
.local_parent(item
.def_id
);
1150 kind
: ImportKind
::Use
,
1154 name
: item
.ident
.to_string(),
1155 value
: String
::new(),
1156 parent
: Some(id_from_def_id(parent
.to_def_id())),
1159 self.write_sub_paths_truncated(&path
);
1162 hir
::ItemKind
::Use(path
, hir
::UseKind
::Glob
) => {
1163 // Make a comma-separated list of names of imported modules.
1164 let names
= self.tcx
.names_imported_by_glob_use(item
.def_id
);
1165 let names
: Vec
<_
> = names
.iter().map(|n
| n
.to_string()).collect();
1167 // Otherwise it's a span with wrong macro expansion info, which
1168 // we don't want to track anyway, since it's probably macro-internal `use`
1169 if let Some(sub_span
) = self.span
.sub_span_of_star(item
.span
) {
1170 if !self.span
.filter_generated(item
.span
) {
1171 let access
= access_from
!(self.save_ctxt
, item
.def_id
);
1172 let span
= self.span_from_span(sub_span
);
1173 let parent
= self.save_ctxt
.tcx
.local_parent(item
.def_id
);
1177 kind
: ImportKind
::GlobUse
,
1181 name
: "*".to_owned(),
1182 value
: names
.join(", "),
1183 parent
: Some(id_from_def_id(parent
.to_def_id())),
1186 self.write_sub_paths(&path
);
1190 hir
::ItemKind
::ExternCrate(_
) => {
1191 let name_span
= item
.ident
.span
;
1192 if !self.span
.filter_generated(name_span
) {
1193 let span
= self.span_from_span(name_span
);
1194 let parent
= self.save_ctxt
.tcx
.local_parent(item
.def_id
);
1196 &Access { public: false, reachable: false }
,
1198 kind
: ImportKind
::ExternCrate
,
1202 name
: item
.ident
.to_string(),
1203 value
: String
::new(),
1204 parent
: Some(id_from_def_id(parent
.to_def_id())),
1209 hir
::ItemKind
::Fn(ref sig
, ref ty_params
, body
) => {
1210 self.process_fn(item
, sig
.decl
, &sig
.header
, ty_params
, body
)
1212 hir
::ItemKind
::Static(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
::Const(ref typ
, body
) => {
1217 let body
= self.tcx
.hir().body(body
);
1218 self.process_static_or_const_item(item
, typ
, &body
.value
)
1220 hir
::ItemKind
::Struct(ref def
, ref ty_params
)
1221 | hir
::ItemKind
::Union(ref def
, ref ty_params
) => {
1222 self.process_struct(item
, def
, ty_params
)
1224 hir
::ItemKind
::Enum(ref def
, ref ty_params
) => self.process_enum(item
, def
, ty_params
),
1225 hir
::ItemKind
::Impl(ref impl_
) => self.process_impl(item
, impl_
),
1226 hir
::ItemKind
::Trait(_
, _
, ref generics
, ref trait_refs
, methods
) => {
1227 self.process_trait(item
, generics
, trait_refs
, methods
)
1229 hir
::ItemKind
::Mod(ref m
) => {
1230 self.process_mod(item
);
1231 intravisit
::walk_mod(self, m
, item
.hir_id());
1233 hir
::ItemKind
::TyAlias(ty
, ref generics
) => {
1234 let qualname
= format
!("::{}", self.tcx
.def_path_str(item
.def_id
.to_def_id()));
1235 let value
= ty_to_string(&ty
);
1236 if !self.span
.filter_generated(item
.ident
.span
) {
1237 let span
= self.span_from_span(item
.ident
.span
);
1238 let id
= id_from_def_id(item
.def_id
.to_def_id());
1239 let attrs
= self.tcx
.hir().attrs(item
.hir_id());
1241 self.dumper
.dump_def(
1242 &access_from
!(self.save_ctxt
, item
.def_id
),
1244 kind
: DefKind
::Type
,
1247 name
: item
.ident
.to_string(),
1248 qualname
: qualname
.clone(),
1253 docs
: self.save_ctxt
.docs_for_attrs(attrs
),
1254 sig
: sig
::item_signature(item
, &self.save_ctxt
),
1255 attributes
: lower_attributes(attrs
.to_vec(), &self.save_ctxt
),
1261 self.process_generic_params(generics
, &qualname
, item
.hir_id());
1263 _
=> intravisit
::walk_item(self, item
),
1267 fn visit_generics(&mut self, generics
: &'tcx hir
::Generics
<'tcx
>) {
1268 for param
in generics
.params
{
1270 hir
::GenericParamKind
::Lifetime { .. }
=> {}
1271 hir
::GenericParamKind
::Type { ref default, .. }
=> {
1272 if let Some(ref ty
) = default {
1276 hir
::GenericParamKind
::Const { ref ty, ref default }
=> {
1278 if let Some(default) = default {
1279 self.visit_anon_const(default);
1284 for pred
in generics
.predicates
{
1285 if let hir
::WherePredicate
::BoundPredicate(ref wbp
) = *pred
{
1286 self.process_bounds(wbp
.bounds
);
1287 self.visit_ty(wbp
.bounded_ty
);
1292 fn visit_ty(&mut self, t
: &'tcx hir
::Ty
<'tcx
>) {
1293 self.process_macro_use(t
.span
);
1295 hir
::TyKind
::Path(ref path
) => {
1296 if generated_code(t
.span
) {
1300 if let Some(id
) = self.lookup_def_id(t
.hir_id
) {
1301 let sub_span
= path
.last_segment_span();
1302 let span
= self.span_from_span(sub_span
);
1303 self.dumper
.dump_ref(Ref
{
1304 kind
: RefKind
::Type
,
1306 ref_id
: id_from_def_id(id
),
1310 if let hir
::QPath
::Resolved(_
, path
) = path
{
1311 self.write_sub_paths_truncated(path
);
1313 intravisit
::walk_qpath(self, path
, t
.hir_id
, t
.span
);
1315 hir
::TyKind
::Array(ref ty
, ref length
) => {
1317 let map
= self.tcx
.hir();
1319 // FIXME(generic_arg_infer): We probably want to
1320 // output the inferred type here? :shrug:
1321 hir
::ArrayLen
::Infer(..) => {}
1322 hir
::ArrayLen
::Body(anon_const
) => self
1323 .nest_typeck_results(self.tcx
.hir().local_def_id(anon_const
.hir_id
), |v
| {
1324 v
.visit_expr(&map
.body(anon_const
.body
).value
)
1328 hir
::TyKind
::OpaqueDef(item_id
, _
) => {
1329 let item
= self.tcx
.hir().item(item_id
);
1330 self.nest_typeck_results(item_id
.def_id
, |v
| v
.visit_item(item
));
1332 _
=> intravisit
::walk_ty(self, t
),
1336 fn visit_expr(&mut self, ex
: &'tcx hir
::Expr
<'tcx
>) {
1337 debug
!("visit_expr {:?}", ex
.kind
);
1338 self.process_macro_use(ex
.span
);
1340 hir
::ExprKind
::Struct(ref path
, ref fields
, ref rest
) => {
1341 let hir_expr
= self.save_ctxt
.tcx
.hir().expect_expr(ex
.hir_id
);
1342 let adt
= match self.save_ctxt
.typeck_results().expr_ty_opt(&hir_expr
) {
1343 Some(ty
) if ty
.ty_adt_def().is_some() => ty
.ty_adt_def().unwrap(),
1345 intravisit
::walk_expr(self, ex
);
1349 let res
= self.save_ctxt
.get_path_res(hir_expr
.hir_id
);
1350 self.process_struct_lit(ex
, path
, fields
, adt
.variant_of_res(res
), *rest
)
1352 hir
::ExprKind
::MethodCall(ref seg
, args
, _
) => self.process_method_call(ex
, seg
, args
),
1353 hir
::ExprKind
::Field(ref sub_ex
, _
) => {
1354 self.visit_expr(&sub_ex
);
1356 if let Some(field_data
) = self.save_ctxt
.get_expr_data(ex
) {
1357 down_cast_data
!(field_data
, RefData
, ex
.span
);
1358 if !generated_code(ex
.span
) {
1359 self.dumper
.dump_ref(field_data
);
1363 hir
::ExprKind
::Closure { ref fn_decl, body, .. }
=> {
1364 let id
= format
!("${}", ex
.hir_id
);
1366 // walk arg and return types
1367 for ty
in fn_decl
.inputs
{
1371 if let hir
::FnRetTy
::Return(ref ret_ty
) = fn_decl
.output
{
1372 self.visit_ty(ret_ty
);
1376 let map
= self.tcx
.hir();
1377 self.nest_typeck_results(self.tcx
.hir().local_def_id(ex
.hir_id
), |v
| {
1378 let body
= map
.body(body
);
1379 v
.process_formals(body
.params
, &id
);
1380 v
.visit_expr(&body
.value
)
1383 hir
::ExprKind
::Repeat(ref expr
, ref length
) => {
1384 self.visit_expr(expr
);
1385 let map
= self.tcx
.hir();
1387 // FIXME(generic_arg_infer): We probably want to
1388 // output the inferred type here? :shrug:
1389 hir
::ArrayLen
::Infer(..) => {}
1390 hir
::ArrayLen
::Body(anon_const
) => self
1391 .nest_typeck_results(self.tcx
.hir().local_def_id(anon_const
.hir_id
), |v
| {
1392 v
.visit_expr(&map
.body(anon_const
.body
).value
)
1396 // In particular, we take this branch for call and path expressions,
1397 // where we'll index the idents involved just by continuing to walk.
1398 _
=> intravisit
::walk_expr(self, ex
),
1402 fn visit_pat(&mut self, p
: &'tcx hir
::Pat
<'tcx
>) {
1403 self.process_macro_use(p
.span
);
1404 self.process_pat(p
);
1407 fn visit_arm(&mut self, arm
: &'tcx hir
::Arm
<'tcx
>) {
1408 self.process_var_decl(&arm
.pat
);
1409 if let Some(hir
::Guard
::If(expr
)) = &arm
.guard
{
1410 self.visit_expr(expr
);
1412 self.visit_expr(&arm
.body
);
1415 fn visit_qpath(&mut self, path
: &'tcx hir
::QPath
<'tcx
>, id
: hir
::HirId
, _
: Span
) {
1416 self.process_path(id
, path
);
1419 fn visit_stmt(&mut self, s
: &'tcx hir
::Stmt
<'tcx
>) {
1420 self.process_macro_use(s
.span
);
1421 intravisit
::walk_stmt(self, s
)
1424 fn visit_local(&mut self, l
: &'tcx hir
::Local
<'tcx
>) {
1425 self.process_macro_use(l
.span
);
1426 self.process_var_decl(&l
.pat
);
1428 // Just walk the initializer and type (don't want to walk the pattern again).
1429 walk_list
!(self, visit_ty
, &l
.ty
);
1430 walk_list
!(self, visit_expr
, &l
.init
);
1433 fn visit_foreign_item(&mut self, item
: &'tcx hir
::ForeignItem
<'tcx
>) {
1434 let access
= access_from
!(self.save_ctxt
, item
.def_id
);
1437 hir
::ForeignItemKind
::Fn(decl
, _
, ref generics
) => {
1438 if let Some(fn_data
) = self.save_ctxt
.get_extern_item_data(item
) {
1439 down_cast_data
!(fn_data
, DefData
, item
.span
);
1441 self.process_generic_params(generics
, &fn_data
.qualname
, item
.hir_id());
1442 self.dumper
.dump_def(&access
, fn_data
);
1445 for ty
in decl
.inputs
{
1449 if let hir
::FnRetTy
::Return(ref ret_ty
) = decl
.output
{
1450 self.visit_ty(ret_ty
);
1453 hir
::ForeignItemKind
::Static(ref ty
, _
) => {
1454 if let Some(var_data
) = self.save_ctxt
.get_extern_item_data(item
) {
1455 down_cast_data
!(var_data
, DefData
, item
.span
);
1456 self.dumper
.dump_def(&access
, var_data
);
1461 hir
::ForeignItemKind
::Type
=> {
1462 if let Some(var_data
) = self.save_ctxt
.get_extern_item_data(item
) {
1463 down_cast_data
!(var_data
, DefData
, item
.span
);
1464 self.dumper
.dump_def(&access
, var_data
);