Skip to content

Commit 622e524

Browse files
committed
Auto merge of #40751 - nrc:save-callback, r=eddyb
save-analysis: allow clients to get data directly without writing to a file.
2 parents 7846dbe + 3ec61ea commit 622e524

File tree

4 files changed

+164
-72
lines changed

4 files changed

+164
-72
lines changed

src/librustc_driver/driver.rs

+1-4
Original file line numberDiff line numberDiff line change
@@ -258,10 +258,7 @@ fn keep_hygiene_data(sess: &Session) -> bool {
258258
}
259259

260260
fn keep_ast(sess: &Session) -> bool {
261-
sess.opts.debugging_opts.keep_ast ||
262-
sess.opts.debugging_opts.save_analysis ||
263-
sess.opts.debugging_opts.save_analysis_csv ||
264-
sess.opts.debugging_opts.save_analysis_api
261+
sess.opts.debugging_opts.keep_ast || ::save_analysis(sess)
265262
}
266263

267264
/// The name used for source code that doesn't originate in a file

src/librustc_driver/lib.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ use pretty::{PpMode, UserIdentifiedItem};
6767

6868
use rustc_resolve as resolve;
6969
use rustc_save_analysis as save;
70+
use rustc_save_analysis::DumpHandler;
7071
use rustc_trans::back::link;
7172
use rustc_trans::back::write::{create_target_machine, RELOC_MODEL_ARGS, CODE_GEN_MODEL_ARGS};
7273
use rustc::dep_graph::DepGraph;
@@ -507,8 +508,9 @@ impl<'a> CompilerCalls<'a> for RustcDefaultCalls {
507508
state.expanded_crate.unwrap(),
508509
state.analysis.unwrap(),
509510
state.crate_name.unwrap(),
510-
state.out_dir,
511-
save_analysis_format(state.session))
511+
DumpHandler::new(save_analysis_format(state.session),
512+
state.out_dir,
513+
state.crate_name.unwrap()))
512514
});
513515
};
514516
control.after_analysis.run_callback_on_error = true;

src/librustc_save_analysis/json_dumper.rs

+40-10
Original file line numberDiff line numberDiff line change
@@ -22,25 +22,55 @@ use external_data::*;
2222
use data::{self, VariableKind};
2323
use dump::Dump;
2424

