]> git.lizzy.rs Git - rust.git/blob - src/librustc_trans/save/mod.rs
1b9976be72f42139784682863f808ff7dcbf000a
[rust.git] / src / librustc_trans / save / mod.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 use session::Session;
12 use middle::ty;
13
14 use std::env;
15 use std::fs::{self, File};
16 use std::path::{Path, PathBuf};
17
18 use syntax::{attr};
19 use syntax::ast::{self, NodeId, DefId};
20 use syntax::ast_util;
21 use syntax::codemap::*;
22 use syntax::parse::token::{self, get_ident, keywords};
23 use syntax::visit::{self, Visitor};
24 use syntax::print::pprust::ty_to_string;
25
26
27 use self::span_utils::SpanUtils;
28
29 mod span_utils;
30 mod recorder;
31
32 mod dump_csv;
33
34 pub struct SaveContext<'l, 'tcx: 'l> {
35     sess: &'l Session,
36     analysis: &'l ty::CrateAnalysis<'tcx>,
37     span_utils: SpanUtils<'l>,
38 }
39
40 pub struct CrateData {
41     pub name: String,
42     pub number: u32,
43 }
44
45 // Data for any entity in the Rust language. The actual data contained varied
46 // with the kind of entity being queried. See the nested structs for details.
47 pub enum Data {
48     FunctionData(FunctionData),
49     VariableData(VariableData),
50 }
51
52 pub struct FunctionData {
53     pub id: NodeId,
54     pub name: String,
55     pub qualname: String,
56     pub declaration: Option<DefId>,
57     pub span: Span,
58     pub scope: NodeId,
59 }
60
61 pub struct VariableData {
62     pub id: NodeId,
63     pub name: String,
64     pub qualname: String,
65     pub span: Span,
66     pub scope: NodeId,
67     pub value: String,
68     pub type_value: String,
69 }
70
71 impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
72     pub fn new(sess: &'l Session,
73                analysis: &'l ty::CrateAnalysis<'tcx>,
74                span_utils: SpanUtils<'l>)
75                -> SaveContext<'l, 'tcx> {
76         SaveContext {
77             sess: sess,
78             analysis: analysis,
79             span_utils: span_utils,
80         }
81     }
82
83     // List external crates used by the current crate.
84     pub fn get_external_crates(&self) -> Vec<CrateData> {
85         let mut result = Vec::new();
86
87         self.sess.cstore.iter_crate_data(|n, cmd| {
88             result.push(CrateData { name: cmd.name.clone(), number: n });
89         });
90
91         result
92     }
93
94     pub fn get_item_data(&self, item: &ast::Item) -> Data {
95         match item.node {
96             ast::Item_::ItemFn(..) => {
97                 let name = self.analysis.ty_cx.map.path_to_string(item.id);
98                 let qualname = format!("::{}", name);
99                 let sub_span = self.span_utils.sub_span_after_keyword(item.span, keywords::Fn);
100
101                 Data::FunctionData(FunctionData {
102                     id: item.id,
103                     name: name,
104                     qualname: qualname,
105                     declaration: None,
106                     span: sub_span.unwrap(),
107                     scope: self.analysis.ty_cx.map.get_parent(item.id),
108                 })
109             }
110             ast::ItemStatic(ref typ, mt, ref expr) => {
111                 let qualname = format!("::{}", self.analysis.ty_cx.map.path_to_string(item.id));
112
113                 // If the variable is immutable, save the initialising expression.
114                 let (value, keyword) = match mt {
115                     ast::MutMutable => (String::from_str("<mutable>"), keywords::Mut),
116                     ast::MutImmutable => (self.span_utils.snippet(expr.span), keywords::Static),
117                 };
118
119                 let sub_span = self.span_utils.sub_span_after_keyword(item.span, keyword);
120
121                 Data::VariableData(VariableData {
122                     id: item.id,
123                     name: get_ident(item.ident).to_string(),
124                     qualname: qualname,
125                     span: sub_span.unwrap(),
126                     scope: self.analysis.ty_cx.map.get_parent(item.id),
127                     value: value,
128                     type_value: ty_to_string(&typ),
129                 })
130             }
131             ast::ItemConst(ref typ, ref expr) => {
132                 let qualname = format!("::{}", self.analysis.ty_cx.map.path_to_string(item.id));
133                 let sub_span = self.span_utils.sub_span_after_keyword(item.span, keywords::Const);
134
135                 Data::VariableData(VariableData {
136                     id: item.id,
137                     name: get_ident(item.ident).to_string(),
138                     qualname: qualname,
139                     span: sub_span.unwrap(),
140                     scope: self.analysis.ty_cx.map.get_parent(item.id),
141                     value: self.span_utils.snippet(expr.span),
142                     type_value: ty_to_string(&typ),
143                 })
144             }
145             _ => {
146                 // FIXME
147                 unimplemented!();
148             }
149         }
150     }
151
152     pub fn get_data_for_id(&self, _id: &NodeId) -> Data {
153         // FIXME
154         unimplemented!();
155     }
156 }
157
158 // An AST visitor for collecting paths from patterns.
159 struct PathCollector {
160     // The Row field identifies the kind of pattern.
161     collected_paths: Vec<(NodeId, ast::Path, ast::Mutability, recorder::Row)>,
162 }
163
164 impl PathCollector {
165     fn new() -> PathCollector {
166         PathCollector {
167             collected_paths: vec![],
168         }
169     }
170 }
171
172 impl<'v> Visitor<'v> for PathCollector {
173     fn visit_pat(&mut self, p: &ast::Pat) {
174         if generated_code(p.span) {
175             return;
176         }
177
178         match p.node {
179             ast::PatStruct(ref path, _, _) => {
180                 self.collected_paths.push((p.id,
181                                            path.clone(),
182                                            ast::MutMutable,
183                                            recorder::StructRef));
184             }
185             ast::PatEnum(ref path, _) |
186             ast::PatQPath(_, ref path) => {
187                 self.collected_paths.push((p.id, path.clone(), ast::MutMutable, recorder::VarRef));
188             }
189             ast::PatIdent(bm, ref path1, _) => {
190                 debug!("PathCollector, visit ident in pat {}: {:?} {:?}",
191                        token::get_ident(path1.node),
192                        p.span,
193                        path1.span);
194                 let immut = match bm {
195                     // Even if the ref is mut, you can't change the ref, only
196                     // the data pointed at, so showing the initialising expression
197                     // is still worthwhile.
198                     ast::BindByRef(_) => ast::MutImmutable,
199                     ast::BindByValue(mt) => mt,
200                 };
201                 // collect path for either visit_local or visit_arm
202                 let path = ast_util::ident_to_path(path1.span, path1.node);
203                 self.collected_paths.push((p.id, path, immut, recorder::VarRef));
204             }
205             _ => {}
206         }
207         visit::walk_pat(self, p);
208     }
209 }
210
211 #[allow(deprecated)]
212 pub fn process_crate(sess: &Session,
213                      krate: &ast::Crate,
214                      analysis: &ty::CrateAnalysis,
215                      odir: Option<&Path>) {
216     if generated_code(krate.span) {
217         return;
218     }
219
220     assert!(analysis.glob_map.is_some());
221     let cratename = match attr::find_crate_name(&krate.attrs) {
222         Some(name) => name.to_string(),
223         None => {
224             info!("Could not find crate name, using 'unknown_crate'");
225             String::from_str("unknown_crate")
226         },
227     };
228
229     info!("Dumping crate {}", cratename);
230
231     // find a path to dump our data to
232     let mut root_path = match env::var_os("DXR_RUST_TEMP_FOLDER") {
233         Some(val) => PathBuf::from(val),
234         None => match odir {
235             Some(val) => val.join("dxr"),
236             None => PathBuf::from("dxr-temp"),
237         },
238     };
239
240     match fs::create_dir_all(&root_path) {
241         Err(e) => sess.err(&format!("Could not create directory {}: {}",
242                            root_path.display(), e)),
243         _ => (),
244     }
245
246     {
247         let disp = root_path.display();
248         info!("Writing output to {}", disp);
249     }
250
251     // Create output file.
252     let mut out_name = cratename.clone();
253     out_name.push_str(".csv");
254     root_path.push(&out_name);
255     let output_file = match File::create(&root_path) {
256         Ok(f) => box f,
257         Err(e) => {
258             let disp = root_path.display();
259             sess.fatal(&format!("Could not open {}: {}", disp, e));
260         }
261     };
262     root_path.pop();
263
264     let mut visitor = dump_csv::DumpCsvVisitor::new(sess, analysis, output_file);
265
266     visitor.dump_crate_info(&cratename[..], krate);
267     visit::walk_crate(&mut visitor, krate);
268 }
269
270 // Utility functions for the module.
271
272 // Helper function to escape quotes in a string
273 fn escape(s: String) -> String {
274     s.replace("\"", "\"\"")
275 }
276
277 // If the expression is a macro expansion or other generated code, run screaming
278 // and don't index.
279 fn generated_code(span: Span) -> bool {
280     span.expn_id != NO_EXPANSION || span  == DUMMY_SP
281 }