386 lines
13 KiB
Rust
Raw Normal View History

// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use session::Session;
use middle::ty;
std: Add a new `env` module This is an implementation of [RFC 578][rfc] which adds a new `std::env` module to replace most of the functionality in the current `std::os` module. More details can be found in the RFC itself, but as a summary the following methods have all been deprecated: [rfc]: https://github.com/rust-lang/rfcs/pull/578 * `os::args_as_bytes` => `env::args` * `os::args` => `env::args` * `os::consts` => `env::consts` * `os::dll_filename` => no replacement, use `env::consts` directly * `os::page_size` => `env::page_size` * `os::make_absolute` => use `env::current_dir` + `join` instead * `os::getcwd` => `env::current_dir` * `os::change_dir` => `env::set_current_dir` * `os::homedir` => `env::home_dir` * `os::tmpdir` => `env::temp_dir` * `os::join_paths` => `env::join_paths` * `os::split_paths` => `env::split_paths` * `os::self_exe_name` => `env::current_exe` * `os::self_exe_path` => use `env::current_exe` + `pop` * `os::set_exit_status` => `env::set_exit_status` * `os::get_exit_status` => `env::get_exit_status` * `os::env` => `env::vars` * `os::env_as_bytes` => `env::vars` * `os::getenv` => `env::var` or `env::var_string` * `os::getenv_as_bytes` => `env::var` * `os::setenv` => `env::set_var` * `os::unsetenv` => `env::remove_var` Many function signatures have also been tweaked for various purposes, but the main changes were: * `Vec`-returning APIs now all return iterators instead * All APIs are now centered around `OsString` instead of `Vec<u8>` or `String`. There is currently on convenience API, `env::var_string`, which can be used to get the value of an environment variable as a unicode `String`. All old APIs are `#[deprecated]` in-place and will remain for some time to allow for migrations. The semantics of the APIs have been tweaked slightly with regard to dealing with invalid unicode (panic instead of replacement). The new `std::env` module is all contained within the `env` feature, so crates must add the following to access the new APIs: #![feature(env)] [breaking-change]
2015-01-27 12:20:58 -08:00
use std::env;
use std::fs::{self, File};
use std::path::{Path, PathBuf};
2015-05-05 22:03:20 +12:00
use syntax::{attr};
2015-05-05 19:27:44 +12:00
use syntax::ast::{self, NodeId, DefId};
2015-05-05 22:03:20 +12:00
use syntax::ast_util;
use syntax::codemap::*;
use syntax::parse::token::{self, get_ident, keywords};
2015-05-05 22:03:20 +12:00
use syntax::visit::{self, Visitor};
use syntax::print::pprust::ty_to_string;
2015-05-05 19:27:44 +12:00
use self::span_utils::SpanUtils;
mod span_utils;
mod recorder;
mod dump_csv;
2015-05-05 19:27:44 +12:00
pub struct SaveContext<'l, 'tcx: 'l> {
sess: &'l Session,
2015-05-05 19:27:44 +12:00
analysis: &'l ty::CrateAnalysis<'tcx>,
span_utils: SpanUtils<'l>,
}
pub struct CrateData {
pub name: String,
pub number: u32,
}
2015-05-15 19:06:56 +12:00
/// Data for any entity in the Rust language. The actual data contained varied
/// with the kind of entity being queried. See the nested structs for details.
2015-05-05 19:27:44 +12:00
pub enum Data {
2015-05-15 19:06:56 +12:00
/// Data for all kinds of functions and methods.
2015-05-05 19:27:44 +12:00
FunctionData(FunctionData),
2015-05-15 19:06:56 +12:00
/// Data for local and global variables (consts and statics).
VariableData(VariableData),
/// Data for modules.
ModData(ModData),
2015-06-02 12:21:20 -07:00
/// Data for Enums.
EnumData(EnumData),
/// Data for the use of some variable (e.g., the use of a local variable, which
/// will refere to that variables declaration).
VariableRefData(VariableRefData),
2015-05-05 19:27:44 +12:00
}
2015-05-15 19:06:56 +12:00
/// Data for all kinds of functions and methods.
2015-05-05 19:27:44 +12:00
pub struct FunctionData {
pub id: NodeId,
pub name: String,
2015-05-05 19:27:44 +12:00
pub qualname: String,
pub declaration: Option<DefId>,
pub span: Span,
pub scope: NodeId,
}
2015-05-15 19:06:56 +12:00
/// Data for local and global variables (consts and statics).
pub struct VariableData {
pub id: NodeId,
pub name: String,
pub qualname: String,
pub span: Span,
pub scope: NodeId,
pub value: String,
pub type_value: String,
}
/// Data for modules.
pub struct ModData {
pub id: NodeId,
pub name: String,
pub qualname: String,
pub span: Span,
pub scope: NodeId,
pub filename: String,
}
2015-06-02 12:21:20 -07:00
/// Data for enum declarations.
pub struct EnumData {
pub id: NodeId,
pub value: String,
pub qualname: String,
pub span: Span,
}
/// Data for the use of some item (e.g., the use of a local variable, which
/// will refere to that variables declaration (by ref_id)).
pub struct VariableRefData {
pub name: String,
pub span: Span,
pub scope: NodeId,
pub ref_id: DefId,
}
2015-05-05 19:27:44 +12:00
impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
pub fn new(sess: &'l Session,
analysis: &'l ty::CrateAnalysis<'tcx>,
span_utils: SpanUtils<'l>)
-> SaveContext<'l, 'tcx> {
SaveContext {
2015-05-05 19:27:44 +12:00
sess: sess,
analysis: analysis,
span_utils: span_utils,
}
}
// List external crates used by the current crate.
pub fn get_external_crates(&self) -> Vec<CrateData> {
let mut result = Vec::new();
self.sess.cstore.iter_crate_data(|n, cmd| {
result.push(CrateData { name: cmd.name.clone(), number: n });
});
result
}
2015-05-05 19:27:44 +12:00
pub fn get_item_data(&self, item: &ast::Item) -> Data {
match item.node {
ast::ItemFn(..) => {
let name = self.analysis.ty_cx.map.path_to_string(item.id);
let qualname = format!("::{}", name);
2015-05-05 19:27:44 +12:00
let sub_span = self.span_utils.sub_span_after_keyword(item.span, keywords::Fn);
Data::FunctionData(FunctionData {
id: item.id,
name: name,
2015-05-05 19:27:44 +12:00
qualname: qualname,
declaration: None,
span: sub_span.unwrap(),
scope: self.analysis.ty_cx.map.get_parent(item.id),
})
}
ast::ItemStatic(ref typ, mt, ref expr) => {
let qualname = format!("::{}", self.analysis.ty_cx.map.path_to_string(item.id));
// If the variable is immutable, save the initialising expression.
let (value, keyword) = match mt {
ast::MutMutable => (String::from("<mutable>"), keywords::Mut),
ast::MutImmutable => (self.span_utils.snippet(expr.span), keywords::Static),
};
let sub_span = self.span_utils.sub_span_after_keyword(item.span, keyword);
Data::VariableData(VariableData {
id: item.id,
name: get_ident(item.ident).to_string(),
qualname: qualname,
span: sub_span.unwrap(),
scope: self.analysis.ty_cx.map.get_parent(item.id),
value: value,
type_value: ty_to_string(&typ),
})
}
ast::ItemConst(ref typ, ref expr) => {
let qualname = format!("::{}", self.analysis.ty_cx.map.path_to_string(item.id));
let sub_span = self.span_utils.sub_span_after_keyword(item.span, keywords::Const);
Data::VariableData(VariableData {
id: item.id,
name: get_ident(item.ident).to_string(),
qualname: qualname,
span: sub_span.unwrap(),
scope: self.analysis.ty_cx.map.get_parent(item.id),
value: self.span_utils.snippet(expr.span),
type_value: ty_to_string(&typ),
})
}
ast::ItemMod(ref m) => {
let qualname = format!("::{}", self.analysis.ty_cx.map.path_to_string(item.id));
let cm = self.sess.codemap();
let filename = cm.span_to_filename(m.inner);
let sub_span = self.span_utils.sub_span_after_keyword(item.span, keywords::Mod);
Data::ModData(ModData {
id: item.id,
name: get_ident(item.ident).to_string(),
qualname: qualname,
span: sub_span.unwrap(),
scope: self.analysis.ty_cx.map.get_parent(item.id),
filename: filename,
})
2015-06-02 12:21:20 -07:00
},
ast::ItemEnum(..) => {
let enum_name = format!("::{}", self.analysis.ty_cx.map.path_to_string(item.id));
let val = self.span_utils.snippet(item.span);
let sub_span = self.span_utils.sub_span_after_keyword(item.span, keywords::Enum);
Data::EnumData(EnumData {
id: item.id,
value: val,
span: sub_span.unwrap(),
qualname: enum_name,
})
},
_ => {
// FIXME
unimplemented!();
}
}
}
pub fn get_expr_data(&self, expr: &ast::Expr) -> Data {
match expr.node {
ast::ExprField(ref sub_ex, ident) => {
let ty = &ty::expr_ty_adjusted(&self.analysis.ty_cx, &sub_ex).sty;
match *ty {
ty::ty_struct(def_id, _) => {
let fields = ty::lookup_struct_fields(&self.analysis.ty_cx, def_id);
for f in &fields {
if f.name == ident.node.name {
let sub_span = self.span_utils.span_for_last_ident(expr.span);
return Data::VariableRefData(VariableRefData {
name: get_ident(ident.node).to_string(),
span: sub_span.unwrap(),
scope: self.analysis.ty_cx.map.get_parent(expr.id),
ref_id: f.id,
});
}
}
self.sess.span_bug(expr.span,
&format!("Couldn't find field {} on {:?}",
&get_ident(ident.node),
ty))
}
_ => self.sess.span_bug(expr.span,
&format!("Expected struct type, found {:?}", ty)),
}
}
2015-05-05 19:27:44 +12:00
_ => {
// FIXME
2015-05-05 19:27:44 +12:00
unimplemented!();
}
}
}
pub fn get_data_for_id(&self, _id: &NodeId) -> Data {
// FIXME
unimplemented!();
2015-05-05 19:27:44 +12:00
}
}
2015-05-05 22:03:20 +12:00
// An AST visitor for collecting paths from patterns.
struct PathCollector {
// The Row field identifies the kind of pattern.
collected_paths: Vec<(NodeId, ast::Path, ast::Mutability, recorder::Row)>,
2015-05-05 22:03:20 +12:00
}
impl PathCollector {
fn new() -> PathCollector {
PathCollector {
collected_paths: vec![],
}
}
}
impl<'v> Visitor<'v> for PathCollector {
fn visit_pat(&mut self, p: &ast::Pat) {
if generated_code(p.span) {
return;
}
2015-05-05 22:03:20 +12:00
match p.node {
ast::PatStruct(ref path, _, _) => {
self.collected_paths.push((p.id,
path.clone(),
ast::MutMutable,
recorder::StructRef));
2015-05-05 22:03:20 +12:00
}
ast::PatEnum(ref path, _) |
ast::PatQPath(_, ref path) => {
self.collected_paths.push((p.id, path.clone(), ast::MutMutable, recorder::VarRef));
2015-05-05 22:03:20 +12:00
}
ast::PatIdent(bm, ref path1, _) => {
debug!("PathCollector, visit ident in pat {}: {:?} {:?}",
token::get_ident(path1.node),
p.span,
path1.span);
2015-05-05 22:03:20 +12:00
let immut = match bm {
// Even if the ref is mut, you can't change the ref, only
// the data pointed at, so showing the initialising expression
// is still worthwhile.
ast::BindByRef(_) => ast::MutImmutable,
ast::BindByValue(mt) => mt,
2015-05-05 22:03:20 +12:00
};
// collect path for either visit_local or visit_arm
let path = ast_util::ident_to_path(path1.span, path1.node);
2015-05-05 22:03:20 +12:00
self.collected_paths.push((p.id, path, immut, recorder::VarRef));
}
_ => {}
}
visit::walk_pat(self, p);
}
}
#[allow(deprecated)]
pub fn process_crate(sess: &Session,
krate: &ast::Crate,
analysis: &ty::CrateAnalysis,
odir: Option<&Path>) {
if generated_code(krate.span) {
return;
}
assert!(analysis.glob_map.is_some());
let cratename = match attr::find_crate_name(&krate.attrs) {
2015-02-04 01:04:50 +01:00
Some(name) => name.to_string(),
None => {
info!("Could not find crate name, using 'unknown_crate'");
String::from("unknown_crate")
},
};
info!("Dumping crate {}", cratename);
// find a path to dump our data to
let mut root_path = match env::var_os("DXR_RUST_TEMP_FOLDER") {
Some(val) => PathBuf::from(val),
None => match odir {
Some(val) => val.join("dxr"),
None => PathBuf::from("dxr-temp"),
},
};
match fs::create_dir_all(&root_path) {
2015-01-07 11:58:31 -05:00
Err(e) => sess.err(&format!("Could not create directory {}: {}",
root_path.display(), e)),
_ => (),
}
{
let disp = root_path.display();
info!("Writing output to {}", disp);
}
2014-07-02 21:27:07 -04:00
// Create output file.
let mut out_name = cratename.clone();
out_name.push_str(".csv");
root_path.push(&out_name);
let output_file = match File::create(&root_path) {
Ok(f) => box f,
Err(e) => {
let disp = root_path.display();
sess.fatal(&format!("Could not open {}: {}", disp, e));
}
};
root_path.pop();
let mut visitor = dump_csv::DumpCsvVisitor::new(sess, analysis, output_file);
visitor.dump_crate_info(&cratename, krate);
visit::walk_crate(&mut visitor, krate);
}
// Utility functions for the module.
// Helper function to escape quotes in a string
fn escape(s: String) -> String {
s.replace("\"", "\"\"")
}
// If the expression is a macro expansion or other generated code, run screaming
// and don't index.
fn generated_code(span: Span) -> bool {
span.expn_id != NO_EXPANSION || span == DUMMY_SP
}