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