Rollup merge of #40751 - nrc:save-callback, r=eddyb
save-analysis: allow clients to get data directly without writing to a file.
This commit is contained in:
commit
51371157e2
|
@ -258,10 +258,7 @@ fn keep_hygiene_data(sess: &Session) -> bool {
|
|||
}
|
||||
|
||||
fn keep_ast(sess: &Session) -> bool {
|
||||
sess.opts.debugging_opts.keep_ast ||
|
||||
sess.opts.debugging_opts.save_analysis ||
|
||||
sess.opts.debugging_opts.save_analysis_csv ||
|
||||
sess.opts.debugging_opts.save_analysis_api
|
||||
sess.opts.debugging_opts.keep_ast || ::save_analysis(sess)
|
||||
}
|
||||
|
||||
/// The name used for source code that doesn't originate in a file
|
||||
|
|
|
@ -67,6 +67,7 @@ use pretty::{PpMode, UserIdentifiedItem};
|
|||
|
||||
use rustc_resolve as resolve;
|
||||
use rustc_save_analysis as save;
|
||||
use rustc_save_analysis::DumpHandler;
|
||||
use rustc_trans::back::link;
|
||||
use rustc_trans::back::write::{create_target_machine, RELOC_MODEL_ARGS, CODE_GEN_MODEL_ARGS};
|
||||
use rustc::dep_graph::DepGraph;
|
||||
|
@ -507,8 +508,9 @@ impl<'a> CompilerCalls<'a> for RustcDefaultCalls {
|
|||
state.expanded_crate.unwrap(),
|
||||
state.analysis.unwrap(),
|
||||
state.crate_name.unwrap(),
|
||||
state.out_dir,
|
||||
save_analysis_format(state.session))
|
||||
DumpHandler::new(save_analysis_format(state.session),
|
||||
state.out_dir,
|
||||
state.crate_name.unwrap()))
|
||||
});
|
||||
};
|
||||
control.after_analysis.run_callback_on_error = true;
|
||||
|
|
|
@ -22,22 +22,52 @@ use external_data::*;
|
|||
use data::{self, VariableKind};
|
||||
use dump::Dump;
|
||||
|
||||
pub struct JsonDumper<'b, W: Write + 'b> {
|
||||
output: &'b mut W,
|
||||
pub struct JsonDumper<O: DumpOutput> {
|
||||
result: Analysis,
|
||||
output: O,
|
||||
}
|
||||
|
||||
impl<'b, W: Write> JsonDumper<'b, W> {
|
||||
pub fn new(writer: &'b mut W) -> JsonDumper<'b, W> {
|
||||
JsonDumper { output: writer, result: Analysis::new() }
|
||||
pub trait DumpOutput {
|
||||
fn dump(&mut self, result: &Analysis);
|
||||
}
|
||||
|
||||
pub struct WriteOutput<'b, W: Write + 'b> {
|
||||
output: &'b mut W,
|
||||
}
|
||||
|
||||
impl<'b, W: Write> DumpOutput for WriteOutput<'b, W> {
|
||||
fn dump(&mut self, result: &Analysis) {
|
||||
if let Err(_) = write!(self.output, "{}", as_json(&result)) {
|
||||
error!("Error writing output");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'b, W: Write> Drop for JsonDumper<'b, W> {
|
||||
pub struct CallbackOutput<'b> {
|
||||
callback: &'b mut FnMut(&Analysis),
|
||||
}
|
||||
|
||||
impl<'b> DumpOutput for CallbackOutput<'b> {
|
||||
fn dump(&mut self, result: &Analysis) {
|
||||
(self.callback)(result)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'b, W: Write> JsonDumper<WriteOutput<'b, W>> {
|
||||
pub fn new(writer: &'b mut W) -> JsonDumper<WriteOutput<'b, W>> {
|
||||
JsonDumper { output: WriteOutput { output: writer }, result: Analysis::new() }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'b> JsonDumper<CallbackOutput<'b>> {
|
||||
pub fn with_callback(callback: &'b mut FnMut(&Analysis)) -> JsonDumper<CallbackOutput<'b>> {
|
||||
JsonDumper { output: CallbackOutput { callback: callback }, result: Analysis::new() }
|
||||
}
|
||||
}
|
||||
|
||||
impl<O: DumpOutput> Drop for JsonDumper<O> {
|
||||
fn drop(&mut self) {
|
||||
if let Err(_) = write!(self.output, "{}", as_json(&self.result)) {
|
||||
error!("Error writing output");
|
||||
}
|
||||
self.output.dump(&self.result);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -49,7 +79,7 @@ macro_rules! impl_fn {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'b, W: Write + 'b> Dump for JsonDumper<'b, W> {
|
||||
impl<'b, O: DumpOutput + 'b> Dump for JsonDumper<O> {
|
||||
fn crate_prelude(&mut self, data: CratePreludeData) {
|
||||
self.result.prelude = Some(data)
|
||||
}
|
||||
|
|
|
@ -48,6 +48,7 @@ use rustc::hir::def::Def;
|
|||
use rustc::hir::map::Node;
|
||||
use rustc::hir::def_id::DefId;
|
||||
use rustc::session::config::CrateType::CrateTypeExecutable;
|
||||
use rustc::session::Session;
|
||||
use rustc::ty::{self, TyCtxt};
|
||||
|
||||
use std::env;
|
||||
|
@ -866,56 +867,132 @@ impl Format {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn process_crate<'l, 'tcx>(tcx: TyCtxt<'l, 'tcx, 'tcx>,
|
||||
krate: &ast::Crate,
|
||||
analysis: &'l ty::CrateAnalysis,
|
||||
cratename: &str,
|
||||
odir: Option<&Path>,
|
||||
format: Format) {
|
||||
/// Defines what to do with the results of saving the analysis.
|
||||
pub trait SaveHandler {
|
||||
fn save<'l, 'tcx>(&mut self,
|
||||
save_ctxt: SaveContext<'l, 'tcx>,
|
||||
krate: &ast::Crate,
|
||||
cratename: &str);
|
||||
}
|
||||
|
||||
/// Dump the save-analysis results to a file.
|
||||
pub struct DumpHandler<'a> {
|
||||
format: Format,
|
||||
odir: Option<&'a Path>,
|
||||
cratename: String
|
||||
}
|
||||
|
||||
impl<'a> DumpHandler<'a> {
|
||||
pub fn new(format: Format, odir: Option<&'a Path>, cratename: &str) -> DumpHandler<'a> {
|
||||
DumpHandler {
|
||||
format: format,
|
||||
odir: odir,
|
||||
cratename: cratename.to_owned()
|
||||
}
|
||||
}
|
||||
|
||||
fn output_file(&self, sess: &Session) -> File {
|
||||
let mut root_path = match env::var_os("RUST_SAVE_ANALYSIS_FOLDER") {
|
||||
Some(val) => PathBuf::from(val),
|
||||
None => match self.odir {
|
||||
Some(val) => val.join("save-analysis"),
|
||||
None => PathBuf::from("save-analysis-temp"),
|
||||
},
|
||||
};
|
||||
|
||||
if let Err(e) = std::fs::create_dir_all(&root_path) {
|
||||
error!("Could not create directory {}: {}", root_path.display(), e);
|
||||
}
|
||||
|
||||
{
|
||||
let disp = root_path.display();
|
||||
info!("Writing output to {}", disp);
|
||||
}
|
||||
|
||||
let executable = 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(&self.cratename);
|
||||
out_name.push_str(&sess.opts.cg.extra_filename);
|
||||
out_name.push_str(self.format.extension());
|
||||
root_path.push(&out_name);
|
||||
let output_file = File::create(&root_path).unwrap_or_else(|e| {
|
||||
let disp = root_path.display();
|
||||
sess.fatal(&format!("Could not open {}: {}", disp, e));
|
||||
});
|
||||
root_path.pop();
|
||||
output_file
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> SaveHandler for DumpHandler<'a> {
|
||||
fn save<'l, 'tcx>(&mut self,
|
||||
save_ctxt: SaveContext<'l, 'tcx>,
|
||||
krate: &ast::Crate,
|
||||
cratename: &str) {
|
||||
macro_rules! dump {
|
||||
($new_dumper: expr) => {{
|
||||
let mut dumper = $new_dumper;
|
||||
let mut visitor = DumpVisitor::new(save_ctxt, &mut dumper);
|
||||
|
||||
visitor.dump_crate_info(cratename, krate);
|
||||
visit::walk_crate(&mut visitor, krate);
|
||||
}}
|
||||
}
|
||||
|
||||
let output = &mut self.output_file(&save_ctxt.tcx.sess);
|
||||
|
||||
match self.format {
|
||||
Format::Csv => dump!(CsvDumper::new(output)),
|
||||
Format::Json => dump!(JsonDumper::new(output)),
|
||||
Format::JsonApi => dump!(JsonApiDumper::new(output)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Call a callback with the results of save-analysis.
|
||||
pub struct CallbackHandler<'b> {
|
||||
pub callback: &'b mut FnMut(&rls_data::Analysis),
|
||||
}
|
||||
|
||||
impl<'b> SaveHandler for CallbackHandler<'b> {
|
||||
fn save<'l, 'tcx>(&mut self,
|
||||
save_ctxt: SaveContext<'l, 'tcx>,
|
||||
krate: &ast::Crate,
|
||||
cratename: &str) {
|
||||
macro_rules! dump {
|
||||
($new_dumper: expr) => {{
|
||||
let mut dumper = $new_dumper;
|
||||
let mut visitor = DumpVisitor::new(save_ctxt, &mut dumper);
|
||||
|
||||
visitor.dump_crate_info(cratename, krate);
|
||||
visit::walk_crate(&mut visitor, krate);
|
||||
}}
|
||||
}
|
||||
|
||||
// We're using the JsonDumper here because it has the format of the
|
||||
// save-analysis results that we will pass to the callback. IOW, we are
|
||||
// using the JsonDumper to collect the save-analysis results, but not
|
||||
// actually to dump them to a file. This is all a bit convoluted and
|
||||
// there is certainly a simpler design here trying to get out (FIXME).
|
||||
dump!(JsonDumper::with_callback(self.callback))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn process_crate<'l, 'tcx, H: SaveHandler>(tcx: TyCtxt<'l, 'tcx, 'tcx>,
|
||||
krate: &ast::Crate,
|
||||
analysis: &'l ty::CrateAnalysis,
|
||||
cratename: &str,
|
||||
mut handler: H) {
|
||||
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("RUST_SAVE_ANALYSIS_FOLDER") {
|
||||
Some(val) => PathBuf::from(val),
|
||||
None => match odir {
|
||||
Some(val) => val.join("save-analysis"),
|
||||
None => PathBuf::from("save-analysis-temp"),
|
||||
},
|
||||
};
|
||||
|
||||
if let Err(e) = std::fs::create_dir_all(&root_path) {
|
||||
tcx.sess.err(&format!("Could not create directory {}: {}",
|
||||
root_path.display(),
|
||||
e));
|
||||
}
|
||||
|
||||
{
|
||||
let disp = root_path.display();
|
||||
info!("Writing output to {}", disp);
|
||||
}
|
||||
|
||||
// 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(format.extension());
|
||||
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 output = &mut output_file;
|
||||
|
||||
let save_ctxt = SaveContext {
|
||||
tcx: tcx,
|
||||
tables: &ty::TypeckTables::empty(),
|
||||
|
@ -923,21 +1000,7 @@ pub fn process_crate<'l, 'tcx>(tcx: TyCtxt<'l, 'tcx, 'tcx>,
|
|||
span_utils: SpanUtils::new(&tcx.sess),
|
||||
};
|
||||
|
||||
macro_rules! dump {
|
||||
($new_dumper: expr) => {{
|
||||
let mut dumper = $new_dumper;
|
||||
let mut visitor = DumpVisitor::new(save_ctxt, &mut dumper);
|
||||
|
||||
visitor.dump_crate_info(cratename, krate);
|
||||
visit::walk_crate(&mut visitor, krate);
|
||||
}}
|
||||
}
|
||||
|
||||
match format {
|
||||
Format::Csv => dump!(CsvDumper::new(output)),
|
||||
Format::Json => dump!(JsonDumper::new(output)),
|
||||
Format::JsonApi => dump!(JsonApiDumper::new(output)),
|
||||
}
|
||||
handler.save(save_ctxt, krate, cratename)
|
||||
}
|
||||
|
||||
// Utility functions for the module.
|
||||
|
|
Loading…
Reference in New Issue