#![feature(rustc_private)]
extern crate rustc_borrowck;
extern crate rustc_data_structures;
extern crate rustc_driver;
extern crate rustc_hir;
extern crate rustc_interface;
extern crate rustc_middle;
extern crate rustc_span;
use std::process::Command;
use flowistry::infoflow::Direction;
use rustc_borrowck::consumers::BodyWithBorrowckFacts;
use rustc_hir::{BodyId, ItemKind};
use rustc_middle::{
mir::{Local, Place},
ty::TyCtxt,
};
use rustc_span::Span;
use rustc_utils::{
BodyExt, PlaceExt, SpanExt,
mir::{borrowck_facts, location_or_arg::LocationOrArg},
source_map::spanner::{EnclosingHirSpans, Spanner},
};
fn compute_dependencies<'tcx>(
tcx: TyCtxt<'tcx>,
body_id: BodyId,
body_with_facts: &BodyWithBorrowckFacts<'tcx>,
) {
println!("Body:\n{}", body_with_facts.body.to_string(tcx).unwrap());
let results = flowistry::infoflow::compute_flow(tcx, body_id, body_with_facts);
let arg_local = Local::from_usize(1);
let arg_place = Place::make(arg_local, &[], tcx);
let targets = vec![vec![(arg_place, LocationOrArg::Arg(arg_local))]];
let location_deps = flowistry::infoflow::compute_dependencies(
&results,
targets.clone(),
Direction::Forward,
)
.remove(0);
println!("The forward dependencies of targets {targets:?} are:");
let body = &body_with_facts.body;
let spanner = Spanner::new(tcx, body_id, body);
let source_map = tcx.sess.source_map();
for location in location_deps.iter() {
let spans = Span::merge_overlaps(spanner.location_to_spans(
*location,
body,
EnclosingHirSpans::OuterOnly,
));
println!("Location {location:?}:");
for span in spans {
println!(
"{}",
textwrap::indent(&source_map.span_to_snippet(span).unwrap(), " ")
);
}
}
}
struct Callbacks;
impl rustc_driver::Callbacks for Callbacks {
fn config(&mut self, config: &mut rustc_interface::Config) {
borrowck_facts::enable_mir_simplification();
config.override_queries = Some(borrowck_facts::override_queries);
}
fn after_analysis<'tcx>(
&mut self,
_compiler: &rustc_interface::interface::Compiler,
tcx: TyCtxt<'tcx>,
) -> rustc_driver::Compilation {
let body_id = tcx
.hir_free_items()
.filter_map(|id| match tcx.hir_item(id).kind {
ItemKind::Fn { body, .. } => Some(body),
_ => None,
})
.next()
.unwrap();
let def_id = tcx.hir_body_owner_def_id(body_id);
let body_with_facts = borrowck_facts::get_body_with_borrowck_facts(tcx, def_id);
compute_dependencies(tcx, body_id, body_with_facts);
rustc_driver::Compilation::Stop
}
}
fn main() {
env_logger::init();
let print_sysroot = Command::new("rustc")
.args(&["--print", "sysroot"])
.output()
.unwrap()
.stdout;
let sysroot = String::from_utf8(print_sysroot).unwrap().trim().to_owned();
let mut args = std::env::args().collect::<Vec<_>>();
args.extend(["--sysroot".into(), sysroot]);
let mut callbacks = Callbacks;
rustc_driver::catch_fatal_errors(|| rustc_driver::run_compiler(&args, &mut callbacks))
.unwrap();
}