25-
pub struct JsonDumper<'b, W: Write + 'b> {
26-
output: &'b mut W,
25+
pub struct JsonDumper<O: DumpOutput> {
2726
result: Analysis,
27+
output: O,
2828
}
2929

30-
impl<'b, W: Write> JsonDumper<'b, W> {
31-
pub fn new(writer: &'b mut W) -> JsonDumper<'b, W> {
32-
JsonDumper { output: writer, result: Analysis::new() }
33-
}
30+
pub trait DumpOutput {
31+
fn dump(&mut self, result: &Analysis);
3432
}
3533

36-
impl<'b, W: Write> Drop for JsonDumper<'b, W> {
37-
fn drop(&mut self) {
38-
if let Err(_) = write!(self.output, "{}", as_json(&self.result)) {
34+
pub struct WriteOutput<'b, W: Write + 'b> {
35+
output: &'b mut W,
36+
}
37+
38+
impl<'b, W: Write> DumpOutput for WriteOutput<'b, W> {
39+
fn dump(&mut self, result: &Analysis) {
40+
if let Err(_) = write!(self.output, "{}", as_json(&result)) {
3941
error!("Error writing output");
4042
}
4143
}
4244
}
4345

46+
pub struct CallbackOutput<'b> {
47+
callback: &'b mut FnMut(&Analysis),
48+
}
49+
50+
impl<'b> DumpOutput for CallbackOutput<'b> {
51+
fn dump(&mut self, result: &Analysis) {
52+
(self.callback)(result)
53+
}
54+
}
55+
56+
impl<'b, W: Write> JsonDumper<WriteOutput<'b, W>> {
57+
pub fn new(writer: &'b mut W) -> JsonDumper<WriteOutput<'b, W>> {
58+
JsonDumper { output: WriteOutput { output: writer }, result: Analysis::new() }
59+
}
60+
}
61+
62+
impl<'b> JsonDumper<CallbackOutput<'b>> {
63+
pub fn with_callback(callback: &'b mut FnMut(&Analysis)) -> JsonDumper<CallbackOutput<'b>> {
64+
JsonDumper { output: CallbackOutput { callback: callback }, result: Analysis::new() }
65+
}
66+
}
67+
68+
impl<O: DumpOutput> Drop for JsonDumper<O> {
69+
fn drop(&mut self) {
70+
self.output.dump(&self.result);
71+
}
72+
}
73+
4474
macro_rules! impl_fn {
4575
($fn_name: ident, $data_type: ident, $bucket: ident) => {
4676
fn $fn_name(&mut self, data: $data_type) {
@@ -49,7 +79,7 @@ macro_rules! impl_fn {
4979
}
5080
}
5181

52-
impl<'b, W: Write + 'b> Dump for JsonDumper<'b, W> {
82+
impl<'b, O: DumpOutput + 'b> Dump for JsonDumper<O> {
5383
fn crate_prelude(&mut self, data: CratePreludeData) {
5484
self.result.prelude = Some(data)
5585
}

src/librustc_save_analysis/lib.rs

+119-56
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ use rustc::hir::def::Def;
4848
use rustc::hir::map::Node;
4949
use rustc::hir::def_id::DefId;
5050
use rustc::session::config::CrateType::CrateTypeExecutable;
51+
use rustc::session::Session;
5152
use rustc::ty::{self, TyCtxt};
5253

5354
use std::env;
@@ -866,55 +867,131 @@ impl Format {
866867
}
867868
}
868869

869-
pub fn process_crate<'l, 'tcx>(tcx: TyCtxt<'l, 'tcx, 'tcx>,
870-
krate: &ast::Crate,
871-
analysis: &'l ty::CrateAnalysis,
872-
cratename: &str,
873-
odir: Option<&Path>,
874-
format: Format) {
875-
let _ignore = tcx.dep_graph.in_ignore();
870+
/// Defines what to do with the results of saving the analysis.
871+
pub trait SaveHandler {
872+
fn save<'l, 'tcx>(&mut self,
873+
save_ctxt: SaveContext<'l, 'tcx>,
874+
krate: &ast::Crate,
875+
cratename: &str);
876+
}
876877

877-
assert!(analysis.glob_map.is_some());
878+
/// Dump the save-analysis results to a file.
879+
pub struct DumpHandler<'a> {
880+
format: Format,
881+
odir: Option<&'a Path>,
882+
cratename: String
883+
}
878884

879-
info!("Dumping crate {}", cratename);
885+
impl<'a> DumpHandler<'a> {
886+
pub fn new(format: Format, odir: Option<&'a Path>, cratename: &str) -> DumpHandler<'a> {
887+
DumpHandler {
888+
format: format,
889+
odir: odir,
890+
cratename: cratename.to_owned()
891+
}
892+
}
880893

881-
// find a path to dump our data to
882-
let mut root_path = match env::var_os("RUST_SAVE_ANALYSIS_FOLDER") {
883-
Some(val) => PathBuf::from(val),
884-
None => match odir {
885-
Some(val) => val.join("save-analysis"),
886-
None => PathBuf::from("save-analysis-temp"),
887-
},
888-
};
894+
fn output_file(&self, sess: &Session) -> File {
895+
let mut root_path = match env::var_os("RUST_SAVE_ANALYSIS_FOLDER") {
896+
Some(val) => PathBuf::from(val),
897+
None => match self.odir {
898+
Some(val) => val.join("save-analysis"),
899+
None => PathBuf::from("save-analysis-temp"),
900+
},
901+
};
889902

890-
if let Err(e) = std::fs::create_dir_all(&root_path) {
891-
tcx.sess.err(&format!("Could not create directory {}: {}",
892-
root_path.display(),
893-
e));
903+
if let Err(e) = std::fs::create_dir_all(&root_path) {
904+
error!("Could not create directory {}: {}", root_path.display(), e);
905+
}
906+
907+
{
908+
let disp = root_path.display();
909+
info!("Writing output to {}", disp);
910+
}
911+
912+
let executable = sess.crate_types.borrow().iter().any(|ct| *ct == CrateTypeExecutable);
913+
let mut out_name = if executable {
914+
"".to_owned()
915+
} else {
916+
"lib".to_owned()
917+
};
918+
out_name.push_str(&self.cratename);
919+
out_name.push_str(&sess.opts.cg.extra_filename);
920+
out_name.push_str(self.format.extension());
921+
root_path.push(&out_name);
922+
let output_file = File::create(&root_path).unwrap_or_else(|e| {
923+
let disp = root_path.display();
924+
sess.fatal(&format!("Could not open {}: {}", disp, e));
925+
});
926+
root_path.pop();
927+
output_file
894928
}
929+
}
930+
931+
impl<'a> SaveHandler for DumpHandler<'a> {
932+
fn save<'l, 'tcx>(&mut self,
933+
save_ctxt: SaveContext<'l, 'tcx>,
934+
krate: &ast::Crate,
935+
cratename: &str) {
936+
macro_rules! dump {
937+
($new_dumper: expr) => {{
938+
let mut dumper = $new_dumper;
939+
let mut visitor = DumpVisitor::new(save_ctxt, &mut dumper);
940+
941+
visitor.dump_crate_info(cratename, krate);
942+
visit::walk_crate(&mut visitor, krate);
943+
}}
944+
}
945+
946+
let output = &mut self.output_file(&save_ctxt.tcx.sess);
895947

896-
{
897-
let disp = root_path.display();
898-
info!("Writing output to {}", disp);
948+
match self.format {
949+
Format::Csv => dump!(CsvDumper::new(output)),
950+
Format::Json => dump!(JsonDumper::new(output)),
951+
Format::JsonApi => dump!(JsonApiDumper::new(output)),
952+
}
899953
}
954+
}
900955

901-
// Create output file.
902-
let executable = tcx.sess.crate_types.borrow().iter().any(|ct| *ct == CrateTypeExecutable);
903-
let mut out_name = if executable {
904-
"".to_owned()
905-
} else {
906-
"lib".to_owned()
907-
};
908-
out_name.push_str(&cratename);
909-
out_name.push_str(&tcx.sess.opts.cg.extra_filename);
910-
out_name.push_str(format.extension());
911-
root_path.push(&out_name);
912-
let mut output_file = File::create(&root_path).unwrap_or_else(|e| {
913-
let disp = root_path.display();
914-
tcx.sess.fatal(&format!("Could not open {}: {}", disp, e));
915-
});
916-
root_path.pop();
917-
let output = &mut output_file;
956+
/// Call a callback with the results of save-analysis.
957+
pub struct CallbackHandler<'b> {
958+
pub callback: &'b mut FnMut(&rls_data::Analysis),
959+
}
960+
961+
impl<'b> SaveHandler for CallbackHandler<'b> {
962+
fn save<'l, 'tcx>(&mut self,
963+
save_ctxt: SaveContext<'l, 'tcx>,
964+
krate: &ast::Crate,
965+
cratename: &str) {
966+
macro_rules! dump {
967+
($new_dumper: expr) => {{
968+
let mut dumper = $new_dumper;
969+
let mut visitor = DumpVisitor::new(save_ctxt, &mut dumper);
970+
971+
visitor.dump_crate_info(cratename, krate);
972+
visit::walk_crate(&mut visitor, krate);
973+
}}
974+
}
975+
976+
// We're using the JsonDumper here because it has the format of the
977+
// save-analysis results that we will pass to the callback. IOW, we are
978+
// using the JsonDumper to collect the save-analysis results, but not
979+
// actually to dump them to a file. This is all a bit convoluted and
980+
// there is certainly a simpler design here trying to get out (FIXME).
981+
dump!(JsonDumper::with_callback(self.callback))
982+
}
983+
}
984+
985+
pub fn process_crate<'l, 'tcx, H: SaveHandler>(tcx: TyCtxt<'l, 'tcx, 'tcx>,
986+
krate: &ast::Crate,
987+
analysis: &'l ty::CrateAnalysis,
988+
cratename: &str,
989+
mut handler: H) {
990+
let _ignore = tcx.dep_graph.in_ignore();
991+
992+
assert!(analysis.glob_map.is_some());
993+
994+
info!("Dumping crate {}", cratename);
918995

919996
let save_ctxt = SaveContext {
920997
tcx: tcx,
@@ -923,21 +1000,7 @@ pub fn process_crate<'l, 'tcx>(tcx: TyCtxt<'l, 'tcx, 'tcx>,
9231000
span_utils: SpanUtils::new(&tcx.sess),
9241001
};
9251002

926-
macro_rules! dump {
927-
($new_dumper: expr) => {{
928-
let mut dumper = $new_dumper;
929-
let mut visitor = DumpVisitor::new(save_ctxt, &mut dumper);
930-
931-
visitor.dump_crate_info(cratename, krate);
932-
visit::walk_crate(&mut visitor, krate);
933-
}}
934-
}
935-
936-
match format {
937-
Format::Csv => dump!(CsvDumper::new(output)),
938-
Format::Json => dump!(JsonDumper::new(output)),
939-
Format::JsonApi => dump!(JsonApiDumper::new(output)),
940-
}
1003+
handler.save(save_ctxt, krate, cratename)
9411004
}
9421005

9431006
// Utility functions for the module.

0 commit comments

Comments
 (0)