rust/src/librustc_trans/save/mod.rs

741 lines
30 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.
2016-02-29 23:36:51 +00:00
use middle::ty::{self, TyCtxt};
use middle::def::Def;
2015-09-01 12:35:05 -04:00
use middle::def_id::DefId;
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-07-31 00:04:06 -07:00
use rustc_front;
use rustc_front::{hir, lowering};
use rustc::front::map::NodeItem;
use rustc::session::config::CrateType::CrateTypeExecutable;
2015-07-09 12:23:29 +12:00
2016-02-11 21:16:33 +03:00
use syntax::ast::{self, NodeId, PatKind};
2015-05-05 22:03:20 +12:00
use syntax::ast_util;
use syntax::codemap::*;
use syntax::parse::token::{self, keywords};
2015-05-05 22:03:20 +12:00
use syntax::visit::{self, Visitor};
use syntax::print::pprust::ty_to_string;
mod csv_dumper;
#[macro_use]
mod data;
mod dump;
mod dump_visitor;
#[macro_use]
pub mod span_utils;
pub use self::csv_dumper::CsvDumper;
pub use self::data::*;
pub use self::dump::Dump;
pub use self::dump_visitor::DumpVisitor;
use self::span_utils::SpanUtils;
// FIXME this is legacy code and should be removed
pub mod recorder {
pub use self::Row::*;
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum Row {
TypeRef,
ModRef,
VarRef,
FnRef,
}
}
2015-05-05 19:27:44 +12:00
pub struct SaveContext<'l, 'tcx: 'l> {
2016-02-29 23:36:51 +00:00
tcx: &'l TyCtxt<'tcx>,
lcx: &'l lowering::LoweringContext<'l>,
2015-05-05 19:27:44 +12:00
span_utils: SpanUtils<'l>,
}
macro_rules! option_try(
($e:expr) => (match $e { Some(e) => e, None => return None })
);
2015-05-05 19:27:44 +12:00
impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
2016-02-29 23:36:51 +00:00
pub fn new(tcx: &'l TyCtxt<'tcx>,
lcx: &'l lowering::LoweringContext<'l>)
2015-09-28 15:00:15 +13:00
-> SaveContext<'l, 'tcx> {
2015-07-14 14:21:54 +12:00
let span_utils = SpanUtils::new(&tcx.sess);
2015-09-25 16:03:28 +12:00
SaveContext::from_span_utils(tcx, lcx, span_utils)
2015-07-14 14:21:54 +12:00
}
2016-02-29 23:36:51 +00:00
pub fn from_span_utils(tcx: &'l TyCtxt<'tcx>,
lcx: &'l lowering::LoweringContext<'l>,
2015-07-14 14:21:54 +12:00
span_utils: SpanUtils<'l>)
-> SaveContext<'l, 'tcx> {
2015-09-28 09:20:49 +13:00
SaveContext {
tcx: tcx,
2015-09-25 16:03:28 +12:00
lcx: lcx,
2015-09-28 09:20:49 +13:00
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();
for n in self.tcx.sess.cstore.crates() {
2015-09-28 09:20:49 +13:00
result.push(CrateData {
name: self.tcx.sess.cstore.crate_name(n),
2015-09-28 09:20:49 +13:00
number: n,
});
}
result
}
2015-05-05 19:27:44 +12:00
pub fn get_item_data(&self, item: &ast::Item) -> Option<Data> {
2015-05-05 19:27:44 +12:00
match item.node {
ast::ItemKind::Fn(..) => {
let name = self.tcx.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);
filter!(self.span_utils, sub_span, item.span, None);
Some(Data::FunctionData(FunctionData {
2015-05-05 19:27:44 +12:00
id: item.id,
name: name,
2015-05-05 19:27:44 +12:00
qualname: qualname,
declaration: None,
span: sub_span.unwrap(),
scope: self.enclosing_scope(item.id),
}))
2015-05-05 19:27:44 +12:00
}
ast::ItemKind::Static(ref typ, mt, ref expr) => {
let qualname = format!("::{}", self.tcx.map.path_to_string(item.id));
// If the variable is immutable, save the initialising expression.
let (value, keyword) = match mt {
ast::Mutability::Mutable => (String::from("<mutable>"), keywords::Mut),
ast::Mutability::Immutable => {
(self.span_utils.snippet(expr.span), keywords::Static)
},
};
let sub_span = self.span_utils.sub_span_after_keyword(item.span, keyword);
filter!(self.span_utils, sub_span, item.span, None);
Some(Data::VariableData(VariableData {
id: item.id,
name: item.ident.to_string(),
qualname: qualname,
span: sub_span.unwrap(),
scope: self.enclosing_scope(item.id),
value: value,
type_value: ty_to_string(&typ),
}))
}
ast::ItemKind::Const(ref typ, ref expr) => {
let qualname = format!("::{}", self.tcx.map.path_to_string(item.id));
let sub_span = self.span_utils.sub_span_after_keyword(item.span, keywords::Const);
filter!(self.span_utils, sub_span, item.span, None);
Some(Data::VariableData(VariableData {
id: item.id,
name: item.ident.to_string(),
qualname: qualname,
span: sub_span.unwrap(),
2015-07-09 12:23:29 +12:00
scope: self.enclosing_scope(item.id),
value: self.span_utils.snippet(expr.span),
type_value: ty_to_string(&typ),
}))
}
ast::ItemKind::Mod(ref m) => {
let qualname = format!("::{}", self.tcx.map.path_to_string(item.id));
let cm = self.tcx.sess.codemap();
let filename = cm.span_to_filename(m.inner);
let sub_span = self.span_utils.sub_span_after_keyword(item.span, keywords::Mod);
filter!(self.span_utils, sub_span, item.span, None);
Some(Data::ModData(ModData {
id: item.id,
name: item.ident.to_string(),
qualname: qualname,
span: sub_span.unwrap(),
scope: self.enclosing_scope(item.id),
filename: filename,
}))
2015-09-02 15:37:07 +12:00
}
ast::ItemKind::Enum(..) => {
let enum_name = format!("::{}", self.tcx.map.path_to_string(item.id));
2015-06-02 12:21:20 -07:00
let val = self.span_utils.snippet(item.span);
let sub_span = self.span_utils.sub_span_after_keyword(item.span, keywords::Enum);
filter!(self.span_utils, sub_span, item.span, None);
Some(Data::EnumData(EnumData {
2015-06-02 12:21:20 -07:00
id: item.id,
value: val,
span: sub_span.unwrap(),
qualname: enum_name,
scope: self.enclosing_scope(item.id),
}))
2015-09-02 15:37:07 +12:00
}
ast::ItemKind::Impl(_, _, _, ref trait_ref, ref typ, _) => {
2015-06-05 17:50:04 +12:00
let mut type_data = None;
let sub_span;
let parent = self.enclosing_scope(item.id);
2015-06-05 17:50:04 +12:00
match typ.node {
// Common case impl for a struct or something basic.
ast::TyKind::Path(None, ref path) => {
sub_span = self.span_utils.sub_span_for_type_name(path.span);
filter!(self.span_utils, sub_span, path.span, None);
2015-09-28 09:20:49 +13:00
type_data = self.lookup_ref_id(typ.id).map(|id| {
TypeRefData {
span: sub_span.unwrap(),
2015-09-28 09:20:49 +13:00
scope: parent,
ref_id: Some(id),
qualname: String::new() // FIXME: generate the real qualname
2015-09-28 09:20:49 +13:00
}
2015-06-05 17:50:04 +12:00
});
2015-09-02 15:37:07 +12:00
}
2015-06-05 17:50:04 +12:00
_ => {
// Less useful case, impl for a compound type.
let span = typ.span;
sub_span = self.span_utils.sub_span_for_type_name(span).or(Some(span));
2015-06-05 17:50:04 +12:00
}
}
2015-09-28 09:20:49 +13:00
let trait_data = trait_ref.as_ref()
.and_then(|tr| self.get_trait_ref_data(tr, parent));
2015-06-05 17:50:04 +12:00
filter!(self.span_utils, sub_span, typ.span, None);
Some(Data::ImplData(ImplData2 {
2015-06-05 17:50:04 +12:00
id: item.id,
span: sub_span.unwrap(),
2015-06-05 17:50:04 +12:00
scope: parent,
trait_ref: trait_data,
self_ref: type_data,
}))
2015-06-05 17:50:04 +12:00
}
_ => {
// FIXME
unimplemented!();
}
}
}
pub fn get_field_data(&self, field: &ast::StructField,
scope: NodeId) -> Option<VariableData> {
2015-06-05 16:03:48 +12:00
match field.node.kind {
ast::NamedField(ident, _) => {
2015-09-28 09:20:49 +13:00
let qualname = format!("::{}::{}", self.tcx.map.path_to_string(scope), ident);
let typ = self.tcx.node_types().get(&field.node.id).unwrap().to_string();
2015-06-05 16:03:48 +12:00
let sub_span = self.span_utils.sub_span_before_token(field.span, token::Colon);
filter!(self.span_utils, sub_span, field.span, None);
2015-07-09 12:23:29 +12:00
Some(VariableData {
2015-06-05 16:03:48 +12:00
id: field.node.id,
name: ident.to_string(),
2015-06-05 16:03:48 +12:00
qualname: qualname,
span: sub_span.unwrap(),
scope: scope,
2015-06-05 16:03:48 +12:00
value: "".to_owned(),
type_value: typ,
2015-07-09 12:23:29 +12:00
})
2015-09-02 15:37:07 +12:00
}
2015-06-05 16:03:48 +12:00
_ => None,
}
}
2015-07-09 12:23:29 +12:00
// FIXME would be nice to take a MethodItem here, but the ast provides both
// trait and impl flavours, so the caller must do the disassembly.
pub fn get_method_data(&self, id: ast::NodeId,
name: ast::Name, span: Span) -> Option<FunctionData> {
2015-07-09 12:23:29 +12:00
// The qualname for a method is the trait name or name of the struct in an impl in
// which the method is declared in, followed by the method's name.
let qualname = match self.tcx.impl_of_method(self.tcx.map.local_def_id(id)) {
Some(impl_id) => match self.tcx.map.get_if_local(impl_id) {
Some(NodeItem(item)) => {
2015-07-09 12:23:29 +12:00
match item.node {
2015-07-31 00:04:06 -07:00
hir::ItemImpl(_, _, _, _, ref ty, _) => {
2015-07-09 12:23:29 +12:00
let mut result = String::from("<");
2016-02-09 21:24:11 +01:00
result.push_str(&rustc_front::print::pprust::ty_to_string(&ty));
2015-07-09 12:23:29 +12:00
match self.tcx.trait_of_item(self.tcx.map.local_def_id(id)) {
2015-07-09 12:23:29 +12:00
Some(def_id) => {
result.push_str(" as ");
2015-09-28 09:20:49 +13:00
result.push_str(&self.tcx.item_path_str(def_id));
2015-09-02 15:37:07 +12:00
}
2015-07-09 12:23:29 +12:00
None => {}
}
result.push_str(">");
result
}
_ => {
self.tcx.sess.span_bug(span,
2015-09-28 09:20:49 +13:00
&format!("Container {:?} for method {} not \
an impl?",
impl_id,
id));
2015-09-02 15:37:07 +12:00
}
2015-07-09 12:23:29 +12:00
}
2015-09-02 15:37:07 +12:00
}
r => {
2015-07-09 12:23:29 +12:00
self.tcx.sess.span_bug(span,
2015-09-28 09:20:49 +13:00
&format!("Container {:?} for method {} is not a node \
item {:?}",
impl_id,
id,
r));
}
2015-07-09 12:23:29 +12:00
},
None => match self.tcx.trait_of_item(self.tcx.map.local_def_id(id)) {
2015-07-09 12:23:29 +12:00
Some(def_id) => {
match self.tcx.map.get_if_local(def_id) {
Some(NodeItem(_)) => {
2015-07-09 12:23:29 +12:00
format!("::{}", self.tcx.item_path_str(def_id))
}
r => {
2015-07-09 12:23:29 +12:00
self.tcx.sess.span_bug(span,
2015-09-28 09:20:49 +13:00
&format!("Could not find container {:?} for \
method {}, got {:?}",
def_id,
id,
r));
2015-07-09 12:23:29 +12:00
}
}
2015-09-02 15:37:07 +12:00
}
2015-07-09 12:23:29 +12:00
None => {
self.tcx.sess.span_bug(span,
2015-09-28 09:20:49 +13:00
&format!("Could not find container for method {}", id));
2015-09-02 15:37:07 +12:00
}
2015-07-09 12:23:29 +12:00
},
};
let qualname = format!("{}::{}", qualname, name);
2015-07-09 12:23:29 +12:00
let def_id = self.tcx.map.local_def_id(id);
2015-09-28 09:20:49 +13:00
let decl_id = self.tcx.trait_item_of_item(def_id).and_then(|new_id| {
let new_def_id = new_id.def_id();
if new_def_id != def_id {
Some(new_def_id)
} else {
None
}
});
2015-07-09 12:23:29 +12:00
let sub_span = self.span_utils.sub_span_after_keyword(span, keywords::Fn);
filter!(self.span_utils, sub_span, span, None);
Some(FunctionData {
2015-07-09 12:23:29 +12:00
id: id,
name: name.to_string(),
2015-07-09 12:23:29 +12:00
qualname: qualname,
declaration: decl_id,
span: sub_span.unwrap(),
scope: self.enclosing_scope(id),
})
2015-07-09 12:23:29 +12:00
}
2015-06-05 17:50:04 +12:00
pub fn get_trait_ref_data(&self,
trait_ref: &ast::TraitRef,
parent: NodeId)
-> Option<TypeRefData> {
self.lookup_ref_id(trait_ref.ref_id).and_then(|def_id| {
let span = trait_ref.path.span;
let sub_span = self.span_utils.sub_span_for_type_name(span).or(Some(span));
filter!(self.span_utils, sub_span, span, None);
Some(TypeRefData {
span: sub_span.unwrap(),
2015-06-05 17:50:04 +12:00
scope: parent,
ref_id: Some(def_id),
qualname: String::new() // FIXME: generate the real qualname
})
2015-06-05 17:50:04 +12:00
})
}
2015-06-15 10:06:01 +12:00
pub fn get_expr_data(&self, expr: &ast::Expr) -> Option<Data> {
let hir_node = lowering::lower_expr(self.lcx, expr);
let ty = self.tcx.expr_ty_adjusted_opt(&hir_node);
if ty.is_none() || ty.unwrap().sty == ty::TyError {
return None;
}
match expr.node {
ast::ExprKind::Field(ref sub_ex, ident) => {
2015-09-25 16:03:28 +12:00
let hir_node = lowering::lower_expr(self.lcx, sub_ex);
match self.tcx.expr_ty_adjusted(&hir_node).sty {
ty::TyStruct(def, _) => {
let f = def.struct_variant().field_named(ident.node.name);
let sub_span = self.span_utils.span_for_last_ident(expr.span);
filter!(self.span_utils, sub_span, expr.span, None);
return Some(Data::VariableRefData(VariableRefData {
name: ident.node.to_string(),
span: sub_span.unwrap(),
scope: self.enclosing_scope(expr.id),
ref_id: f.did,
}));
}
2015-06-15 10:06:01 +12:00
_ => {
debug!("Expected struct type, found {:?}", ty);
None
}
}
}
ast::ExprKind::Struct(ref path, _, _) => {
2015-09-25 16:03:28 +12:00
let hir_node = lowering::lower_expr(self.lcx, expr);
match self.tcx.expr_ty_adjusted(&hir_node).sty {
ty::TyStruct(def, _) => {
2015-06-09 09:51:54 +12:00
let sub_span = self.span_utils.span_for_last_ident(path.span);
filter!(self.span_utils, sub_span, path.span, None);
2015-06-15 10:06:01 +12:00
Some(Data::TypeRefData(TypeRefData {
2015-06-09 09:51:54 +12:00
span: sub_span.unwrap(),
scope: self.enclosing_scope(expr.id),
ref_id: Some(def.did),
qualname: String::new() // FIXME: generate the real qualname
2015-06-15 10:06:01 +12:00
}))
2015-06-09 09:51:54 +12:00
}
_ => {
2015-06-15 10:06:01 +12:00
// FIXME ty could legitimately be a TyEnum, but then we will fail
// later if we try to look up the fields.
debug!("expected TyStruct, found {:?}", ty);
None
2015-06-09 09:51:54 +12:00
}
}
}
ast::ExprKind::MethodCall(..) => {
2015-07-07 11:42:43 +12:00
let method_call = ty::MethodCall::expr(expr.id);
let method_id = self.tcx.tables.borrow().method_map[&method_call].def_id;
let (def_id, decl_id) = match self.tcx.impl_or_trait_item(method_id).container() {
ty::ImplContainer(_) => (Some(method_id), None),
2015-09-02 15:37:07 +12:00
ty::TraitContainer(_) => (None, Some(method_id)),
2015-07-07 11:42:43 +12:00
};
let sub_span = self.span_utils.sub_span_for_meth_name(expr.span);
filter!(self.span_utils, sub_span, expr.span, None);
let parent = self.enclosing_scope(expr.id);
2015-07-07 11:42:43 +12:00
Some(Data::MethodCallData(MethodCallData {
span: sub_span.unwrap(),
2015-07-08 14:30:18 +12:00
scope: parent,
2015-07-07 11:42:43 +12:00
ref_id: def_id,
2015-07-08 14:30:18 +12:00
decl_id: decl_id,
2015-07-07 11:42:43 +12:00
}))
}
ast::ExprKind::Path(_, ref path) => {
self.get_path_data(expr.id, path)
2015-07-08 14:30:18 +12:00
}
2015-05-05 19:27:44 +12:00
_ => {
// FIXME
2015-05-05 19:27:44 +12:00
unimplemented!();
}
}
}
2015-09-02 15:37:07 +12:00
pub fn get_path_data(&self, id: NodeId, path: &ast::Path) -> Option<Data> {
2015-07-08 14:30:18 +12:00
let def_map = self.tcx.def_map.borrow();
if !def_map.contains_key(&id) {
self.tcx.sess.span_bug(path.span,
&format!("def_map has no key for {} in visit_expr", id));
}
let def = def_map.get(&id).unwrap().full_def();
let sub_span = self.span_utils.span_for_last_ident(path.span);
filter!(self.span_utils, sub_span, path.span, None);
2015-07-08 14:30:18 +12:00
match def {
Def::Upvar(..) |
Def::Local(..) |
Def::Static(..) |
Def::Const(..) |
Def::AssociatedConst(..) |
Def::Variant(..) => {
Some(Data::VariableRefData(VariableRefData {
2015-07-08 14:30:18 +12:00
name: self.span_utils.snippet(sub_span.unwrap()),
span: sub_span.unwrap(),
scope: self.enclosing_scope(id),
2015-07-08 14:30:18 +12:00
ref_id: def.def_id(),
}))
2015-07-08 14:30:18 +12:00
}
Def::Struct(def_id) |
Def::Enum(def_id) |
Def::TyAlias(def_id) |
Def::Trait(def_id) |
Def::TyParam(_, _, def_id, _) => {
Some(Data::TypeRefData(TypeRefData {
2015-07-08 14:30:18 +12:00
span: sub_span.unwrap(),
ref_id: Some(def_id),
scope: self.enclosing_scope(id),
qualname: String::new() // FIXME: generate the real qualname
}))
2015-07-08 14:30:18 +12:00
}
Def::Method(decl_id) => {
2015-07-08 14:30:18 +12:00
let sub_span = self.span_utils.sub_span_for_meth_name(path.span);
filter!(self.span_utils, sub_span, path.span, None);
let def_id = if decl_id.is_local() {
2015-07-08 14:30:18 +12:00
let ti = self.tcx.impl_or_trait_item(decl_id);
match ti.container() {
ty::TraitContainer(def_id) => {
2015-09-28 09:20:49 +13:00
self.tcx
.trait_items(def_id)
.iter()
2015-09-28 09:20:49 +13:00
.find(|mr| mr.name() == ti.name() && self.trait_method_has_body(mr))
.map(|mr| mr.def_id())
2015-07-08 14:30:18 +12:00
}
ty::ImplContainer(def_id) => {
2015-07-08 14:30:18 +12:00
let impl_items = self.tcx.impl_items.borrow();
Some(impl_items.get(&def_id)
.unwrap()
.iter()
.find(|mr| {
2015-09-28 09:20:49 +13:00
self.tcx.impl_or_trait_item(mr.def_id()).name() ==
ti.name()
})
2015-07-08 14:30:18 +12:00
.unwrap()
.def_id())
}
}
} else {
None
};
Some(Data::MethodCallData(MethodCallData {
2015-07-08 14:30:18 +12:00
span: sub_span.unwrap(),
scope: self.enclosing_scope(id),
2015-07-08 14:30:18 +12:00
ref_id: def_id,
decl_id: Some(decl_id),
}))
2015-09-02 15:37:07 +12:00
}
Def::Fn(def_id) => {
Some(Data::FunctionCallData(FunctionCallData {
2015-07-08 14:30:18 +12:00
ref_id: def_id,
span: sub_span.unwrap(),
scope: self.enclosing_scope(id),
}))
2015-07-08 14:30:18 +12:00
}
Def::Mod(def_id) => {
Some(Data::ModRefData(ModRefData {
ref_id: Some(def_id),
span: sub_span.unwrap(),
scope: self.enclosing_scope(id),
qualname: String::new() // FIXME: generate the real qualname
}))
}
_ => None,
2015-07-08 14:30:18 +12:00
}
}
fn trait_method_has_body(&self, mr: &ty::ImplOrTraitItem) -> bool {
let def_id = mr.def_id();
if let Some(node_id) = self.tcx.map.as_local_node_id(def_id) {
let trait_item = self.tcx.map.expect_trait_item(node_id);
if let hir::TraitItem_::MethodTraitItem(_, Some(_)) = trait_item.node {
true
} else {
false
}
} else {
false
}
}
2015-06-09 09:51:54 +12:00
pub fn get_field_ref_data(&self,
field_ref: &ast::Field,
2015-08-07 14:41:33 +03:00
variant: ty::VariantDef,
2015-06-09 09:51:54 +12:00
parent: NodeId)
-> Option<VariableRefData> {
let f = variant.field_named(field_ref.ident.node.name);
// We don't really need a sub-span here, but no harm done
let sub_span = self.span_utils.span_for_last_ident(field_ref.ident.span);
filter!(self.span_utils, sub_span, field_ref.ident.span, None);
Some(VariableRefData {
name: field_ref.ident.node.to_string(),
span: sub_span.unwrap(),
scope: parent,
ref_id: f.did,
})
2015-06-09 09:51:54 +12:00
}
/// Attempt to return MacroUseData for any AST node.
///
/// For a given piece of AST defined by the supplied Span and NodeId,
/// returns None if the node is not macro-generated or the span is malformed,
/// else uses the expansion callsite and callee to return some MacroUseData.
pub fn get_macro_use_data(&self, span: Span, id: NodeId) -> Option<MacroUseData> {
if !generated_code(span) {
return None;
}
// Note we take care to use the source callsite/callee, to handle
// nested expansions and ensure we only generate data for source-visible
// macro uses.
let callsite = self.tcx.sess.codemap().source_callsite(span);
let callee = self.tcx.sess.codemap().source_callee(span);
let callee = option_try!(callee);
let callee_span = option_try!(callee.span);
// Ignore attribute macros, their spans are usually mangled
if let MacroAttribute(_) = callee.format {
return None;
}
// If the callee is an imported macro from an external crate, need to get
// the source span and name from the session, as their spans are localized
// when read in, and no longer correspond to the source.
if let Some(mac) = self.tcx.sess.imported_macro_spans.borrow().get(&callee_span) {
let &(ref mac_name, mac_span) = mac;
return Some(MacroUseData {
span: callsite,
name: mac_name.clone(),
callee_span: mac_span,
scope: self.enclosing_scope(id),
imported: true,
qualname: String::new()// FIXME: generate the real qualname
});
}
Some(MacroUseData {
span: callsite,
name: callee.name().to_string(),
callee_span: callee_span,
scope: self.enclosing_scope(id),
imported: false,
qualname: String::new() // FIXME: generate the real qualname
})
}
pub fn get_data_for_id(&self, _id: &NodeId) -> Data {
// FIXME
unimplemented!();
2015-05-05 19:27:44 +12:00
}
2015-06-05 17:50:04 +12:00
fn lookup_ref_id(&self, ref_id: NodeId) -> Option<DefId> {
if !self.tcx.def_map.borrow().contains_key(&ref_id) {
self.tcx.sess.bug(&format!("def_map has no key for {} in lookup_type_ref",
ref_id));
2015-06-05 17:50:04 +12:00
}
let def = self.tcx.def_map.borrow().get(&ref_id).unwrap().full_def();
2015-06-05 17:50:04 +12:00
match def {
Def::PrimTy(_) | Def::SelfTy(..) => None,
2015-06-05 17:50:04 +12:00
_ => Some(def.def_id()),
}
}
#[inline]
pub fn enclosing_scope(&self, id: NodeId) -> NodeId {
self.tcx.map.get_enclosing_scope(id).unwrap_or(0)
}
}
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 {
2015-09-02 15:37:07 +12:00
PathCollector { collected_paths: vec![] }
2015-05-05 22:03:20 +12:00
}
}
impl<'v> Visitor<'v> for PathCollector {
fn visit_pat(&mut self, p: &ast::Pat) {
match p.node {
2016-02-11 21:16:33 +03:00
PatKind::Struct(ref path, _, _) => {
self.collected_paths.push((p.id, path.clone(),
ast::Mutability::Mutable, recorder::TypeRef));
2015-05-05 22:03:20 +12:00
}
PatKind::TupleStruct(ref path, _) |
PatKind::Path(ref path) |
2016-02-11 21:16:33 +03:00
PatKind::QPath(_, ref path) => {
self.collected_paths.push((p.id, path.clone(),
ast::Mutability::Mutable, recorder::VarRef));
2015-05-05 22:03:20 +12:00
}
2016-02-11 21:16:33 +03:00
PatKind::Ident(bm, ref path1, _) => {
debug!("PathCollector, visit ident in pat {}: {:?} {:?}",
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::BindingMode::ByRef(_) => ast::Mutability::Immutable,
ast::BindingMode::ByValue(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);
}
}
2016-02-29 23:36:51 +00:00
pub fn process_crate<'l, 'tcx>(tcx: &'l TyCtxt<'tcx>,
lcx: &'l lowering::LoweringContext<'l>,
2015-09-25 16:03:28 +12:00
krate: &ast::Crate,
analysis: &ty::CrateAnalysis,
cratename: &str,
2015-09-25 16:03:28 +12:00
odir: Option<&Path>) {
let _ignore = tcx.dep_graph.in_ignore();
assert!(analysis.glob_map.is_some());
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"),
},
};
if let Err(e) = fs::create_dir_all(&root_path) {
tcx.sess.err(&format!("Could not create directory {}: {}",
2015-09-28 09:20:49 +13:00
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 executable = tcx.sess.crate_types.borrow().iter().any(|ct| *ct == CrateTypeExecutable);
let mut out_name = if executable {
"".to_owned()
} else {
"lib".to_owned()
};
out_name.push_str(&cratename);
out_name.push_str(&tcx.sess.opts.cg.extra_filename);
out_name.push_str(".csv");
root_path.push(&out_name);
let mut output_file = File::create(&root_path).unwrap_or_else(|e| {
let disp = root_path.display();
tcx.sess.fatal(&format!("Could not open {}: {}", disp, e));
});
root_path.pop();
let utils = SpanUtils::new(&tcx.sess);
let mut dumper = CsvDumper::new(&mut output_file, utils);
let mut visitor = DumpVisitor::new(tcx, lcx, analysis, &mut dumper);
// FIXME: we don't write anything!
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("\"", "\"\"")
}
// Helper function to determine if a span came from a
// macro expansion or syntax extension.
2015-07-14 13:40:02 +12:00
pub fn generated_code(span: Span) -> bool {
2015-09-02 15:37:07 +12:00
span.expn_id != NO_EXPANSION || span == DUMMY_SP
}