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