]> git.lizzy.rs Git - rust.git/blob - src/librustc_save_analysis/dump_visitor.rs
Rollup merge of #61095 - ehuss:update-cargo, 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::{Res, DefKind as HirDefKind};
17 use rustc::hir::def_id::DefId;
18 use rustc::session::config::Input;
19 use rustc::span_bug;
20 use rustc::ty::{self, DefIdTree, TyCtxt};
21 use rustc_data_structures::fx::FxHashSet;
22
23 use std::path::Path;
24 use std::env;
25
26 use syntax::ast::{self, Attribute, NodeId, PatKind, 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_res(ref_id) {
237             Res::PrimTy(..) | Res::SelfTy(..) | Res::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.nest_tables(id, |v| {
467             v.visit_ty(typ);
468             if let Some(expr) = expr {
469                 v.visit_expr(expr);
470             }
471         });
472     }
473
474     // FIXME tuple structs should generate tuple-specific data.
475     fn process_struct(
476         &mut self,
477         item: &'l ast::Item,
478         def: &'l ast::VariantData,
479         ty_params: &'l ast::Generics,
480     ) {
481         debug!("process_struct {:?} {:?}", item, item.span);
482         let name = item.ident.to_string();
483         let qualname = format!("::{}",
484             self.tcx.def_path_str(self.tcx.hir().local_def_id(item.id)));
485
486         let kind = match item.node {
487             ast::ItemKind::Struct(_, _) => DefKind::Struct,
488             ast::ItemKind::Union(_, _) => DefKind::Union,
489             _ => unreachable!(),
490         };
491
492         let (value, fields) = match item.node {
493             ast::ItemKind::Struct(ast::VariantData::Struct(ref fields, ..), ..) |
494             ast::ItemKind::Union(ast::VariantData::Struct(ref fields, ..), ..) => {
495                 let include_priv_fields = !self.save_ctxt.config.pub_only;
496                 let fields_str = fields
497                     .iter()
498                     .enumerate()
499                     .filter_map(|(i, f)| {
500                         if include_priv_fields || f.vis.node.is_pub() {
501                             f.ident
502                                 .map(|i| i.to_string())
503                                 .or_else(|| Some(i.to_string()))
504                         } else {
505                             None
506                         }
507                     })
508                     .collect::<Vec<_>>()
509                     .join(", ");
510                 let value = format!("{} {{ {} }}", name, fields_str);
511                 (
512                     value,
513                     fields
514                         .iter()
515                         .map(|f| id_from_node_id(f.id, &self.save_ctxt))
516                         .collect(),
517                 )
518             }
519             _ => (String::new(), vec![]),
520         };
521
522         if !self.span.filter_generated(item.ident.span) {
523             let span = self.span_from_span(item.ident.span);
524             let hir_id = self.tcx.hir().node_to_hir_id(item.id);
525             self.dumper.dump_def(
526                 &access_from!(self.save_ctxt, item, hir_id),
527                 Def {
528                     kind,
529                     id: id_from_node_id(item.id, &self.save_ctxt),
530                     span,
531                     name,
532                     qualname: qualname.clone(),
533                     value,
534                     parent: None,
535                     children: fields,
536                     decl_id: None,
537                     docs: self.save_ctxt.docs_for_attrs(&item.attrs),
538                     sig: sig::item_signature(item, &self.save_ctxt),
539                     attributes: lower_attributes(item.attrs.clone(), &self.save_ctxt),
540                 },
541             );
542         }
543
544         for field in def.fields() {
545             self.process_struct_field_def(field, item.id);
546             self.visit_ty(&field.ty);
547         }
548
549         self.process_generic_params(ty_params, &qualname, item.id);
550     }
551
552     fn process_enum(
553         &mut self,
554         item: &'l ast::Item,
555         enum_definition: &'l ast::EnumDef,
556         ty_params: &'l ast::Generics,
557     ) {
558         let enum_data = self.save_ctxt.get_item_data(item);
559         let enum_data = match enum_data {
560             None => return,
561             Some(data) => data,
562         };
563         down_cast_data!(enum_data, DefData, item.span);
564
565         let hir_id = self.tcx.hir().node_to_hir_id(item.id);
566         let access = access_from!(self.save_ctxt, item, hir_id);
567
568         for variant in &enum_definition.variants {
569             let name = variant.node.ident.name.to_string();
570             let qualname = format!("{}::{}", enum_data.qualname, name);
571             let name_span = variant.node.ident.span;
572
573             match variant.node.data {
574                 ast::VariantData::Struct(ref fields, ..) => {
575                     let fields_str = fields
576                         .iter()
577                         .enumerate()
578                         .map(|(i, f)| {
579                             f.ident.map(|i| i.to_string()).unwrap_or_else(|| i.to_string())
580                         })
581                         .collect::<Vec<_>>()
582                         .join(", ");
583                     let value = format!("{}::{} {{ {} }}", enum_data.name, name, fields_str);
584                     if !self.span.filter_generated(name_span) {
585                         let span = self.span_from_span(name_span);
586                         let id = id_from_node_id(variant.node.id, &self.save_ctxt);
587                         let parent = Some(id_from_node_id(item.id, &self.save_ctxt));
588
589                         self.dumper.dump_def(
590                             &access,
591                             Def {
592                                 kind: DefKind::StructVariant,
593                                 id,
594                                 span,
595                                 name,
596                                 qualname,
597                                 value,
598                                 parent,
599                                 children: vec![],
600                                 decl_id: None,
601                                 docs: self.save_ctxt.docs_for_attrs(&variant.node.attrs),
602                                 sig: sig::variant_signature(variant, &self.save_ctxt),
603                                 attributes: lower_attributes(
604                                     variant.node.attrs.clone(),
605                                     &self.save_ctxt,
606                                 ),
607                             },
608                         );
609                     }
610                 }
611                 ref v => {
612                     let mut value = format!("{}::{}", enum_data.name, name);
613                     if let &ast::VariantData::Tuple(ref fields, _) = v {
614                         value.push('(');
615                         value.push_str(&fields
616                             .iter()
617                             .map(|f| ty_to_string(&f.ty))
618                             .collect::<Vec<_>>()
619                             .join(", "));
620                         value.push(')');
621                     }
622                     if !self.span.filter_generated(name_span) {
623                         let span = self.span_from_span(name_span);
624                         let id = id_from_node_id(variant.node.id, &self.save_ctxt);
625                         let parent = Some(id_from_node_id(item.id, &self.save_ctxt));
626
627                         self.dumper.dump_def(
628                             &access,
629                             Def {
630                                 kind: DefKind::TupleVariant,
631                                 id,
632                                 span,
633                                 name,
634                                 qualname,
635                                 value,
636                                 parent,
637                                 children: vec![],
638                                 decl_id: None,
639                                 docs: self.save_ctxt.docs_for_attrs(&variant.node.attrs),
640                                 sig: sig::variant_signature(variant, &self.save_ctxt),
641                                 attributes: lower_attributes(
642                                     variant.node.attrs.clone(),
643                                     &self.save_ctxt,
644                                 ),
645                             },
646                         );
647                     }
648                 }
649             }
650
651
652             for field in variant.node.data.fields() {
653                 self.process_struct_field_def(field, variant.node.id);
654                 self.visit_ty(&field.ty);
655             }
656         }
657         self.process_generic_params(ty_params, &enum_data.qualname, item.id);
658         self.dumper.dump_def(&access, enum_data);
659     }
660
661     fn process_impl(
662         &mut self,
663         item: &'l ast::Item,
664         generics: &'l ast::Generics,
665         trait_ref: &'l Option<ast::TraitRef>,
666         typ: &'l ast::Ty,
667         impl_items: &'l [ast::ImplItem],
668     ) {
669         if let Some(impl_data) = self.save_ctxt.get_item_data(item) {
670             if !self.span.filter_generated(item.span) {
671                 if let super::Data::RelationData(rel, imp) = impl_data {
672                     self.dumper.dump_relation(rel);
673                     self.dumper.dump_impl(imp);
674                 } else {
675                     span_bug!(item.span, "unexpected data kind: {:?}", impl_data);
676                 }
677             }
678         }
679         self.visit_ty(&typ);
680         if let &Some(ref trait_ref) = trait_ref {
681             self.process_path(trait_ref.ref_id, &trait_ref.path);
682         }
683         self.process_generic_params(generics, "", item.id);
684         for impl_item in impl_items {
685             let map = &self.tcx.hir();
686             self.process_impl_item(impl_item, map.local_def_id(item.id));
687         }
688     }
689
690     fn process_trait(
691         &mut self,
692         item: &'l ast::Item,
693         generics: &'l ast::Generics,
694         trait_refs: &'l ast::GenericBounds,
695         methods: &'l [ast::TraitItem],
696     ) {
697         let name = item.ident.to_string();
698         let qualname = format!("::{}",
699             self.tcx.def_path_str(self.tcx.hir().local_def_id(item.id)));
700         let mut val = name.clone();
701         if !generics.params.is_empty() {
702             val.push_str(&generic_params_to_string(&generics.params));
703         }
704         if !trait_refs.is_empty() {
705             val.push_str(": ");
706             val.push_str(&bounds_to_string(trait_refs));
707         }
708         if !self.span.filter_generated(item.ident.span) {
709             let id = id_from_node_id(item.id, &self.save_ctxt);
710             let span = self.span_from_span(item.ident.span);
711             let children = methods
712                 .iter()
713                 .map(|i| id_from_node_id(i.id, &self.save_ctxt))
714                 .collect();
715             let hir_id = self.tcx.hir().node_to_hir_id(item.id);
716             self.dumper.dump_def(
717                 &access_from!(self.save_ctxt, item, hir_id),
718                 Def {
719                     kind: DefKind::Trait,
720                     id,
721                     span,
722                     name,
723                     qualname: qualname.clone(),
724                     value: val,
725                     parent: None,
726                     children,
727                     decl_id: None,
728                     docs: self.save_ctxt.docs_for_attrs(&item.attrs),
729                     sig: sig::item_signature(item, &self.save_ctxt),
730                     attributes: lower_attributes(item.attrs.clone(), &self.save_ctxt),
731                 },
732             );
733         }
734
735         // super-traits
736         for super_bound in trait_refs.iter() {
737             let trait_ref = match *super_bound {
738                 ast::GenericBound::Trait(ref trait_ref, _) => trait_ref,
739                 ast::GenericBound::Outlives(..) => continue,
740             };
741
742             let trait_ref = &trait_ref.trait_ref;
743             if let Some(id) = self.lookup_def_id(trait_ref.ref_id) {
744                 let sub_span = trait_ref.path.segments.last().unwrap().ident.span;
745                 if !self.span.filter_generated(sub_span) {
746                     let span = self.span_from_span(sub_span);
747                     self.dumper.dump_ref(Ref {
748                         kind: RefKind::Type,
749                         span: span.clone(),
750                         ref_id: id_from_def_id(id),
751                     });
752
753                     self.dumper.dump_relation(Relation {
754                         kind: RelationKind::SuperTrait,
755                         span,
756                         from: id_from_def_id(id),
757                         to: id_from_node_id(item.id, &self.save_ctxt),
758                     });
759                 }
760             }
761         }
762
763         // walk generics and methods
764         self.process_generic_params(generics, &qualname, item.id);
765         for method in methods {
766             let map = &self.tcx.hir();
767             self.process_trait_item(method, map.local_def_id(item.id))
768         }
769     }
770
771     // `item` is the module in question, represented as an item.
772     fn process_mod(&mut self, item: &ast::Item) {
773         if let Some(mod_data) = self.save_ctxt.get_item_data(item) {
774             down_cast_data!(mod_data, DefData, item.span);
775             let hir_id = self.tcx.hir().node_to_hir_id(item.id);
776             self.dumper.dump_def(&access_from!(self.save_ctxt, item, hir_id), mod_data);
777         }
778     }
779
780     fn dump_path_ref(&mut self, id: NodeId, path: &ast::Path) {
781         let path_data = self.save_ctxt.get_path_data(id, path);
782         if let Some(path_data) = path_data {
783             self.dumper.dump_ref(path_data);
784         }
785     }
786
787     fn process_path(&mut self, id: NodeId, path: &'l ast::Path) {
788         if self.span.filter_generated(path.span) {
789             return;
790         }
791         self.dump_path_ref(id, path);
792
793         // Type arguments
794         for seg in &path.segments {
795             if let Some(ref generic_args) = seg.args {
796                 match **generic_args {
797                     ast::GenericArgs::AngleBracketed(ref data) => {
798                         for arg in &data.args {
799                             match arg {
800                                 ast::GenericArg::Type(ty) => self.visit_ty(ty),
801                                 _ => {}
802                             }
803                         }
804                     }
805                     ast::GenericArgs::Parenthesized(ref data) => {
806                         for t in &data.inputs {
807                             self.visit_ty(t);
808                         }
809                         if let Some(ref t) = data.output {
810                             self.visit_ty(t);
811                         }
812                     }
813                 }
814             }
815         }
816
817         self.write_sub_paths_truncated(path);
818     }
819
820     fn process_struct_lit(
821         &mut self,
822         ex: &'l ast::Expr,
823         path: &'l ast::Path,
824         fields: &'l [ast::Field],
825         variant: &'l ty::VariantDef,
826         base: &'l Option<P<ast::Expr>>,
827     ) {
828         if let Some(struct_lit_data) = self.save_ctxt.get_expr_data(ex) {
829             self.write_sub_paths_truncated(path);
830             down_cast_data!(struct_lit_data, RefData, ex.span);
831             if !generated_code(ex.span) {
832                 self.dumper.dump_ref(struct_lit_data);
833             }
834
835             for field in fields {
836                 if let Some(field_data) = self.save_ctxt.get_field_ref_data(field, variant) {
837                     self.dumper.dump_ref(field_data);
838                 }
839
840                 self.visit_expr(&field.expr)
841             }
842         }
843
844         walk_list!(self, visit_expr, base);
845     }
846
847     fn process_method_call(
848         &mut self,
849         ex: &'l ast::Expr,
850         seg: &'l ast::PathSegment,
851         args: &'l [P<ast::Expr>],
852     ) {
853         debug!("process_method_call {:?} {:?}", ex, ex.span);
854         if let Some(mcd) = self.save_ctxt.get_expr_data(ex) {
855             down_cast_data!(mcd, RefData, ex.span);
856             if !generated_code(ex.span) {
857                 self.dumper.dump_ref(mcd);
858             }
859         }
860
861         // Explicit types in the turbo-fish.
862         if let Some(ref generic_args) = seg.args {
863             if let ast::GenericArgs::AngleBracketed(ref data) = **generic_args {
864                 for arg in &data.args {
865                     match arg {
866                         ast::GenericArg::Type(ty) => self.visit_ty(ty),
867                         _ => {}
868                     }
869                 }
870             }
871         }
872
873         // walk receiver and args
874         walk_list!(self, visit_expr, args);
875     }
876
877     fn process_pat(&mut self, p: &'l ast::Pat) {
878         match p.node {
879             PatKind::Struct(ref _path, ref fields, _) => {
880                 // FIXME do something with _path?
881                 let hir_id = self.tcx.hir().node_to_hir_id(p.id);
882                 let adt = match self.save_ctxt.tables.node_type_opt(hir_id) {
883                     Some(ty) => ty.ty_adt_def().unwrap(),
884                     None => {
885                         visit::walk_pat(self, p);
886                         return;
887                     }
888                 };
889                 let variant = adt.variant_of_res(self.save_ctxt.get_path_res(p.id));
890
891                 for &Spanned { node: ref field, .. } in fields {
892                     if let Some(index) = self.tcx.find_field_index(field.ident, variant) {
893                         if !self.span.filter_generated(field.ident.span) {
894                             let span = self.span_from_span(field.ident.span);
895                             self.dumper.dump_ref(Ref {
896                                 kind: RefKind::Variable,
897                                 span,
898                                 ref_id: id_from_def_id(variant.fields[index].did),
899                             });
900                         }
901                     }
902                     self.visit_pat(&field.pat);
903                 }
904             }
905             _ => visit::walk_pat(self, p),
906         }
907     }
908
909     fn process_var_decl_multi(&mut self, pats: &'l [P<ast::Pat>]) {
910         let mut collector = PathCollector::new();
911         for pattern in pats {
912             // collect paths from the arm's patterns
913             collector.visit_pat(&pattern);
914             self.visit_pat(&pattern);
915         }
916
917         // process collected paths
918         for (id, ident, immut) in collector.collected_idents {
919             match self.save_ctxt.get_path_res(id) {
920                 Res::Local(hir_id) => {
921                     let mut value = if immut == ast::Mutability::Immutable {
922                         self.span.snippet(ident.span)
923                     } else {
924                         "<mutable>".to_owned()
925                     };
926                     let id = self.tcx.hir().hir_to_node_id(hir_id);
927                     let typ = self.save_ctxt
928                         .tables
929                         .node_type_opt(hir_id)
930                         .map(|t| t.to_string())
931                         .unwrap_or_default();
932                     value.push_str(": ");
933                     value.push_str(&typ);
934
935                     if !self.span.filter_generated(ident.span) {
936                         let qualname = format!("{}${}", ident.to_string(), id);
937                         let id = id_from_node_id(id, &self.save_ctxt);
938                         let span = self.span_from_span(ident.span);
939
940                         self.dumper.dump_def(
941                             &Access {
942                                 public: false,
943                                 reachable: false,
944                             },
945                             Def {
946                                 kind: DefKind::Local,
947                                 id,
948                                 span,
949                                 name: ident.to_string(),
950                                 qualname,
951                                 value: typ,
952                                 parent: None,
953                                 children: vec![],
954                                 decl_id: None,
955                                 docs: String::new(),
956                                 sig: None,
957                                 attributes: vec![],
958                             },
959                         );
960                     }
961                 }
962                 Res::Def(HirDefKind::Ctor(..), _) |
963                 Res::Def(HirDefKind::Const, _) |
964                 Res::Def(HirDefKind::AssociatedConst, _) |
965                 Res::Def(HirDefKind::Struct, _) |
966                 Res::Def(HirDefKind::Variant, _) |
967                 Res::Def(HirDefKind::TyAlias, _) |
968                 Res::Def(HirDefKind::AssociatedTy, _) |
969                 Res::SelfTy(..) => {
970                     self.dump_path_ref(id, &ast::Path::from_ident(ident));
971                 }
972                 def => error!(
973                     "unexpected definition kind when processing collected idents: {:?}",
974                     def
975                 ),
976             }
977         }
978
979         for (id, ref path) in collector.collected_paths {
980             self.process_path(id, path);
981         }
982     }
983
984     fn process_var_decl(&mut self, p: &'l ast::Pat, value: String) {
985         // The local could declare multiple new vars, we must walk the
986         // pattern and collect them all.
987         let mut collector = PathCollector::new();
988         collector.visit_pat(&p);
989         self.visit_pat(&p);
990
991         for (id, ident, immut) in collector.collected_idents {
992             let mut value = match immut {
993                 ast::Mutability::Immutable => value.to_string(),
994                 _ => String::new(),
995             };
996             let hir_id = self.tcx.hir().node_to_hir_id(id);
997             let typ = match self.save_ctxt.tables.node_type_opt(hir_id) {
998                 Some(typ) => {
999                     let typ = typ.to_string();
1000                     if !value.is_empty() {
1001                         value.push_str(": ");
1002                     }
1003                     value.push_str(&typ);
1004                     typ
1005                 }
1006                 None => String::new(),
1007             };
1008
1009             // Rust uses the id of the pattern for var lookups, so we'll use it too.
1010             if !self.span.filter_generated(ident.span) {
1011                 let qualname = format!("{}${}", ident.to_string(), id);
1012                 let id = id_from_node_id(id, &self.save_ctxt);
1013                 let span = self.span_from_span(ident.span);
1014
1015                 self.dumper.dump_def(
1016                     &Access {
1017                         public: false,
1018                         reachable: false,
1019                     },
1020                     Def {
1021                         kind: DefKind::Local,
1022                         id,
1023                         span,
1024                         name: ident.to_string(),
1025                         qualname,
1026                         value: typ,
1027                         parent: None,
1028                         children: vec![],
1029                         decl_id: None,
1030                         docs: String::new(),
1031                         sig: None,
1032                         attributes: vec![],
1033                     },
1034                 );
1035             }
1036         }
1037     }
1038
1039     /// Extracts macro use and definition information from the AST node defined
1040     /// by the given NodeId, using the expansion information from the node's
1041     /// span.
1042     ///
1043     /// If the span is not macro-generated, do nothing, else use callee and
1044     /// callsite spans to record macro definition and use data, using the
1045     /// mac_uses and mac_defs sets to prevent multiples.
1046     fn process_macro_use(&mut self, _span: Span) {
1047         // FIXME if we're not dumping the defs (see below), there is no point
1048         // dumping refs either.
1049         // let source_span = span.source_callsite();
1050         // if !self.macro_calls.insert(source_span) {
1051         //     return;
1052         // }
1053
1054         // let data = match self.save_ctxt.get_macro_use_data(span) {
1055         //     None => return,
1056         //     Some(data) => data,
1057         // };
1058
1059         // self.dumper.macro_use(data);
1060
1061         // FIXME write the macro def
1062         // let mut hasher = DefaultHasher::new();
1063         // data.callee_span.hash(&mut hasher);
1064         // let hash = hasher.finish();
1065         // let qualname = format!("{}::{}", data.name, hash);
1066         // Don't write macro definition for imported macros
1067         // if !self.mac_defs.contains(&data.callee_span)
1068         //     && !data.imported {
1069         //     self.mac_defs.insert(data.callee_span);
1070         //     if let Some(sub_span) = self.span.span_for_macro_def_name(data.callee_span) {
1071         //         self.dumper.macro_data(MacroData {
1072         //             span: sub_span,
1073         //             name: data.name.clone(),
1074         //             qualname: qualname.clone(),
1075         //             // FIXME where do macro docs come from?
1076         //             docs: String::new(),
1077         //         }.lower(self.tcx));
1078         //     }
1079         // }
1080     }
1081
1082     fn process_trait_item(&mut self, trait_item: &'l ast::TraitItem, trait_id: DefId) {
1083         self.process_macro_use(trait_item.span);
1084         let vis_span = trait_item.span.shrink_to_lo();
1085         match trait_item.node {
1086             ast::TraitItemKind::Const(ref ty, ref expr) => {
1087                 self.process_assoc_const(
1088                     trait_item.id,
1089                     trait_item.ident,
1090                     &ty,
1091                     expr.as_ref().map(|e| &**e),
1092                     trait_id,
1093                     respan(vis_span, ast::VisibilityKind::Public),
1094                     &trait_item.attrs,
1095                 );
1096             }
1097             ast::TraitItemKind::Method(ref sig, ref body) => {
1098                 self.process_method(
1099                     sig,
1100                     body.as_ref().map(|x| &**x),
1101                     trait_item.id,
1102                     trait_item.ident,
1103                     &trait_item.generics,
1104                     respan(vis_span, ast::VisibilityKind::Public),
1105                     trait_item.span,
1106                 );
1107             }
1108             ast::TraitItemKind::Type(ref bounds, ref default_ty) => {
1109                 // FIXME do something with _bounds (for type refs)
1110                 let name = trait_item.ident.name.to_string();
1111                 let qualname = format!("::{}",
1112                     self.tcx.def_path_str(self.tcx.hir().local_def_id(trait_item.id)));
1113
1114                 if !self.span.filter_generated(trait_item.ident.span) {
1115                     let span = self.span_from_span(trait_item.ident.span);
1116                     let id = id_from_node_id(trait_item.id, &self.save_ctxt);
1117
1118                     self.dumper.dump_def(
1119                         &Access {
1120                             public: true,
1121                             reachable: true,
1122                         },
1123                         Def {
1124                             kind: DefKind::Type,
1125                             id,
1126                             span,
1127                             name,
1128                             qualname,
1129                             value: self.span.snippet(trait_item.span),
1130                             parent: Some(id_from_def_id(trait_id)),
1131                             children: vec![],
1132                             decl_id: None,
1133                             docs: self.save_ctxt.docs_for_attrs(&trait_item.attrs),
1134                             sig: sig::assoc_type_signature(
1135                                 trait_item.id,
1136                                 trait_item.ident,
1137                                 Some(bounds),
1138                                 default_ty.as_ref().map(|ty| &**ty),
1139                                 &self.save_ctxt,
1140                             ),
1141                             attributes: lower_attributes(trait_item.attrs.clone(), &self.save_ctxt),
1142                         },
1143                     );
1144                 }
1145
1146                 if let &Some(ref default_ty) = default_ty {
1147                     self.visit_ty(default_ty)
1148                 }
1149             }
1150             ast::TraitItemKind::Macro(_) => {}
1151         }
1152     }
1153
1154     fn process_impl_item(&mut self, impl_item: &'l ast::ImplItem, impl_id: DefId) {
1155         self.process_macro_use(impl_item.span);
1156         match impl_item.node {
1157             ast::ImplItemKind::Const(ref ty, ref expr) => {
1158                 self.process_assoc_const(
1159                     impl_item.id,
1160                     impl_item.ident,
1161                     &ty,
1162                     Some(expr),
1163                     impl_id,
1164                     impl_item.vis.clone(),
1165                     &impl_item.attrs,
1166                 );
1167             }
1168             ast::ImplItemKind::Method(ref sig, ref body) => {
1169                 self.process_method(
1170                     sig,
1171                     Some(body),
1172                     impl_item.id,
1173                     impl_item.ident,
1174                     &impl_item.generics,
1175                     impl_item.vis.clone(),
1176                     impl_item.span,
1177                 );
1178             }
1179             ast::ImplItemKind::Type(ref ty) => {
1180                 // FIXME: uses of the assoc type should ideally point to this
1181                 // 'def' and the name here should be a ref to the def in the
1182                 // trait.
1183                 self.visit_ty(ty)
1184             }
1185             ast::ImplItemKind::Existential(ref bounds) => {
1186                 // FIXME: uses of the assoc type should ideally point to this
1187                 // 'def' and the name here should be a ref to the def in the
1188                 // trait.
1189                 for bound in bounds.iter() {
1190                     if let ast::GenericBound::Trait(trait_ref, _) = bound {
1191                         self.process_path(trait_ref.trait_ref.ref_id, &trait_ref.trait_ref.path)
1192                     }
1193                 }
1194             }
1195             ast::ImplItemKind::Macro(_) => {}
1196         }
1197     }
1198
1199     /// Dumps imports in a use tree recursively.
1200     ///
1201     /// A use tree is an import that may contain nested braces (RFC 2128). The `use_tree` parameter
1202     /// is the current use tree under scrutiny, while `id` and `prefix` are its corresponding node
1203     /// ID and path. `root_item` is the topmost use tree in the hierarchy.
1204     ///
1205     /// If `use_tree` is a simple or glob import, it is dumped into the analysis data. Otherwise,
1206     /// each child use tree is dumped recursively.
1207     fn process_use_tree(&mut self,
1208                          use_tree: &'l ast::UseTree,
1209                          id: NodeId,
1210                          root_item: &'l ast::Item,
1211                          prefix: &ast::Path) {
1212         let path = &use_tree.prefix;
1213
1214         // The access is calculated using the current tree ID, but with the root tree's visibility
1215         // (since nested trees don't have their own visibility).
1216         let hir_id = self.tcx.hir().node_to_hir_id(id);
1217         let access = access_from!(self.save_ctxt, root_item, hir_id);
1218
1219         // The parent `DefId` of a given use tree is always the enclosing item.
1220         let parent = self.save_ctxt.tcx.hir().opt_local_def_id(id)
1221             .and_then(|id| self.save_ctxt.tcx.parent(id))
1222             .map(id_from_def_id);
1223
1224         match use_tree.kind {
1225             ast::UseTreeKind::Simple(alias, ..) => {
1226                 let ident = use_tree.ident();
1227                 let path = ast::Path {
1228                     segments: prefix.segments
1229                         .iter()
1230                         .chain(path.segments.iter())
1231                         .cloned()
1232                         .collect(),
1233                     span: path.span,
1234                 };
1235
1236                 let sub_span = path.segments.last().unwrap().ident.span;
1237                 if !self.span.filter_generated(sub_span) {
1238                     let ref_id = self.lookup_def_id(id).map(|id| id_from_def_id(id));
1239                     let alias_span = alias.map(|i| self.span_from_span(i.span));
1240                     let span = self.span_from_span(sub_span);
1241                     self.dumper.import(&access, Import {
1242                         kind: ImportKind::Use,
1243                         ref_id,
1244                         span,
1245                         alias_span,
1246                         name: ident.to_string(),
1247                         value: String::new(),
1248                         parent,
1249                     });
1250                     self.write_sub_paths_truncated(&path);
1251                 }
1252             }
1253             ast::UseTreeKind::Glob => {
1254                 let path = ast::Path {
1255                     segments: prefix.segments
1256                         .iter()
1257                         .chain(path.segments.iter())
1258                         .cloned()
1259                         .collect(),
1260                     span: path.span,
1261                 };
1262
1263                 // Make a comma-separated list of names of imported modules.
1264                 let def_id = self.tcx.hir().local_def_id(id);
1265                 let names = self.tcx.names_imported_by_glob_use(def_id);
1266                 let names: Vec<_> = names.iter().map(|n| n.to_string()).collect();
1267
1268                 // Otherwise it's a span with wrong macro expansion info, which
1269                 // we don't want to track anyway, since it's probably macro-internal `use`
1270                 if let Some(sub_span) =
1271                     self.span.sub_span_of_token(use_tree.span, token::BinOp(token::Star))
1272                 {
1273                     if !self.span.filter_generated(use_tree.span) {
1274                         let span = self.span_from_span(sub_span);
1275
1276                         self.dumper.import(&access, Import {
1277                             kind: ImportKind::GlobUse,
1278                             ref_id: None,
1279                             span,
1280                             alias_span: None,
1281                             name: "*".to_owned(),
1282                             value: names.join(", "),
1283                             parent,
1284                         });
1285                         self.write_sub_paths(&path);
1286                     }
1287                 }
1288             }
1289             ast::UseTreeKind::Nested(ref nested_items) => {
1290                 let prefix = ast::Path {
1291                     segments: prefix.segments
1292                         .iter()
1293                         .chain(path.segments.iter())
1294                         .cloned()
1295                         .collect(),
1296                     span: path.span,
1297                 };
1298                 for &(ref tree, id) in nested_items {
1299                     self.process_use_tree(tree, id, root_item, &prefix);
1300                 }
1301             }
1302         }
1303     }
1304
1305     fn process_bounds(&mut self, bounds: &'l ast::GenericBounds) {
1306         for bound in bounds {
1307             if let ast::GenericBound::Trait(ref trait_ref, _) = *bound {
1308                 self.process_path(trait_ref.trait_ref.ref_id, &trait_ref.trait_ref.path)
1309             }
1310         }
1311     }
1312 }
1313
1314 impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> Visitor<'l> for DumpVisitor<'l, 'tcx, 'll, O> {
1315     fn visit_mod(&mut self, m: &'l ast::Mod, span: Span, attrs: &[ast::Attribute], id: NodeId) {
1316         // Since we handle explicit modules ourselves in visit_item, this should
1317         // only get called for the root module of a crate.
1318         assert_eq!(id, ast::CRATE_NODE_ID);
1319
1320         let qualname = format!("::{}",
1321             self.tcx.def_path_str(self.tcx.hir().local_def_id(id)));
1322
1323         let cm = self.tcx.sess.source_map();
1324         let filename = cm.span_to_filename(span);
1325         let data_id = id_from_node_id(id, &self.save_ctxt);
1326         let children = m.items
1327             .iter()
1328             .map(|i| id_from_node_id(i.id, &self.save_ctxt))
1329             .collect();
1330         let span = self.span_from_span(span);
1331
1332         self.dumper.dump_def(
1333             &Access {
1334                 public: true,
1335                 reachable: true,
1336             },
1337             Def {
1338                 kind: DefKind::Mod,
1339                 id: data_id,
1340                 name: String::new(),
1341                 qualname,
1342                 span,
1343                 value: filename.to_string(),
1344                 children,
1345                 parent: None,
1346                 decl_id: None,
1347                 docs: self.save_ctxt.docs_for_attrs(attrs),
1348                 sig: None,
1349                 attributes: lower_attributes(attrs.to_owned(), &self.save_ctxt),
1350             },
1351         );
1352         self.nest_scope(id, |v| visit::walk_mod(v, m));
1353     }
1354
1355     fn visit_item(&mut self, item: &'l ast::Item) {
1356         use syntax::ast::ItemKind::*;
1357         self.process_macro_use(item.span);
1358         match item.node {
1359             Use(ref use_tree) => {
1360                 let prefix = ast::Path {
1361                     segments: vec![],
1362                     span: DUMMY_SP,
1363                 };
1364                 self.process_use_tree(use_tree, item.id, item, &prefix);
1365             }
1366             ExternCrate(_) => {
1367                 let name_span = item.ident.span;
1368                 if !self.span.filter_generated(name_span) {
1369                     let span = self.span_from_span(name_span);
1370                     let parent = self.save_ctxt.tcx.hir().opt_local_def_id(item.id)
1371                         .and_then(|id| self.save_ctxt.tcx.parent(id))
1372                         .map(id_from_def_id);
1373                     self.dumper.import(
1374                         &Access {
1375                             public: false,
1376                             reachable: false,
1377                         },
1378                         Import {
1379                             kind: ImportKind::ExternCrate,
1380                             ref_id: None,
1381                             span,
1382                             alias_span: None,
1383                             name: item.ident.to_string(),
1384                             value: String::new(),
1385                             parent,
1386                         },
1387                     );
1388                 }
1389             }
1390             Fn(ref decl, .., ref ty_params, ref body) => {
1391                 self.process_fn(item, &decl, ty_params, &body)
1392             }
1393             Static(ref typ, _, ref expr) => self.process_static_or_const_item(item, typ, expr),
1394             Const(ref typ, ref expr) => self.process_static_or_const_item(item, &typ, &expr),
1395             Struct(ref def, ref ty_params) | Union(ref def, ref ty_params) => {
1396                 self.process_struct(item, def, ty_params)
1397             }
1398             Enum(ref def, ref ty_params) => self.process_enum(item, def, ty_params),
1399             Impl(.., ref ty_params, ref trait_ref, ref typ, ref impl_items) => {
1400                 self.process_impl(item, ty_params, trait_ref, &typ, impl_items)
1401             }
1402             Trait(_, _, ref generics, ref trait_refs, ref methods) => {
1403                 self.process_trait(item, generics, trait_refs, methods)
1404             }
1405             Mod(ref m) => {
1406                 self.process_mod(item);
1407                 self.nest_scope(item.id, |v| visit::walk_mod(v, m));
1408             }
1409             Ty(ref ty, ref ty_params) => {
1410                 let qualname = format!("::{}",
1411                     self.tcx.def_path_str(self.tcx.hir().local_def_id(item.id)));
1412                 let value = ty_to_string(&ty);
1413                 if !self.span.filter_generated(item.ident.span) {
1414                     let span = self.span_from_span(item.ident.span);
1415                     let id = id_from_node_id(item.id, &self.save_ctxt);
1416                     let hir_id = self.tcx.hir().node_to_hir_id(item.id);
1417
1418                     self.dumper.dump_def(
1419                         &access_from!(self.save_ctxt, item, hir_id),
1420                         Def {
1421                             kind: DefKind::Type,
1422                             id,
1423                             span,
1424                             name: item.ident.to_string(),
1425                             qualname: qualname.clone(),
1426                             value,
1427                             parent: None,
1428                             children: vec![],
1429                             decl_id: None,
1430                             docs: self.save_ctxt.docs_for_attrs(&item.attrs),
1431                             sig: sig::item_signature(item, &self.save_ctxt),
1432                             attributes: lower_attributes(item.attrs.clone(), &self.save_ctxt),
1433                         },
1434                     );
1435                 }
1436
1437                 self.visit_ty(&ty);
1438                 self.process_generic_params(ty_params, &qualname, item.id);
1439             }
1440             Existential(ref _bounds, ref ty_params) => {
1441                 let qualname = format!("::{}",
1442                     self.tcx.def_path_str(self.tcx.hir().local_def_id(item.id)));
1443                 // FIXME do something with _bounds
1444                 let value = String::new();
1445                 if !self.span.filter_generated(item.ident.span) {
1446                     let span = self.span_from_span(item.ident.span);
1447                     let id = id_from_node_id(item.id, &self.save_ctxt);
1448                     let hir_id = self.tcx.hir().node_to_hir_id(item.id);
1449
1450                     self.dumper.dump_def(
1451                         &access_from!(self.save_ctxt, item, hir_id),
1452                         Def {
1453                             kind: DefKind::Type,
1454                             id,
1455                             span,
1456                             name: item.ident.to_string(),
1457                             qualname: qualname.clone(),
1458                             value,
1459                             parent: None,
1460                             children: vec![],
1461                             decl_id: None,
1462                             docs: self.save_ctxt.docs_for_attrs(&item.attrs),
1463                             sig: sig::item_signature(item, &self.save_ctxt),
1464                             attributes: lower_attributes(item.attrs.clone(), &self.save_ctxt),
1465                         },
1466                     );
1467                 }
1468
1469                 self.process_generic_params(ty_params, &qualname, item.id);
1470             }
1471             Mac(_) => (),
1472             _ => visit::walk_item(self, item),
1473         }
1474     }
1475
1476     fn visit_generics(&mut self, generics: &'l ast::Generics) {
1477         for param in &generics.params {
1478             match param.kind {
1479                 ast::GenericParamKind::Lifetime { .. } => {}
1480                 ast::GenericParamKind::Type { ref default, .. } => {
1481                     self.process_bounds(&param.bounds);
1482                     if let Some(ref ty) = default {
1483                         self.visit_ty(&ty);
1484                     }
1485                 }
1486                 ast::GenericParamKind::Const { ref ty } => {
1487                     self.process_bounds(&param.bounds);
1488                     self.visit_ty(&ty);
1489                 }
1490             }
1491         }
1492         for pred in &generics.where_clause.predicates {
1493             if let ast::WherePredicate::BoundPredicate(ref wbp) = *pred {
1494                 self.process_bounds(&wbp.bounds);
1495                 self.visit_ty(&wbp.bounded_ty);
1496             }
1497         }
1498     }
1499
1500     fn visit_ty(&mut self, t: &'l ast::Ty) {
1501         self.process_macro_use(t.span);
1502         match t.node {
1503             ast::TyKind::Path(_, ref path) => {
1504                 if generated_code(t.span) {
1505                     return;
1506                 }
1507
1508                 if let Some(id) = self.lookup_def_id(t.id) {
1509                     let sub_span = path.segments.last().unwrap().ident.span;
1510                     let span = self.span_from_span(sub_span);
1511                     self.dumper.dump_ref(Ref {
1512                         kind: RefKind::Type,
1513                         span,
1514                         ref_id: id_from_def_id(id),
1515                     });
1516                 }
1517
1518                 self.write_sub_paths_truncated(path);
1519                 visit::walk_path(self, path);
1520             }
1521             ast::TyKind::Array(ref element, ref length) => {
1522                 self.visit_ty(element);
1523                 self.nest_tables(length.id, |v| v.visit_expr(&length.value));
1524             }
1525             _ => visit::walk_ty(self, t),
1526         }
1527     }
1528
1529     fn visit_expr(&mut self, ex: &'l ast::Expr) {
1530         debug!("visit_expr {:?}", ex.node);
1531         self.process_macro_use(ex.span);
1532         match ex.node {
1533             ast::ExprKind::Struct(ref path, ref fields, ref base) => {
1534                 let hir_expr = self.save_ctxt.tcx.hir().expect_expr(ex.id);
1535                 let adt = match self.save_ctxt.tables.expr_ty_opt(&hir_expr) {
1536                     Some(ty) if ty.ty_adt_def().is_some() => ty.ty_adt_def().unwrap(),
1537                     _ => {
1538                         visit::walk_expr(self, ex);
1539                         return;
1540                     }
1541                 };
1542                 let node_id = self.save_ctxt.tcx.hir().hir_to_node_id(hir_expr.hir_id);
1543                 let res = self.save_ctxt.get_path_res(node_id);
1544                 self.process_struct_lit(ex, path, fields, adt.variant_of_res(res), base)
1545             }
1546             ast::ExprKind::MethodCall(ref seg, ref args) => self.process_method_call(ex, seg, args),
1547             ast::ExprKind::Field(ref sub_ex, _) => {
1548                 self.visit_expr(&sub_ex);
1549
1550                 if let Some(field_data) = self.save_ctxt.get_expr_data(ex) {
1551                     down_cast_data!(field_data, RefData, ex.span);
1552                     if !generated_code(ex.span) {
1553                         self.dumper.dump_ref(field_data);
1554                     }
1555                 }
1556             }
1557             ast::ExprKind::Closure(_, _, _, ref decl, ref body, _fn_decl_span) => {
1558                 let id = format!("${}", ex.id);
1559
1560                 // walk arg and return types
1561                 for arg in &decl.inputs {
1562                     self.visit_ty(&arg.ty);
1563                 }
1564
1565                 if let ast::FunctionRetTy::Ty(ref ret_ty) = decl.output {
1566                     self.visit_ty(&ret_ty);
1567                 }
1568
1569                 // walk the body
1570                 self.nest_tables(ex.id, |v| {
1571                     v.process_formals(&decl.inputs, &id);
1572                     v.nest_scope(ex.id, |v| v.visit_expr(body))
1573                 });
1574             }
1575             ast::ExprKind::ForLoop(ref pattern, ref subexpression, ref block, _) => {
1576                 let value = self.span.snippet(subexpression.span);
1577                 self.process_var_decl(pattern, value);
1578                 debug!("for loop, walk sub-expr: {:?}", subexpression.node);
1579                 self.visit_expr(subexpression);
1580                 visit::walk_block(self, block);
1581             }
1582             ast::ExprKind::WhileLet(ref pats, ref subexpression, ref block, _) => {
1583                 self.process_var_decl_multi(pats);
1584                 debug!("for loop, walk sub-expr: {:?}", subexpression.node);
1585                 self.visit_expr(subexpression);
1586                 visit::walk_block(self, block);
1587             }
1588             ast::ExprKind::IfLet(ref pats, ref subexpression, ref block, ref opt_else) => {
1589                 self.process_var_decl_multi(pats);
1590                 self.visit_expr(subexpression);
1591                 visit::walk_block(self, block);
1592                 opt_else.as_ref().map(|el| self.visit_expr(el));
1593             }
1594             ast::ExprKind::Repeat(ref element, ref count) => {
1595                 self.visit_expr(element);
1596                 self.nest_tables(count.id, |v| v.visit_expr(&count.value));
1597             }
1598             // In particular, we take this branch for call and path expressions,
1599             // where we'll index the idents involved just by continuing to walk.
1600             _ => visit::walk_expr(self, ex),
1601         }
1602     }
1603
1604     fn visit_mac(&mut self, mac: &'l ast::Mac) {
1605         // These shouldn't exist in the AST at this point, log a span bug.
1606         span_bug!(
1607             mac.span,
1608             "macro invocation should have been expanded out of AST"
1609         );
1610     }
1611
1612     fn visit_pat(&mut self, p: &'l ast::Pat) {
1613         self.process_macro_use(p.span);
1614         self.process_pat(p);
1615     }
1616
1617     fn visit_arm(&mut self, arm: &'l ast::Arm) {
1618         self.process_var_decl_multi(&arm.pats);
1619         match arm.guard {
1620             Some(ast::Guard::If(ref expr)) => self.visit_expr(expr),
1621             _ => {}
1622         }
1623         self.visit_expr(&arm.body);
1624     }
1625
1626     fn visit_path(&mut self, p: &'l ast::Path, id: NodeId) {
1627         self.process_path(id, p);
1628     }
1629
1630     fn visit_stmt(&mut self, s: &'l ast::Stmt) {
1631         self.process_macro_use(s.span);
1632         visit::walk_stmt(self, s)
1633     }
1634
1635     fn visit_local(&mut self, l: &'l ast::Local) {
1636         self.process_macro_use(l.span);
1637         let value = l.init
1638             .as_ref()
1639             .map(|i| self.span.snippet(i.span))
1640             .unwrap_or_default();
1641         self.process_var_decl(&l.pat, value);
1642
1643         // Just walk the initialiser and type (don't want to walk the pattern again).
1644         walk_list!(self, visit_ty, &l.ty);
1645         walk_list!(self, visit_expr, &l.init);
1646     }
1647
1648     fn visit_foreign_item(&mut self, item: &'l ast::ForeignItem) {
1649         let hir_id = self.tcx.hir().node_to_hir_id(item.id);
1650         let access = access_from!(self.save_ctxt, item, hir_id);
1651
1652         match item.node {
1653             ast::ForeignItemKind::Fn(ref decl, ref generics) => {
1654                 if let Some(fn_data) = self.save_ctxt.get_extern_item_data(item) {
1655                     down_cast_data!(fn_data, DefData, item.span);
1656
1657                     self.process_generic_params(generics, &fn_data.qualname, item.id);
1658                     self.dumper.dump_def(&access, fn_data);
1659                 }
1660
1661                 for arg in &decl.inputs {
1662                     self.visit_ty(&arg.ty);
1663                 }
1664
1665                 if let ast::FunctionRetTy::Ty(ref ret_ty) = decl.output {
1666                     self.visit_ty(&ret_ty);
1667                 }
1668             }
1669             ast::ForeignItemKind::Static(ref ty, _) => {
1670                 if let Some(var_data) = self.save_ctxt.get_extern_item_data(item) {
1671                     down_cast_data!(var_data, DefData, item.span);
1672                     self.dumper.dump_def(&access, var_data);
1673                 }
1674
1675                 self.visit_ty(ty);
1676             }
1677             ast::ForeignItemKind::Ty => {
1678                 if let Some(var_data) = self.save_ctxt.get_extern_item_data(item) {
1679                     down_cast_data!(var_data, DefData, item.span);
1680                     self.dumper.dump_def(&access, var_data);
1681                 }
1682             }
1683             ast::ForeignItemKind::Macro(..) => {}
1684         }
1685     }
1686 }