]> git.proxmox.com Git - rustc.git/blob - src/librustc_save_analysis/lib.rs
Imported Upstream version 1.9.0+dfsg1
[rustc.git] / src / librustc_save_analysis / lib.rs
1 // Copyright 2012-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 #![crate_name = "rustc_save_analysis"]
12 #![unstable(feature = "rustc_private", issue = "27812")]
13 #![crate_type = "dylib"]
14 #![crate_type = "rlib"]
15 #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
16 html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
17 html_root_url = "https://doc.rust-lang.org/nightly/")]
18 #![cfg_attr(not(stage0), deny(warnings))]
19
20 #![feature(custom_attribute)]
21 #![allow(unused_attributes)]
22 #![feature(rustc_private)]
23 #![feature(staged_api)]
24
25 #[macro_use] extern crate rustc;
26
27 #[macro_use] extern crate log;
28 #[macro_use] extern crate syntax;
29
30 use rustc::hir::{self, lowering};
31 use rustc::hir::map::NodeItem;
32 use rustc::hir::def::Def;
33 use rustc::hir::def_id::DefId;
34 use rustc::session::config::CrateType::CrateTypeExecutable;
35 use rustc::ty::{self, TyCtxt};
36
37 use std::env;
38 use std::fs::{self, File};
39 use std::path::{Path, PathBuf};
40
41 use syntax::ast::{self, NodeId, PatKind};
42 use syntax::codemap::*;
43 use syntax::parse::token::{self, keywords};
44 use syntax::visit::{self, Visitor};
45 use syntax::print::pprust::ty_to_string;
46
47 mod csv_dumper;
48 mod data;
49 mod dump;
50 mod dump_visitor;
51 #[macro_use]
52 pub mod span_utils;
53
54 pub use self::csv_dumper::CsvDumper;
55 pub use self::data::*;
56 pub use self::dump::Dump;
57 pub use self::dump_visitor::DumpVisitor;
58 use self::span_utils::SpanUtils;
59
60 // FIXME this is legacy code and should be removed
61 pub mod recorder {
62 pub use self::Row::*;
63
64 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
65 pub enum Row {
66 TypeRef,
67 ModRef,
68 VarRef,
69 FnRef,
70 }
71 }
72
73 pub struct SaveContext<'l, 'tcx: 'l> {
74 tcx: &'l TyCtxt<'tcx>,
75 lcx: &'l lowering::LoweringContext<'l>,
76 span_utils: SpanUtils<'l>,
77 }
78
79 macro_rules! option_try(
80 ($e:expr) => (match $e { Some(e) => e, None => return None })
81 );
82
83 impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
84 pub fn new(tcx: &'l TyCtxt<'tcx>,
85 lcx: &'l lowering::LoweringContext<'l>)
86 -> SaveContext<'l, 'tcx> {
87 let span_utils = SpanUtils::new(&tcx.sess);
88 SaveContext::from_span_utils(tcx, lcx, span_utils)
89 }
90
91 pub fn from_span_utils(tcx: &'l TyCtxt<'tcx>,
92 lcx: &'l lowering::LoweringContext<'l>,
93 span_utils: SpanUtils<'l>)
94 -> SaveContext<'l, 'tcx> {
95 SaveContext {
96 tcx: tcx,
97 lcx: lcx,
98 span_utils: span_utils,
99 }
100 }
101
102 // List external crates used by the current crate.
103 pub fn get_external_crates(&self) -> Vec<CrateData> {
104 let mut result = Vec::new();
105
106 for n in self.tcx.sess.cstore.crates() {
107 result.push(CrateData {
108 name: (&self.tcx.sess.cstore.crate_name(n)[..]).to_owned(),
109 number: n,
110 });
111 }
112
113 result
114 }
115
116 pub fn get_item_data(&self, item: &ast::Item) -> Option<Data> {
117 match item.node {
118 ast::ItemKind::Fn(..) => {
119 let name = self.tcx.node_path_str(item.id);
120 let qualname = format!("::{}", name);
121 let sub_span = self.span_utils.sub_span_after_keyword(item.span, keywords::Fn);
122 filter!(self.span_utils, sub_span, item.span, None);
123 Some(Data::FunctionData(FunctionData {
124 id: item.id,
125 name: name,
126 qualname: qualname,
127 declaration: None,
128 span: sub_span.unwrap(),
129 scope: self.enclosing_scope(item.id),
130 }))
131 }
132 ast::ItemKind::Static(ref typ, mt, ref expr) => {
133 let qualname = format!("::{}", self.tcx.node_path_str(item.id));
134
135 // If the variable is immutable, save the initialising expression.
136 let (value, keyword) = match mt {
137 ast::Mutability::Mutable => (String::from("<mutable>"), keywords::Mut),
138 ast::Mutability::Immutable => {
139 (self.span_utils.snippet(expr.span), keywords::Static)
140 },
141 };
142
143 let sub_span = self.span_utils.sub_span_after_keyword(item.span, keyword);
144 filter!(self.span_utils, sub_span, item.span, None);
145 Some(Data::VariableData(VariableData {
146 id: item.id,
147 name: item.ident.to_string(),
148 qualname: qualname,
149 span: sub_span.unwrap(),
150 scope: self.enclosing_scope(item.id),
151 value: value,
152 type_value: ty_to_string(&typ),
153 }))
154 }
155 ast::ItemKind::Const(ref typ, ref expr) => {
156 let qualname = format!("::{}", self.tcx.node_path_str(item.id));
157 let sub_span = self.span_utils.sub_span_after_keyword(item.span, keywords::Const);
158 filter!(self.span_utils, sub_span, item.span, None);
159 Some(Data::VariableData(VariableData {
160 id: item.id,
161 name: item.ident.to_string(),
162 qualname: qualname,
163 span: sub_span.unwrap(),
164 scope: self.enclosing_scope(item.id),
165 value: self.span_utils.snippet(expr.span),
166 type_value: ty_to_string(&typ),
167 }))
168 }
169 ast::ItemKind::Mod(ref m) => {
170 let qualname = format!("::{}", self.tcx.node_path_str(item.id));
171
172 let cm = self.tcx.sess.codemap();
173 let filename = cm.span_to_filename(m.inner);
174
175 let sub_span = self.span_utils.sub_span_after_keyword(item.span, keywords::Mod);
176 filter!(self.span_utils, sub_span, item.span, None);
177 Some(Data::ModData(ModData {
178 id: item.id,
179 name: item.ident.to_string(),
180 qualname: qualname,
181 span: sub_span.unwrap(),
182 scope: self.enclosing_scope(item.id),
183 filename: filename,
184 }))
185 }
186 ast::ItemKind::Enum(..) => {
187 let enum_name = format!("::{}", self.tcx.node_path_str(item.id));
188 let val = self.span_utils.snippet(item.span);
189 let sub_span = self.span_utils.sub_span_after_keyword(item.span, keywords::Enum);
190 filter!(self.span_utils, sub_span, item.span, None);
191 Some(Data::EnumData(EnumData {
192 id: item.id,
193 value: val,
194 span: sub_span.unwrap(),
195 qualname: enum_name,
196 scope: self.enclosing_scope(item.id),
197 }))
198 }
199 ast::ItemKind::Impl(_, _, _, ref trait_ref, ref typ, _) => {
200 let mut type_data = None;
201 let sub_span;
202
203 let parent = self.enclosing_scope(item.id);
204
205 match typ.node {
206 // Common case impl for a struct or something basic.
207 ast::TyKind::Path(None, ref path) => {
208 sub_span = self.span_utils.sub_span_for_type_name(path.span);
209 filter!(self.span_utils, sub_span, path.span, None);
210 type_data = self.lookup_ref_id(typ.id).map(|id| {
211 TypeRefData {
212 span: sub_span.unwrap(),
213 scope: parent,
214 ref_id: Some(id),
215 qualname: String::new() // FIXME: generate the real qualname
216 }
217 });
218 }
219 _ => {
220 // Less useful case, impl for a compound type.
221 let span = typ.span;
222 sub_span = self.span_utils.sub_span_for_type_name(span).or(Some(span));
223 }
224 }
225
226 let trait_data = trait_ref.as_ref()
227 .and_then(|tr| self.get_trait_ref_data(tr, parent));
228
229 filter!(self.span_utils, sub_span, typ.span, None);
230 Some(Data::ImplData(ImplData2 {
231 id: item.id,
232 span: sub_span.unwrap(),
233 scope: parent,
234 trait_ref: trait_data,
235 self_ref: type_data,
236 }))
237 }
238 _ => {
239 // FIXME
240 bug!();
241 }
242 }
243 }
244
245 pub fn get_field_data(&self, field: &ast::StructField,
246 scope: NodeId) -> Option<VariableData> {
247 if let Some(ident) = field.ident {
248 let qualname = format!("::{}::{}", self.tcx.node_path_str(scope), ident);
249 let typ = self.tcx.node_types().get(&field.id).unwrap().to_string();
250 let sub_span = self.span_utils.sub_span_before_token(field.span, token::Colon);
251 filter!(self.span_utils, sub_span, field.span, None);
252 Some(VariableData {
253 id: field.id,
254 name: ident.to_string(),
255 qualname: qualname,
256 span: sub_span.unwrap(),
257 scope: scope,
258 value: "".to_owned(),
259 type_value: typ,
260 })
261 } else {
262 None
263 }
264 }
265
266 // FIXME would be nice to take a MethodItem here, but the ast provides both
267 // trait and impl flavours, so the caller must do the disassembly.
268 pub fn get_method_data(&self, id: ast::NodeId,
269 name: ast::Name, span: Span) -> Option<FunctionData> {
270 // The qualname for a method is the trait name or name of the struct in an impl in
271 // which the method is declared in, followed by the method's name.
272 let qualname = match self.tcx.impl_of_method(self.tcx.map.local_def_id(id)) {
273 Some(impl_id) => match self.tcx.map.get_if_local(impl_id) {
274 Some(NodeItem(item)) => {
275 match item.node {
276 hir::ItemImpl(_, _, _, _, ref ty, _) => {
277 let mut result = String::from("<");
278 result.push_str(&rustc::hir::print::ty_to_string(&ty));
279
280 match self.tcx.trait_of_item(self.tcx.map.local_def_id(id)) {
281 Some(def_id) => {
282 result.push_str(" as ");
283 result.push_str(&self.tcx.item_path_str(def_id));
284 }
285 None => {}
286 }
287 result.push_str(">");
288 result
289 }
290 _ => {
291 span_bug!(span,
292 "Container {:?} for method {} not an impl?",
293 impl_id,
294 id);
295 }
296 }
297 }
298 r => {
299 span_bug!(span,
300 "Container {:?} for method {} is not a node item {:?}",
301 impl_id,
302 id,
303 r);
304 }
305 },
306 None => match self.tcx.trait_of_item(self.tcx.map.local_def_id(id)) {
307 Some(def_id) => {
308 match self.tcx.map.get_if_local(def_id) {
309 Some(NodeItem(_)) => {
310 format!("::{}", self.tcx.item_path_str(def_id))
311 }
312 r => {
313 span_bug!(span,
314 "Could not find container {:?} for \
315 method {}, got {:?}",
316 def_id,
317 id,
318 r);
319 }
320 }
321 }
322 None => {
323 span_bug!(span, "Could not find container for method {}", id);
324 }
325 },
326 };
327
328 let qualname = format!("{}::{}", qualname, name);
329
330 let def_id = self.tcx.map.local_def_id(id);
331 let decl_id = self.tcx.trait_item_of_item(def_id).and_then(|new_id| {
332 let new_def_id = new_id.def_id();
333 if new_def_id != def_id {
334 Some(new_def_id)
335 } else {
336 None
337 }
338 });
339
340 let sub_span = self.span_utils.sub_span_after_keyword(span, keywords::Fn);
341 filter!(self.span_utils, sub_span, span, None);
342 Some(FunctionData {
343 id: id,
344 name: name.to_string(),
345 qualname: qualname,
346 declaration: decl_id,
347 span: sub_span.unwrap(),
348 scope: self.enclosing_scope(id),
349 })
350 }
351
352 pub fn get_trait_ref_data(&self,
353 trait_ref: &ast::TraitRef,
354 parent: NodeId)
355 -> Option<TypeRefData> {
356 self.lookup_ref_id(trait_ref.ref_id).and_then(|def_id| {
357 let span = trait_ref.path.span;
358 let sub_span = self.span_utils.sub_span_for_type_name(span).or(Some(span));
359 filter!(self.span_utils, sub_span, span, None);
360 Some(TypeRefData {
361 span: sub_span.unwrap(),
362 scope: parent,
363 ref_id: Some(def_id),
364 qualname: String::new() // FIXME: generate the real qualname
365 })
366 })
367 }
368
369 pub fn get_expr_data(&self, expr: &ast::Expr) -> Option<Data> {
370 let hir_node = lowering::lower_expr(self.lcx, expr);
371 let ty = self.tcx.expr_ty_adjusted_opt(&hir_node);
372 if ty.is_none() || ty.unwrap().sty == ty::TyError {
373 return None;
374 }
375 match expr.node {
376 ast::ExprKind::Field(ref sub_ex, ident) => {
377 let hir_node = lowering::lower_expr(self.lcx, sub_ex);
378 match self.tcx.expr_ty_adjusted(&hir_node).sty {
379 ty::TyStruct(def, _) => {
380 let f = def.struct_variant().field_named(ident.node.name);
381 let sub_span = self.span_utils.span_for_last_ident(expr.span);
382 filter!(self.span_utils, sub_span, expr.span, None);
383 return Some(Data::VariableRefData(VariableRefData {
384 name: ident.node.to_string(),
385 span: sub_span.unwrap(),
386 scope: self.enclosing_scope(expr.id),
387 ref_id: f.did,
388 }));
389 }
390 _ => {
391 debug!("Expected struct type, found {:?}", ty);
392 None
393 }
394 }
395 }
396 ast::ExprKind::Struct(ref path, _, _) => {
397 let hir_node = lowering::lower_expr(self.lcx, expr);
398 match self.tcx.expr_ty_adjusted(&hir_node).sty {
399 ty::TyStruct(def, _) => {
400 let sub_span = self.span_utils.span_for_last_ident(path.span);
401 filter!(self.span_utils, sub_span, path.span, None);
402 Some(Data::TypeRefData(TypeRefData {
403 span: sub_span.unwrap(),
404 scope: self.enclosing_scope(expr.id),
405 ref_id: Some(def.did),
406 qualname: String::new() // FIXME: generate the real qualname
407 }))
408 }
409 _ => {
410 // FIXME ty could legitimately be a TyEnum, but then we will fail
411 // later if we try to look up the fields.
412 debug!("expected TyStruct, found {:?}", ty);
413 None
414 }
415 }
416 }
417 ast::ExprKind::MethodCall(..) => {
418 let method_call = ty::MethodCall::expr(expr.id);
419 let method_id = self.tcx.tables.borrow().method_map[&method_call].def_id;
420 let (def_id, decl_id) = match self.tcx.impl_or_trait_item(method_id).container() {
421 ty::ImplContainer(_) => (Some(method_id), None),
422 ty::TraitContainer(_) => (None, Some(method_id)),
423 };
424 let sub_span = self.span_utils.sub_span_for_meth_name(expr.span);
425 filter!(self.span_utils, sub_span, expr.span, None);
426 let parent = self.enclosing_scope(expr.id);
427 Some(Data::MethodCallData(MethodCallData {
428 span: sub_span.unwrap(),
429 scope: parent,
430 ref_id: def_id,
431 decl_id: decl_id,
432 }))
433 }
434 ast::ExprKind::Path(_, ref path) => {
435 self.get_path_data(expr.id, path)
436 }
437 _ => {
438 // FIXME
439 bug!();
440 }
441 }
442 }
443
444 pub fn get_path_data(&self, id: NodeId, path: &ast::Path) -> Option<Data> {
445 let def_map = self.tcx.def_map.borrow();
446 if !def_map.contains_key(&id) {
447 span_bug!(path.span, "def_map has no key for {} in visit_expr", id);
448 }
449 let def = def_map.get(&id).unwrap().full_def();
450 let sub_span = self.span_utils.span_for_last_ident(path.span);
451 filter!(self.span_utils, sub_span, path.span, None);
452 match def {
453 Def::Upvar(..) |
454 Def::Local(..) |
455 Def::Static(..) |
456 Def::Const(..) |
457 Def::AssociatedConst(..) |
458 Def::Variant(..) => {
459 Some(Data::VariableRefData(VariableRefData {
460 name: self.span_utils.snippet(sub_span.unwrap()),
461 span: sub_span.unwrap(),
462 scope: self.enclosing_scope(id),
463 ref_id: def.def_id(),
464 }))
465 }
466 Def::Struct(def_id) |
467 Def::Enum(def_id) |
468 Def::TyAlias(def_id) |
469 Def::Trait(def_id) |
470 Def::TyParam(_, _, def_id, _) => {
471 Some(Data::TypeRefData(TypeRefData {
472 span: sub_span.unwrap(),
473 ref_id: Some(def_id),
474 scope: self.enclosing_scope(id),
475 qualname: String::new() // FIXME: generate the real qualname
476 }))
477 }
478 Def::Method(decl_id) => {
479 let sub_span = self.span_utils.sub_span_for_meth_name(path.span);
480 filter!(self.span_utils, sub_span, path.span, None);
481 let def_id = if decl_id.is_local() {
482 let ti = self.tcx.impl_or_trait_item(decl_id);
483 match ti.container() {
484 ty::TraitContainer(def_id) => {
485 self.tcx
486 .trait_items(def_id)
487 .iter()
488 .find(|mr| mr.name() == ti.name() && self.trait_method_has_body(mr))
489 .map(|mr| mr.def_id())
490 }
491 ty::ImplContainer(def_id) => {
492 let impl_items = self.tcx.impl_items.borrow();
493 Some(impl_items.get(&def_id)
494 .unwrap()
495 .iter()
496 .find(|mr| {
497 self.tcx.impl_or_trait_item(mr.def_id()).name() ==
498 ti.name()
499 })
500 .unwrap()
501 .def_id())
502 }
503 }
504 } else {
505 None
506 };
507 Some(Data::MethodCallData(MethodCallData {
508 span: sub_span.unwrap(),
509 scope: self.enclosing_scope(id),
510 ref_id: def_id,
511 decl_id: Some(decl_id),
512 }))
513 }
514 Def::Fn(def_id) => {
515 Some(Data::FunctionCallData(FunctionCallData {
516 ref_id: def_id,
517 span: sub_span.unwrap(),
518 scope: self.enclosing_scope(id),
519 }))
520 }
521 Def::Mod(def_id) => {
522 Some(Data::ModRefData(ModRefData {
523 ref_id: Some(def_id),
524 span: sub_span.unwrap(),
525 scope: self.enclosing_scope(id),
526 qualname: String::new() // FIXME: generate the real qualname
527 }))
528 }
529 _ => None,
530 }
531 }
532
533 fn trait_method_has_body(&self, mr: &ty::ImplOrTraitItem) -> bool {
534 let def_id = mr.def_id();
535 if let Some(node_id) = self.tcx.map.as_local_node_id(def_id) {
536 let trait_item = self.tcx.map.expect_trait_item(node_id);
537 if let hir::TraitItem_::MethodTraitItem(_, Some(_)) = trait_item.node {
538 true
539 } else {
540 false
541 }
542 } else {
543 false
544 }
545 }
546
547 pub fn get_field_ref_data(&self,
548 field_ref: &ast::Field,
549 variant: ty::VariantDef,
550 parent: NodeId)
551 -> Option<VariableRefData> {
552 let f = variant.field_named(field_ref.ident.node.name);
553 // We don't really need a sub-span here, but no harm done
554 let sub_span = self.span_utils.span_for_last_ident(field_ref.ident.span);
555 filter!(self.span_utils, sub_span, field_ref.ident.span, None);
556 Some(VariableRefData {
557 name: field_ref.ident.node.to_string(),
558 span: sub_span.unwrap(),
559 scope: parent,
560 ref_id: f.did,
561 })
562 }
563
564 /// Attempt to return MacroUseData for any AST node.
565 ///
566 /// For a given piece of AST defined by the supplied Span and NodeId,
567 /// returns None if the node is not macro-generated or the span is malformed,
568 /// else uses the expansion callsite and callee to return some MacroUseData.
569 pub fn get_macro_use_data(&self, span: Span, id: NodeId) -> Option<MacroUseData> {
570 if !generated_code(span) {
571 return None;
572 }
573 // Note we take care to use the source callsite/callee, to handle
574 // nested expansions and ensure we only generate data for source-visible
575 // macro uses.
576 let callsite = self.tcx.sess.codemap().source_callsite(span);
577 let callee = self.tcx.sess.codemap().source_callee(span);
578 let callee = option_try!(callee);
579 let callee_span = option_try!(callee.span);
580
581 // Ignore attribute macros, their spans are usually mangled
582 if let MacroAttribute(_) = callee.format {
583 return None;
584 }
585
586 // If the callee is an imported macro from an external crate, need to get
587 // the source span and name from the session, as their spans are localized
588 // when read in, and no longer correspond to the source.
589 if let Some(mac) = self.tcx.sess.imported_macro_spans.borrow().get(&callee_span) {
590 let &(ref mac_name, mac_span) = mac;
591 return Some(MacroUseData {
592 span: callsite,
593 name: mac_name.clone(),
594 callee_span: mac_span,
595 scope: self.enclosing_scope(id),
596 imported: true,
597 qualname: String::new()// FIXME: generate the real qualname
598 });
599 }
600
601 Some(MacroUseData {
602 span: callsite,
603 name: callee.name().to_string(),
604 callee_span: callee_span,
605 scope: self.enclosing_scope(id),
606 imported: false,
607 qualname: String::new() // FIXME: generate the real qualname
608 })
609 }
610
611 pub fn get_data_for_id(&self, _id: &NodeId) -> Data {
612 // FIXME
613 bug!();
614 }
615
616 fn lookup_ref_id(&self, ref_id: NodeId) -> Option<DefId> {
617 if !self.tcx.def_map.borrow().contains_key(&ref_id) {
618 bug!("def_map has no key for {} in lookup_type_ref", ref_id);
619 }
620 let def = self.tcx.def_map.borrow().get(&ref_id).unwrap().full_def();
621 match def {
622 Def::PrimTy(_) | Def::SelfTy(..) => None,
623 _ => Some(def.def_id()),
624 }
625 }
626
627 #[inline]
628 pub fn enclosing_scope(&self, id: NodeId) -> NodeId {
629 self.tcx.map.get_enclosing_scope(id).unwrap_or(0)
630 }
631 }
632
633 // An AST visitor for collecting paths from patterns.
634 struct PathCollector {
635 // The Row field identifies the kind of pattern.
636 collected_paths: Vec<(NodeId, ast::Path, ast::Mutability, recorder::Row)>,
637 }
638
639 impl PathCollector {
640 fn new() -> PathCollector {
641 PathCollector { collected_paths: vec![] }
642 }
643 }
644
645 impl<'v> Visitor<'v> for PathCollector {
646 fn visit_pat(&mut self, p: &ast::Pat) {
647 match p.node {
648 PatKind::Struct(ref path, _, _) => {
649 self.collected_paths.push((p.id, path.clone(),
650 ast::Mutability::Mutable, recorder::TypeRef));
651 }
652 PatKind::TupleStruct(ref path, _) |
653 PatKind::Path(ref path) |
654 PatKind::QPath(_, ref path) => {
655 self.collected_paths.push((p.id, path.clone(),
656 ast::Mutability::Mutable, recorder::VarRef));
657 }
658 PatKind::Ident(bm, ref path1, _) => {
659 debug!("PathCollector, visit ident in pat {}: {:?} {:?}",
660 path1.node,
661 p.span,
662 path1.span);
663 let immut = match bm {
664 // Even if the ref is mut, you can't change the ref, only
665 // the data pointed at, so showing the initialising expression
666 // is still worthwhile.
667 ast::BindingMode::ByRef(_) => ast::Mutability::Immutable,
668 ast::BindingMode::ByValue(mt) => mt,
669 };
670 // collect path for either visit_local or visit_arm
671 let path = ast::Path::from_ident(path1.span, path1.node);
672 self.collected_paths.push((p.id, path, immut, recorder::VarRef));
673 }
674 _ => {}
675 }
676 visit::walk_pat(self, p);
677 }
678 }
679
680 pub fn process_crate<'l, 'tcx>(tcx: &'l TyCtxt<'tcx>,
681 lcx: &'l lowering::LoweringContext<'l>,
682 krate: &ast::Crate,
683 analysis: &ty::CrateAnalysis,
684 cratename: &str,
685 odir: Option<&Path>) {
686 let _ignore = tcx.dep_graph.in_ignore();
687
688 assert!(analysis.glob_map.is_some());
689
690 info!("Dumping crate {}", cratename);
691
692 // find a path to dump our data to
693 let mut root_path = match env::var_os("DXR_RUST_TEMP_FOLDER") {
694 Some(val) => PathBuf::from(val),
695 None => match odir {
696 Some(val) => val.join("dxr"),
697 None => PathBuf::from("dxr-temp"),
698 },
699 };
700
701 if let Err(e) = fs::create_dir_all(&root_path) {
702 tcx.sess.err(&format!("Could not create directory {}: {}",
703 root_path.display(),
704 e));
705 }
706
707 {
708 let disp = root_path.display();
709 info!("Writing output to {}", disp);
710 }
711
712 // Create output file.
713 let executable = tcx.sess.crate_types.borrow().iter().any(|ct| *ct == CrateTypeExecutable);
714 let mut out_name = if executable {
715 "".to_owned()
716 } else {
717 "lib".to_owned()
718 };
719 out_name.push_str(&cratename);
720 out_name.push_str(&tcx.sess.opts.cg.extra_filename);
721 out_name.push_str(".csv");
722 root_path.push(&out_name);
723 let mut output_file = File::create(&root_path).unwrap_or_else(|e| {
724 let disp = root_path.display();
725 tcx.sess.fatal(&format!("Could not open {}: {}", disp, e));
726 });
727 root_path.pop();
728
729 let utils = SpanUtils::new(&tcx.sess);
730 let mut dumper = CsvDumper::new(&mut output_file, utils);
731 let mut visitor = DumpVisitor::new(tcx, lcx, analysis, &mut dumper);
732 // FIXME: we don't write anything!
733
734 visitor.dump_crate_info(cratename, krate);
735 visit::walk_crate(&mut visitor, krate);
736 }
737
738 // Utility functions for the module.
739
740 // Helper function to escape quotes in a string
741 fn escape(s: String) -> String {
742 s.replace("\"", "\"\"")
743 }
744
745 // Helper function to determine if a span came from a
746 // macro expansion or syntax extension.
747 pub fn generated_code(span: Span) -> bool {
748 span.expn_id != NO_EXPANSION || span == DUMMY_SP
749 }