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