]> git.lizzy.rs Git - rust.git/blob - src/librustc_save_analysis/dump_visitor.rs
Improve some compiletest documentation
[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.data.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.data.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.data.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::StructCtor(..) |
961                 HirDef::VariantCtor(..) |
962                 HirDef::Const(..) |
963                 HirDef::AssociatedConst(..) |
964                 HirDef::Struct(..) |
965                 HirDef::Variant(..) |
966                 HirDef::TyAlias(..) |
967                 HirDef::AssociatedTy(..) |
968                 HirDef::SelfTy(..) => {
969                     self.dump_path_ref(id, &ast::Path::from_ident(ident));
970                 }
971                 def => error!(
972                     "unexpected definition kind when processing collected idents: {:?}",
973                     def
974                 ),
975             }
976         }
977
978         for (id, ref path) in collector.collected_paths {
979             self.process_path(id, path);
980         }
981     }
982
983     fn process_var_decl(&mut self, p: &'l ast::Pat, value: String) {
984         // The local could declare multiple new vars, we must walk the
985         // pattern and collect them all.
986         let mut collector = PathCollector::new();
987         collector.visit_pat(&p);
988         self.visit_pat(&p);
989
990         for (id, ident, immut) in collector.collected_idents {
991             let mut value = match immut {
992                 ast::Mutability::Immutable => value.to_string(),
993                 _ => String::new(),
994             };
995             let hir_id = self.tcx.hir().node_to_hir_id(id);
996             let typ = match self.save_ctxt.tables.node_type_opt(hir_id) {
997                 Some(typ) => {
998                     let typ = typ.to_string();
999                     if !value.is_empty() {
1000                         value.push_str(": ");
1001                     }
1002                     value.push_str(&typ);
1003                     typ
1004                 }
1005                 None => String::new(),
1006             };
1007
1008             // Rust uses the id of the pattern for var lookups, so we'll use it too.
1009             if !self.span.filter_generated(ident.span) {
1010                 let qualname = format!("{}${}", ident.to_string(), id);
1011                 let id = id_from_node_id(id, &self.save_ctxt);
1012                 let span = self.span_from_span(ident.span);
1013
1014                 self.dumper.dump_def(
1015                     &Access {
1016                         public: false,
1017                         reachable: false,
1018                     },
1019                     Def {
1020                         kind: DefKind::Local,
1021                         id,
1022                         span,
1023                         name: ident.to_string(),
1024                         qualname,
1025                         value: typ,
1026                         parent: None,
1027                         children: vec![],
1028                         decl_id: None,
1029                         docs: String::new(),
1030                         sig: None,
1031                         attributes: vec![],
1032                     },
1033                 );
1034             }
1035         }
1036     }
1037
1038     /// Extracts macro use and definition information from the AST node defined
1039     /// by the given NodeId, using the expansion information from the node's
1040     /// span.
1041     ///
1042     /// If the span is not macro-generated, do nothing, else use callee and
1043     /// callsite spans to record macro definition and use data, using the
1044     /// mac_uses and mac_defs sets to prevent multiples.
1045     fn process_macro_use(&mut self, _span: Span) {
1046         // FIXME if we're not dumping the defs (see below), there is no point
1047         // dumping refs either.
1048         // let source_span = span.source_callsite();
1049         // if !self.macro_calls.insert(source_span) {
1050         //     return;
1051         // }
1052
1053         // let data = match self.save_ctxt.get_macro_use_data(span) {
1054         //     None => return,
1055         //     Some(data) => data,
1056         // };
1057
1058         // self.dumper.macro_use(data);
1059
1060         // FIXME write the macro def
1061         // let mut hasher = DefaultHasher::new();
1062         // data.callee_span.hash(&mut hasher);
1063         // let hash = hasher.finish();
1064         // let qualname = format!("{}::{}", data.name, hash);
1065         // Don't write macro definition for imported macros
1066         // if !self.mac_defs.contains(&data.callee_span)
1067         //     && !data.imported {
1068         //     self.mac_defs.insert(data.callee_span);
1069         //     if let Some(sub_span) = self.span.span_for_macro_def_name(data.callee_span) {
1070         //         self.dumper.macro_data(MacroData {
1071         //             span: sub_span,
1072         //             name: data.name.clone(),
1073         //             qualname: qualname.clone(),
1074         //             // FIXME where do macro docs come from?
1075         //             docs: String::new(),
1076         //         }.lower(self.tcx));
1077         //     }
1078         // }
1079     }
1080
1081     fn process_trait_item(&mut self, trait_item: &'l ast::TraitItem, trait_id: DefId) {
1082         self.process_macro_use(trait_item.span);
1083         let vis_span = trait_item.span.shrink_to_lo();
1084         match trait_item.node {
1085             ast::TraitItemKind::Const(ref ty, ref expr) => {
1086                 self.process_assoc_const(
1087                     trait_item.id,
1088                     trait_item.ident,
1089                     &ty,
1090                     expr.as_ref().map(|e| &**e),
1091                     trait_id,
1092                     respan(vis_span, ast::VisibilityKind::Public),
1093                     &trait_item.attrs,
1094                 );
1095             }
1096             ast::TraitItemKind::Method(ref sig, ref body) => {
1097                 self.process_method(
1098                     sig,
1099                     body.as_ref().map(|x| &**x),
1100                     trait_item.id,
1101                     trait_item.ident,
1102                     &trait_item.generics,
1103                     respan(vis_span, ast::VisibilityKind::Public),
1104                     trait_item.span,
1105                 );
1106             }
1107             ast::TraitItemKind::Type(ref bounds, ref default_ty) => {
1108                 // FIXME do something with _bounds (for type refs)
1109                 let name = trait_item.ident.name.to_string();
1110                 let qualname = format!("::{}",
1111                     self.tcx.def_path_str(self.tcx.hir().local_def_id(trait_item.id)));
1112
1113                 if !self.span.filter_generated(trait_item.ident.span) {
1114                     let span = self.span_from_span(trait_item.ident.span);
1115                     let id = id_from_node_id(trait_item.id, &self.save_ctxt);
1116
1117                     self.dumper.dump_def(
1118                         &Access {
1119                             public: true,
1120                             reachable: true,
1121                         },
1122                         Def {
1123                             kind: DefKind::Type,
1124                             id,
1125                             span,
1126                             name,
1127                             qualname,
1128                             value: self.span.snippet(trait_item.span),
1129                             parent: Some(id_from_def_id(trait_id)),
1130                             children: vec![],
1131                             decl_id: None,
1132                             docs: self.save_ctxt.docs_for_attrs(&trait_item.attrs),
1133                             sig: sig::assoc_type_signature(
1134                                 trait_item.id,
1135                                 trait_item.ident,
1136                                 Some(bounds),
1137                                 default_ty.as_ref().map(|ty| &**ty),
1138                                 &self.save_ctxt,
1139                             ),
1140                             attributes: lower_attributes(trait_item.attrs.clone(), &self.save_ctxt),
1141                         },
1142                     );
1143                 }
1144
1145                 if let &Some(ref default_ty) = default_ty {
1146                     self.visit_ty(default_ty)
1147                 }
1148             }
1149             ast::TraitItemKind::Macro(_) => {}
1150         }
1151     }
1152
1153     fn process_impl_item(&mut self, impl_item: &'l ast::ImplItem, impl_id: DefId) {
1154         self.process_macro_use(impl_item.span);
1155         match impl_item.node {
1156             ast::ImplItemKind::Const(ref ty, ref expr) => {
1157                 self.process_assoc_const(
1158                     impl_item.id,
1159                     impl_item.ident,
1160                     &ty,
1161                     Some(expr),
1162                     impl_id,
1163                     impl_item.vis.clone(),
1164                     &impl_item.attrs,
1165                 );
1166             }
1167             ast::ImplItemKind::Method(ref sig, ref body) => {
1168                 self.process_method(
1169                     sig,
1170                     Some(body),
1171                     impl_item.id,
1172                     impl_item.ident,
1173                     &impl_item.generics,
1174                     impl_item.vis.clone(),
1175                     impl_item.span,
1176                 );
1177             }
1178             ast::ImplItemKind::Type(ref ty) => {
1179                 // FIXME uses of the assoc type should ideally point to this
1180                 // 'def' and the name here should be a ref to the def in the
1181                 // trait.
1182                 self.visit_ty(ty)
1183             }
1184             ast::ImplItemKind::Existential(ref bounds) => {
1185                 // FIXME uses of the assoc type should ideally point to this
1186                 // 'def' and the name here should be a ref to the def in the
1187                 // trait.
1188                 for bound in bounds.iter() {
1189                     if let ast::GenericBound::Trait(trait_ref, _) = bound {
1190                         self.process_path(trait_ref.trait_ref.ref_id, &trait_ref.trait_ref.path)
1191                     }
1192                 }
1193             }
1194             ast::ImplItemKind::Macro(_) => {}
1195         }
1196     }
1197
1198     /// Dumps imports in a use tree recursively.
1199     ///
1200     /// A use tree is an import that may contain nested braces (RFC 2128). The `use_tree` parameter
1201     /// is the current use tree under scrutiny, while `id` and `prefix` are its corresponding node
1202     /// ID and path. `root_item` is the topmost use tree in the hierarchy.
1203     ///
1204     /// If `use_tree` is a simple or glob import, it is dumped into the analysis data. Otherwise,
1205     /// each child use tree is dumped recursively.
1206     fn process_use_tree(&mut self,
1207                          use_tree: &'l ast::UseTree,
1208                          id: NodeId,
1209                          root_item: &'l ast::Item,
1210                          prefix: &ast::Path) {
1211         let path = &use_tree.prefix;
1212
1213         // The access is calculated using the current tree ID, but with the root tree's visibility
1214         // (since nested trees don't have their own visibility).
1215         let hir_id = self.tcx.hir().node_to_hir_id(id);
1216         let access = access_from!(self.save_ctxt, root_item, hir_id);
1217
1218         // The parent def id of a given use tree is always the enclosing item.
1219         let parent = self.save_ctxt.tcx.hir().opt_local_def_id(id)
1220             .and_then(|id| self.save_ctxt.tcx.parent(id))
1221             .map(id_from_def_id);
1222
1223         match use_tree.kind {
1224             ast::UseTreeKind::Simple(alias, ..) => {
1225                 let ident = use_tree.ident();
1226                 let path = ast::Path {
1227                     segments: prefix.segments
1228                         .iter()
1229                         .chain(path.segments.iter())
1230                         .cloned()
1231                         .collect(),
1232                     span: path.span,
1233                 };
1234
1235                 let sub_span = path.segments.last().unwrap().ident.span;
1236                 if !self.span.filter_generated(sub_span) {
1237                     let ref_id = self.lookup_def_id(id).map(|id| id_from_def_id(id));
1238                     let alias_span = alias.map(|i| self.span_from_span(i.span));
1239                     let span = self.span_from_span(sub_span);
1240                     self.dumper.import(&access, Import {
1241                         kind: ImportKind::Use,
1242                         ref_id,
1243                         span,
1244                         alias_span,
1245                         name: ident.to_string(),
1246                         value: String::new(),
1247                         parent,
1248                     });
1249                     self.write_sub_paths_truncated(&path);
1250                 }
1251             }
1252             ast::UseTreeKind::Glob => {
1253                 let path = ast::Path {
1254                     segments: prefix.segments
1255                         .iter()
1256                         .chain(path.segments.iter())
1257                         .cloned()
1258                         .collect(),
1259                     span: path.span,
1260                 };
1261
1262                 // Make a comma-separated list of names of imported modules.
1263                 let def_id = self.tcx.hir().local_def_id(id);
1264                 let names = self.tcx.names_imported_by_glob_use(def_id);
1265                 let names: Vec<_> = names.iter().map(|n| n.to_string()).collect();
1266
1267                 // Otherwise it's a span with wrong macro expansion info, which
1268                 // we don't want to track anyway, since it's probably macro-internal `use`
1269                 if let Some(sub_span) =
1270                     self.span.sub_span_of_token(use_tree.span, token::BinOp(token::Star))
1271                 {
1272                     if !self.span.filter_generated(use_tree.span) {
1273                         let span = self.span_from_span(sub_span);
1274
1275                         self.dumper.import(&access, Import {
1276                             kind: ImportKind::GlobUse,
1277                             ref_id: None,
1278                             span,
1279                             alias_span: None,
1280                             name: "*".to_owned(),
1281                             value: names.join(", "),
1282                             parent,
1283                         });
1284                         self.write_sub_paths(&path);
1285                     }
1286                 }
1287             }
1288             ast::UseTreeKind::Nested(ref nested_items) => {
1289                 let prefix = ast::Path {
1290                     segments: prefix.segments
1291                         .iter()
1292                         .chain(path.segments.iter())
1293                         .cloned()
1294                         .collect(),
1295                     span: path.span,
1296                 };
1297                 for &(ref tree, id) in nested_items {
1298                     self.process_use_tree(tree, id, root_item, &prefix);
1299                 }
1300             }
1301         }
1302     }
1303
1304     fn process_bounds(&mut self, bounds: &'l ast::GenericBounds) {
1305         for bound in bounds {
1306             if let ast::GenericBound::Trait(ref trait_ref, _) = *bound {
1307                 self.process_path(trait_ref.trait_ref.ref_id, &trait_ref.trait_ref.path)
1308             }
1309         }
1310     }
1311 }
1312
1313 impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> Visitor<'l> for DumpVisitor<'l, 'tcx, 'll, O> {
1314     fn visit_mod(&mut self, m: &'l ast::Mod, span: Span, attrs: &[ast::Attribute], id: NodeId) {
1315         // Since we handle explicit modules ourselves in visit_item, this should
1316         // only get called for the root module of a crate.
1317         assert_eq!(id, ast::CRATE_NODE_ID);
1318
1319         let qualname = format!("::{}",
1320             self.tcx.def_path_str(self.tcx.hir().local_def_id(id)));
1321
1322         let cm = self.tcx.sess.source_map();
1323         let filename = cm.span_to_filename(span);
1324         let data_id = id_from_node_id(id, &self.save_ctxt);
1325         let children = m.items
1326             .iter()
1327             .map(|i| id_from_node_id(i.id, &self.save_ctxt))
1328             .collect();
1329         let span = self.span_from_span(span);
1330
1331         self.dumper.dump_def(
1332             &Access {
1333                 public: true,
1334                 reachable: true,
1335             },
1336             Def {
1337                 kind: DefKind::Mod,
1338                 id: data_id,
1339                 name: String::new(),
1340                 qualname,
1341                 span,
1342                 value: filename.to_string(),
1343                 children,
1344                 parent: None,
1345                 decl_id: None,
1346                 docs: self.save_ctxt.docs_for_attrs(attrs),
1347                 sig: None,
1348                 attributes: lower_attributes(attrs.to_owned(), &self.save_ctxt),
1349             },
1350         );
1351         self.nest_scope(id, |v| visit::walk_mod(v, m));
1352     }
1353
1354     fn visit_item(&mut self, item: &'l ast::Item) {
1355         use syntax::ast::ItemKind::*;
1356         self.process_macro_use(item.span);
1357         match item.node {
1358             Use(ref use_tree) => {
1359                 let prefix = ast::Path {
1360                     segments: vec![],
1361                     span: DUMMY_SP,
1362                 };
1363                 self.process_use_tree(use_tree, item.id, item, &prefix);
1364             }
1365             ExternCrate(_) => {
1366                 let name_span = item.ident.span;
1367                 if !self.span.filter_generated(name_span) {
1368                     let span = self.span_from_span(name_span);
1369                     let parent = self.save_ctxt.tcx.hir().opt_local_def_id(item.id)
1370                         .and_then(|id| self.save_ctxt.tcx.parent(id))
1371                         .map(id_from_def_id);
1372                     self.dumper.import(
1373                         &Access {
1374                             public: false,
1375                             reachable: false,
1376                         },
1377                         Import {
1378                             kind: ImportKind::ExternCrate,
1379                             ref_id: None,
1380                             span,
1381                             alias_span: None,
1382                             name: item.ident.to_string(),
1383                             value: String::new(),
1384                             parent,
1385                         },
1386                     );
1387                 }
1388             }
1389             Fn(ref decl, .., ref ty_params, ref body) => {
1390                 self.process_fn(item, &decl, ty_params, &body)
1391             }
1392             Static(ref typ, _, ref expr) => self.process_static_or_const_item(item, typ, expr),
1393             Const(ref typ, ref expr) => self.process_static_or_const_item(item, &typ, &expr),
1394             Struct(ref def, ref ty_params) | Union(ref def, ref ty_params) => {
1395                 self.process_struct(item, def, ty_params)
1396             }
1397             Enum(ref def, ref ty_params) => self.process_enum(item, def, ty_params),
1398             Impl(.., ref ty_params, ref trait_ref, ref typ, ref impl_items) => {
1399                 self.process_impl(item, ty_params, trait_ref, &typ, impl_items)
1400             }
1401             Trait(_, _, ref generics, ref trait_refs, ref methods) => {
1402                 self.process_trait(item, generics, trait_refs, methods)
1403             }
1404             Mod(ref m) => {
1405                 self.process_mod(item);
1406                 self.nest_scope(item.id, |v| visit::walk_mod(v, m));
1407             }
1408             Ty(ref ty, ref ty_params) => {
1409                 let qualname = format!("::{}",
1410                     self.tcx.def_path_str(self.tcx.hir().local_def_id(item.id)));
1411                 let value = ty_to_string(&ty);
1412                 if !self.span.filter_generated(item.ident.span) {
1413                     let span = self.span_from_span(item.ident.span);
1414                     let id = id_from_node_id(item.id, &self.save_ctxt);
1415                     let hir_id = self.tcx.hir().node_to_hir_id(item.id);
1416
1417                     self.dumper.dump_def(
1418                         &access_from!(self.save_ctxt, item, hir_id),
1419                         Def {
1420                             kind: DefKind::Type,
1421                             id,
1422                             span,
1423                             name: item.ident.to_string(),
1424                             qualname: qualname.clone(),
1425                             value,
1426                             parent: None,
1427                             children: vec![],
1428                             decl_id: None,
1429                             docs: self.save_ctxt.docs_for_attrs(&item.attrs),
1430                             sig: sig::item_signature(item, &self.save_ctxt),
1431                             attributes: lower_attributes(item.attrs.clone(), &self.save_ctxt),
1432                         },
1433                     );
1434                 }
1435
1436                 self.visit_ty(&ty);
1437                 self.process_generic_params(ty_params, &qualname, item.id);
1438             }
1439             Existential(ref _bounds, ref ty_params) => {
1440                 let qualname = format!("::{}",
1441                     self.tcx.def_path_str(self.tcx.hir().local_def_id(item.id)));
1442                 // FIXME do something with _bounds
1443                 let value = String::new();
1444                 if !self.span.filter_generated(item.ident.span) {
1445                     let span = self.span_from_span(item.ident.span);
1446                     let id = id_from_node_id(item.id, &self.save_ctxt);
1447                     let hir_id = self.tcx.hir().node_to_hir_id(item.id);
1448
1449                     self.dumper.dump_def(
1450                         &access_from!(self.save_ctxt, item, hir_id),
1451                         Def {
1452                             kind: DefKind::Type,
1453                             id,
1454                             span,
1455                             name: item.ident.to_string(),
1456                             qualname: qualname.clone(),
1457                             value,
1458                             parent: None,
1459                             children: vec![],
1460                             decl_id: None,
1461                             docs: self.save_ctxt.docs_for_attrs(&item.attrs),
1462                             sig: sig::item_signature(item, &self.save_ctxt),
1463                             attributes: lower_attributes(item.attrs.clone(), &self.save_ctxt),
1464                         },
1465                     );
1466                 }
1467
1468                 self.process_generic_params(ty_params, &qualname, item.id);
1469             }
1470             Mac(_) => (),
1471             _ => visit::walk_item(self, item),
1472         }
1473     }
1474
1475     fn visit_generics(&mut self, generics: &'l ast::Generics) {
1476         for param in &generics.params {
1477             match param.kind {
1478                 ast::GenericParamKind::Lifetime { .. } => {}
1479                 ast::GenericParamKind::Type { ref default, .. } => {
1480                     self.process_bounds(&param.bounds);
1481                     if let Some(ref ty) = default {
1482                         self.visit_ty(&ty);
1483                     }
1484                 }
1485                 ast::GenericParamKind::Const { ref ty } => {
1486                     self.process_bounds(&param.bounds);
1487                     self.visit_ty(&ty);
1488                 }
1489             }
1490         }
1491         for pred in &generics.where_clause.predicates {
1492             if let ast::WherePredicate::BoundPredicate(ref wbp) = *pred {
1493                 self.process_bounds(&wbp.bounds);
1494                 self.visit_ty(&wbp.bounded_ty);
1495             }
1496         }
1497     }
1498
1499     fn visit_ty(&mut self, t: &'l ast::Ty) {
1500         self.process_macro_use(t.span);
1501         match t.node {
1502             ast::TyKind::Path(_, ref path) => {
1503                 if generated_code(t.span) {
1504                     return;
1505                 }
1506
1507                 if let Some(id) = self.lookup_def_id(t.id) {
1508                     let sub_span = path.segments.last().unwrap().ident.span;
1509                     let span = self.span_from_span(sub_span);
1510                     self.dumper.dump_ref(Ref {
1511                         kind: RefKind::Type,
1512                         span,
1513                         ref_id: id_from_def_id(id),
1514                     });
1515                 }
1516
1517                 self.write_sub_paths_truncated(path);
1518                 visit::walk_path(self, path);
1519             }
1520             ast::TyKind::Array(ref element, ref length) => {
1521                 self.visit_ty(element);
1522                 self.nest_tables(length.id, |v| v.visit_expr(&length.value));
1523             }
1524             _ => visit::walk_ty(self, t),
1525         }
1526     }
1527
1528     fn visit_expr(&mut self, ex: &'l ast::Expr) {
1529         debug!("visit_expr {:?}", ex.node);
1530         self.process_macro_use(ex.span);
1531         match ex.node {
1532             ast::ExprKind::Struct(ref path, ref fields, ref base) => {
1533                 let hir_expr = self.save_ctxt.tcx.hir().expect_expr(ex.id);
1534                 let adt = match self.save_ctxt.tables.expr_ty_opt(&hir_expr) {
1535                     Some(ty) if ty.ty_adt_def().is_some() => ty.ty_adt_def().unwrap(),
1536                     _ => {
1537                         visit::walk_expr(self, ex);
1538                         return;
1539                     }
1540                 };
1541                 let node_id = self.save_ctxt.tcx.hir().hir_to_node_id(hir_expr.hir_id);
1542                 let def = self.save_ctxt.get_path_def(node_id);
1543                 self.process_struct_lit(ex, path, fields, adt.variant_of_def(def), base)
1544             }
1545             ast::ExprKind::MethodCall(ref seg, ref args) => self.process_method_call(ex, seg, args),
1546             ast::ExprKind::Field(ref sub_ex, _) => {
1547                 self.visit_expr(&sub_ex);
1548
1549                 if let Some(field_data) = self.save_ctxt.get_expr_data(ex) {
1550                     down_cast_data!(field_data, RefData, ex.span);
1551                     if !generated_code(ex.span) {
1552                         self.dumper.dump_ref(field_data);
1553                     }
1554                 }
1555             }
1556             ast::ExprKind::Closure(_, _, _, ref decl, ref body, _fn_decl_span) => {
1557                 let id = format!("${}", ex.id);
1558
1559                 // walk arg and return types
1560                 for arg in &decl.inputs {
1561                     self.visit_ty(&arg.ty);
1562                 }
1563
1564                 if let ast::FunctionRetTy::Ty(ref ret_ty) = decl.output {
1565                     self.visit_ty(&ret_ty);
1566                 }
1567
1568                 // walk the body
1569                 self.nest_tables(ex.id, |v| {
1570                     v.process_formals(&decl.inputs, &id);
1571                     v.nest_scope(ex.id, |v| v.visit_expr(body))
1572                 });
1573             }
1574             ast::ExprKind::ForLoop(ref pattern, ref subexpression, ref block, _) => {
1575                 let value = self.span.snippet(subexpression.span);
1576                 self.process_var_decl(pattern, value);
1577                 debug!("for loop, walk sub-expr: {:?}", subexpression.node);
1578                 self.visit_expr(subexpression);
1579                 visit::walk_block(self, block);
1580             }
1581             ast::ExprKind::WhileLet(ref pats, ref subexpression, ref block, _) => {
1582                 self.process_var_decl_multi(pats);
1583                 debug!("for loop, walk sub-expr: {:?}", subexpression.node);
1584                 self.visit_expr(subexpression);
1585                 visit::walk_block(self, block);
1586             }
1587             ast::ExprKind::IfLet(ref pats, ref subexpression, ref block, ref opt_else) => {
1588                 self.process_var_decl_multi(pats);
1589                 self.visit_expr(subexpression);
1590                 visit::walk_block(self, block);
1591                 opt_else.as_ref().map(|el| self.visit_expr(el));
1592             }
1593             ast::ExprKind::Repeat(ref element, ref count) => {
1594                 self.visit_expr(element);
1595                 self.nest_tables(count.id, |v| v.visit_expr(&count.value));
1596             }
1597             // In particular, we take this branch for call and path expressions,
1598             // where we'll index the idents involved just by continuing to walk.
1599             _ => visit::walk_expr(self, ex),
1600         }
1601     }
1602
1603     fn visit_mac(&mut self, mac: &'l ast::Mac) {
1604         // These shouldn't exist in the AST at this point, log a span bug.
1605         span_bug!(
1606             mac.span,
1607             "macro invocation should have been expanded out of AST"
1608         );
1609     }
1610
1611     fn visit_pat(&mut self, p: &'l ast::Pat) {
1612         self.process_macro_use(p.span);
1613         self.process_pat(p);
1614     }
1615
1616     fn visit_arm(&mut self, arm: &'l ast::Arm) {
1617         self.process_var_decl_multi(&arm.pats);
1618         match arm.guard {
1619             Some(ast::Guard::If(ref expr)) => self.visit_expr(expr),
1620             _ => {}
1621         }
1622         self.visit_expr(&arm.body);
1623     }
1624
1625     fn visit_path(&mut self, p: &'l ast::Path, id: NodeId) {
1626         self.process_path(id, p);
1627     }
1628
1629     fn visit_stmt(&mut self, s: &'l ast::Stmt) {
1630         self.process_macro_use(s.span);
1631         visit::walk_stmt(self, s)
1632     }
1633
1634     fn visit_local(&mut self, l: &'l ast::Local) {
1635         self.process_macro_use(l.span);
1636         let value = l.init
1637             .as_ref()
1638             .map(|i| self.span.snippet(i.span))
1639             .unwrap_or_default();
1640         self.process_var_decl(&l.pat, value);
1641
1642         // Just walk the initialiser and type (don't want to walk the pattern again).
1643         walk_list!(self, visit_ty, &l.ty);
1644         walk_list!(self, visit_expr, &l.init);
1645     }
1646
1647     fn visit_foreign_item(&mut self, item: &'l ast::ForeignItem) {
1648         let hir_id = self.tcx.hir().node_to_hir_id(item.id);
1649         let access = access_from!(self.save_ctxt, item, hir_id);
1650
1651         match item.node {
1652             ast::ForeignItemKind::Fn(ref decl, ref generics) => {
1653                 if let Some(fn_data) = self.save_ctxt.get_extern_item_data(item) {
1654                     down_cast_data!(fn_data, DefData, item.span);
1655
1656                     self.process_generic_params(generics, &fn_data.qualname, item.id);
1657                     self.dumper.dump_def(&access, fn_data);
1658                 }
1659
1660                 for arg in &decl.inputs {
1661                     self.visit_ty(&arg.ty);
1662                 }
1663
1664                 if let ast::FunctionRetTy::Ty(ref ret_ty) = decl.output {
1665                     self.visit_ty(&ret_ty);
1666                 }
1667             }
1668             ast::ForeignItemKind::Static(ref ty, _) => {
1669                 if let Some(var_data) = self.save_ctxt.get_extern_item_data(item) {
1670                     down_cast_data!(var_data, DefData, item.span);
1671                     self.dumper.dump_def(&access, var_data);
1672                 }
1673
1674                 self.visit_ty(ty);
1675             }
1676             ast::ForeignItemKind::Ty => {
1677                 if let Some(var_data) = self.save_ctxt.get_extern_item_data(item) {
1678                     down_cast_data!(var_data, DefData, item.span);
1679                     self.dumper.dump_def(&access, var_data);
1680                 }
1681             }
1682             ast::ForeignItemKind::Macro(..) => {}
1683         }
1684     }
1685 }