]> git.lizzy.rs Git - rust.git/blob - src/librustc_save_analysis/dump_visitor.rs
Rollup merge of #66710 - vorner:weak-into-raw-null-docs, r=dtolnay
[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::ImplItem],
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::TraitItem],
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                             match arg {
815                                 ast::GenericArg::Type(ty) => self.visit_ty(ty),
816                                 _ => {}
817                             }
818                         }
819                     }
820                     ast::GenericArgs::Parenthesized(ref data) => {
821                         for t in &data.inputs {
822                             self.visit_ty(t);
823                         }
824                         if let Some(ref t) = data.output {
825                             self.visit_ty(t);
826                         }
827                     }
828                 }
829             }
830         }
831
832         self.write_sub_paths_truncated(path);
833     }
834
835     fn process_struct_lit(
836         &mut self,
837         ex: &'l ast::Expr,
838         path: &'l ast::Path,
839         fields: &'l [ast::Field],
840         variant: &'l ty::VariantDef,
841         base: &'l Option<P<ast::Expr>>,
842     ) {
843         if let Some(struct_lit_data) = self.save_ctxt.get_expr_data(ex) {
844             self.write_sub_paths_truncated(path);
845             down_cast_data!(struct_lit_data, RefData, ex.span);
846             if !generated_code(ex.span) {
847                 self.dumper.dump_ref(struct_lit_data);
848             }
849
850             for field in fields {
851                 if let Some(field_data) = self.save_ctxt.get_field_ref_data(field, variant) {
852                     self.dumper.dump_ref(field_data);
853                 }
854
855                 self.visit_expr(&field.expr)
856             }
857         }
858
859         walk_list!(self, visit_expr, base);
860     }
861
862     fn process_method_call(
863         &mut self,
864         ex: &'l ast::Expr,
865         seg: &'l ast::PathSegment,
866         args: &'l [P<ast::Expr>],
867     ) {
868         debug!("process_method_call {:?} {:?}", ex, ex.span);
869         if let Some(mcd) = self.save_ctxt.get_expr_data(ex) {
870             down_cast_data!(mcd, RefData, ex.span);
871             if !generated_code(ex.span) {
872                 self.dumper.dump_ref(mcd);
873             }
874         }
875
876         // Explicit types in the turbo-fish.
877         if let Some(ref generic_args) = seg.args {
878             if let ast::GenericArgs::AngleBracketed(ref data) = **generic_args {
879                 for arg in &data.args {
880                     match arg {
881                         ast::GenericArg::Type(ty) => self.visit_ty(ty),
882                         _ => {}
883                     }
884                 }
885             }
886         }
887
888         // walk receiver and args
889         walk_list!(self, visit_expr, args);
890     }
891
892     fn process_pat(&mut self, p: &'l ast::Pat) {
893         match p.kind {
894             PatKind::Struct(ref _path, ref fields, _) => {
895                 // FIXME do something with _path?
896                 let hir_id = self.tcx.hir().node_to_hir_id(p.id);
897                 let adt = match self.save_ctxt.tables.node_type_opt(hir_id) {
898                     Some(ty) => ty.ty_adt_def().unwrap(),
899                     None => {
900                         visit::walk_pat(self, p);
901                         return;
902                     }
903                 };
904                 let variant = adt.variant_of_res(self.save_ctxt.get_path_res(p.id));
905
906                 for field in fields {
907                     if let Some(index) = self.tcx.find_field_index(field.ident, variant) {
908                         if !self.span.filter_generated(field.ident.span) {
909                             let span = self.span_from_span(field.ident.span);
910                             self.dumper.dump_ref(Ref {
911                                 kind: RefKind::Variable,
912                                 span,
913                                 ref_id: id_from_def_id(variant.fields[index].did),
914                             });
915                         }
916                     }
917                     self.visit_pat(&field.pat);
918                 }
919             }
920             _ => visit::walk_pat(self, p),
921         }
922     }
923
924     fn process_var_decl(&mut self, pat: &'l ast::Pat) {
925         // The pattern could declare multiple new vars,
926         // we must walk the pattern and collect them all.
927         let mut collector = PathCollector::new();
928         collector.visit_pat(&pat);
929         self.visit_pat(&pat);
930
931         // Process collected paths.
932         for (id, ident, _) in collector.collected_idents {
933             match self.save_ctxt.get_path_res(id) {
934                 Res::Local(hir_id) => {
935                     let id = self.tcx.hir().hir_to_node_id(hir_id);
936                     let typ = self.save_ctxt.tables.node_type_opt(hir_id)
937                         .map(|t| t.to_string())
938                         .unwrap_or_default();
939
940                     // Rust uses the id of the pattern for var lookups, so we'll use it too.
941                     if !self.span.filter_generated(ident.span) {
942                         let qualname = format!("{}${}", ident.to_string(), id);
943                         let id = id_from_node_id(id, &self.save_ctxt);
944                         let span = self.span_from_span(ident.span);
945
946                         self.dumper.dump_def(
947                             &Access {
948                                 public: false,
949                                 reachable: false,
950                             },
951                             Def {
952                                 kind: DefKind::Local,
953                                 id,
954                                 span,
955                                 name: ident.to_string(),
956                                 qualname,
957                                 value: typ,
958                                 parent: None,
959                                 children: vec![],
960                                 decl_id: None,
961                                 docs: String::new(),
962                                 sig: None,
963                                 attributes: vec![],
964                             },
965                         );
966                     }
967                 }
968                 Res::Def(HirDefKind::Ctor(..), _) |
969                 Res::Def(HirDefKind::Const, _) |
970                 Res::Def(HirDefKind::AssocConst, _) |
971                 Res::Def(HirDefKind::Struct, _) |
972                 Res::Def(HirDefKind::Variant, _) |
973                 Res::Def(HirDefKind::TyAlias, _) |
974                 Res::Def(HirDefKind::AssocTy, _) |
975                 Res::SelfTy(..) => {
976                     self.dump_path_ref(id, &ast::Path::from_ident(ident));
977                 }
978                 def => error!(
979                     "unexpected definition kind when processing collected idents: {:?}",
980                     def
981                 ),
982             }
983         }
984
985         for (id, ref path) in collector.collected_paths {
986             self.process_path(id, path);
987         }
988     }
989
990     /// Extracts macro use and definition information from the AST node defined
991     /// by the given NodeId, using the expansion information from the node's
992     /// span.
993     ///
994     /// If the span is not macro-generated, do nothing, else use callee and
995     /// callsite spans to record macro definition and use data, using the
996     /// mac_uses and mac_defs sets to prevent multiples.
997     fn process_macro_use(&mut self, _span: Span) {
998         // FIXME if we're not dumping the defs (see below), there is no point
999         // dumping refs either.
1000         // let source_span = span.source_callsite();
1001         // if !self.macro_calls.insert(source_span) {
1002         //     return;
1003         // }
1004
1005         // let data = match self.save_ctxt.get_macro_use_data(span) {
1006         //     None => return,
1007         //     Some(data) => data,
1008         // };
1009
1010         // self.dumper.macro_use(data);
1011
1012         // FIXME write the macro def
1013         // let mut hasher = DefaultHasher::new();
1014         // data.callee_span.hash(&mut hasher);
1015         // let hash = hasher.finish();
1016         // let qualname = format!("{}::{}", data.name, hash);
1017         // Don't write macro definition for imported macros
1018         // if !self.mac_defs.contains(&data.callee_span)
1019         //     && !data.imported {
1020         //     self.mac_defs.insert(data.callee_span);
1021         //     if let Some(sub_span) = self.span.span_for_macro_def_name(data.callee_span) {
1022         //         self.dumper.macro_data(MacroData {
1023         //             span: sub_span,
1024         //             name: data.name.clone(),
1025         //             qualname: qualname.clone(),
1026         //             // FIXME where do macro docs come from?
1027         //             docs: String::new(),
1028         //         }.lower(self.tcx));
1029         //     }
1030         // }
1031     }
1032
1033     fn process_trait_item(&mut self, trait_item: &'l ast::TraitItem, trait_id: DefId) {
1034         self.process_macro_use(trait_item.span);
1035         let vis_span = trait_item.span.shrink_to_lo();
1036         match trait_item.kind {
1037             ast::TraitItemKind::Const(ref ty, ref expr) => {
1038                 self.process_assoc_const(
1039                     trait_item.id,
1040                     trait_item.ident,
1041                     &ty,
1042                     expr.as_ref().map(|e| &**e),
1043                     trait_id,
1044                     respan(vis_span, ast::VisibilityKind::Public),
1045                     &trait_item.attrs,
1046                 );
1047             }
1048             ast::TraitItemKind::Method(ref sig, ref body) => {
1049                 self.process_method(
1050                     sig,
1051                     body.as_ref().map(|x| &**x),
1052                     trait_item.id,
1053                     trait_item.ident,
1054                     &trait_item.generics,
1055                     respan(vis_span, ast::VisibilityKind::Public),
1056                     trait_item.span,
1057                 );
1058             }
1059             ast::TraitItemKind::Type(ref bounds, ref default_ty) => {
1060                 // FIXME do something with _bounds (for type refs)
1061                 let name = trait_item.ident.name.to_string();
1062                 let qualname = format!("::{}",
1063                     self.tcx.def_path_str(self.tcx.hir().local_def_id_from_node_id(trait_item.id)));
1064
1065                 if !self.span.filter_generated(trait_item.ident.span) {
1066                     let span = self.span_from_span(trait_item.ident.span);
1067                     let id = id_from_node_id(trait_item.id, &self.save_ctxt);
1068
1069                     self.dumper.dump_def(
1070                         &Access {
1071                             public: true,
1072                             reachable: true,
1073                         },
1074                         Def {
1075                             kind: DefKind::Type,
1076                             id,
1077                             span,
1078                             name,
1079                             qualname,
1080                             value: self.span.snippet(trait_item.span),
1081                             parent: Some(id_from_def_id(trait_id)),
1082                             children: vec![],
1083                             decl_id: None,
1084                             docs: self.save_ctxt.docs_for_attrs(&trait_item.attrs),
1085                             sig: sig::assoc_type_signature(
1086                                 trait_item.id,
1087                                 trait_item.ident,
1088                                 Some(bounds),
1089                                 default_ty.as_ref().map(|ty| &**ty),
1090                                 &self.save_ctxt,
1091                             ),
1092                             attributes: lower_attributes(trait_item.attrs.clone(), &self.save_ctxt),
1093                         },
1094                     );
1095                 }
1096
1097                 if let &Some(ref default_ty) = default_ty {
1098                     self.visit_ty(default_ty)
1099                 }
1100             }
1101             ast::TraitItemKind::Macro(_) => {}
1102         }
1103     }
1104
1105     fn process_impl_item(&mut self, impl_item: &'l ast::ImplItem, impl_id: DefId) {
1106         self.process_macro_use(impl_item.span);
1107         match impl_item.kind {
1108             ast::ImplItemKind::Const(ref ty, ref expr) => {
1109                 self.process_assoc_const(
1110                     impl_item.id,
1111                     impl_item.ident,
1112                     &ty,
1113                     Some(expr),
1114                     impl_id,
1115                     impl_item.vis.clone(),
1116                     &impl_item.attrs,
1117                 );
1118             }
1119             ast::ImplItemKind::Method(ref sig, ref body) => {
1120                 self.process_method(
1121                     sig,
1122                     Some(body),
1123                     impl_item.id,
1124                     impl_item.ident,
1125                     &impl_item.generics,
1126                     impl_item.vis.clone(),
1127                     impl_item.span,
1128                 );
1129             }
1130             ast::ImplItemKind::TyAlias(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::ImplItemKind::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 }