]> git.proxmox.com Git - rustc.git/blob - src/librustc_trans/save/dump_csv.rs
Imported Upstream version 1.8.0+dfsg1
[rustc.git] / src / librustc_trans / save / dump_csv.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 //! Output a CSV file containing the output from rustc's analysis. The data is
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).
26 //! Recorder is used for recording the output in csv format. FmtStrs separates
27 //! the format of the output away from extracting it from the compiler.
28 //! DumpCsvVisitor walks the AST and processes it.
29
30
31 use super::{escape, generated_code, recorder, SaveContext, PathCollector, Data};
32
33 use session::Session;
34
35 use middle::def::Def;
36 use middle::def_id::DefId;
37 use middle::ty;
38
39 use std::fs::File;
40 use std::hash::*;
41 use std::collections::HashSet;
42
43 use syntax::ast::{self, NodeId, PatKind};
44 use syntax::codemap::*;
45 use syntax::parse::token::{self, keywords};
46 use syntax::visit::{self, Visitor};
47 use syntax::print::pprust::{path_to_string, ty_to_string};
48 use syntax::ptr::P;
49
50 use rustc_front::lowering::{lower_expr, LoweringContext};
51
52 use super::span_utils::SpanUtils;
53 use super::recorder::{Recorder, FmtStrs};
54
55 macro_rules! down_cast_data {
56 ($id:ident, $kind:ident, $this:ident, $sp:expr) => {
57 let $id = if let super::Data::$kind(data) = $id {
58 data
59 } else {
60 $this.sess.span_bug($sp, &format!("unexpected data kind: {:?}", $id));
61 }
62 };
63 }
64
65 pub struct DumpCsvVisitor<'l, 'tcx: 'l> {
66 save_ctxt: SaveContext<'l, 'tcx>,
67 sess: &'l Session,
68 tcx: &'l ty::ctxt<'tcx>,
69 analysis: &'l ty::CrateAnalysis<'l>,
70
71 span: SpanUtils<'l>,
72 fmt: FmtStrs<'l, 'tcx>,
73
74 cur_scope: NodeId,
75
76 // Set of macro definition (callee) spans, and the set
77 // of macro use (callsite) spans. We store these to ensure
78 // we only write one macro def per unique macro definition, and
79 // one macro use per unique callsite span.
80 mac_defs: HashSet<Span>,
81 mac_uses: HashSet<Span>,
82
83 }
84
85 impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> {
86 pub fn new(tcx: &'l ty::ctxt<'tcx>,
87 lcx: &'l LoweringContext<'l>,
88 analysis: &'l ty::CrateAnalysis<'l>,
89 output_file: Box<File>)
90 -> DumpCsvVisitor<'l, 'tcx> {
91 let span_utils = SpanUtils::new(&tcx.sess);
92 DumpCsvVisitor {
93 sess: &tcx.sess,
94 tcx: tcx,
95 save_ctxt: SaveContext::from_span_utils(tcx, lcx, span_utils.clone()),
96 analysis: analysis,
97 span: span_utils.clone(),
98 fmt: FmtStrs::new(box Recorder {
99 out: output_file,
100 dump_spans: false,
101 },
102 span_utils,
103 tcx),
104 cur_scope: 0,
105 mac_defs: HashSet::new(),
106 mac_uses: HashSet::new(),
107 }
108 }
109
110 fn nest<F>(&mut self, scope_id: NodeId, f: F)
111 where F: FnOnce(&mut DumpCsvVisitor<'l, 'tcx>)
112 {
113 let parent_scope = self.cur_scope;
114 self.cur_scope = scope_id;
115 f(self);
116 self.cur_scope = parent_scope;
117 }
118
119 pub fn dump_crate_info(&mut self, name: &str, krate: &ast::Crate) {
120 let source_file = self.tcx.sess.local_crate_source_file.as_ref();
121 let crate_root = match source_file {
122 Some(source_file) => match source_file.file_name() {
123 Some(_) => source_file.parent().unwrap().display().to_string(),
124 None => source_file.display().to_string(),
125 },
126 None => "<no source>".to_owned(),
127 };
128
129 // The current crate.
130 self.fmt.crate_str(krate.span, name, &crate_root);
131
132 // Dump info about all the external crates referenced from this crate.
133 for c in &self.save_ctxt.get_external_crates() {
134 self.fmt.external_crate_str(krate.span, &c.name, c.number);
135 }
136 self.fmt.recorder.record("end_external_crates\n");
137 }
138
139 // Return all non-empty prefixes of a path.
140 // For each prefix, we return the span for the last segment in the prefix and
141 // a str representation of the entire prefix.
142 fn process_path_prefixes(&self, path: &ast::Path) -> Vec<(Span, String)> {
143 let spans = self.span.spans_for_path_segments(path);
144
145 // Paths to enums seem to not match their spans - the span includes all the
146 // variants too. But they seem to always be at the end, so I hope we can cope with
147 // always using the first ones. So, only error out if we don't have enough spans.
148 // What could go wrong...?
149 if spans.len() < path.segments.len() {
150 if generated_code(path.span) {
151 return vec!();
152 }
153 error!("Mis-calculated spans for path '{}'. Found {} spans, expected {}. Found spans:",
154 path_to_string(path),
155 spans.len(),
156 path.segments.len());
157 for s in &spans {
158 let loc = self.sess.codemap().lookup_char_pos(s.lo);
159 error!(" '{}' in {}, line {}",
160 self.span.snippet(*s),
161 loc.file.name,
162 loc.line);
163 }
164 return vec!();
165 }
166
167 let mut result: Vec<(Span, String)> = vec!();
168
169 let mut segs = vec!();
170 for (i, (seg, span)) in path.segments.iter().zip(&spans).enumerate() {
171 segs.push(seg.clone());
172 let sub_path = ast::Path {
173 span: *span, // span for the last segment
174 global: path.global,
175 segments: segs,
176 };
177 let qualname = if i == 0 && path.global {
178 format!("::{}", path_to_string(&sub_path))
179 } else {
180 path_to_string(&sub_path)
181 };
182 result.push((*span, qualname));
183 segs = sub_path.segments;
184 }
185
186 result
187 }
188
189 // The global arg allows us to override the global-ness of the path (which
190 // actually means 'does the path start with `::`', rather than 'is the path
191 // semantically global). We use the override for `use` imports (etc.) where
192 // the syntax is non-global, but the semantics are global.
193 fn write_sub_paths(&mut self, path: &ast::Path, global: bool) {
194 let sub_paths = self.process_path_prefixes(path);
195 for (i, &(ref span, ref qualname)) in sub_paths.iter().enumerate() {
196 let qualname = if i == 0 && global && !path.global {
197 format!("::{}", qualname)
198 } else {
199 qualname.clone()
200 };
201 self.fmt.sub_mod_ref_str(path.span, *span, &qualname, self.cur_scope);
202 }
203 }
204
205 // As write_sub_paths, but does not process the last ident in the path (assuming it
206 // will be processed elsewhere). See note on write_sub_paths about global.
207 fn write_sub_paths_truncated(&mut self, path: &ast::Path, global: bool) {
208 let sub_paths = self.process_path_prefixes(path);
209 let len = sub_paths.len();
210 if len <= 1 {
211 return;
212 }
213
214 let sub_paths = &sub_paths[..len-1];
215 for (i, &(ref span, ref qualname)) in sub_paths.iter().enumerate() {
216 let qualname = if i == 0 && global && !path.global {
217 format!("::{}", qualname)
218 } else {
219 qualname.clone()
220 };
221 self.fmt.sub_mod_ref_str(path.span, *span, &qualname, self.cur_scope);
222 }
223 }
224
225 // As write_sub_paths, but expects a path of the form module_path::trait::method
226 // Where trait could actually be a struct too.
227 fn write_sub_path_trait_truncated(&mut self, path: &ast::Path) {
228 let sub_paths = self.process_path_prefixes(path);
229 let len = sub_paths.len();
230 if len <= 1 {
231 return;
232 }
233 let sub_paths = &sub_paths[.. (len-1)];
234
235 // write the trait part of the sub-path
236 let (ref span, ref qualname) = sub_paths[len-2];
237 self.fmt.sub_type_ref_str(path.span, *span, &qualname);
238
239 // write the other sub-paths
240 if len <= 2 {
241 return;
242 }
243 let sub_paths = &sub_paths[..len-2];
244 for &(ref span, ref qualname) in sub_paths {
245 self.fmt.sub_mod_ref_str(path.span, *span, &qualname, self.cur_scope);
246 }
247 }
248
249 // looks up anything, not just a type
250 fn lookup_type_ref(&self, ref_id: NodeId) -> Option<DefId> {
251 if !self.tcx.def_map.borrow().contains_key(&ref_id) {
252 self.sess.bug(&format!("def_map has no key for {} in lookup_type_ref",
253 ref_id));
254 }
255 let def = self.tcx.def_map.borrow().get(&ref_id).unwrap().full_def();
256 match def {
257 Def::PrimTy(..) => None,
258 Def::SelfTy(..) => None,
259 _ => Some(def.def_id()),
260 }
261 }
262
263 fn lookup_def_kind(&self, ref_id: NodeId, span: Span) -> Option<recorder::Row> {
264 let def_map = self.tcx.def_map.borrow();
265 if !def_map.contains_key(&ref_id) {
266 self.sess.span_bug(span,
267 &format!("def_map has no key for {} in lookup_def_kind",
268 ref_id));
269 }
270 let def = def_map.get(&ref_id).unwrap().full_def();
271 match def {
272 Def::Mod(_) |
273 Def::ForeignMod(_) => Some(recorder::ModRef),
274 Def::Struct(..) => Some(recorder::TypeRef),
275 Def::Enum(..) |
276 Def::TyAlias(..) |
277 Def::AssociatedTy(..) |
278 Def::Trait(_) => Some(recorder::TypeRef),
279 Def::Static(_, _) |
280 Def::Const(_) |
281 Def::AssociatedConst(..) |
282 Def::Local(..) |
283 Def::Variant(..) |
284 Def::Upvar(..) => Some(recorder::VarRef),
285
286 Def::Fn(..) => Some(recorder::FnRef),
287
288 Def::SelfTy(..) |
289 Def::Label(_) |
290 Def::TyParam(..) |
291 Def::Method(..) |
292 Def::PrimTy(_) |
293 Def::Err => {
294 self.sess.span_bug(span,
295 &format!("lookup_def_kind for unexpected item: {:?}", def));
296 }
297 }
298 }
299
300 fn process_formals(&mut self, formals: &Vec<ast::Arg>, qualname: &str) {
301 for arg in formals {
302 self.visit_pat(&arg.pat);
303 let mut collector = PathCollector::new();
304 collector.visit_pat(&arg.pat);
305 let span_utils = self.span.clone();
306 for &(id, ref p, _, _) in &collector.collected_paths {
307 let typ = self.tcx.node_types().get(&id).unwrap().to_string();
308 // get the span only for the name of the variable (I hope the path is only ever a
309 // variable name, but who knows?)
310 self.fmt.formal_str(p.span,
311 span_utils.span_for_last_ident(p.span),
312 id,
313 qualname,
314 &path_to_string(p),
315 &typ);
316 }
317 }
318 }
319
320 fn process_method(&mut self,
321 sig: &ast::MethodSig,
322 body: Option<&ast::Block>,
323 id: ast::NodeId,
324 name: ast::Name,
325 span: Span) {
326 debug!("process_method: {}:{}", id, name);
327
328 if let Some(method_data) = self.save_ctxt.get_method_data(id, name, span) {
329
330 if body.is_some() {
331 self.fmt.method_str(span,
332 Some(method_data.span),
333 method_data.id,
334 &method_data.qualname,
335 method_data.declaration,
336 method_data.scope);
337 self.process_formals(&sig.decl.inputs, &method_data.qualname);
338 } else {
339 self.fmt.method_decl_str(span,
340 Some(method_data.span),
341 method_data.id,
342 &method_data.qualname,
343 method_data.scope);
344 }
345 self.process_generic_params(&sig.generics, span, &method_data.qualname, id);
346 }
347
348 // walk arg and return types
349 for arg in &sig.decl.inputs {
350 self.visit_ty(&arg.ty);
351 }
352
353 if let ast::FunctionRetTy::Ty(ref ret_ty) = sig.decl.output {
354 self.visit_ty(ret_ty);
355 }
356
357 // walk the fn body
358 if let Some(body) = body {
359 self.nest(id, |v| v.visit_block(body));
360 }
361 }
362
363 fn process_trait_ref(&mut self, trait_ref: &ast::TraitRef) {
364 let trait_ref_data = self.save_ctxt.get_trait_ref_data(trait_ref, self.cur_scope);
365 if let Some(trait_ref_data) = trait_ref_data {
366 self.fmt.ref_str(recorder::TypeRef,
367 trait_ref.path.span,
368 Some(trait_ref_data.span),
369 trait_ref_data.ref_id,
370 trait_ref_data.scope);
371 visit::walk_path(self, &trait_ref.path);
372 }
373 }
374
375 fn process_struct_field_def(&mut self, field: &ast::StructField, parent_id: NodeId) {
376 let field_data = self.save_ctxt.get_field_data(field, parent_id);
377 if let Some(field_data) = field_data {
378 self.fmt.field_str(field.span,
379 Some(field_data.span),
380 field_data.id,
381 &field_data.name,
382 &field_data.qualname,
383 &field_data.type_value,
384 field_data.scope);
385 }
386 }
387
388 // Dump generic params bindings, then visit_generics
389 fn process_generic_params(&mut self,
390 generics: &ast::Generics,
391 full_span: Span,
392 prefix: &str,
393 id: NodeId) {
394 // We can't only use visit_generics since we don't have spans for param
395 // bindings, so we reparse the full_span to get those sub spans.
396 // However full span is the entire enum/fn/struct block, so we only want
397 // the first few to match the number of generics we're looking for.
398 let param_sub_spans = self.span.spans_for_ty_params(full_span,
399 (generics.ty_params.len() as isize));
400 for (param, param_ss) in generics.ty_params.iter().zip(param_sub_spans) {
401 // Append $id to name to make sure each one is unique
402 let name = format!("{}::{}${}",
403 prefix,
404 escape(self.span.snippet(param_ss)),
405 id);
406 self.fmt.typedef_str(full_span, Some(param_ss), param.id, &name, "");
407 }
408 self.visit_generics(generics);
409 }
410
411 fn process_fn(&mut self,
412 item: &ast::Item,
413 decl: &ast::FnDecl,
414 ty_params: &ast::Generics,
415 body: &ast::Block) {
416 if let Some(fn_data) = self.save_ctxt.get_item_data(item) {
417 down_cast_data!(fn_data, FunctionData, self, item.span);
418 self.fmt.fn_str(item.span,
419 Some(fn_data.span),
420 fn_data.id,
421 &fn_data.qualname,
422 fn_data.scope);
423
424 self.process_formals(&decl.inputs, &fn_data.qualname);
425 self.process_generic_params(ty_params, item.span, &fn_data.qualname, item.id);
426 }
427
428 for arg in &decl.inputs {
429 self.visit_ty(&arg.ty);
430 }
431
432 if let ast::FunctionRetTy::Ty(ref ret_ty) = decl.output {
433 self.visit_ty(&ret_ty);
434 }
435
436 self.nest(item.id, |v| v.visit_block(&body));
437 }
438
439 fn process_static_or_const_item(&mut self, item: &ast::Item, typ: &ast::Ty, expr: &ast::Expr) {
440 if let Some(var_data) = self.save_ctxt.get_item_data(item) {
441 down_cast_data!(var_data, VariableData, self, item.span);
442 self.fmt.static_str(item.span,
443 Some(var_data.span),
444 var_data.id,
445 &var_data.name,
446 &var_data.qualname,
447 &var_data.value,
448 &var_data.type_value,
449 var_data.scope);
450 }
451 self.visit_ty(&typ);
452 self.visit_expr(expr);
453 }
454
455 fn process_const(&mut self,
456 id: ast::NodeId,
457 name: ast::Name,
458 span: Span,
459 typ: &ast::Ty,
460 expr: &ast::Expr) {
461 let qualname = format!("::{}", self.tcx.map.path_to_string(id));
462
463 let sub_span = self.span.sub_span_after_keyword(span, keywords::Const);
464
465 self.fmt.static_str(span,
466 sub_span,
467 id,
468 &name.as_str(),
469 &qualname,
470 &self.span.snippet(expr.span),
471 &ty_to_string(&typ),
472 self.cur_scope);
473
474 // walk type and init value
475 self.visit_ty(typ);
476 self.visit_expr(expr);
477 }
478
479 fn process_struct(&mut self,
480 item: &ast::Item,
481 def: &ast::VariantData,
482 ty_params: &ast::Generics) {
483 let qualname = format!("::{}", self.tcx.map.path_to_string(item.id));
484
485 let val = self.span.snippet(item.span);
486 let sub_span = self.span.sub_span_after_keyword(item.span, keywords::Struct);
487 self.fmt.struct_str(item.span,
488 sub_span,
489 item.id,
490 def.id(),
491 &qualname,
492 self.cur_scope,
493 &val);
494
495 // fields
496 for field in def.fields() {
497 self.process_struct_field_def(field, item.id);
498 self.visit_ty(&field.node.ty);
499 }
500
501 self.process_generic_params(ty_params, item.span, &qualname, item.id);
502 }
503
504 fn process_enum(&mut self,
505 item: &ast::Item,
506 enum_definition: &ast::EnumDef,
507 ty_params: &ast::Generics) {
508 let enum_data = self.save_ctxt.get_item_data(item);
509 let enum_data = match enum_data {
510 None => return,
511 Some(data) => data,
512 };
513 down_cast_data!(enum_data, EnumData, self, item.span);
514 self.fmt.enum_str(item.span,
515 Some(enum_data.span),
516 enum_data.id,
517 &enum_data.qualname,
518 enum_data.scope,
519 &enum_data.value);
520
521 for variant in &enum_definition.variants {
522 let name = &variant.node.name.name.as_str();
523 let mut qualname = enum_data.qualname.clone();
524 qualname.push_str("::");
525 qualname.push_str(name);
526 let val = self.span.snippet(variant.span);
527
528 match variant.node.data {
529 ast::VariantData::Struct(..) => {
530 self.fmt.struct_variant_str(variant.span,
531 self.span.span_for_first_ident(variant.span),
532 variant.node.data.id(),
533 &qualname,
534 &enum_data.qualname,
535 &val,
536 enum_data.scope);
537 }
538 _ => {
539 self.fmt.tuple_variant_str(variant.span,
540 self.span.span_for_first_ident(variant.span),
541 variant.node.data.id(),
542 name,
543 &qualname,
544 &enum_data.qualname,
545 &val,
546 enum_data.scope);
547 }
548 }
549
550
551 for field in variant.node.data.fields() {
552 self.process_struct_field_def(field, variant.node.data.id());
553 self.visit_ty(&field.node.ty);
554 }
555 }
556 self.process_generic_params(ty_params, item.span, &enum_data.qualname, enum_data.id);
557 }
558
559 fn process_impl(&mut self,
560 item: &ast::Item,
561 type_parameters: &ast::Generics,
562 trait_ref: &Option<ast::TraitRef>,
563 typ: &ast::Ty,
564 impl_items: &[ast::ImplItem]) {
565 let mut has_self_ref = false;
566 if let Some(impl_data) = self.save_ctxt.get_item_data(item) {
567 down_cast_data!(impl_data, ImplData, self, item.span);
568 if let Some(ref self_ref) = impl_data.self_ref {
569 has_self_ref = true;
570 self.fmt.ref_str(recorder::TypeRef,
571 item.span,
572 Some(self_ref.span),
573 self_ref.ref_id,
574 self_ref.scope);
575 }
576 if let Some(ref trait_ref_data) = impl_data.trait_ref {
577 self.fmt.ref_str(recorder::TypeRef,
578 item.span,
579 Some(trait_ref_data.span),
580 trait_ref_data.ref_id,
581 trait_ref_data.scope);
582 visit::walk_path(self, &trait_ref.as_ref().unwrap().path);
583 }
584
585 self.fmt.impl_str(item.span,
586 Some(impl_data.span),
587 impl_data.id,
588 impl_data.self_ref.map(|data| data.ref_id),
589 impl_data.trait_ref.map(|data| data.ref_id),
590 impl_data.scope);
591 }
592 if !has_self_ref {
593 self.visit_ty(&typ);
594 }
595 self.process_generic_params(type_parameters, item.span, "", item.id);
596 for impl_item in impl_items {
597 self.visit_impl_item(impl_item);
598 }
599 }
600
601 fn process_trait(&mut self,
602 item: &ast::Item,
603 generics: &ast::Generics,
604 trait_refs: &ast::TyParamBounds,
605 methods: &[ast::TraitItem]) {
606 let qualname = format!("::{}", self.tcx.map.path_to_string(item.id));
607 let val = self.span.snippet(item.span);
608 let sub_span = self.span.sub_span_after_keyword(item.span, keywords::Trait);
609 self.fmt.trait_str(item.span,
610 sub_span,
611 item.id,
612 &qualname,
613 self.cur_scope,
614 &val);
615
616 // super-traits
617 for super_bound in trait_refs.iter() {
618 let trait_ref = match *super_bound {
619 ast::TraitTyParamBound(ref trait_ref, _) => {
620 trait_ref
621 }
622 ast::RegionTyParamBound(..) => {
623 continue;
624 }
625 };
626
627 let trait_ref = &trait_ref.trait_ref;
628 match self.lookup_type_ref(trait_ref.ref_id) {
629 Some(id) => {
630 let sub_span = self.span.sub_span_for_type_name(trait_ref.path.span);
631 self.fmt.ref_str(recorder::TypeRef,
632 trait_ref.path.span,
633 sub_span,
634 id,
635 self.cur_scope);
636 self.fmt.inherit_str(trait_ref.path.span, sub_span, id, item.id);
637 }
638 None => (),
639 }
640 }
641
642 // walk generics and methods
643 self.process_generic_params(generics, item.span, &qualname, item.id);
644 for method in methods {
645 self.visit_trait_item(method)
646 }
647 }
648
649 // `item` is the module in question, represented as an item.
650 fn process_mod(&mut self, item: &ast::Item) {
651 if let Some(mod_data) = self.save_ctxt.get_item_data(item) {
652 down_cast_data!(mod_data, ModData, self, item.span);
653 self.fmt.mod_str(item.span,
654 Some(mod_data.span),
655 mod_data.id,
656 &mod_data.qualname,
657 mod_data.scope,
658 &mod_data.filename);
659 }
660 }
661
662 fn process_path(&mut self, id: NodeId, path: &ast::Path, ref_kind: Option<recorder::Row>) {
663 let path_data = self.save_ctxt.get_path_data(id, path);
664 if generated_code(path.span) && path_data.is_none() {
665 return;
666 }
667
668 let path_data = match path_data {
669 Some(pd) => pd,
670 None => {
671 self.tcx.sess.span_bug(path.span,
672 &format!("Unexpected def kind while looking up path in \
673 `{}`",
674 self.span.snippet(path.span)))
675 }
676 };
677 match path_data {
678 Data::VariableRefData(ref vrd) => {
679 self.fmt.ref_str(ref_kind.unwrap_or(recorder::VarRef),
680 path.span,
681 Some(vrd.span),
682 vrd.ref_id,
683 vrd.scope);
684
685 }
686 Data::TypeRefData(ref trd) => {
687 self.fmt.ref_str(recorder::TypeRef,
688 path.span,
689 Some(trd.span),
690 trd.ref_id,
691 trd.scope);
692 }
693 Data::MethodCallData(ref mcd) => {
694 self.fmt.meth_call_str(path.span,
695 Some(mcd.span),
696 mcd.ref_id,
697 mcd.decl_id,
698 mcd.scope);
699 }
700 Data::FunctionCallData(fcd) => {
701 self.fmt.fn_call_str(path.span, Some(fcd.span), fcd.ref_id, fcd.scope);
702 }
703 _ => {
704 self.sess.span_bug(path.span,
705 &format!("Unexpected data: {:?}", path_data));
706 }
707 }
708
709 // Modules or types in the path prefix.
710 let def_map = self.tcx.def_map.borrow();
711 let def = def_map.get(&id).unwrap().full_def();
712 match def {
713 Def::Method(did) => {
714 let ti = self.tcx.impl_or_trait_item(did);
715 if let ty::MethodTraitItem(m) = ti {
716 if m.explicit_self == ty::ExplicitSelfCategory::Static {
717 self.write_sub_path_trait_truncated(path);
718 }
719 }
720 }
721 Def::Local(..) |
722 Def::Static(_,_) |
723 Def::Const(..) |
724 Def::AssociatedConst(..) |
725 Def::Struct(..) |
726 Def::Variant(..) |
727 Def::Fn(..) => self.write_sub_paths_truncated(path, false),
728 _ => {}
729 }
730 }
731
732 fn process_struct_lit(&mut self,
733 ex: &ast::Expr,
734 path: &ast::Path,
735 fields: &Vec<ast::Field>,
736 variant: ty::VariantDef,
737 base: &Option<P<ast::Expr>>) {
738 self.write_sub_paths_truncated(path, false);
739
740 if let Some(struct_lit_data) = self.save_ctxt.get_expr_data(ex) {
741 down_cast_data!(struct_lit_data, TypeRefData, self, ex.span);
742 self.fmt.ref_str(recorder::TypeRef,
743 ex.span,
744 Some(struct_lit_data.span),
745 struct_lit_data.ref_id,
746 struct_lit_data.scope);
747 let scope = self.save_ctxt.enclosing_scope(ex.id);
748
749 for field in fields {
750 if let Some(field_data) = self.save_ctxt
751 .get_field_ref_data(field, variant, scope) {
752
753 self.fmt.ref_str(recorder::VarRef,
754 field.ident.span,
755 Some(field_data.span),
756 field_data.ref_id,
757 field_data.scope);
758 }
759
760 self.visit_expr(&field.expr)
761 }
762 }
763
764 walk_list!(self, visit_expr, base);
765 }
766
767 fn process_method_call(&mut self, ex: &ast::Expr, args: &Vec<P<ast::Expr>>) {
768 if let Some(call_data) = self.save_ctxt.get_expr_data(ex) {
769 down_cast_data!(call_data, MethodCallData, self, ex.span);
770 self.fmt.meth_call_str(ex.span,
771 Some(call_data.span),
772 call_data.ref_id,
773 call_data.decl_id,
774 call_data.scope);
775 }
776
777 // walk receiver and args
778 walk_list!(self, visit_expr, args);
779 }
780
781 fn process_pat(&mut self, p: &ast::Pat) {
782 match p.node {
783 PatKind::Struct(ref path, ref fields, _) => {
784 visit::walk_path(self, path);
785 let adt = self.tcx.node_id_to_type(p.id).ty_adt_def().unwrap();
786 let def = self.tcx.def_map.borrow()[&p.id].full_def();
787 let variant = adt.variant_of_def(def);
788
789 for &Spanned { node: ref field, span } in fields {
790 let sub_span = self.span.span_for_first_ident(span);
791 if let Some(f) = variant.find_field_named(field.ident.name) {
792 self.fmt.ref_str(recorder::VarRef, span, sub_span, f.did, self.cur_scope);
793 }
794 self.visit_pat(&field.pat);
795 }
796 }
797 _ => visit::walk_pat(self, p),
798 }
799 }
800
801
802 fn process_var_decl(&mut self, p: &ast::Pat, value: String) {
803 // The local could declare multiple new vars, we must walk the
804 // pattern and collect them all.
805 let mut collector = PathCollector::new();
806 collector.visit_pat(&p);
807 self.visit_pat(&p);
808
809 for &(id, ref p, immut, _) in &collector.collected_paths {
810 let value = if immut == ast::Mutability::Immutable {
811 value.to_string()
812 } else {
813 "<mutable>".to_string()
814 };
815 let types = self.tcx.node_types();
816 let typ = types.get(&id).map(|t| t.to_string()).unwrap_or(String::new());
817 // Get the span only for the name of the variable (I hope the path
818 // is only ever a variable name, but who knows?).
819 let sub_span = self.span.span_for_last_ident(p.span);
820 // Rust uses the id of the pattern for var lookups, so we'll use it too.
821 self.fmt.variable_str(p.span,
822 sub_span,
823 id,
824 &path_to_string(p),
825 &value,
826 &typ);
827 }
828 }
829
830 /// Extract macro use and definition information from the AST node defined
831 /// by the given NodeId, using the expansion information from the node's
832 /// span.
833 ///
834 /// If the span is not macro-generated, do nothing, else use callee and
835 /// callsite spans to record macro definition and use data, using the
836 /// mac_uses and mac_defs sets to prevent multiples.
837 fn process_macro_use(&mut self, span: Span, id: NodeId) {
838 let data = match self.save_ctxt.get_macro_use_data(span, id) {
839 None => return,
840 Some(data) => data,
841 };
842 let mut hasher = SipHasher::new();
843 data.callee_span.hash(&mut hasher);
844 let hash = hasher.finish();
845 let qualname = format!("{}::{}", data.name, hash);
846 // Don't write macro definition for imported macros
847 if !self.mac_defs.contains(&data.callee_span)
848 && !data.imported {
849 self.mac_defs.insert(data.callee_span);
850 if let Some(sub_span) = self.span.span_for_macro_def_name(data.callee_span) {
851 self.fmt.macro_str(data.callee_span, sub_span,
852 data.name.clone(), qualname.clone());
853 }
854 }
855 if !self.mac_uses.contains(&data.span) {
856 self.mac_uses.insert(data.span);
857 if let Some(sub_span) = self.span.span_for_macro_use_name(data.span) {
858 self.fmt.macro_use_str(data.span, sub_span, data.name,
859 qualname, data.scope);
860 }
861 }
862 }
863 }
864
865 impl<'l, 'tcx, 'v> Visitor<'v> for DumpCsvVisitor<'l, 'tcx> {
866 fn visit_item(&mut self, item: &ast::Item) {
867 use syntax::ast::ItemKind::*;
868 self.process_macro_use(item.span, item.id);
869 match item.node {
870 Use(ref use_item) => {
871 match use_item.node {
872 ast::ViewPathSimple(ident, ref path) => {
873 let sub_span = self.span.span_for_last_ident(path.span);
874 let mod_id = match self.lookup_type_ref(item.id) {
875 Some(def_id) => {
876 match self.lookup_def_kind(item.id, path.span) {
877 Some(kind) => self.fmt.ref_str(kind,
878 path.span,
879 sub_span,
880 def_id,
881 self.cur_scope),
882 None => {}
883 }
884 Some(def_id)
885 }
886 None => None,
887 };
888
889 // 'use' always introduces an alias, if there is not an explicit
890 // one, there is an implicit one.
891 let sub_span = match self.span.sub_span_after_keyword(use_item.span,
892 keywords::As) {
893 Some(sub_span) => Some(sub_span),
894 None => sub_span,
895 };
896
897 self.fmt.use_alias_str(path.span,
898 sub_span,
899 item.id,
900 mod_id,
901 &ident.name.as_str(),
902 self.cur_scope);
903 self.write_sub_paths_truncated(path, true);
904 }
905 ast::ViewPathGlob(ref path) => {
906 // Make a comma-separated list of names of imported modules.
907 let mut name_string = String::new();
908 let glob_map = &self.analysis.glob_map;
909 let glob_map = glob_map.as_ref().unwrap();
910 if glob_map.contains_key(&item.id) {
911 for n in glob_map.get(&item.id).unwrap() {
912 if !name_string.is_empty() {
913 name_string.push_str(", ");
914 }
915 name_string.push_str(&n.as_str());
916 }
917 }
918
919 let sub_span = self.span
920 .sub_span_of_token(path.span, token::BinOp(token::Star));
921 self.fmt.use_glob_str(path.span,
922 sub_span,
923 item.id,
924 &name_string,
925 self.cur_scope);
926 self.write_sub_paths(path, true);
927 }
928 ast::ViewPathList(ref path, ref list) => {
929 for plid in list {
930 match plid.node {
931 ast::PathListItemKind::Ident { id, .. } => {
932 match self.lookup_type_ref(id) {
933 Some(def_id) => match self.lookup_def_kind(id, plid.span) {
934 Some(kind) => {
935 self.fmt.ref_str(kind,
936 plid.span,
937 Some(plid.span),
938 def_id,
939 self.cur_scope);
940 }
941 None => (),
942 },
943 None => (),
944 }
945 }
946 ast::PathListItemKind::Mod { .. } => (),
947 }
948 }
949
950 self.write_sub_paths(path, true);
951 }
952 }
953 }
954 ExternCrate(ref s) => {
955 let location = match *s {
956 Some(s) => s.to_string(),
957 None => item.ident.to_string(),
958 };
959 let alias_span = self.span.span_for_last_ident(item.span);
960 let cnum = match self.sess.cstore.extern_mod_stmt_cnum(item.id) {
961 Some(cnum) => cnum,
962 None => 0,
963 };
964 self.fmt.extern_crate_str(item.span,
965 alias_span,
966 item.id,
967 cnum,
968 &item.ident.name.as_str(),
969 &location,
970 self.cur_scope);
971 }
972 Fn(ref decl, _, _, _, ref ty_params, ref body) =>
973 self.process_fn(item, &decl, ty_params, &body),
974 Static(ref typ, _, ref expr) =>
975 self.process_static_or_const_item(item, typ, expr),
976 Const(ref typ, ref expr) =>
977 self.process_static_or_const_item(item, &typ, &expr),
978 Struct(ref def, ref ty_params) => self.process_struct(item, def, ty_params),
979 Enum(ref def, ref ty_params) => self.process_enum(item, def, ty_params),
980 Impl(_, _,
981 ref ty_params,
982 ref trait_ref,
983 ref typ,
984 ref impl_items) => {
985 self.process_impl(item, ty_params, trait_ref, &typ, impl_items)
986 }
987 Trait(_, ref generics, ref trait_refs, ref methods) =>
988 self.process_trait(item, generics, trait_refs, methods),
989 Mod(ref m) => {
990 self.process_mod(item);
991 self.nest(item.id, |v| visit::walk_mod(v, m));
992 }
993 Ty(ref ty, ref ty_params) => {
994 let qualname = format!("::{}", self.tcx.map.path_to_string(item.id));
995 let value = ty_to_string(&ty);
996 let sub_span = self.span.sub_span_after_keyword(item.span, keywords::Type);
997 self.fmt.typedef_str(item.span, sub_span, item.id, &qualname, &value);
998
999 self.visit_ty(&ty);
1000 self.process_generic_params(ty_params, item.span, &qualname, item.id);
1001 }
1002 Mac(_) => (),
1003 _ => visit::walk_item(self, item),
1004 }
1005 }
1006
1007 fn visit_generics(&mut self, generics: &ast::Generics) {
1008 for param in generics.ty_params.iter() {
1009 for bound in param.bounds.iter() {
1010 if let ast::TraitTyParamBound(ref trait_ref, _) = *bound {
1011 self.process_trait_ref(&trait_ref.trait_ref);
1012 }
1013 }
1014 if let Some(ref ty) = param.default {
1015 self.visit_ty(&ty);
1016 }
1017 }
1018 }
1019
1020 fn visit_trait_item(&mut self, trait_item: &ast::TraitItem) {
1021 self.process_macro_use(trait_item.span, trait_item.id);
1022 match trait_item.node {
1023 ast::TraitItemKind::Const(ref ty, Some(ref expr)) => {
1024 self.process_const(trait_item.id,
1025 trait_item.ident.name,
1026 trait_item.span,
1027 &ty,
1028 &expr);
1029 }
1030 ast::TraitItemKind::Method(ref sig, ref body) => {
1031 self.process_method(sig,
1032 body.as_ref().map(|x| &**x),
1033 trait_item.id,
1034 trait_item.ident.name,
1035 trait_item.span);
1036 }
1037 ast::TraitItemKind::Const(_, None) |
1038 ast::TraitItemKind::Type(..) => {}
1039 }
1040 }
1041
1042 fn visit_impl_item(&mut self, impl_item: &ast::ImplItem) {
1043 self.process_macro_use(impl_item.span, impl_item.id);
1044 match impl_item.node {
1045 ast::ImplItemKind::Const(ref ty, ref expr) => {
1046 self.process_const(impl_item.id,
1047 impl_item.ident.name,
1048 impl_item.span,
1049 &ty,
1050 &expr);
1051 }
1052 ast::ImplItemKind::Method(ref sig, ref body) => {
1053 self.process_method(sig,
1054 Some(body),
1055 impl_item.id,
1056 impl_item.ident.name,
1057 impl_item.span);
1058 }
1059 ast::ImplItemKind::Type(_) |
1060 ast::ImplItemKind::Macro(_) => {}
1061 }
1062 }
1063
1064 fn visit_ty(&mut self, t: &ast::Ty) {
1065 self.process_macro_use(t.span, t.id);
1066 match t.node {
1067 ast::TyKind::Path(_, ref path) => {
1068 match self.lookup_type_ref(t.id) {
1069 Some(id) => {
1070 let sub_span = self.span.sub_span_for_type_name(t.span);
1071 self.fmt.ref_str(recorder::TypeRef, t.span, sub_span, id, self.cur_scope);
1072 }
1073 None => (),
1074 }
1075
1076 self.write_sub_paths_truncated(path, false);
1077
1078 visit::walk_path(self, path);
1079 }
1080 _ => visit::walk_ty(self, t),
1081 }
1082 }
1083
1084 fn visit_expr(&mut self, ex: &ast::Expr) {
1085 self.process_macro_use(ex.span, ex.id);
1086 match ex.node {
1087 ast::ExprKind::Call(ref _f, ref _args) => {
1088 // Don't need to do anything for function calls,
1089 // because just walking the callee path does what we want.
1090 visit::walk_expr(self, ex);
1091 }
1092 ast::ExprKind::Path(_, ref path) => {
1093 self.process_path(ex.id, path, None);
1094 visit::walk_expr(self, ex);
1095 }
1096 ast::ExprKind::Struct(ref path, ref fields, ref base) => {
1097 let hir_expr = lower_expr(self.save_ctxt.lcx, ex);
1098 let adt = self.tcx.expr_ty(&hir_expr).ty_adt_def().unwrap();
1099 let def = self.tcx.resolve_expr(&hir_expr);
1100 self.process_struct_lit(ex, path, fields, adt.variant_of_def(def), base)
1101 }
1102 ast::ExprKind::MethodCall(_, _, ref args) => self.process_method_call(ex, args),
1103 ast::ExprKind::Field(ref sub_ex, _) => {
1104 self.visit_expr(&sub_ex);
1105
1106 if let Some(field_data) = self.save_ctxt.get_expr_data(ex) {
1107 down_cast_data!(field_data, VariableRefData, self, ex.span);
1108 self.fmt.ref_str(recorder::VarRef,
1109 ex.span,
1110 Some(field_data.span),
1111 field_data.ref_id,
1112 field_data.scope);
1113 }
1114 }
1115 ast::ExprKind::TupField(ref sub_ex, idx) => {
1116 self.visit_expr(&sub_ex);
1117
1118 let hir_node = lower_expr(self.save_ctxt.lcx, sub_ex);
1119 let ty = &self.tcx.expr_ty_adjusted(&hir_node).sty;
1120 match *ty {
1121 ty::TyStruct(def, _) => {
1122 let sub_span = self.span.sub_span_after_token(ex.span, token::Dot);
1123 self.fmt.ref_str(recorder::VarRef,
1124 ex.span,
1125 sub_span,
1126 def.struct_variant().fields[idx.node].did,
1127 self.cur_scope);
1128 }
1129 ty::TyTuple(_) => {}
1130 _ => self.sess.span_bug(ex.span,
1131 &format!("Expected struct or tuple type, found {:?}",
1132 ty)),
1133 }
1134 }
1135 ast::ExprKind::Closure(_, ref decl, ref body) => {
1136 let mut id = String::from("$");
1137 id.push_str(&ex.id.to_string());
1138 self.process_formals(&decl.inputs, &id);
1139
1140 // walk arg and return types
1141 for arg in &decl.inputs {
1142 self.visit_ty(&arg.ty);
1143 }
1144
1145 if let ast::FunctionRetTy::Ty(ref ret_ty) = decl.output {
1146 self.visit_ty(&ret_ty);
1147 }
1148
1149 // walk the body
1150 self.nest(ex.id, |v| v.visit_block(&body));
1151 }
1152 ast::ExprKind::ForLoop(ref pattern, ref subexpression, ref block, _) |
1153 ast::ExprKind::WhileLet(ref pattern, ref subexpression, ref block, _) => {
1154 let value = self.span.snippet(mk_sp(ex.span.lo, subexpression.span.hi));
1155 self.process_var_decl(pattern, value);
1156 visit::walk_expr(self, subexpression);
1157 visit::walk_block(self, block);
1158 }
1159 ast::ExprKind::IfLet(ref pattern, ref subexpression, ref block, ref opt_else) => {
1160 let value = self.span.snippet(mk_sp(ex.span.lo, subexpression.span.hi));
1161 self.process_var_decl(pattern, value);
1162 visit::walk_expr(self, subexpression);
1163 visit::walk_block(self, block);
1164 opt_else.as_ref().map(|el| visit::walk_expr(self, el));
1165 }
1166 _ => {
1167 visit::walk_expr(self, ex)
1168 }
1169 }
1170 }
1171
1172 fn visit_mac(&mut self, mac: &ast::Mac) {
1173 // These shouldn't exist in the AST at this point, log a span bug.
1174 self.sess.span_bug(mac.span, "macro invocation should have been expanded out of AST");
1175 }
1176
1177 fn visit_pat(&mut self, p: &ast::Pat) {
1178 self.process_macro_use(p.span, p.id);
1179 self.process_pat(p);
1180 }
1181
1182 fn visit_arm(&mut self, arm: &ast::Arm) {
1183 let mut collector = PathCollector::new();
1184 for pattern in &arm.pats {
1185 // collect paths from the arm's patterns
1186 collector.visit_pat(&pattern);
1187 self.visit_pat(&pattern);
1188 }
1189
1190 // This is to get around borrow checking, because we need mut self to call process_path.
1191 let mut paths_to_process = vec![];
1192
1193 // process collected paths
1194 for &(id, ref p, immut, ref_kind) in &collector.collected_paths {
1195 let def_map = self.tcx.def_map.borrow();
1196 if !def_map.contains_key(&id) {
1197 self.sess.span_bug(p.span,
1198 &format!("def_map has no key for {} in visit_arm", id));
1199 }
1200 let def = def_map.get(&id).unwrap().full_def();
1201 match def {
1202 Def::Local(_, id) => {
1203 let value = if immut == ast::Mutability::Immutable {
1204 self.span.snippet(p.span).to_string()
1205 } else {
1206 "<mutable>".to_string()
1207 };
1208
1209 assert!(p.segments.len() == 1,
1210 "qualified path for local variable def in arm");
1211 self.fmt.variable_str(p.span, Some(p.span), id, &path_to_string(p), &value, "")
1212 }
1213 Def::Variant(..) | Def::Enum(..) |
1214 Def::TyAlias(..) | Def::Struct(..) => {
1215 paths_to_process.push((id, p.clone(), Some(ref_kind)))
1216 }
1217 // FIXME(nrc) what are these doing here?
1218 Def::Static(_, _) |
1219 Def::Const(..) |
1220 Def::AssociatedConst(..) => {}
1221 _ => error!("unexpected definition kind when processing collected paths: {:?}",
1222 def),
1223 }
1224 }
1225
1226 for &(id, ref path, ref_kind) in &paths_to_process {
1227 self.process_path(id, path, ref_kind);
1228 }
1229 walk_list!(self, visit_expr, &arm.guard);
1230 self.visit_expr(&arm.body);
1231 }
1232
1233 fn visit_stmt(&mut self, s: &ast::Stmt) {
1234 let id = s.node.id();
1235 self.process_macro_use(s.span, id.unwrap());
1236 visit::walk_stmt(self, s)
1237 }
1238
1239 fn visit_local(&mut self, l: &ast::Local) {
1240 self.process_macro_use(l.span, l.id);
1241 let value = self.span.snippet(l.span);
1242 self.process_var_decl(&l.pat, value);
1243
1244 // Just walk the initialiser and type (don't want to walk the pattern again).
1245 walk_list!(self, visit_ty, &l.ty);
1246 walk_list!(self, visit_expr, &l.init);
1247 }
1248 }