]> git.proxmox.com Git - rustc.git/blame - src/librustc_save_analysis/dump_visitor.rs
New upstream version 1.13.0+dfsg1
[rustc.git] / src / librustc_save_analysis / dump_visitor.rs
CommitLineData
d9579d0f
AL
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
54a0048b 11//! Write the output of rustc's analysis to an implementor of Dump. The data is
d9579d0f
AL
12//! primarily designed to be used as input to the DXR tool, specifically its
13//! Rust plugin. It could also be used by IDEs or other code browsing, search, or
14//! cross-referencing tools.
15//!
16//! Dumping the analysis is implemented by walking the AST and getting a bunch of
17//! info out from all over the place. We use Def IDs to identify objects. The
18//! tricky part is getting syntactic (span, source text) and semantic (reference
19//! Def IDs) information for parts of expressions which the compiler has discarded.
20//! E.g., in a path `foo::bar::baz`, the compiler only keeps a span for the whole
21//! path and a reference to `baz`, but we want spans and references for all three
22//! idents.
23//!
24//! SpanUtils is used to manipulate spans. In particular, to extract sub-spans
25//! from spans (e.g., the span for `bar` from the above example path).
54a0048b
SL
26//! DumpVisitor walks the AST and processes it, and an implementor of Dump
27//! is used for recording the output in a format-agnostic way (see CsvDumper
28//! for an example).
d9579d0f 29
9e0c209e 30use rustc::hir;
54a0048b 31use rustc::hir::def::Def;
9e0c209e
SL
32use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
33use rustc::hir::map::{Node, NodeItem};
54a0048b 34use rustc::session::Session;
3157f602 35use rustc::ty::{self, TyCtxt, ImplOrTraitItem, ImplOrTraitItemContainer};
d9579d0f 36
7453a54e 37use std::collections::HashSet;
9e0c209e 38use std::collections::hash_map::DefaultHasher;
54a0048b 39use std::hash::*;
d9579d0f 40
9e0c209e 41use syntax::ast::{self, NodeId, PatKind, Attribute, CRATE_NODE_ID};
c1a9b12d 42use syntax::parse::token::{self, keywords};
d9579d0f 43use syntax::visit::{self, Visitor};
a7813a04 44use syntax::print::pprust::{path_to_string, ty_to_string, bounds_to_string, generics_to_string};
d9579d0f 45use syntax::ptr::P;
3157f602
XL
46use syntax::codemap::Spanned;
47use syntax_pos::*;
d9579d0f 48
9e0c209e 49use super::{escape, generated_code, SaveContext, PathCollector, docs_for_attrs};
54a0048b
SL
50use super::data::*;
51use super::dump::Dump;
9e0c209e 52use super::external_data::{Lower, make_def_id};
d9579d0f 53use super::span_utils::SpanUtils;
54a0048b 54use super::recorder;
d9579d0f 55
62682a34 56macro_rules! down_cast_data {
54a0048b 57 ($id:ident, $kind:ident, $sp:expr) => {
62682a34
SL
58 let $id = if let super::Data::$kind(data) = $id {
59 data
60 } else {
54a0048b 61 span_bug!($sp, "unexpected data kind: {:?}", $id);
5bcae85e 62 };
62682a34
SL
63 };
64}
d9579d0f 65
a7813a04 66pub struct DumpVisitor<'l, 'tcx: 'l, 'll, D: 'll> {
d9579d0f
AL
67 save_ctxt: SaveContext<'l, 'tcx>,
68 sess: &'l Session,
a7813a04 69 tcx: TyCtxt<'l, 'tcx, 'tcx>,
b039eaaf 70 analysis: &'l ty::CrateAnalysis<'l>,
a7813a04 71 dumper: &'ll mut D,
d9579d0f
AL
72
73 span: SpanUtils<'l>,
d9579d0f 74
e9174d1e 75 cur_scope: NodeId,
7453a54e
SL
76
77 // Set of macro definition (callee) spans, and the set
78 // of macro use (callsite) spans. We store these to ensure
79 // we only write one macro def per unique macro definition, and
80 // one macro use per unique callsite span.
81 mac_defs: HashSet<Span>,
82 mac_uses: HashSet<Span>,
d9579d0f
AL
83}
84
a7813a04
XL
85impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
86 pub fn new(tcx: TyCtxt<'l, 'tcx, 'tcx>,
87 save_ctxt: SaveContext<'l, 'tcx>,
b039eaaf 88 analysis: &'l ty::CrateAnalysis<'l>,
a7813a04
XL
89 dumper: &'ll mut D)
90 -> DumpVisitor<'l, 'tcx, 'll, D> {
c1a9b12d 91 let span_utils = SpanUtils::new(&tcx.sess);
54a0048b 92 DumpVisitor {
62682a34
SL
93 sess: &tcx.sess,
94 tcx: tcx,
a7813a04 95 save_ctxt: save_ctxt,
d9579d0f 96 analysis: analysis,
54a0048b 97 dumper: dumper,
62682a34 98 span: span_utils.clone(),
9e0c209e 99 cur_scope: CRATE_NODE_ID,
7453a54e
SL
100 mac_defs: HashSet::new(),
101 mac_uses: HashSet::new(),
d9579d0f
AL
102 }
103 }
104
e9174d1e 105 fn nest<F>(&mut self, scope_id: NodeId, f: F)
a7813a04 106 where F: FnOnce(&mut DumpVisitor<'l, 'tcx, 'll, D>)
d9579d0f
AL
107 {
108 let parent_scope = self.cur_scope;
109 self.cur_scope = scope_id;
110 f(self);
111 self.cur_scope = parent_scope;
112 }
113
114 pub fn dump_crate_info(&mut self, name: &str, krate: &ast::Crate) {
92a42be0 115 let source_file = self.tcx.sess.local_crate_source_file.as_ref();
54a0048b
SL
116 let crate_root = source_file.map(|source_file| {
117 match source_file.file_name() {
92a42be0
SL
118 Some(_) => source_file.parent().unwrap().display().to_string(),
119 None => source_file.display().to_string(),
54a0048b
SL
120 }
121 });
122
123 // Info about all the external crates referenced from this crate.
124 let external_crates = self.save_ctxt.get_external_crates().into_iter().map(|c| {
a7813a04 125 let lo_loc = self.span.sess.codemap().lookup_char_pos(c.span.lo);
54a0048b
SL
126 ExternalCrateData {
127 name: c.name,
9e0c209e 128 num: CrateNum::from_u32(c.number),
a7813a04 129 file_name: SpanUtils::make_path_string(&lo_loc.file.name),
54a0048b
SL
130 }
131 }).collect();
92a42be0 132
d9579d0f 133 // The current crate.
54a0048b
SL
134 let data = CratePreludeData {
135 crate_name: name.into(),
a7813a04
XL
136 crate_root: crate_root.unwrap_or("<no source>".to_owned()),
137 external_crates: external_crates,
138 span: krate.span,
54a0048b 139 };
d9579d0f 140
a7813a04 141 self.dumper.crate_prelude(data.lower(self.tcx));
d9579d0f
AL
142 }
143
144 // Return all non-empty prefixes of a path.
145 // For each prefix, we return the span for the last segment in the prefix and
146 // a str representation of the entire prefix.
147 fn process_path_prefixes(&self, path: &ast::Path) -> Vec<(Span, String)> {
148 let spans = self.span.spans_for_path_segments(path);
149
150 // Paths to enums seem to not match their spans - the span includes all the
151 // variants too. But they seem to always be at the end, so I hope we can cope with
152 // always using the first ones. So, only error out if we don't have enough spans.
153 // What could go wrong...?
154 if spans.len() < path.segments.len() {
7453a54e
SL
155 if generated_code(path.span) {
156 return vec!();
157 }
b039eaaf
SL
158 error!("Mis-calculated spans for path '{}'. Found {} spans, expected {}. Found spans:",
159 path_to_string(path),
160 spans.len(),
161 path.segments.len());
d9579d0f
AL
162 for s in &spans {
163 let loc = self.sess.codemap().lookup_char_pos(s.lo);
164 error!(" '{}' in {}, line {}",
b039eaaf
SL
165 self.span.snippet(*s),
166 loc.file.name,
167 loc.line);
d9579d0f
AL
168 }
169 return vec!();
170 }
171
172 let mut result: Vec<(Span, String)> = vec!();
173
174 let mut segs = vec!();
62682a34 175 for (i, (seg, span)) in path.segments.iter().zip(&spans).enumerate() {
d9579d0f 176 segs.push(seg.clone());
e9174d1e
SL
177 let sub_path = ast::Path {
178 span: *span, // span for the last segment
179 global: path.global,
180 segments: segs,
181 };
d9579d0f
AL
182 let qualname = if i == 0 && path.global {
183 format!("::{}", path_to_string(&sub_path))
184 } else {
185 path_to_string(&sub_path)
186 };
187 result.push((*span, qualname));
188 segs = sub_path.segments;
189 }
190
191 result
192 }
193
194 // The global arg allows us to override the global-ness of the path (which
195 // actually means 'does the path start with `::`', rather than 'is the path
196 // semantically global). We use the override for `use` imports (etc.) where
197 // the syntax is non-global, but the semantics are global.
198 fn write_sub_paths(&mut self, path: &ast::Path, global: bool) {
199 let sub_paths = self.process_path_prefixes(path);
200 for (i, &(ref span, ref qualname)) in sub_paths.iter().enumerate() {
201 let qualname = if i == 0 && global && !path.global {
202 format!("::{}", qualname)
203 } else {
204 qualname.clone()
205 };
a7813a04 206 self.dumper.mod_ref(ModRefData {
54a0048b
SL
207 span: *span,
208 qualname: qualname,
209 scope: self.cur_scope,
210 ref_id: None
a7813a04 211 }.lower(self.tcx));
d9579d0f
AL
212 }
213 }
214
215 // As write_sub_paths, but does not process the last ident in the path (assuming it
216 // will be processed elsewhere). See note on write_sub_paths about global.
217 fn write_sub_paths_truncated(&mut self, path: &ast::Path, global: bool) {
218 let sub_paths = self.process_path_prefixes(path);
219 let len = sub_paths.len();
220 if len <= 1 {
221 return;
222 }
223
224 let sub_paths = &sub_paths[..len-1];
225 for (i, &(ref span, ref qualname)) in sub_paths.iter().enumerate() {
226 let qualname = if i == 0 && global && !path.global {
227 format!("::{}", qualname)
228 } else {
229 qualname.clone()
230 };
a7813a04 231 self.dumper.mod_ref(ModRefData {
54a0048b
SL
232 span: *span,
233 qualname: qualname,
234 scope: self.cur_scope,
235 ref_id: None
a7813a04 236 }.lower(self.tcx));
d9579d0f
AL
237 }
238 }
239
240 // As write_sub_paths, but expects a path of the form module_path::trait::method
241 // Where trait could actually be a struct too.
242 fn write_sub_path_trait_truncated(&mut self, path: &ast::Path) {
243 let sub_paths = self.process_path_prefixes(path);
244 let len = sub_paths.len();
245 if len <= 1 {
246 return;
247 }
248 let sub_paths = &sub_paths[.. (len-1)];
249
250 // write the trait part of the sub-path
251 let (ref span, ref qualname) = sub_paths[len-2];
a7813a04 252 self.dumper.type_ref(TypeRefData {
54a0048b
SL
253 ref_id: None,
254 span: *span,
255 qualname: qualname.to_owned(),
9e0c209e 256 scope: CRATE_NODE_ID
a7813a04 257 }.lower(self.tcx));
d9579d0f
AL
258
259 // write the other sub-paths
260 if len <= 2 {
261 return;
262 }
263 let sub_paths = &sub_paths[..len-2];
264 for &(ref span, ref qualname) in sub_paths {
a7813a04 265 self.dumper.mod_ref(ModRefData {
54a0048b
SL
266 span: *span,
267 qualname: qualname.to_owned(),
268 scope: self.cur_scope,
269 ref_id: None
a7813a04 270 }.lower(self.tcx));
d9579d0f
AL
271 }
272 }
273
274 // looks up anything, not just a type
275 fn lookup_type_ref(&self, ref_id: NodeId) -> Option<DefId> {
9e0c209e
SL
276 self.tcx.expect_def_or_none(ref_id).and_then(|def| {
277 match def {
278 Def::PrimTy(..) => None,
279 Def::SelfTy(..) => None,
280 def => Some(def.def_id()),
281 }
282 })
d9579d0f
AL
283 }
284
54a0048b
SL
285 fn process_def_kind(&mut self,
286 ref_id: NodeId,
287 span: Span,
288 sub_span: Option<Span>,
289 def_id: DefId,
290 scope: NodeId) {
291 if self.span.filter_generated(sub_span, span) {
292 return;
293 }
294
3157f602 295 let def = self.tcx.expect_def(ref_id);
d9579d0f 296 match def {
9e0c209e 297 Def::Mod(_) => {
a7813a04 298 self.dumper.mod_ref(ModRefData {
54a0048b
SL
299 span: sub_span.expect("No span found for mod ref"),
300 ref_id: Some(def_id),
301 scope: scope,
302 qualname: String::new()
a7813a04 303 }.lower(self.tcx));
54a0048b
SL
304 }
305 Def::Struct(..) |
9e0c209e 306 Def::Union(..) |
7453a54e
SL
307 Def::Enum(..) |
308 Def::TyAlias(..) |
309 Def::AssociatedTy(..) |
54a0048b 310 Def::Trait(_) => {
a7813a04 311 self.dumper.type_ref(TypeRefData {
54a0048b
SL
312 span: sub_span.expect("No span found for type ref"),
313 ref_id: Some(def_id),
314 scope: scope,
315 qualname: String::new()
a7813a04 316 }.lower(self.tcx));
54a0048b 317 }
9e0c209e 318 Def::Static(..) |
7453a54e
SL
319 Def::Const(_) |
320 Def::AssociatedConst(..) |
321 Def::Local(..) |
322 Def::Variant(..) |
54a0048b 323 Def::Upvar(..) => {
a7813a04 324 self.dumper.variable_ref(VariableRefData {
54a0048b
SL
325 span: sub_span.expect("No span found for var ref"),
326 ref_id: def_id,
327 scope: scope,
328 name: String::new()
a7813a04 329 }.lower(self.tcx));
54a0048b
SL
330 }
331 Def::Fn(..) => {
a7813a04 332 self.dumper.function_ref(FunctionRefData {
54a0048b
SL
333 span: sub_span.expect("No span found for fn ref"),
334 ref_id: def_id,
335 scope: scope
a7813a04 336 }.lower(self.tcx));
54a0048b 337 }
7453a54e
SL
338 Def::SelfTy(..) |
339 Def::Label(_) |
340 Def::TyParam(..) |
341 Def::Method(..) |
342 Def::PrimTy(_) |
343 Def::Err => {
54a0048b
SL
344 span_bug!(span,
345 "process_def_kind for unexpected item: {:?}",
346 def);
e9174d1e 347 }
d9579d0f
AL
348 }
349 }
350
351 fn process_formals(&mut self, formals: &Vec<ast::Arg>, qualname: &str) {
352 for arg in formals {
353 self.visit_pat(&arg.pat);
354 let mut collector = PathCollector::new();
355 collector.visit_pat(&arg.pat);
356 let span_utils = self.span.clone();
9e0c209e 357 for &(id, ref p, ..) in &collector.collected_paths {
62682a34 358 let typ = self.tcx.node_types().get(&id).unwrap().to_string();
d9579d0f
AL
359 // get the span only for the name of the variable (I hope the path is only ever a
360 // variable name, but who knows?)
54a0048b
SL
361 let sub_span = span_utils.span_for_last_ident(p.span);
362 if !self.span.filter_generated(sub_span, p.span) {
a7813a04 363 self.dumper.variable(VariableData {
54a0048b 364 id: id,
3157f602 365 kind: VariableKind::Local,
54a0048b
SL
366 span: sub_span.expect("No span found for variable"),
367 name: path_to_string(p),
368 qualname: format!("{}::{}", qualname, path_to_string(p)),
369 type_value: typ,
370 value: String::new(),
9e0c209e
SL
371 scope: CRATE_NODE_ID,
372 parent: None,
373 visibility: Visibility::Inherited,
374 docs: String::new(),
a7813a04 375 }.lower(self.tcx));
54a0048b 376 }
d9579d0f
AL
377 }
378 }
379 }
380
c1a9b12d
SL
381 fn process_method(&mut self,
382 sig: &ast::MethodSig,
d9579d0f 383 body: Option<&ast::Block>,
c1a9b12d
SL
384 id: ast::NodeId,
385 name: ast::Name,
9e0c209e
SL
386 vis: Visibility,
387 attrs: &[Attribute],
d9579d0f 388 span: Span) {
c1a9b12d 389 debug!("process_method: {}:{}", id, name);
d9579d0f 390
7453a54e 391 if let Some(method_data) = self.save_ctxt.get_method_data(id, name, span) {
d9579d0f 392
a7813a04 393 let sig_str = ::make_signature(&sig.decl, &sig.generics);
7453a54e 394 if body.is_some() {
7453a54e 395 self.process_formals(&sig.decl.inputs, &method_data.qualname);
7453a54e 396 }
3157f602
XL
397
398 // If the method is defined in an impl, then try and find the corresponding
399 // method decl in a trait, and if there is one, make a decl_id for it. This
400 // requires looking up the impl, then the trait, then searching for a method
401 // with the right name.
402 if !self.span.filter_generated(Some(method_data.span), span) {
403 let container =
404 self.tcx.impl_or_trait_item(self.tcx.map.local_def_id(id)).container();
9e0c209e
SL
405 let mut trait_id;
406 let mut decl_id = None;
407 match container {
408 ImplOrTraitItemContainer::ImplContainer(id) => {
409 trait_id = self.tcx.trait_id_of_impl(id);
410
411 match trait_id {
412 Some(id) => {
413 for item in &**self.tcx.trait_items(id) {
414 if let &ImplOrTraitItem::MethodTraitItem(ref m) = item {
415 if m.name == name {
416 decl_id = Some(m.def_id);
417 break;
418 }
419 }
420 }
421 }
422 None => {
423 if let Some(NodeItem(item)) = self.tcx.map.get_if_local(id) {
424 if let hir::ItemImpl(_, _, _, _, ref ty, _) = item.node {
425 trait_id = self.lookup_type_ref(ty.id);
426 }
3157f602
XL
427 }
428 }
429 }
9e0c209e
SL
430 }
431 ImplOrTraitItemContainer::TraitContainer(id) => {
432 trait_id = Some(id);
433 }
434 }
3157f602
XL
435
436 self.dumper.method(MethodData {
437 id: method_data.id,
438 name: method_data.name,
439 span: method_data.span,
440 scope: method_data.scope,
441 qualname: method_data.qualname.clone(),
442 value: sig_str,
443 decl_id: decl_id,
9e0c209e
SL
444 parent: trait_id,
445 visibility: vis,
446 docs: docs_for_attrs(attrs),
3157f602
XL
447 }.lower(self.tcx));
448 }
449
7453a54e 450 self.process_generic_params(&sig.generics, span, &method_data.qualname, id);
d9579d0f
AL
451 }
452
453 // walk arg and return types
454 for arg in &sig.decl.inputs {
455 self.visit_ty(&arg.ty);
456 }
457
7453a54e 458 if let ast::FunctionRetTy::Ty(ref ret_ty) = sig.decl.output {
d9579d0f
AL
459 self.visit_ty(ret_ty);
460 }
461
462 // walk the fn body
463 if let Some(body) = body {
464 self.nest(id, |v| v.visit_block(body));
465 }
d9579d0f
AL
466 }
467
62682a34
SL
468 fn process_trait_ref(&mut self, trait_ref: &ast::TraitRef) {
469 let trait_ref_data = self.save_ctxt.get_trait_ref_data(trait_ref, self.cur_scope);
470 if let Some(trait_ref_data) = trait_ref_data {
54a0048b 471 if !self.span.filter_generated(Some(trait_ref_data.span), trait_ref.path.span) {
a7813a04 472 self.dumper.type_ref(trait_ref_data.lower(self.tcx));
54a0048b
SL
473 }
474
62682a34 475 visit::walk_path(self, &trait_ref.path);
d9579d0f
AL
476 }
477 }
478
e9174d1e 479 fn process_struct_field_def(&mut self, field: &ast::StructField, parent_id: NodeId) {
62682a34 480 let field_data = self.save_ctxt.get_field_data(field, parent_id);
54a0048b
SL
481 if let Some(mut field_data) = field_data {
482 if !self.span.filter_generated(Some(field_data.span), field.span) {
54a0048b 483 field_data.value = String::new();
a7813a04 484 self.dumper.variable(field_data.lower(self.tcx));
54a0048b 485 }
d9579d0f
AL
486 }
487 }
488
489 // Dump generic params bindings, then visit_generics
490 fn process_generic_params(&mut self,
e9174d1e 491 generics: &ast::Generics,
d9579d0f
AL
492 full_span: Span,
493 prefix: &str,
494 id: NodeId) {
495 // We can't only use visit_generics since we don't have spans for param
496 // bindings, so we reparse the full_span to get those sub spans.
497 // However full span is the entire enum/fn/struct block, so we only want
498 // the first few to match the number of generics we're looking for.
499 let param_sub_spans = self.span.spans_for_ty_params(full_span,
b039eaaf 500 (generics.ty_params.len() as isize));
62682a34 501 for (param, param_ss) in generics.ty_params.iter().zip(param_sub_spans) {
a7813a04 502 let name = escape(self.span.snippet(param_ss));
d9579d0f 503 // Append $id to name to make sure each one is unique
a7813a04
XL
504 let qualname = format!("{}::{}${}",
505 prefix,
506 name,
507 id);
54a0048b 508 if !self.span.filter_generated(Some(param_ss), full_span) {
a7813a04 509 self.dumper.typedef(TypeDefData {
54a0048b 510 span: param_ss,
a7813a04 511 name: name,
54a0048b 512 id: param.id,
a7813a04 513 qualname: qualname,
9e0c209e
SL
514 value: String::new(),
515 visibility: Visibility::Inherited,
516 parent: None,
517 docs: String::new(),
a7813a04 518 }.lower(self.tcx));
54a0048b 519 }
d9579d0f
AL
520 }
521 self.visit_generics(generics);
522 }
523
524 fn process_fn(&mut self,
525 item: &ast::Item,
526 decl: &ast::FnDecl,
527 ty_params: &ast::Generics,
528 body: &ast::Block) {
7453a54e 529 if let Some(fn_data) = self.save_ctxt.get_item_data(item) {
54a0048b
SL
530 down_cast_data!(fn_data, FunctionData, item.span);
531 if !self.span.filter_generated(Some(fn_data.span), item.span) {
a7813a04 532 self.dumper.function(fn_data.clone().lower(self.tcx));
54a0048b 533 }
7453a54e
SL
534
535 self.process_formals(&decl.inputs, &fn_data.qualname);
536 self.process_generic_params(ty_params, item.span, &fn_data.qualname, item.id);
537 }
d9579d0f
AL
538
539 for arg in &decl.inputs {
540 self.visit_ty(&arg.ty);
541 }
542
7453a54e 543 if let ast::FunctionRetTy::Ty(ref ret_ty) = decl.output {
d9579d0f
AL
544 self.visit_ty(&ret_ty);
545 }
546
547 self.nest(item.id, |v| v.visit_block(&body));
548 }
549
e9174d1e 550 fn process_static_or_const_item(&mut self, item: &ast::Item, typ: &ast::Ty, expr: &ast::Expr) {
7453a54e 551 if let Some(var_data) = self.save_ctxt.get_item_data(item) {
54a0048b
SL
552 down_cast_data!(var_data, VariableData, item.span);
553 if !self.span.filter_generated(Some(var_data.span), item.span) {
a7813a04 554 self.dumper.variable(var_data.lower(self.tcx));
54a0048b 555 }
7453a54e 556 }
d9579d0f
AL
557 self.visit_ty(&typ);
558 self.visit_expr(expr);
559 }
560
9e0c209e
SL
561 fn process_assoc_const(&mut self,
562 id: ast::NodeId,
563 name: ast::Name,
564 span: Span,
565 typ: &ast::Ty,
566 expr: &ast::Expr,
567 parent_id: DefId,
568 vis: Visibility,
569 attrs: &[Attribute]) {
54a0048b 570 let qualname = format!("::{}", self.tcx.node_path_str(id));
d9579d0f 571
b039eaaf 572 let sub_span = self.span.sub_span_after_keyword(span, keywords::Const);
d9579d0f 573
54a0048b 574 if !self.span.filter_generated(sub_span, span) {
a7813a04 575 self.dumper.variable(VariableData {
54a0048b 576 span: sub_span.expect("No span found for variable"),
3157f602 577 kind: VariableKind::Const,
54a0048b
SL
578 id: id,
579 name: name.to_string(),
580 qualname: qualname,
581 value: self.span.snippet(expr.span),
582 type_value: ty_to_string(&typ),
9e0c209e
SL
583 scope: self.cur_scope,
584 parent: Some(parent_id),
585 visibility: vis,
586 docs: docs_for_attrs(attrs),
a7813a04 587 }.lower(self.tcx));
54a0048b 588 }
d9579d0f
AL
589
590 // walk type and init value
591 self.visit_ty(typ);
592 self.visit_expr(expr);
593 }
594
a7813a04 595 // FIXME tuple structs should generate tuple-specific data.
d9579d0f
AL
596 fn process_struct(&mut self,
597 item: &ast::Item,
b039eaaf 598 def: &ast::VariantData,
d9579d0f 599 ty_params: &ast::Generics) {
a7813a04 600 let name = item.ident.to_string();
54a0048b 601 let qualname = format!("::{}", self.tcx.node_path_str(item.id));
d9579d0f 602
d9579d0f 603 let sub_span = self.span.sub_span_after_keyword(item.span, keywords::Struct);
3157f602
XL
604 let (val, fields) =
605 if let ast::ItemKind::Struct(ast::VariantData::Struct(ref fields, _), _) = item.node
606 {
a7813a04
XL
607 let fields_str = fields.iter()
608 .enumerate()
609 .map(|(i, f)| f.ident.map(|i| i.to_string())
610 .unwrap_or(i.to_string()))
611 .collect::<Vec<_>>()
612 .join(", ");
3157f602 613 (format!("{} {{ {} }}", name, fields_str), fields.iter().map(|f| f.id).collect())
a7813a04 614 } else {
3157f602 615 (String::new(), vec![])
a7813a04
XL
616 };
617
54a0048b 618 if !self.span.filter_generated(sub_span, item.span) {
a7813a04 619 self.dumper.struct_data(StructData {
54a0048b
SL
620 span: sub_span.expect("No span found for struct"),
621 id: item.id,
a7813a04 622 name: name,
54a0048b
SL
623 ctor_id: def.id(),
624 qualname: qualname.clone(),
625 scope: self.cur_scope,
3157f602
XL
626 value: val,
627 fields: fields,
9e0c209e
SL
628 visibility: From::from(&item.vis),
629 docs: docs_for_attrs(&item.attrs),
a7813a04 630 }.lower(self.tcx));
54a0048b
SL
631 }
632
d9579d0f
AL
633
634 // fields
b039eaaf 635 for field in def.fields() {
62682a34 636 self.process_struct_field_def(field, item.id);
54a0048b 637 self.visit_ty(&field.ty);
d9579d0f
AL
638 }
639
62682a34 640 self.process_generic_params(ty_params, item.span, &qualname, item.id);
d9579d0f
AL
641 }
642
643 fn process_enum(&mut self,
644 item: &ast::Item,
645 enum_definition: &ast::EnumDef,
646 ty_params: &ast::Generics) {
62682a34 647 let enum_data = self.save_ctxt.get_item_data(item);
7453a54e
SL
648 let enum_data = match enum_data {
649 None => return,
650 Some(data) => data,
651 };
54a0048b 652 down_cast_data!(enum_data, EnumData, item.span);
a7813a04
XL
653 if !self.span.filter_generated(Some(enum_data.span), item.span) {
654 self.dumper.enum_data(enum_data.clone().lower(self.tcx));
54a0048b 655 }
62682a34 656
d9579d0f 657 for variant in &enum_definition.variants {
a7813a04 658 let name = variant.node.name.name.to_string();
62682a34 659 let mut qualname = enum_data.qualname.clone();
d9579d0f 660 qualname.push_str("::");
a7813a04 661 qualname.push_str(&name);
b039eaaf 662
7453a54e 663 match variant.node.data {
a7813a04 664 ast::VariantData::Struct(ref fields, _) => {
54a0048b 665 let sub_span = self.span.span_for_first_ident(variant.span);
a7813a04
XL
666 let fields_str = fields.iter()
667 .enumerate()
668 .map(|(i, f)| f.ident.map(|i| i.to_string())
669 .unwrap_or(i.to_string()))
670 .collect::<Vec<_>>()
671 .join(", ");
672 let val = format!("{}::{} {{ {} }}", enum_data.name, name, fields_str);
54a0048b 673 if !self.span.filter_generated(sub_span, variant.span) {
a7813a04 674 self.dumper.struct_variant(StructVariantData {
54a0048b
SL
675 span: sub_span.expect("No span found for struct variant"),
676 id: variant.node.data.id(),
a7813a04 677 name: name,
54a0048b
SL
678 qualname: qualname,
679 type_value: enum_data.qualname.clone(),
680 value: val,
9e0c209e
SL
681 scope: enum_data.scope,
682 parent: Some(make_def_id(item.id, &self.tcx.map)),
683 docs: docs_for_attrs(&variant.node.attrs),
a7813a04 684 }.lower(self.tcx));
54a0048b 685 }
7453a54e 686 }
a7813a04 687 ref v => {
54a0048b 688 let sub_span = self.span.span_for_first_ident(variant.span);
a7813a04
XL
689 let mut val = format!("{}::{}", enum_data.name, name);
690 if let &ast::VariantData::Tuple(ref fields, _) = v {
691 val.push('(');
692 val.push_str(&fields.iter()
693 .map(|f| ty_to_string(&f.ty))
694 .collect::<Vec<_>>()
695 .join(", "));
696 val.push(')');
697 }
54a0048b 698 if !self.span.filter_generated(sub_span, variant.span) {
a7813a04 699 self.dumper.tuple_variant(TupleVariantData {
54a0048b
SL
700 span: sub_span.expect("No span found for tuple variant"),
701 id: variant.node.data.id(),
a7813a04 702 name: name,
54a0048b
SL
703 qualname: qualname,
704 type_value: enum_data.qualname.clone(),
705 value: val,
9e0c209e
SL
706 scope: enum_data.scope,
707 parent: Some(make_def_id(item.id, &self.tcx.map)),
708 docs: docs_for_attrs(&variant.node.attrs),
a7813a04 709 }.lower(self.tcx));
54a0048b 710 }
7453a54e
SL
711 }
712 }
713
b039eaaf
SL
714
715 for field in variant.node.data.fields() {
716 self.process_struct_field_def(field, variant.node.data.id());
54a0048b 717 self.visit_ty(&field.ty);
d9579d0f
AL
718 }
719 }
62682a34 720 self.process_generic_params(ty_params, item.span, &enum_data.qualname, enum_data.id);
d9579d0f
AL
721 }
722
723 fn process_impl(&mut self,
724 item: &ast::Item,
725 type_parameters: &ast::Generics,
726 trait_ref: &Option<ast::TraitRef>,
727 typ: &ast::Ty,
7453a54e
SL
728 impl_items: &[ast::ImplItem]) {
729 let mut has_self_ref = false;
730 if let Some(impl_data) = self.save_ctxt.get_item_data(item) {
54a0048b 731 down_cast_data!(impl_data, ImplData, item.span);
7453a54e
SL
732 if let Some(ref self_ref) = impl_data.self_ref {
733 has_self_ref = true;
54a0048b 734 if !self.span.filter_generated(Some(self_ref.span), item.span) {
a7813a04 735 self.dumper.type_ref(self_ref.clone().lower(self.tcx));
54a0048b 736 }
62682a34 737 }
7453a54e 738 if let Some(ref trait_ref_data) = impl_data.trait_ref {
54a0048b 739 if !self.span.filter_generated(Some(trait_ref_data.span), item.span) {
a7813a04 740 self.dumper.type_ref(trait_ref_data.clone().lower(self.tcx));
54a0048b
SL
741 }
742
7453a54e 743 visit::walk_path(self, &trait_ref.as_ref().unwrap().path);
d9579d0f 744 }
7453a54e 745
54a0048b 746 if !self.span.filter_generated(Some(impl_data.span), item.span) {
a7813a04 747 self.dumper.impl_data(ImplData {
54a0048b
SL
748 id: impl_data.id,
749 span: impl_data.span,
750 scope: impl_data.scope,
751 trait_ref: impl_data.trait_ref.map(|d| d.ref_id.unwrap()),
752 self_ref: impl_data.self_ref.map(|d| d.ref_id.unwrap())
a7813a04 753 }.lower(self.tcx));
54a0048b 754 }
d9579d0f 755 }
7453a54e
SL
756 if !has_self_ref {
757 self.visit_ty(&typ);
d9579d0f 758 }
d9579d0f
AL
759 self.process_generic_params(type_parameters, item.span, "", item.id);
760 for impl_item in impl_items {
9e0c209e
SL
761 let map = &self.tcx.map;
762 self.process_impl_item(impl_item, make_def_id(item.id, map));
d9579d0f
AL
763 }
764 }
765
766 fn process_trait(&mut self,
767 item: &ast::Item,
768 generics: &ast::Generics,
9cc50fc6 769 trait_refs: &ast::TyParamBounds,
7453a54e 770 methods: &[ast::TraitItem]) {
a7813a04 771 let name = item.ident.to_string();
54a0048b 772 let qualname = format!("::{}", self.tcx.node_path_str(item.id));
a7813a04
XL
773 let mut val = name.clone();
774 if !generics.lifetimes.is_empty() || !generics.ty_params.is_empty() {
775 val.push_str(&generics_to_string(generics));
776 }
777 if !trait_refs.is_empty() {
778 val.push_str(": ");
779 val.push_str(&bounds_to_string(trait_refs));
780 }
d9579d0f 781 let sub_span = self.span.sub_span_after_keyword(item.span, keywords::Trait);
54a0048b 782 if !self.span.filter_generated(sub_span, item.span) {
a7813a04 783 self.dumper.trait_data(TraitData {
54a0048b
SL
784 span: sub_span.expect("No span found for trait"),
785 id: item.id,
a7813a04 786 name: name,
54a0048b
SL
787 qualname: qualname.clone(),
788 scope: self.cur_scope,
3157f602
XL
789 value: val,
790 items: methods.iter().map(|i| i.id).collect(),
9e0c209e
SL
791 visibility: From::from(&item.vis),
792 docs: docs_for_attrs(&item.attrs),
a7813a04 793 }.lower(self.tcx));
54a0048b 794 }
d9579d0f
AL
795
796 // super-traits
62682a34 797 for super_bound in trait_refs.iter() {
d9579d0f
AL
798 let trait_ref = match *super_bound {
799 ast::TraitTyParamBound(ref trait_ref, _) => {
800 trait_ref
801 }
802 ast::RegionTyParamBound(..) => {
803 continue;
804 }
805 };
806
807 let trait_ref = &trait_ref.trait_ref;
54a0048b
SL
808 if let Some(id) = self.lookup_type_ref(trait_ref.ref_id) {
809 let sub_span = self.span.sub_span_for_type_name(trait_ref.path.span);
810 if !self.span.filter_generated(sub_span, trait_ref.path.span) {
a7813a04 811 self.dumper.type_ref(TypeRefData {
54a0048b
SL
812 span: sub_span.expect("No span found for trait ref"),
813 ref_id: Some(id),
814 scope: self.cur_scope,
815 qualname: String::new()
a7813a04 816 }.lower(self.tcx));
54a0048b
SL
817 }
818
819 if !self.span.filter_generated(sub_span, trait_ref.path.span) {
820 let sub_span = sub_span.expect("No span for inheritance");
821 self.dumper.inheritance(InheritanceData {
822 span: sub_span,
823 base_id: id,
824 deriv_id: item.id
a7813a04 825 }.lower(self.tcx));
e9174d1e 826 }
d9579d0f
AL
827 }
828 }
829
830 // walk generics and methods
62682a34 831 self.process_generic_params(generics, item.span, &qualname, item.id);
d9579d0f 832 for method in methods {
9e0c209e
SL
833 let map = &self.tcx.map;
834 self.process_trait_item(method, make_def_id(item.id, map))
d9579d0f
AL
835 }
836 }
837
e9174d1e
SL
838 // `item` is the module in question, represented as an item.
839 fn process_mod(&mut self, item: &ast::Item) {
7453a54e 840 if let Some(mod_data) = self.save_ctxt.get_item_data(item) {
54a0048b
SL
841 down_cast_data!(mod_data, ModData, item.span);
842 if !self.span.filter_generated(Some(mod_data.span), item.span) {
a7813a04 843 self.dumper.mod_data(mod_data.lower(self.tcx));
54a0048b 844 }
7453a54e 845 }
d9579d0f
AL
846 }
847
e9174d1e 848 fn process_path(&mut self, id: NodeId, path: &ast::Path, ref_kind: Option<recorder::Row>) {
7453a54e
SL
849 let path_data = self.save_ctxt.get_path_data(id, path);
850 if generated_code(path.span) && path_data.is_none() {
c1a9b12d 851 return;
d9579d0f
AL
852 }
853
c1a9b12d
SL
854 let path_data = match path_data {
855 Some(pd) => pd,
856 None => {
54a0048b
SL
857 span_bug!(path.span,
858 "Unexpected def kind while looking up path in `{}`",
859 self.span.snippet(path.span))
c1a9b12d
SL
860 }
861 };
54a0048b 862
c1a9b12d 863 match path_data {
54a0048b
SL
864 Data::VariableRefData(vrd) => {
865 // FIXME: this whole block duplicates the code in process_def_kind
866 if !self.span.filter_generated(Some(vrd.span), path.span) {
867 match ref_kind {
868 Some(recorder::TypeRef) => {
a7813a04 869 self.dumper.type_ref(TypeRefData {
54a0048b
SL
870 span: vrd.span,
871 ref_id: Some(vrd.ref_id),
872 scope: vrd.scope,
873 qualname: String::new()
a7813a04 874 }.lower(self.tcx));
54a0048b
SL
875 }
876 Some(recorder::FnRef) => {
a7813a04 877 self.dumper.function_ref(FunctionRefData {
54a0048b
SL
878 span: vrd.span,
879 ref_id: vrd.ref_id,
880 scope: vrd.scope
a7813a04 881 }.lower(self.tcx));
54a0048b
SL
882 }
883 Some(recorder::ModRef) => {
a7813a04 884 self.dumper.mod_ref( ModRefData {
54a0048b
SL
885 span: vrd.span,
886 ref_id: Some(vrd.ref_id),
887 scope: vrd.scope,
888 qualname: String::new()
a7813a04 889 }.lower(self.tcx));
54a0048b
SL
890 }
891 Some(recorder::VarRef) | None
a7813a04 892 => self.dumper.variable_ref(vrd.lower(self.tcx))
54a0048b
SL
893 }
894 }
c1a9b12d
SL
895
896 }
54a0048b
SL
897 Data::TypeRefData(trd) => {
898 if !self.span.filter_generated(Some(trd.span), path.span) {
a7813a04 899 self.dumper.type_ref(trd.lower(self.tcx));
54a0048b 900 }
c1a9b12d 901 }
54a0048b
SL
902 Data::MethodCallData(mcd) => {
903 if !self.span.filter_generated(Some(mcd.span), path.span) {
a7813a04 904 self.dumper.method_call(mcd.lower(self.tcx));
54a0048b 905 }
c1a9b12d
SL
906 }
907 Data::FunctionCallData(fcd) => {
54a0048b 908 if !self.span.filter_generated(Some(fcd.span), path.span) {
a7813a04 909 self.dumper.function_call(fcd.lower(self.tcx));
54a0048b 910 }
c1a9b12d
SL
911 }
912 _ => {
54a0048b 913 span_bug!(path.span, "Unexpected data: {:?}", path_data);
d9579d0f 914 }
d9579d0f 915 }
c1a9b12d
SL
916
917 // Modules or types in the path prefix.
3157f602 918 match self.tcx.expect_def(id) {
7453a54e 919 Def::Method(did) => {
c1a9b12d 920 let ti = self.tcx.impl_or_trait_item(did);
d9579d0f 921 if let ty::MethodTraitItem(m) = ti {
9cc50fc6 922 if m.explicit_self == ty::ExplicitSelfCategory::Static {
d9579d0f
AL
923 self.write_sub_path_trait_truncated(path);
924 }
925 }
926 }
7453a54e 927 Def::Local(..) |
9e0c209e 928 Def::Static(..) |
7453a54e
SL
929 Def::Const(..) |
930 Def::AssociatedConst(..) |
931 Def::Struct(..) |
932 Def::Variant(..) |
933 Def::Fn(..) => self.write_sub_paths_truncated(path, false),
e9174d1e 934 _ => {}
d9579d0f
AL
935 }
936 }
937
938 fn process_struct_lit(&mut self,
939 ex: &ast::Expr,
940 path: &ast::Path,
941 fields: &Vec<ast::Field>,
e9174d1e 942 variant: ty::VariantDef,
d9579d0f 943 base: &Option<P<ast::Expr>>) {
d9579d0f
AL
944 self.write_sub_paths_truncated(path, false);
945
62682a34 946 if let Some(struct_lit_data) = self.save_ctxt.get_expr_data(ex) {
54a0048b
SL
947 down_cast_data!(struct_lit_data, TypeRefData, ex.span);
948 if !self.span.filter_generated(Some(struct_lit_data.span), ex.span) {
a7813a04 949 self.dumper.type_ref(struct_lit_data.lower(self.tcx));
54a0048b
SL
950 }
951
c1a9b12d 952 let scope = self.save_ctxt.enclosing_scope(ex.id);
62682a34
SL
953
954 for field in fields {
7453a54e
SL
955 if let Some(field_data) = self.save_ctxt
956 .get_field_ref_data(field, variant, scope) {
d9579d0f 957
54a0048b 958 if !self.span.filter_generated(Some(field_data.span), field.ident.span) {
a7813a04 959 self.dumper.variable_ref(field_data.lower(self.tcx));
54a0048b 960 }
7453a54e 961 }
62682a34
SL
962
963 self.visit_expr(&field.expr)
964 }
d9579d0f 965 }
62682a34 966
b039eaaf 967 walk_list!(self, visit_expr, base);
d9579d0f
AL
968 }
969
e9174d1e 970 fn process_method_call(&mut self, ex: &ast::Expr, args: &Vec<P<ast::Expr>>) {
54a0048b
SL
971 if let Some(mcd) = self.save_ctxt.get_expr_data(ex) {
972 down_cast_data!(mcd, MethodCallData, ex.span);
973 if !self.span.filter_generated(Some(mcd.span), ex.span) {
a7813a04 974 self.dumper.method_call(mcd.lower(self.tcx));
54a0048b 975 }
c1a9b12d 976 }
d9579d0f
AL
977
978 // walk receiver and args
b039eaaf 979 walk_list!(self, visit_expr, args);
d9579d0f
AL
980 }
981
e9174d1e 982 fn process_pat(&mut self, p: &ast::Pat) {
d9579d0f 983 match p.node {
7453a54e 984 PatKind::Struct(ref path, ref fields, _) => {
d9579d0f 985 visit::walk_path(self, path);
e9174d1e 986 let adt = self.tcx.node_id_to_type(p.id).ty_adt_def().unwrap();
3157f602 987 let variant = adt.variant_of_def(self.tcx.expect_def(p.id));
d9579d0f 988
e9174d1e 989 for &Spanned { node: ref field, span } in fields {
e9174d1e
SL
990 let sub_span = self.span.span_for_first_ident(span);
991 if let Some(f) = variant.find_field_named(field.ident.name) {
54a0048b 992 if !self.span.filter_generated(sub_span, span) {
a7813a04 993 self.dumper.variable_ref(VariableRefData {
54a0048b
SL
994 span: sub_span.expect("No span fund for var ref"),
995 ref_id: f.did,
996 scope: self.cur_scope,
997 name: String::new()
a7813a04 998 }.lower(self.tcx));
54a0048b 999 }
d9579d0f 1000 }
e9174d1e 1001 self.visit_pat(&field.pat);
d9579d0f
AL
1002 }
1003 }
e9174d1e 1004 _ => visit::walk_pat(self, p),
d9579d0f
AL
1005 }
1006 }
b039eaaf
SL
1007
1008
1009 fn process_var_decl(&mut self, p: &ast::Pat, value: String) {
1010 // The local could declare multiple new vars, we must walk the
1011 // pattern and collect them all.
1012 let mut collector = PathCollector::new();
1013 collector.visit_pat(&p);
1014 self.visit_pat(&p);
1015
1016 for &(id, ref p, immut, _) in &collector.collected_paths {
9e0c209e
SL
1017 let mut value = match immut {
1018 ast::Mutability::Immutable => value.to_string(),
1019 _ => String::new(),
b039eaaf
SL
1020 };
1021 let types = self.tcx.node_types();
9e0c209e
SL
1022 let typ = match types.get(&id) {
1023 Some(typ) => {
1024 let typ = typ.to_string();
1025 if !value.is_empty() {
1026 value.push_str(": ");
1027 }
1028 value.push_str(&typ);
1029 typ
1030 }
1031 None => String::new(),
1032 };
1033
b039eaaf
SL
1034 // Get the span only for the name of the variable (I hope the path
1035 // is only ever a variable name, but who knows?).
1036 let sub_span = self.span.span_for_last_ident(p.span);
1037 // Rust uses the id of the pattern for var lookups, so we'll use it too.
54a0048b 1038 if !self.span.filter_generated(sub_span, p.span) {
a7813a04 1039 self.dumper.variable(VariableData {
54a0048b 1040 span: sub_span.expect("No span found for variable"),
3157f602 1041 kind: VariableKind::Local,
54a0048b
SL
1042 id: id,
1043 name: path_to_string(p),
1044 qualname: format!("{}${}", path_to_string(p), id),
1045 value: value,
1046 type_value: typ,
9e0c209e
SL
1047 scope: CRATE_NODE_ID,
1048 parent: None,
1049 visibility: Visibility::Inherited,
1050 docs: String::new(),
a7813a04 1051 }.lower(self.tcx));
54a0048b 1052 }
b039eaaf
SL
1053 }
1054 }
7453a54e
SL
1055
1056 /// Extract macro use and definition information from the AST node defined
1057 /// by the given NodeId, using the expansion information from the node's
1058 /// span.
1059 ///
1060 /// If the span is not macro-generated, do nothing, else use callee and
1061 /// callsite spans to record macro definition and use data, using the
1062 /// mac_uses and mac_defs sets to prevent multiples.
1063 fn process_macro_use(&mut self, span: Span, id: NodeId) {
1064 let data = match self.save_ctxt.get_macro_use_data(span, id) {
1065 None => return,
1066 Some(data) => data,
1067 };
9e0c209e 1068 let mut hasher = DefaultHasher::new();
7453a54e
SL
1069 data.callee_span.hash(&mut hasher);
1070 let hash = hasher.finish();
1071 let qualname = format!("{}::{}", data.name, hash);
1072 // Don't write macro definition for imported macros
1073 if !self.mac_defs.contains(&data.callee_span)
1074 && !data.imported {
1075 self.mac_defs.insert(data.callee_span);
1076 if let Some(sub_span) = self.span.span_for_macro_def_name(data.callee_span) {
a7813a04 1077 self.dumper.macro_data(MacroData {
54a0048b
SL
1078 span: sub_span,
1079 name: data.name.clone(),
9e0c209e
SL
1080 qualname: qualname.clone(),
1081 // FIXME where do macro docs come from?
1082 docs: String::new(),
a7813a04 1083 }.lower(self.tcx));
7453a54e
SL
1084 }
1085 }
1086 if !self.mac_uses.contains(&data.span) {
1087 self.mac_uses.insert(data.span);
1088 if let Some(sub_span) = self.span.span_for_macro_use_name(data.span) {
a7813a04 1089 self.dumper.macro_use(MacroUseData {
54a0048b
SL
1090 span: sub_span,
1091 name: data.name,
1092 qualname: qualname,
1093 scope: data.scope,
1094 callee_span: data.callee_span,
9e0c209e 1095 imported: data.imported,
a7813a04 1096 }.lower(self.tcx));
7453a54e
SL
1097 }
1098 }
1099 }
9e0c209e
SL
1100
1101 fn process_trait_item(&mut self, trait_item: &ast::TraitItem, trait_id: DefId) {
1102 self.process_macro_use(trait_item.span, trait_item.id);
1103 match trait_item.node {
1104 ast::TraitItemKind::Const(ref ty, Some(ref expr)) => {
1105 self.process_assoc_const(trait_item.id,
1106 trait_item.ident.name,
1107 trait_item.span,
1108 &ty,
1109 &expr,
1110 trait_id,
1111 Visibility::Public,
1112 &trait_item.attrs);
1113 }
1114 ast::TraitItemKind::Method(ref sig, ref body) => {
1115 self.process_method(sig,
1116 body.as_ref().map(|x| &**x),
1117 trait_item.id,
1118 trait_item.ident.name,
1119 Visibility::Public,
1120 &trait_item.attrs,
1121 trait_item.span);
1122 }
1123 ast::TraitItemKind::Const(_, None) |
1124 ast::TraitItemKind::Type(..) |
1125 ast::TraitItemKind::Macro(_) => {}
1126 }
1127 }
1128
1129 fn process_impl_item(&mut self, impl_item: &ast::ImplItem, impl_id: DefId) {
1130 self.process_macro_use(impl_item.span, impl_item.id);
1131 match impl_item.node {
1132 ast::ImplItemKind::Const(ref ty, ref expr) => {
1133 self.process_assoc_const(impl_item.id,
1134 impl_item.ident.name,
1135 impl_item.span,
1136 &ty,
1137 &expr,
1138 impl_id,
1139 From::from(&impl_item.vis),
1140 &impl_item.attrs);
1141 }
1142 ast::ImplItemKind::Method(ref sig, ref body) => {
1143 self.process_method(sig,
1144 Some(body),
1145 impl_item.id,
1146 impl_item.ident.name,
1147 From::from(&impl_item.vis),
1148 &impl_item.attrs,
1149 impl_item.span);
1150 }
1151 ast::ImplItemKind::Type(_) |
1152 ast::ImplItemKind::Macro(_) => {}
1153 }
1154 }
d9579d0f
AL
1155}
1156
3157f602 1157impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor for DumpVisitor<'l, 'tcx, 'll, D> {
d9579d0f 1158 fn visit_item(&mut self, item: &ast::Item) {
7453a54e
SL
1159 use syntax::ast::ItemKind::*;
1160 self.process_macro_use(item.span, item.id);
d9579d0f 1161 match item.node {
7453a54e 1162 Use(ref use_item) => {
d9579d0f
AL
1163 match use_item.node {
1164 ast::ViewPathSimple(ident, ref path) => {
1165 let sub_span = self.span.span_for_last_ident(path.span);
1166 let mod_id = match self.lookup_type_ref(item.id) {
1167 Some(def_id) => {
54a0048b
SL
1168 let scope = self.cur_scope;
1169 self.process_def_kind(item.id, path.span, sub_span, def_id, scope);
1170
d9579d0f 1171 Some(def_id)
e9174d1e 1172 }
d9579d0f
AL
1173 None => None,
1174 };
1175
1176 // 'use' always introduces an alias, if there is not an explicit
1177 // one, there is an implicit one.
b039eaaf
SL
1178 let sub_span = match self.span.sub_span_after_keyword(use_item.span,
1179 keywords::As) {
1180 Some(sub_span) => Some(sub_span),
1181 None => sub_span,
1182 };
d9579d0f 1183
54a0048b 1184 if !self.span.filter_generated(sub_span, path.span) {
a7813a04 1185 self.dumper.use_data(UseData {
54a0048b
SL
1186 span: sub_span.expect("No span found for use"),
1187 id: item.id,
1188 mod_id: mod_id,
a7813a04 1189 name: ident.to_string(),
9e0c209e
SL
1190 scope: self.cur_scope,
1191 visibility: From::from(&item.vis),
a7813a04 1192 }.lower(self.tcx));
54a0048b 1193 }
d9579d0f
AL
1194 self.write_sub_paths_truncated(path, true);
1195 }
1196 ast::ViewPathGlob(ref path) => {
1197 // Make a comma-separated list of names of imported modules.
54a0048b 1198 let mut names = vec![];
d9579d0f
AL
1199 let glob_map = &self.analysis.glob_map;
1200 let glob_map = glob_map.as_ref().unwrap();
1201 if glob_map.contains_key(&item.id) {
1202 for n in glob_map.get(&item.id).unwrap() {
54a0048b 1203 names.push(n.to_string());
d9579d0f
AL
1204 }
1205 }
1206
b039eaaf 1207 let sub_span = self.span
a7813a04
XL
1208 .sub_span_of_token(item.span, token::BinOp(token::Star));
1209 if !self.span.filter_generated(sub_span, item.span) {
1210 self.dumper.use_glob(UseGlobData {
54a0048b
SL
1211 span: sub_span.expect("No span found for use glob"),
1212 id: item.id,
1213 names: names,
9e0c209e
SL
1214 scope: self.cur_scope,
1215 visibility: From::from(&item.vis),
a7813a04 1216 }.lower(self.tcx));
54a0048b 1217 }
d9579d0f
AL
1218 self.write_sub_paths(path, true);
1219 }
1220 ast::ViewPathList(ref path, ref list) => {
1221 for plid in list {
9e0c209e
SL
1222 let scope = self.cur_scope;
1223 let id = plid.node.id;
1224 if let Some(def_id) = self.lookup_type_ref(id) {
1225 let span = plid.span;
1226 self.process_def_kind(id, span, Some(span), def_id, scope);
d9579d0f
AL
1227 }
1228 }
1229
1230 self.write_sub_paths(path, true);
1231 }
1232 }
1233 }
7453a54e 1234 ExternCrate(ref s) => {
d9579d0f
AL
1235 let location = match *s {
1236 Some(s) => s.to_string(),
c1a9b12d 1237 None => item.ident.to_string(),
d9579d0f
AL
1238 };
1239 let alias_span = self.span.span_for_last_ident(item.span);
92a42be0 1240 let cnum = match self.sess.cstore.extern_mod_stmt_cnum(item.id) {
d9579d0f 1241 Some(cnum) => cnum,
9e0c209e 1242 None => LOCAL_CRATE,
d9579d0f 1243 };
54a0048b
SL
1244
1245 if !self.span.filter_generated(alias_span, item.span) {
a7813a04 1246 self.dumper.extern_crate(ExternCrateData {
54a0048b 1247 id: item.id,
a7813a04 1248 name: item.ident.to_string(),
54a0048b
SL
1249 crate_num: cnum,
1250 location: location,
1251 span: alias_span.expect("No span found for extern crate"),
1252 scope: self.cur_scope,
a7813a04 1253 }.lower(self.tcx));
54a0048b 1254 }
d9579d0f 1255 }
9e0c209e 1256 Fn(ref decl, .., ref ty_params, ref body) =>
7453a54e
SL
1257 self.process_fn(item, &decl, ty_params, &body),
1258 Static(ref typ, _, ref expr) =>
d9579d0f 1259 self.process_static_or_const_item(item, typ, expr),
7453a54e 1260 Const(ref typ, ref expr) =>
d9579d0f 1261 self.process_static_or_const_item(item, &typ, &expr),
7453a54e
SL
1262 Struct(ref def, ref ty_params) => self.process_struct(item, def, ty_params),
1263 Enum(ref def, ref ty_params) => self.process_enum(item, def, ty_params),
9e0c209e 1264 Impl(..,
d9579d0f
AL
1265 ref ty_params,
1266 ref trait_ref,
1267 ref typ,
1268 ref impl_items) => {
b039eaaf 1269 self.process_impl(item, ty_params, trait_ref, &typ, impl_items)
d9579d0f 1270 }
7453a54e 1271 Trait(_, ref generics, ref trait_refs, ref methods) =>
d9579d0f 1272 self.process_trait(item, generics, trait_refs, methods),
7453a54e 1273 Mod(ref m) => {
62682a34
SL
1274 self.process_mod(item);
1275 self.nest(item.id, |v| visit::walk_mod(v, m));
1276 }
7453a54e 1277 Ty(ref ty, ref ty_params) => {
54a0048b 1278 let qualname = format!("::{}", self.tcx.node_path_str(item.id));
7453a54e 1279 let value = ty_to_string(&ty);
d9579d0f 1280 let sub_span = self.span.sub_span_after_keyword(item.span, keywords::Type);
54a0048b 1281 if !self.span.filter_generated(sub_span, item.span) {
a7813a04 1282 self.dumper.typedef(TypeDefData {
54a0048b 1283 span: sub_span.expect("No span found for typedef"),
a7813a04 1284 name: item.ident.to_string(),
54a0048b
SL
1285 id: item.id,
1286 qualname: qualname.clone(),
9e0c209e
SL
1287 value: value,
1288 visibility: From::from(&item.vis),
1289 parent: None,
1290 docs: docs_for_attrs(&item.attrs),
a7813a04 1291 }.lower(self.tcx));
54a0048b 1292 }
d9579d0f 1293
7453a54e 1294 self.visit_ty(&ty);
d9579d0f 1295 self.process_generic_params(ty_params, item.span, &qualname, item.id);
e9174d1e 1296 }
7453a54e 1297 Mac(_) => (),
d9579d0f
AL
1298 _ => visit::walk_item(self, item),
1299 }
1300 }
1301
1302 fn visit_generics(&mut self, generics: &ast::Generics) {
62682a34
SL
1303 for param in generics.ty_params.iter() {
1304 for bound in param.bounds.iter() {
d9579d0f
AL
1305 if let ast::TraitTyParamBound(ref trait_ref, _) = *bound {
1306 self.process_trait_ref(&trait_ref.trait_ref);
1307 }
1308 }
1309 if let Some(ref ty) = param.default {
7453a54e 1310 self.visit_ty(&ty);
d9579d0f
AL
1311 }
1312 }
1313 }
1314
d9579d0f 1315 fn visit_ty(&mut self, t: &ast::Ty) {
7453a54e 1316 self.process_macro_use(t.span, t.id);
d9579d0f 1317 match t.node {
7453a54e 1318 ast::TyKind::Path(_, ref path) => {
54a0048b
SL
1319 if let Some(id) = self.lookup_type_ref(t.id) {
1320 let sub_span = self.span.sub_span_for_type_name(t.span);
1321 if !self.span.filter_generated(sub_span, t.span) {
a7813a04 1322 self.dumper.type_ref(TypeRefData {
54a0048b
SL
1323 span: sub_span.expect("No span found for type ref"),
1324 ref_id: Some(id),
1325 scope: self.cur_scope,
1326 qualname: String::new()
a7813a04 1327 }.lower(self.tcx));
e9174d1e 1328 }
d9579d0f
AL
1329 }
1330
1331 self.write_sub_paths_truncated(path, false);
1332
1333 visit::walk_path(self, path);
e9174d1e 1334 }
d9579d0f
AL
1335 _ => visit::walk_ty(self, t),
1336 }
1337 }
1338
1339 fn visit_expr(&mut self, ex: &ast::Expr) {
7453a54e 1340 self.process_macro_use(ex.span, ex.id);
d9579d0f 1341 match ex.node {
7453a54e 1342 ast::ExprKind::Call(ref _f, ref _args) => {
d9579d0f
AL
1343 // Don't need to do anything for function calls,
1344 // because just walking the callee path does what we want.
1345 visit::walk_expr(self, ex);
1346 }
7453a54e 1347 ast::ExprKind::Path(_, ref path) => {
c1a9b12d 1348 self.process_path(ex.id, path, None);
d9579d0f
AL
1349 visit::walk_expr(self, ex);
1350 }
7453a54e 1351 ast::ExprKind::Struct(ref path, ref fields, ref base) => {
a7813a04 1352 let hir_expr = self.save_ctxt.tcx.map.expect_expr(ex.id);
e9174d1e 1353 let adt = self.tcx.expr_ty(&hir_expr).ty_adt_def().unwrap();
3157f602 1354 let def = self.tcx.expect_def(hir_expr.id);
b039eaaf 1355 self.process_struct_lit(ex, path, fields, adt.variant_of_def(def), base)
e9174d1e 1356 }
9e0c209e 1357 ast::ExprKind::MethodCall(.., ref args) => self.process_method_call(ex, args),
7453a54e 1358 ast::ExprKind::Field(ref sub_ex, _) => {
62682a34
SL
1359 self.visit_expr(&sub_ex);
1360
1361 if let Some(field_data) = self.save_ctxt.get_expr_data(ex) {
54a0048b
SL
1362 down_cast_data!(field_data, VariableRefData, ex.span);
1363 if !self.span.filter_generated(Some(field_data.span), ex.span) {
a7813a04 1364 self.dumper.variable_ref(field_data.lower(self.tcx));
54a0048b 1365 }
d9579d0f 1366 }
e9174d1e 1367 }
7453a54e
SL
1368 ast::ExprKind::TupField(ref sub_ex, idx) => {
1369 self.visit_expr(&sub_ex);
d9579d0f 1370
5bcae85e
SL
1371 let hir_node = match self.save_ctxt.tcx.map.find(sub_ex.id) {
1372 Some(Node::NodeExpr(expr)) => expr,
1373 _ => {
1374 debug!("Missing or weird node for sub-expression {} in {:?}",
1375 sub_ex.id, ex);
1376 return;
1377 }
1378 };
e9174d1e 1379 let ty = &self.tcx.expr_ty_adjusted(&hir_node).sty;
d9579d0f 1380 match *ty {
9e0c209e 1381 ty::TyAdt(def, _) => {
e9174d1e 1382 let sub_span = self.span.sub_span_after_token(ex.span, token::Dot);
54a0048b 1383 if !self.span.filter_generated(sub_span, ex.span) {
a7813a04 1384 self.dumper.variable_ref(VariableRefData {
54a0048b
SL
1385 span: sub_span.expect("No span found for var ref"),
1386 ref_id: def.struct_variant().fields[idx.node].did,
1387 scope: self.cur_scope,
1388 name: String::new()
a7813a04 1389 }.lower(self.tcx));
54a0048b 1390 }
d9579d0f 1391 }
62682a34 1392 ty::TyTuple(_) => {}
54a0048b
SL
1393 _ => span_bug!(ex.span,
1394 "Expected struct or tuple type, found {:?}",
1395 ty),
d9579d0f 1396 }
e9174d1e 1397 }
a7813a04 1398 ast::ExprKind::Closure(_, ref decl, ref body, _fn_decl_span) => {
62682a34 1399 let mut id = String::from("$");
d9579d0f 1400 id.push_str(&ex.id.to_string());
62682a34 1401 self.process_formals(&decl.inputs, &id);
d9579d0f
AL
1402
1403 // walk arg and return types
1404 for arg in &decl.inputs {
7453a54e 1405 self.visit_ty(&arg.ty);
d9579d0f
AL
1406 }
1407
7453a54e
SL
1408 if let ast::FunctionRetTy::Ty(ref ret_ty) = decl.output {
1409 self.visit_ty(&ret_ty);
d9579d0f
AL
1410 }
1411
1412 // walk the body
7453a54e 1413 self.nest(ex.id, |v| v.visit_block(&body));
e9174d1e 1414 }
7453a54e
SL
1415 ast::ExprKind::ForLoop(ref pattern, ref subexpression, ref block, _) |
1416 ast::ExprKind::WhileLet(ref pattern, ref subexpression, ref block, _) => {
a7813a04 1417 let value = self.span.snippet(subexpression.span);
b039eaaf
SL
1418 self.process_var_decl(pattern, value);
1419 visit::walk_expr(self, subexpression);
1420 visit::walk_block(self, block);
1421 }
7453a54e 1422 ast::ExprKind::IfLet(ref pattern, ref subexpression, ref block, ref opt_else) => {
a7813a04 1423 let value = self.span.snippet(subexpression.span);
b039eaaf
SL
1424 self.process_var_decl(pattern, value);
1425 visit::walk_expr(self, subexpression);
1426 visit::walk_block(self, block);
1427 opt_else.as_ref().map(|el| visit::walk_expr(self, el));
1428 }
d9579d0f
AL
1429 _ => {
1430 visit::walk_expr(self, ex)
1431 }
1432 }
1433 }
1434
7453a54e
SL
1435 fn visit_mac(&mut self, mac: &ast::Mac) {
1436 // These shouldn't exist in the AST at this point, log a span bug.
54a0048b 1437 span_bug!(mac.span, "macro invocation should have been expanded out of AST");
d9579d0f
AL
1438 }
1439
1440 fn visit_pat(&mut self, p: &ast::Pat) {
7453a54e 1441 self.process_macro_use(p.span, p.id);
d9579d0f
AL
1442 self.process_pat(p);
1443 }
1444
1445 fn visit_arm(&mut self, arm: &ast::Arm) {
1446 let mut collector = PathCollector::new();
1447 for pattern in &arm.pats {
1448 // collect paths from the arm's patterns
1449 collector.visit_pat(&pattern);
1450 self.visit_pat(&pattern);
1451 }
1452
1453 // This is to get around borrow checking, because we need mut self to call process_path.
1454 let mut paths_to_process = vec![];
c1a9b12d 1455
d9579d0f
AL
1456 // process collected paths
1457 for &(id, ref p, immut, ref_kind) in &collector.collected_paths {
3157f602 1458 match self.tcx.expect_def(id) {
9e0c209e
SL
1459 Def::Local(def_id) => {
1460 let id = self.tcx.map.as_local_node_id(def_id).unwrap();
1461 let mut value = if immut == ast::Mutability::Immutable {
d9579d0f
AL
1462 self.span.snippet(p.span).to_string()
1463 } else {
1464 "<mutable>".to_string()
1465 };
9e0c209e
SL
1466 let typ = self.tcx.node_types()
1467 .get(&id).map(|t| t.to_string()).unwrap_or(String::new());
1468 value.push_str(": ");
1469 value.push_str(&typ);
d9579d0f 1470
b039eaaf
SL
1471 assert!(p.segments.len() == 1,
1472 "qualified path for local variable def in arm");
54a0048b 1473 if !self.span.filter_generated(Some(p.span), p.span) {
a7813a04 1474 self.dumper.variable(VariableData {
54a0048b 1475 span: p.span,
3157f602 1476 kind: VariableKind::Local,
54a0048b
SL
1477 id: id,
1478 name: path_to_string(p),
1479 qualname: format!("{}${}", path_to_string(p), id),
1480 value: value,
9e0c209e
SL
1481 type_value: typ,
1482 scope: CRATE_NODE_ID,
1483 parent: None,
1484 visibility: Visibility::Inherited,
1485 docs: String::new(),
a7813a04 1486 }.lower(self.tcx));
54a0048b 1487 }
d9579d0f 1488 }
7453a54e
SL
1489 Def::Variant(..) | Def::Enum(..) |
1490 Def::TyAlias(..) | Def::Struct(..) => {
d9579d0f
AL
1491 paths_to_process.push((id, p.clone(), Some(ref_kind)))
1492 }
1493 // FIXME(nrc) what are these doing here?
9e0c209e 1494 Def::Static(..) |
7453a54e
SL
1495 Def::Const(..) |
1496 Def::AssociatedConst(..) => {}
3157f602
XL
1497 def => error!("unexpected definition kind when processing collected paths: {:?}",
1498 def),
d9579d0f
AL
1499 }
1500 }
c1a9b12d 1501
d9579d0f 1502 for &(id, ref path, ref_kind) in &paths_to_process {
c1a9b12d 1503 self.process_path(id, path, ref_kind);
d9579d0f 1504 }
b039eaaf 1505 walk_list!(self, visit_expr, &arm.guard);
c1a9b12d 1506 self.visit_expr(&arm.body);
d9579d0f
AL
1507 }
1508
1509 fn visit_stmt(&mut self, s: &ast::Stmt) {
3157f602 1510 self.process_macro_use(s.span, s.id);
d9579d0f
AL
1511 visit::walk_stmt(self, s)
1512 }
1513
1514 fn visit_local(&mut self, l: &ast::Local) {
7453a54e 1515 self.process_macro_use(l.span, l.id);
a7813a04 1516 let value = l.init.as_ref().map(|i| self.span.snippet(i.span)).unwrap_or(String::new());
b039eaaf 1517 self.process_var_decl(&l.pat, value);
d9579d0f
AL
1518
1519 // Just walk the initialiser and type (don't want to walk the pattern again).
b039eaaf
SL
1520 walk_list!(self, visit_ty, &l.ty);
1521 walk_list!(self, visit_expr, &l.init);
d9579d0f
AL
1522 }
1523}