]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_save_analysis/src/dump_visitor.rs
Rollup merge of #100964 - bjorn3:sync_cg_clif-2022-08-24, r=bjorn3
[rust.git] / compiler / rustc_save_analysis / src / dump_visitor.rs
1 //! Write the output of rustc's analysis to an implementor of Dump.
2 //!
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
9 //! idents.
10 //!
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.
15
16 use rustc_ast as ast;
17 use rustc_ast::walk_list;
18 use rustc_data_structures::fx::FxHashSet;
19 use rustc_hir as hir;
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;
29 use rustc_span::*;
30
31 use std::env;
32 use std::path::Path;
33
34 use crate::dumper::{Access, Dumper};
35 use crate::sig;
36 use crate::span_utils::SpanUtils;
37 use crate::{
38     escape, generated_code, id_from_def_id, id_from_hir_id, lower_attributes, PathCollector,
39     SaveContext,
40 };
41
42 use rls_data::{
43     CompilationOptions, CratePreludeData, Def, DefKind, GlobalCrateId, Import, ImportKind, Ref,
44     RefKind, Relation, RelationKind, SpanData,
45 };
46
47 use tracing::{debug, error};
48
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);
54         };
55     };
56 }
57
58 macro_rules! access_from {
59     ($save_ctxt:expr, $id:expr) => {
60         Access {
61             public: $save_ctxt.tcx.visibility($id).is_public(),
62             reachable: $save_ctxt.access_levels.is_reachable($id),
63         }
64     };
65 }
66
67 pub struct DumpVisitor<'tcx> {
68     pub save_ctxt: SaveContext<'tcx>,
69     tcx: TyCtxt<'tcx>,
70     dumper: Dumper,
71
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>,
79 }
80
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());
85         DumpVisitor { tcx: save_ctxt.tcx, save_ctxt, dumper, span: span_utils }
86     }
87
88     pub fn analysis(&self) -> &rls_data::Analysis {
89         self.dumper.analysis()
90     }
91
92     fn nest_typeck_results<F>(&mut self, item_def_id: LocalDefId, f: F)
93     where
94         F: FnOnce(&mut Self),
95     {
96         let typeck_results = if self.tcx.has_typeck_results(item_def_id) {
97             Some(self.tcx.typeck(item_def_id))
98         } else {
99             None
100         };
101
102         let old_maybe_typeck_results = self.save_ctxt.maybe_typeck_results;
103         self.save_ctxt.maybe_typeck_results = typeck_results;
104         f(self);
105         self.save_ctxt.maybe_typeck_results = old_maybe_typeck_results;
106     }
107
108     fn span_from_span(&self, span: Span) -> SpanData {
109         self.save_ctxt.span_from_span(span)
110     }
111
112     fn lookup_def_id(&self, ref_id: hir::HirId) -> Option<DefId> {
113         self.save_ctxt.lookup_def_id(ref_id)
114     }
115
116     pub fn dump_crate_info(&mut self, name: &str) {
117         let source_file = self.tcx.sess.local_crate_source_file.as_ref();
118         let crate_root = source_file.map(|source_file| {
119             let source_file = Path::new(source_file);
120             match source_file.file_name() {
121                 Some(_) => source_file.parent().unwrap().display(),
122                 None => source_file.display(),
123             }
124             .to_string()
125         });
126
127         let data = CratePreludeData {
128             crate_id: GlobalCrateId {
129                 name: name.into(),
130                 disambiguator: (self.tcx.sess.local_stable_crate_id().to_u64(), 0),
131             },
132             crate_root: crate_root.unwrap_or_else(|| "<no source>".to_owned()),
133             external_crates: self.save_ctxt.get_external_crates(),
134             span: self.span_from_span(self.tcx.def_span(CRATE_DEF_ID)),
135         };
136
137         self.dumper.crate_prelude(data);
138     }
139
140     pub fn dump_compilation_options(&mut self, input: &Input, crate_name: &str) {
141         // Apply possible `remap-path-prefix` remapping to the input source file
142         // (and don't include remapping args anymore)
143         let (program, arguments) = {
144             let remap_arg_indices = {
145                 let mut indices = FxHashSet::default();
146                 // Args are guaranteed to be valid UTF-8 (checked early)
147                 for (i, e) in env::args().enumerate() {
148                     if e.starts_with("--remap-path-prefix=") {
149                         indices.insert(i);
150                     } else if e == "--remap-path-prefix" {
151                         indices.insert(i);
152                         indices.insert(i + 1);
153                     }
154                 }
155                 indices
156             };
157
158             let mut args = env::args()
159                 .enumerate()
160                 .filter(|(i, _)| !remap_arg_indices.contains(i))
161                 .map(|(_, arg)| match input {
162                     Input::File(ref path) if path == Path::new(&arg) => {
163                         let mapped = &self.tcx.sess.local_crate_source_file;
164                         mapped.as_ref().unwrap().to_string_lossy().into()
165                     }
166                     _ => arg,
167                 });
168
169             (args.next().unwrap(), args.collect())
170         };
171
172         let data = CompilationOptions {
173             directory: self.tcx.sess.opts.working_dir.remapped_path_if_available().into(),
174             program,
175             arguments,
176             output: self.save_ctxt.compilation_output(crate_name),
177         };
178
179         self.dumper.compilation_opts(data);
180     }
181
182     fn write_segments(&mut self, segments: impl IntoIterator<Item = &'tcx hir::PathSegment<'tcx>>) {
183         for seg in segments {
184             if let Some(data) = self.save_ctxt.get_path_segment_data(seg) {
185                 self.dumper.dump_ref(data);
186             }
187         }
188     }
189
190     fn write_sub_paths(&mut self, path: &'tcx hir::Path<'tcx>) {
191         self.write_segments(path.segments)
192     }
193
194     // As write_sub_paths, but does not process the last ident in the path (assuming it
195     // will be processed elsewhere). See note on write_sub_paths about global.
196     fn write_sub_paths_truncated(&mut self, path: &'tcx hir::Path<'tcx>) {
197         if let [segments @ .., _] = path.segments {
198             self.write_segments(segments)
199         }
200     }
201
202     fn process_formals(&mut self, formals: &'tcx [hir::Param<'tcx>], qualname: &str) {
203         for arg in formals {
204             self.visit_pat(&arg.pat);
205             let mut collector = PathCollector::new(self.tcx);
206             collector.visit_pat(&arg.pat);
207
208             for (hir_id, ident, ..) in collector.collected_idents {
209                 let typ = match self.save_ctxt.typeck_results().node_type_opt(hir_id) {
210                     Some(s) => s.to_string(),
211                     None => continue,
212                 };
213                 if !self.span.filter_generated(ident.span) {
214                     let id = id_from_hir_id(hir_id, &self.save_ctxt);
215                     let span = self.span_from_span(ident.span);
216
217                     self.dumper.dump_def(
218                         &Access { public: false, reachable: false },
219                         Def {
220                             kind: DefKind::Local,
221                             id,
222                             span,
223                             name: ident.to_string(),
224                             qualname: format!("{}::{}", qualname, ident),
225                             value: typ,
226                             parent: None,
227                             children: vec![],
228                             decl_id: None,
229                             docs: String::new(),
230                             sig: None,
231                             attributes: vec![],
232                         },
233                     );
234                 }
235             }
236         }
237     }
238
239     fn process_method(
240         &mut self,
241         sig: &'tcx hir::FnSig<'tcx>,
242         body: Option<hir::BodyId>,
243         def_id: LocalDefId,
244         ident: Ident,
245         generics: &'tcx hir::Generics<'tcx>,
246         span: Span,
247     ) {
248         debug!("process_method: {:?}:{}", def_id, ident);
249
250         let map = self.tcx.hir();
251         let hir_id = map.local_def_id_to_hir_id(def_id);
252         self.nest_typeck_results(def_id, |v| {
253             if let Some(mut method_data) = v.save_ctxt.get_method_data(hir_id, ident, span) {
254                 if let Some(body) = body {
255                     v.process_formals(map.body(body).params, &method_data.qualname);
256                 }
257                 v.process_generic_params(&generics, &method_data.qualname, hir_id);
258
259                 method_data.value =
260                     fn_to_string(sig.decl, sig.header, Some(ident.name), generics, &[], None);
261                 method_data.sig = sig::method_signature(hir_id, ident, generics, sig, &v.save_ctxt);
262
263                 v.dumper.dump_def(&access_from!(v.save_ctxt, def_id), method_data);
264             }
265
266             // walk arg and return types
267             for arg in sig.decl.inputs {
268                 v.visit_ty(arg);
269             }
270
271             if let hir::FnRetTy::Return(ref ret_ty) = sig.decl.output {
272                 v.visit_ty(ret_ty)
273             }
274
275             // walk the fn body
276             if let Some(body) = body {
277                 v.visit_expr(&map.body(body).value);
278             }
279         });
280     }
281
282     fn process_struct_field_def(
283         &mut self,
284         field: &'tcx hir::FieldDef<'tcx>,
285         parent_id: hir::HirId,
286     ) {
287         let field_data = self.save_ctxt.get_field_data(field, parent_id);
288         if let Some(field_data) = field_data {
289             self.dumper.dump_def(
290                 &access_from!(self.save_ctxt, self.tcx.hir().local_def_id(field.hir_id)),
291                 field_data,
292             );
293         }
294     }
295
296     // Dump generic params bindings, then visit_generics
297     fn process_generic_params(
298         &mut self,
299         generics: &'tcx hir::Generics<'tcx>,
300         prefix: &str,
301         id: hir::HirId,
302     ) {
303         for param in generics.params {
304             match param.kind {
305                 hir::GenericParamKind::Lifetime { .. } => {}
306                 hir::GenericParamKind::Type { .. } => {
307                     let param_ss = param.name.ident().span;
308                     let name = escape(self.span.snippet(param_ss));
309                     // Append $id to name to make sure each one is unique.
310                     let qualname = format!("{}::{}${}", prefix, name, id);
311                     if !self.span.filter_generated(param_ss) {
312                         let id = id_from_hir_id(param.hir_id, &self.save_ctxt);
313                         let span = self.span_from_span(param_ss);
314
315                         self.dumper.dump_def(
316                             &Access { public: false, reachable: false },
317                             Def {
318                                 kind: DefKind::Type,
319                                 id,
320                                 span,
321                                 name,
322                                 qualname,
323                                 value: String::new(),
324                                 parent: None,
325                                 children: vec![],
326                                 decl_id: None,
327                                 docs: String::new(),
328                                 sig: None,
329                                 attributes: vec![],
330                             },
331                         );
332                     }
333                 }
334                 hir::GenericParamKind::Const { .. } => {}
335             }
336         }
337
338         self.visit_generics(generics)
339     }
340
341     fn process_fn(
342         &mut self,
343         item: &'tcx hir::Item<'tcx>,
344         decl: &'tcx hir::FnDecl<'tcx>,
345         _header: &'tcx hir::FnHeader,
346         ty_params: &'tcx hir::Generics<'tcx>,
347         body: hir::BodyId,
348     ) {
349         let map = self.tcx.hir();
350         self.nest_typeck_results(item.def_id, |v| {
351             let body = map.body(body);
352             if let Some(fn_data) = v.save_ctxt.get_item_data(item) {
353                 down_cast_data!(fn_data, DefData, item.span);
354                 v.process_formals(body.params, &fn_data.qualname);
355                 v.process_generic_params(ty_params, &fn_data.qualname, item.hir_id());
356
357                 v.dumper.dump_def(&access_from!(v.save_ctxt, item.def_id), fn_data);
358             }
359
360             for arg in decl.inputs {
361                 v.visit_ty(arg)
362             }
363
364             if let hir::FnRetTy::Return(ref ret_ty) = decl.output {
365                 v.visit_ty(ret_ty)
366             }
367
368             v.visit_expr(&body.value);
369         });
370     }
371
372     fn process_static_or_const_item(
373         &mut self,
374         item: &'tcx hir::Item<'tcx>,
375         typ: &'tcx hir::Ty<'tcx>,
376         expr: &'tcx hir::Expr<'tcx>,
377     ) {
378         self.nest_typeck_results(item.def_id, |v| {
379             if let Some(var_data) = v.save_ctxt.get_item_data(item) {
380                 down_cast_data!(var_data, DefData, item.span);
381                 v.dumper.dump_def(&access_from!(v.save_ctxt, item.def_id), var_data);
382             }
383             v.visit_ty(&typ);
384             v.visit_expr(expr);
385         });
386     }
387
388     fn process_assoc_const(
389         &mut self,
390         def_id: LocalDefId,
391         ident: Ident,
392         typ: &'tcx hir::Ty<'tcx>,
393         expr: Option<&'tcx hir::Expr<'tcx>>,
394         parent_id: DefId,
395         attrs: &'tcx [ast::Attribute],
396     ) {
397         let qualname = format!("::{}", self.tcx.def_path_str(def_id.to_def_id()));
398
399         if !self.span.filter_generated(ident.span) {
400             let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id);
401             let sig = sig::assoc_const_signature(hir_id, ident.name, typ, expr, &self.save_ctxt);
402             let span = self.span_from_span(ident.span);
403
404             self.dumper.dump_def(
405                 &access_from!(self.save_ctxt, def_id),
406                 Def {
407                     kind: DefKind::Const,
408                     id: id_from_hir_id(hir_id, &self.save_ctxt),
409                     span,
410                     name: ident.name.to_string(),
411                     qualname,
412                     value: ty_to_string(&typ),
413                     parent: Some(id_from_def_id(parent_id)),
414                     children: vec![],
415                     decl_id: None,
416                     docs: self.save_ctxt.docs_for_attrs(attrs),
417                     sig,
418                     attributes: lower_attributes(attrs.to_owned(), &self.save_ctxt),
419                 },
420             );
421         }
422
423         // walk type and init value
424         self.nest_typeck_results(def_id, |v| {
425             v.visit_ty(typ);
426             if let Some(expr) = expr {
427                 v.visit_expr(expr);
428             }
429         });
430     }
431
432     // FIXME tuple structs should generate tuple-specific data.
433     fn process_struct(
434         &mut self,
435         item: &'tcx hir::Item<'tcx>,
436         def: &'tcx hir::VariantData<'tcx>,
437         ty_params: &'tcx hir::Generics<'tcx>,
438     ) {
439         debug!("process_struct {:?} {:?}", item, item.span);
440         let name = item.ident.to_string();
441         let qualname = format!("::{}", self.tcx.def_path_str(item.def_id.to_def_id()));
442
443         let kind = match item.kind {
444             hir::ItemKind::Struct(_, _) => DefKind::Struct,
445             hir::ItemKind::Union(_, _) => DefKind::Union,
446             _ => unreachable!(),
447         };
448
449         let (value, fields) = match item.kind {
450             hir::ItemKind::Struct(hir::VariantData::Struct(ref fields, ..), ..)
451             | hir::ItemKind::Union(hir::VariantData::Struct(ref fields, ..), ..) => {
452                 let include_priv_fields = !self.save_ctxt.config.pub_only;
453                 let fields_str = fields
454                     .iter()
455                     .filter_map(|f| {
456                         if include_priv_fields {
457                             return Some(f.ident.to_string());
458                         }
459                         let def_id = self.save_ctxt.tcx.hir().local_def_id(f.hir_id);
460                         if self.save_ctxt.tcx.visibility(def_id).is_public() {
461                             Some(f.ident.to_string())
462                         } else {
463                             None
464                         }
465                     })
466                     .collect::<Vec<_>>()
467                     .join(", ");
468                 let value = format!("{} {{ {} }}", name, fields_str);
469                 (value, fields.iter().map(|f| id_from_hir_id(f.hir_id, &self.save_ctxt)).collect())
470             }
471             _ => (String::new(), vec![]),
472         };
473
474         if !self.span.filter_generated(item.ident.span) {
475             let span = self.span_from_span(item.ident.span);
476             let attrs = self.tcx.hir().attrs(item.hir_id());
477             self.dumper.dump_def(
478                 &access_from!(self.save_ctxt, item.def_id),
479                 Def {
480                     kind,
481                     id: id_from_def_id(item.def_id.to_def_id()),
482                     span,
483                     name,
484                     qualname: qualname.clone(),
485                     value,
486                     parent: None,
487                     children: fields,
488                     decl_id: None,
489                     docs: self.save_ctxt.docs_for_attrs(attrs),
490                     sig: sig::item_signature(item, &self.save_ctxt),
491                     attributes: lower_attributes(attrs.to_vec(), &self.save_ctxt),
492                 },
493             );
494         }
495
496         self.nest_typeck_results(item.def_id, |v| {
497             for field in def.fields() {
498                 v.process_struct_field_def(field, item.hir_id());
499                 v.visit_ty(&field.ty);
500             }
501
502             v.process_generic_params(ty_params, &qualname, item.hir_id());
503         });
504     }
505
506     fn process_enum(
507         &mut self,
508         item: &'tcx hir::Item<'tcx>,
509         enum_definition: &'tcx hir::EnumDef<'tcx>,
510         ty_params: &'tcx hir::Generics<'tcx>,
511     ) {
512         let enum_data = self.save_ctxt.get_item_data(item);
513         let Some(enum_data) = enum_data else {
514             return;
515         };
516         down_cast_data!(enum_data, DefData, item.span);
517
518         let access = access_from!(self.save_ctxt, item.def_id);
519
520         for variant in enum_definition.variants {
521             let name = variant.ident.name.to_string();
522             let qualname = format!("{}::{}", enum_data.qualname, name);
523             let name_span = variant.ident.span;
524
525             match variant.data {
526                 hir::VariantData::Struct(ref fields, ..) => {
527                     let fields_str =
528                         fields.iter().map(|f| f.ident.to_string()).collect::<Vec<_>>().join(", ");
529                     let value = format!("{}::{} {{ {} }}", enum_data.name, name, fields_str);
530                     if !self.span.filter_generated(name_span) {
531                         let span = self.span_from_span(name_span);
532                         let id = id_from_hir_id(variant.id, &self.save_ctxt);
533                         let parent = Some(id_from_def_id(item.def_id.to_def_id()));
534                         let attrs = self.tcx.hir().attrs(variant.id);
535
536                         self.dumper.dump_def(
537                             &access,
538                             Def {
539                                 kind: DefKind::StructVariant,
540                                 id,
541                                 span,
542                                 name,
543                                 qualname,
544                                 value,
545                                 parent,
546                                 children: vec![],
547                                 decl_id: None,
548                                 docs: self.save_ctxt.docs_for_attrs(attrs),
549                                 sig: sig::variant_signature(variant, &self.save_ctxt),
550                                 attributes: lower_attributes(attrs.to_vec(), &self.save_ctxt),
551                             },
552                         );
553                     }
554                 }
555                 ref v => {
556                     let mut value = format!("{}::{}", enum_data.name, name);
557                     if let hir::VariantData::Tuple(fields, _) = v {
558                         value.push('(');
559                         value.push_str(
560                             &fields
561                                 .iter()
562                                 .map(|f| ty_to_string(&f.ty))
563                                 .collect::<Vec<_>>()
564                                 .join(", "),
565                         );
566                         value.push(')');
567                     }
568                     if !self.span.filter_generated(name_span) {
569                         let span = self.span_from_span(name_span);
570                         let id = id_from_hir_id(variant.id, &self.save_ctxt);
571                         let parent = Some(id_from_def_id(item.def_id.to_def_id()));
572                         let attrs = self.tcx.hir().attrs(variant.id);
573
574                         self.dumper.dump_def(
575                             &access,
576                             Def {
577                                 kind: DefKind::TupleVariant,
578                                 id,
579                                 span,
580                                 name,
581                                 qualname,
582                                 value,
583                                 parent,
584                                 children: vec![],
585                                 decl_id: None,
586                                 docs: self.save_ctxt.docs_for_attrs(attrs),
587                                 sig: sig::variant_signature(variant, &self.save_ctxt),
588                                 attributes: lower_attributes(attrs.to_vec(), &self.save_ctxt),
589                             },
590                         );
591                     }
592                 }
593             }
594
595             for field in variant.data.fields() {
596                 self.process_struct_field_def(field, variant.id);
597                 self.visit_ty(field.ty);
598             }
599         }
600         self.process_generic_params(ty_params, &enum_data.qualname, item.hir_id());
601         self.dumper.dump_def(&access, enum_data);
602     }
603
604     fn process_impl(&mut self, item: &'tcx hir::Item<'tcx>, impl_: &'tcx hir::Impl<'tcx>) {
605         if let Some(impl_data) = self.save_ctxt.get_item_data(item) {
606             if !self.span.filter_generated(item.span) {
607                 if let super::Data::RelationData(rel, imp) = impl_data {
608                     self.dumper.dump_relation(rel);
609                     self.dumper.dump_impl(imp);
610                 } else {
611                     span_bug!(item.span, "unexpected data kind: {:?}", impl_data);
612                 }
613             }
614         }
615
616         let map = self.tcx.hir();
617         self.nest_typeck_results(item.def_id, |v| {
618             v.visit_ty(&impl_.self_ty);
619             if let Some(trait_ref) = &impl_.of_trait {
620                 v.process_path(trait_ref.hir_ref_id, &hir::QPath::Resolved(None, &trait_ref.path));
621             }
622             v.process_generic_params(&impl_.generics, "", item.hir_id());
623             for impl_item in impl_.items {
624                 v.process_impl_item(map.impl_item(impl_item.id), item.def_id.to_def_id());
625             }
626         });
627     }
628
629     fn process_trait(
630         &mut self,
631         item: &'tcx hir::Item<'tcx>,
632         generics: &'tcx hir::Generics<'tcx>,
633         trait_refs: hir::GenericBounds<'tcx>,
634         methods: &'tcx [hir::TraitItemRef],
635     ) {
636         let name = item.ident.to_string();
637         let qualname = format!("::{}", self.tcx.def_path_str(item.def_id.to_def_id()));
638         let mut val = name.clone();
639         if !generics.params.is_empty() {
640             val.push_str(&generic_params_to_string(generics.params));
641         }
642         if !trait_refs.is_empty() {
643             val.push_str(": ");
644             val.push_str(&bounds_to_string(trait_refs));
645         }
646         if !self.span.filter_generated(item.ident.span) {
647             let id = id_from_def_id(item.def_id.to_def_id());
648             let span = self.span_from_span(item.ident.span);
649             let children =
650                 methods.iter().map(|i| id_from_def_id(i.id.def_id.to_def_id())).collect();
651             let attrs = self.tcx.hir().attrs(item.hir_id());
652             self.dumper.dump_def(
653                 &access_from!(self.save_ctxt, item.def_id),
654                 Def {
655                     kind: DefKind::Trait,
656                     id,
657                     span,
658                     name,
659                     qualname: qualname.clone(),
660                     value: val,
661                     parent: None,
662                     children,
663                     decl_id: None,
664                     docs: self.save_ctxt.docs_for_attrs(attrs),
665                     sig: sig::item_signature(item, &self.save_ctxt),
666                     attributes: lower_attributes(attrs.to_vec(), &self.save_ctxt),
667                 },
668             );
669         }
670
671         // supertraits
672         for super_bound in trait_refs.iter() {
673             let (def_id, sub_span) = match *super_bound {
674                 hir::GenericBound::Trait(ref trait_ref, _) => (
675                     self.lookup_def_id(trait_ref.trait_ref.hir_ref_id),
676                     trait_ref.trait_ref.path.segments.last().unwrap().ident.span,
677                 ),
678                 hir::GenericBound::LangItemTrait(lang_item, span, _, _) => {
679                     (Some(self.tcx.require_lang_item(lang_item, Some(span))), span)
680                 }
681                 hir::GenericBound::Outlives(..) => continue,
682             };
683
684             if let Some(id) = def_id {
685                 if !self.span.filter_generated(sub_span) {
686                     let span = self.span_from_span(sub_span);
687                     self.dumper.dump_ref(Ref {
688                         kind: RefKind::Type,
689                         span: span.clone(),
690                         ref_id: id_from_def_id(id),
691                     });
692
693                     self.dumper.dump_relation(Relation {
694                         kind: RelationKind::SuperTrait,
695                         span,
696                         from: id_from_def_id(id),
697                         to: id_from_def_id(item.def_id.to_def_id()),
698                     });
699                 }
700             }
701         }
702
703         // walk generics and methods
704         self.process_generic_params(generics, &qualname, item.hir_id());
705         for method in methods {
706             let map = self.tcx.hir();
707             self.process_trait_item(map.trait_item(method.id), item.def_id.to_def_id())
708         }
709     }
710
711     // `item` is the module in question, represented as an( item.
712     fn process_mod(&mut self, item: &'tcx hir::Item<'tcx>) {
713         if let Some(mod_data) = self.save_ctxt.get_item_data(item) {
714             down_cast_data!(mod_data, DefData, item.span);
715             self.dumper.dump_def(&access_from!(self.save_ctxt, item.def_id), mod_data);
716         }
717     }
718
719     fn dump_path_ref(&mut self, id: hir::HirId, path: &hir::QPath<'tcx>) {
720         let path_data = self.save_ctxt.get_path_data(id, path);
721         if let Some(path_data) = path_data {
722             self.dumper.dump_ref(path_data);
723         }
724     }
725
726     fn dump_path_segment_ref(&mut self, id: hir::HirId, segment: &hir::PathSegment<'tcx>) {
727         let segment_data = self.save_ctxt.get_path_segment_data_with_id(segment, id);
728         if let Some(segment_data) = segment_data {
729             self.dumper.dump_ref(segment_data);
730         }
731     }
732
733     fn process_path(&mut self, id: hir::HirId, path: &hir::QPath<'tcx>) {
734         if self.span.filter_generated(path.span()) {
735             return;
736         }
737         self.dump_path_ref(id, path);
738
739         // Type arguments
740         let segments = match path {
741             hir::QPath::Resolved(ty, path) => {
742                 if let Some(ty) = ty {
743                     self.visit_ty(ty);
744                 }
745                 path.segments
746             }
747             hir::QPath::TypeRelative(ty, segment) => {
748                 self.visit_ty(ty);
749                 std::slice::from_ref(*segment)
750             }
751             hir::QPath::LangItem(..) => return,
752         };
753         for seg in segments {
754             if let Some(ref generic_args) = seg.args {
755                 for arg in generic_args.args {
756                     if let hir::GenericArg::Type(ref ty) = arg {
757                         self.visit_ty(ty);
758                     }
759                 }
760             }
761         }
762
763         if let hir::QPath::Resolved(_, path) = path {
764             self.write_sub_paths_truncated(path);
765         }
766     }
767
768     fn process_struct_lit(
769         &mut self,
770         ex: &'tcx hir::Expr<'tcx>,
771         path: &'tcx hir::QPath<'tcx>,
772         fields: &'tcx [hir::ExprField<'tcx>],
773         variant: &'tcx ty::VariantDef,
774         rest: Option<&'tcx hir::Expr<'tcx>>,
775     ) {
776         if let Some(_ex_res_data) = self.save_ctxt.get_expr_data(ex) {
777             if let hir::QPath::Resolved(_, path) = path {
778                 self.write_sub_paths_truncated(path);
779             }
780             // For MyEnum::MyVariant, get_expr_data gives us MyEnum, not MyVariant.
781             // For recording the span's ref id, we want MyVariant.
782             if !generated_code(ex.span) {
783                 let sub_span = path.last_segment_span();
784                 let span = self.save_ctxt.span_from_span(sub_span);
785                 let reff =
786                     Ref { kind: RefKind::Type, span, ref_id: id_from_def_id(variant.def_id) };
787                 self.dumper.dump_ref(reff);
788             }
789
790             for field in fields {
791                 if let Some(field_data) = self.save_ctxt.get_field_ref_data(field, variant) {
792                     self.dumper.dump_ref(field_data);
793                 }
794
795                 self.visit_expr(&field.expr)
796             }
797         }
798
799         if let Some(base) = rest {
800             self.visit_expr(&base);
801         }
802     }
803
804     fn process_method_call(
805         &mut self,
806         ex: &'tcx hir::Expr<'tcx>,
807         seg: &'tcx hir::PathSegment<'tcx>,
808         args: &'tcx [hir::Expr<'tcx>],
809     ) {
810         debug!("process_method_call {:?} {:?}", ex, ex.span);
811         if let Some(mcd) = self.save_ctxt.get_expr_data(ex) {
812             down_cast_data!(mcd, RefData, ex.span);
813             if !generated_code(ex.span) {
814                 self.dumper.dump_ref(mcd);
815             }
816         }
817
818         // Explicit types in the turbo-fish.
819         if let Some(generic_args) = seg.args {
820             for arg in generic_args.args {
821                 if let hir::GenericArg::Type(ty) = arg {
822                     self.visit_ty(&ty)
823                 };
824             }
825         }
826
827         // walk receiver and args
828         walk_list!(self, visit_expr, args);
829     }
830
831     fn process_pat(&mut self, p: &'tcx hir::Pat<'tcx>) {
832         match p.kind {
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(),
837                     _ => {
838                         intravisit::walk_pat(self, p);
839                         return;
840                     }
841                 };
842                 let variant = adt.variant_of_res(self.save_ctxt.get_path_res(p.hir_id));
843
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,
850                                 span,
851                                 ref_id: id_from_def_id(variant.fields[index].did),
852                             });
853                         }
854                     }
855                     self.visit_pat(&field.pat);
856                 }
857             }
858             _ => intravisit::walk_pat(self, p),
859         }
860     }
861
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);
868
869         // Process collected paths.
870         for (id, ident, _) in collector.collected_idents {
871             let res = self.save_ctxt.get_path_res(id);
872             match res {
873                 Res::Local(hir_id) => {
874                     let typ = self
875                         .save_ctxt
876                         .typeck_results()
877                         .node_type_opt(hir_id)
878                         .map(|t| t.to_string())
879                         .unwrap_or_default();
880
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);
886
887                         self.dumper.dump_def(
888                             &Access { public: false, reachable: false },
889                             Def {
890                                 kind: DefKind::Local,
891                                 id,
892                                 span,
893                                 name: ident.to_string(),
894                                 qualname,
895                                 value: typ,
896                                 parent: None,
897                                 children: vec![],
898                                 decl_id: None,
899                                 docs: String::new(),
900                                 sig: None,
901                                 attributes: vec![],
902                             },
903                         );
904                     }
905                 }
906                 Res::Def(
907                     HirDefKind::Ctor(..)
908                     | HirDefKind::Const
909                     | HirDefKind::AssocConst
910                     | HirDefKind::Struct
911                     | HirDefKind::Variant
912                     | HirDefKind::TyAlias
913                     | HirDefKind::AssocTy,
914                     _,
915                 )
916                 | Res::SelfTy { .. } => {
917                     self.dump_path_segment_ref(id, &hir::PathSegment::from_ident(ident));
918                 }
919                 def => {
920                     error!("unexpected definition kind when processing collected idents: {:?}", def)
921                 }
922             }
923         }
924
925         for (id, ref path) in collector.collected_paths {
926             self.process_path(id, path);
927         }
928     }
929
930     /// Extracts macro use and definition information from the AST node defined
931     /// by the given NodeId, using the expansion information from the node's
932     /// span.
933     ///
934     /// If the span is not macro-generated, do nothing, else use callee and
935     /// callsite spans to record macro definition and use data, using the
936     /// mac_uses and mac_defs sets to prevent multiples.
937     fn process_macro_use(&mut self, _span: Span) {
938         // FIXME if we're not dumping the defs (see below), there is no point
939         // dumping refs either.
940         // let source_span = span.source_callsite();
941         // if !self.macro_calls.insert(source_span) {
942         //     return;
943         // }
944
945         // let data = match self.save_ctxt.get_macro_use_data(span) {
946         //     None => return,
947         //     Some(data) => data,
948         // };
949
950         // self.dumper.macro_use(data);
951
952         // FIXME write the macro def
953         // let mut hasher = DefaultHasher::new();
954         // data.callee_span.hash(&mut hasher);
955         // let hash = hasher.finish();
956         // let qualname = format!("{}::{}", data.name, hash);
957         // Don't write macro definition for imported macros
958         // if !self.mac_defs.contains(&data.callee_span)
959         //     && !data.imported {
960         //     self.mac_defs.insert(data.callee_span);
961         //     if let Some(sub_span) = self.span.span_for_macro_def_name(data.callee_span) {
962         //         self.dumper.macro_data(MacroData {
963         //             span: sub_span,
964         //             name: data.name.clone(),
965         //             qualname: qualname.clone(),
966         //             // FIXME where do macro docs come from?
967         //             docs: String::new(),
968         //         }.lower(self.tcx));
969         //     }
970         // }
971     }
972
973     fn process_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>, trait_id: DefId) {
974         self.process_macro_use(trait_item.span);
975         match trait_item.kind {
976             hir::TraitItemKind::Const(ref ty, body) => {
977                 let body = body.map(|b| &self.tcx.hir().body(b).value);
978                 let attrs = self.tcx.hir().attrs(trait_item.hir_id());
979                 self.process_assoc_const(
980                     trait_item.def_id,
981                     trait_item.ident,
982                     &ty,
983                     body,
984                     trait_id,
985                     attrs,
986                 );
987             }
988             hir::TraitItemKind::Fn(ref sig, ref trait_fn) => {
989                 let body =
990                     if let hir::TraitFn::Provided(body) = trait_fn { Some(*body) } else { None };
991                 self.process_method(
992                     sig,
993                     body,
994                     trait_item.def_id,
995                     trait_item.ident,
996                     &trait_item.generics,
997                     trait_item.span,
998                 );
999             }
1000             hir::TraitItemKind::Type(ref bounds, ref default_ty) => {
1001                 // FIXME do something with _bounds (for type refs)
1002                 let name = trait_item.ident.name.to_string();
1003                 let qualname =
1004                     format!("::{}", self.tcx.def_path_str(trait_item.def_id.to_def_id()));
1005
1006                 if !self.span.filter_generated(trait_item.ident.span) {
1007                     let span = self.span_from_span(trait_item.ident.span);
1008                     let id = id_from_def_id(trait_item.def_id.to_def_id());
1009                     let attrs = self.tcx.hir().attrs(trait_item.hir_id());
1010
1011                     self.dumper.dump_def(
1012                         &Access { public: true, reachable: true },
1013                         Def {
1014                             kind: DefKind::Type,
1015                             id,
1016                             span,
1017                             name,
1018                             qualname,
1019                             value: self.span.snippet(trait_item.span),
1020                             parent: Some(id_from_def_id(trait_id)),
1021                             children: vec![],
1022                             decl_id: None,
1023                             docs: self.save_ctxt.docs_for_attrs(attrs),
1024                             sig: sig::assoc_type_signature(
1025                                 trait_item.hir_id(),
1026                                 trait_item.ident,
1027                                 Some(bounds),
1028                                 default_ty.as_ref().map(|ty| &**ty),
1029                                 &self.save_ctxt,
1030                             ),
1031                             attributes: lower_attributes(attrs.to_vec(), &self.save_ctxt),
1032                         },
1033                     );
1034                 }
1035
1036                 if let Some(default_ty) = default_ty {
1037                     self.visit_ty(default_ty)
1038                 }
1039             }
1040         }
1041     }
1042
1043     fn process_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>, impl_id: DefId) {
1044         self.process_macro_use(impl_item.span);
1045         match impl_item.kind {
1046             hir::ImplItemKind::Const(ref ty, body) => {
1047                 let body = self.tcx.hir().body(body);
1048                 let attrs = self.tcx.hir().attrs(impl_item.hir_id());
1049                 self.process_assoc_const(
1050                     impl_item.def_id,
1051                     impl_item.ident,
1052                     &ty,
1053                     Some(&body.value),
1054                     impl_id,
1055                     attrs,
1056                 );
1057             }
1058             hir::ImplItemKind::Fn(ref sig, body) => {
1059                 self.process_method(
1060                     sig,
1061                     Some(body),
1062                     impl_item.def_id,
1063                     impl_item.ident,
1064                     &impl_item.generics,
1065                     impl_item.span,
1066                 );
1067             }
1068             hir::ImplItemKind::TyAlias(ref ty) => {
1069                 // FIXME: uses of the assoc type should ideally point to this
1070                 // 'def' and the name here should be a ref to the def in the
1071                 // trait.
1072                 self.visit_ty(ty)
1073             }
1074         }
1075     }
1076
1077     pub(crate) fn process_crate(&mut self) {
1078         let id = hir::CRATE_HIR_ID;
1079         let qualname =
1080             format!("::{}", self.tcx.def_path_str(self.tcx.hir().local_def_id(id).to_def_id()));
1081
1082         let sm = self.tcx.sess.source_map();
1083         let krate_mod = self.tcx.hir().root_module();
1084         let filename = sm.span_to_filename(krate_mod.spans.inner_span);
1085         let data_id = id_from_hir_id(id, &self.save_ctxt);
1086         let children =
1087             krate_mod.item_ids.iter().map(|i| id_from_def_id(i.def_id.to_def_id())).collect();
1088         let span = self.span_from_span(krate_mod.spans.inner_span);
1089         let attrs = self.tcx.hir().attrs(id);
1090
1091         self.dumper.dump_def(
1092             &Access { public: true, reachable: true },
1093             Def {
1094                 kind: DefKind::Mod,
1095                 id: data_id,
1096                 name: String::new(),
1097                 qualname,
1098                 span,
1099                 value: filename.prefer_remapped().to_string(),
1100                 children,
1101                 parent: None,
1102                 decl_id: None,
1103                 docs: self.save_ctxt.docs_for_attrs(attrs),
1104                 sig: None,
1105                 attributes: lower_attributes(attrs.to_owned(), &self.save_ctxt),
1106             },
1107         );
1108         self.tcx.hir().walk_toplevel_module(self);
1109     }
1110
1111     fn process_bounds(&mut self, bounds: hir::GenericBounds<'tcx>) {
1112         for bound in bounds {
1113             if let hir::GenericBound::Trait(ref trait_ref, _) = *bound {
1114                 self.process_path(
1115                     trait_ref.trait_ref.hir_ref_id,
1116                     &hir::QPath::Resolved(None, &trait_ref.trait_ref.path),
1117                 )
1118             }
1119         }
1120     }
1121 }
1122
1123 impl<'tcx> Visitor<'tcx> for DumpVisitor<'tcx> {
1124     type NestedFilter = nested_filter::All;
1125
1126     fn nested_visit_map(&mut self) -> Self::Map {
1127         self.tcx.hir()
1128     }
1129
1130     fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
1131         self.process_macro_use(item.span);
1132         match item.kind {
1133             hir::ItemKind::Use(path, hir::UseKind::Single) => {
1134                 let sub_span = path.segments.last().unwrap().ident.span;
1135                 if !self.span.filter_generated(sub_span) {
1136                     let access = access_from!(self.save_ctxt, item.def_id);
1137                     let ref_id = self.lookup_def_id(item.hir_id()).map(id_from_def_id);
1138                     let span = self.span_from_span(sub_span);
1139                     let parent = self.save_ctxt.tcx.local_parent(item.def_id);
1140                     self.dumper.import(
1141                         &access,
1142                         Import {
1143                             kind: ImportKind::Use,
1144                             ref_id,
1145                             span,
1146                             alias_span: None,
1147                             name: item.ident.to_string(),
1148                             value: String::new(),
1149                             parent: Some(id_from_def_id(parent.to_def_id())),
1150                         },
1151                     );
1152                     self.write_sub_paths_truncated(&path);
1153                 }
1154             }
1155             hir::ItemKind::Use(path, hir::UseKind::Glob) => {
1156                 // Make a comma-separated list of names of imported modules.
1157                 let names = self.tcx.names_imported_by_glob_use(item.def_id);
1158                 let names: Vec<_> = names.iter().map(|n| n.to_string()).collect();
1159
1160                 // Otherwise it's a span with wrong macro expansion info, which
1161                 // we don't want to track anyway, since it's probably macro-internal `use`
1162                 if let Some(sub_span) = self.span.sub_span_of_star(item.span) {
1163                     if !self.span.filter_generated(item.span) {
1164                         let access = access_from!(self.save_ctxt, item.def_id);
1165                         let span = self.span_from_span(sub_span);
1166                         let parent = self.save_ctxt.tcx.local_parent(item.def_id);
1167                         self.dumper.import(
1168                             &access,
1169                             Import {
1170                                 kind: ImportKind::GlobUse,
1171                                 ref_id: None,
1172                                 span,
1173                                 alias_span: None,
1174                                 name: "*".to_owned(),
1175                                 value: names.join(", "),
1176                                 parent: Some(id_from_def_id(parent.to_def_id())),
1177                             },
1178                         );
1179                         self.write_sub_paths(&path);
1180                     }
1181                 }
1182             }
1183             hir::ItemKind::ExternCrate(_) => {
1184                 let name_span = item.ident.span;
1185                 if !self.span.filter_generated(name_span) {
1186                     let span = self.span_from_span(name_span);
1187                     let parent = self.save_ctxt.tcx.local_parent(item.def_id);
1188                     self.dumper.import(
1189                         &Access { public: false, reachable: false },
1190                         Import {
1191                             kind: ImportKind::ExternCrate,
1192                             ref_id: None,
1193                             span,
1194                             alias_span: None,
1195                             name: item.ident.to_string(),
1196                             value: String::new(),
1197                             parent: Some(id_from_def_id(parent.to_def_id())),
1198                         },
1199                     );
1200                 }
1201             }
1202             hir::ItemKind::Fn(ref sig, ref ty_params, body) => {
1203                 self.process_fn(item, sig.decl, &sig.header, ty_params, body)
1204             }
1205             hir::ItemKind::Static(ref typ, _, body) => {
1206                 let body = self.tcx.hir().body(body);
1207                 self.process_static_or_const_item(item, typ, &body.value)
1208             }
1209             hir::ItemKind::Const(ref typ, body) => {
1210                 let body = self.tcx.hir().body(body);
1211                 self.process_static_or_const_item(item, typ, &body.value)
1212             }
1213             hir::ItemKind::Struct(ref def, ref ty_params)
1214             | hir::ItemKind::Union(ref def, ref ty_params) => {
1215                 self.process_struct(item, def, ty_params)
1216             }
1217             hir::ItemKind::Enum(ref def, ref ty_params) => self.process_enum(item, def, ty_params),
1218             hir::ItemKind::Impl(ref impl_) => self.process_impl(item, impl_),
1219             hir::ItemKind::Trait(_, _, ref generics, ref trait_refs, methods) => {
1220                 self.process_trait(item, generics, trait_refs, methods)
1221             }
1222             hir::ItemKind::Mod(ref m) => {
1223                 self.process_mod(item);
1224                 intravisit::walk_mod(self, m, item.hir_id());
1225             }
1226             hir::ItemKind::TyAlias(ty, ref generics) => {
1227                 let qualname = format!("::{}", self.tcx.def_path_str(item.def_id.to_def_id()));
1228                 let value = ty_to_string(&ty);
1229                 if !self.span.filter_generated(item.ident.span) {
1230                     let span = self.span_from_span(item.ident.span);
1231                     let id = id_from_def_id(item.def_id.to_def_id());
1232                     let attrs = self.tcx.hir().attrs(item.hir_id());
1233
1234                     self.dumper.dump_def(
1235                         &access_from!(self.save_ctxt, item.def_id),
1236                         Def {
1237                             kind: DefKind::Type,
1238                             id,
1239                             span,
1240                             name: item.ident.to_string(),
1241                             qualname: qualname.clone(),
1242                             value,
1243                             parent: None,
1244                             children: vec![],
1245                             decl_id: None,
1246                             docs: self.save_ctxt.docs_for_attrs(attrs),
1247                             sig: sig::item_signature(item, &self.save_ctxt),
1248                             attributes: lower_attributes(attrs.to_vec(), &self.save_ctxt),
1249                         },
1250                     );
1251                 }
1252
1253                 self.visit_ty(ty);
1254                 self.process_generic_params(generics, &qualname, item.hir_id());
1255             }
1256             _ => intravisit::walk_item(self, item),
1257         }
1258     }
1259
1260     fn visit_generics(&mut self, generics: &'tcx hir::Generics<'tcx>) {
1261         for param in generics.params {
1262             match param.kind {
1263                 hir::GenericParamKind::Lifetime { .. } => {}
1264                 hir::GenericParamKind::Type { ref default, .. } => {
1265                     if let Some(ref ty) = default {
1266                         self.visit_ty(ty);
1267                     }
1268                 }
1269                 hir::GenericParamKind::Const { ref ty, ref default } => {
1270                     self.visit_ty(ty);
1271                     if let Some(default) = default {
1272                         self.visit_anon_const(default);
1273                     }
1274                 }
1275             }
1276         }
1277         for pred in generics.predicates {
1278             if let hir::WherePredicate::BoundPredicate(ref wbp) = *pred {
1279                 self.process_bounds(wbp.bounds);
1280                 self.visit_ty(wbp.bounded_ty);
1281             }
1282         }
1283     }
1284
1285     fn visit_ty(&mut self, t: &'tcx hir::Ty<'tcx>) {
1286         self.process_macro_use(t.span);
1287         match t.kind {
1288             hir::TyKind::Path(ref path) => {
1289                 if generated_code(t.span) {
1290                     return;
1291                 }
1292
1293                 if let Some(id) = self.lookup_def_id(t.hir_id) {
1294                     let sub_span = path.last_segment_span();
1295                     let span = self.span_from_span(sub_span);
1296                     self.dumper.dump_ref(Ref {
1297                         kind: RefKind::Type,
1298                         span,
1299                         ref_id: id_from_def_id(id),
1300                     });
1301                 }
1302
1303                 if let hir::QPath::Resolved(_, path) = path {
1304                     self.write_sub_paths_truncated(path);
1305                 }
1306                 intravisit::walk_qpath(self, path, t.hir_id, t.span);
1307             }
1308             hir::TyKind::Array(ref ty, ref length) => {
1309                 self.visit_ty(ty);
1310                 let map = self.tcx.hir();
1311                 match length {
1312                     // FIXME(generic_arg_infer): We probably want to
1313                     // output the inferred type here? :shrug:
1314                     hir::ArrayLen::Infer(..) => {}
1315                     hir::ArrayLen::Body(anon_const) => self
1316                         .nest_typeck_results(self.tcx.hir().local_def_id(anon_const.hir_id), |v| {
1317                             v.visit_expr(&map.body(anon_const.body).value)
1318                         }),
1319                 }
1320             }
1321             hir::TyKind::OpaqueDef(item_id, _) => {
1322                 let item = self.tcx.hir().item(item_id);
1323                 self.nest_typeck_results(item_id.def_id, |v| v.visit_item(item));
1324             }
1325             _ => intravisit::walk_ty(self, t),
1326         }
1327     }
1328
1329     fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) {
1330         debug!("visit_expr {:?}", ex.kind);
1331         self.process_macro_use(ex.span);
1332         match ex.kind {
1333             hir::ExprKind::Struct(ref path, ref fields, ref rest) => {
1334                 let hir_expr = self.save_ctxt.tcx.hir().expect_expr(ex.hir_id);
1335                 let adt = match self.save_ctxt.typeck_results().expr_ty_opt(&hir_expr) {
1336                     Some(ty) if ty.ty_adt_def().is_some() => ty.ty_adt_def().unwrap(),
1337                     _ => {
1338                         intravisit::walk_expr(self, ex);
1339                         return;
1340                     }
1341                 };
1342                 let res = self.save_ctxt.get_path_res(hir_expr.hir_id);
1343                 self.process_struct_lit(ex, path, fields, adt.variant_of_res(res), *rest)
1344             }
1345             hir::ExprKind::MethodCall(ref seg, args, _) => self.process_method_call(ex, seg, args),
1346             hir::ExprKind::Field(ref sub_ex, _) => {
1347                 self.visit_expr(&sub_ex);
1348
1349                 if let Some(field_data) = self.save_ctxt.get_expr_data(ex) {
1350                     down_cast_data!(field_data, RefData, ex.span);
1351                     if !generated_code(ex.span) {
1352                         self.dumper.dump_ref(field_data);
1353                     }
1354                 }
1355             }
1356             hir::ExprKind::Closure(&hir::Closure { ref fn_decl, body, .. }) => {
1357                 let id = format!("${}", ex.hir_id);
1358
1359                 // walk arg and return types
1360                 for ty in fn_decl.inputs {
1361                     self.visit_ty(ty);
1362                 }
1363
1364                 if let hir::FnRetTy::Return(ref ret_ty) = fn_decl.output {
1365                     self.visit_ty(ret_ty);
1366                 }
1367
1368                 // walk the body
1369                 let map = self.tcx.hir();
1370                 self.nest_typeck_results(self.tcx.hir().local_def_id(ex.hir_id), |v| {
1371                     let body = map.body(body);
1372                     v.process_formals(body.params, &id);
1373                     v.visit_expr(&body.value)
1374                 });
1375             }
1376             hir::ExprKind::Repeat(ref expr, ref length) => {
1377                 self.visit_expr(expr);
1378                 let map = self.tcx.hir();
1379                 match length {
1380                     // FIXME(generic_arg_infer): We probably want to
1381                     // output the inferred type here? :shrug:
1382                     hir::ArrayLen::Infer(..) => {}
1383                     hir::ArrayLen::Body(anon_const) => self
1384                         .nest_typeck_results(self.tcx.hir().local_def_id(anon_const.hir_id), |v| {
1385                             v.visit_expr(&map.body(anon_const.body).value)
1386                         }),
1387                 }
1388             }
1389             // In particular, we take this branch for call and path expressions,
1390             // where we'll index the idents involved just by continuing to walk.
1391             _ => intravisit::walk_expr(self, ex),
1392         }
1393     }
1394
1395     fn visit_pat(&mut self, p: &'tcx hir::Pat<'tcx>) {
1396         self.process_macro_use(p.span);
1397         self.process_pat(p);
1398     }
1399
1400     fn visit_arm(&mut self, arm: &'tcx hir::Arm<'tcx>) {
1401         self.process_var_decl(&arm.pat);
1402         if let Some(hir::Guard::If(expr)) = &arm.guard {
1403             self.visit_expr(expr);
1404         }
1405         self.visit_expr(&arm.body);
1406     }
1407
1408     fn visit_qpath(&mut self, path: &'tcx hir::QPath<'tcx>, id: hir::HirId, _: Span) {
1409         self.process_path(id, path);
1410     }
1411
1412     fn visit_stmt(&mut self, s: &'tcx hir::Stmt<'tcx>) {
1413         self.process_macro_use(s.span);
1414         intravisit::walk_stmt(self, s)
1415     }
1416
1417     fn visit_local(&mut self, l: &'tcx hir::Local<'tcx>) {
1418         self.process_macro_use(l.span);
1419         self.process_var_decl(&l.pat);
1420
1421         // Just walk the initializer, the else branch and type (don't want to walk the pattern again).
1422         walk_list!(self, visit_ty, &l.ty);
1423         walk_list!(self, visit_expr, &l.init);
1424         walk_list!(self, visit_block, l.els);
1425     }
1426
1427     fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem<'tcx>) {
1428         let access = access_from!(self.save_ctxt, item.def_id);
1429
1430         match item.kind {
1431             hir::ForeignItemKind::Fn(decl, _, ref generics) => {
1432                 if let Some(fn_data) = self.save_ctxt.get_extern_item_data(item) {
1433                     down_cast_data!(fn_data, DefData, item.span);
1434
1435                     self.process_generic_params(generics, &fn_data.qualname, item.hir_id());
1436                     self.dumper.dump_def(&access, fn_data);
1437                 }
1438
1439                 for ty in decl.inputs {
1440                     self.visit_ty(ty);
1441                 }
1442
1443                 if let hir::FnRetTy::Return(ref ret_ty) = decl.output {
1444                     self.visit_ty(ret_ty);
1445                 }
1446             }
1447             hir::ForeignItemKind::Static(ref ty, _) => {
1448                 if let Some(var_data) = self.save_ctxt.get_extern_item_data(item) {
1449                     down_cast_data!(var_data, DefData, item.span);
1450                     self.dumper.dump_def(&access, var_data);
1451                 }
1452
1453                 self.visit_ty(ty);
1454             }
1455             hir::ForeignItemKind::Type => {
1456                 if let Some(var_data) = self.save_ctxt.get_extern_item_data(item) {
1457                     down_cast_data!(var_data, DefData, item.span);
1458                     self.dumper.dump_def(&access, var_data);
1459                 }
1460             }
1461         }
1462     }
1463 }