use std::cell::RefCell;
use log::debug;
use rustc_borrowck::consumers::BodyWithBorrowckFacts;
use rustc_hir::BodyId;
use rustc_middle::ty::TyCtxt;
use rustc_utils::{BodyExt, block_timer};
pub use self::{
analysis::{FlowAnalysis, FlowDomain},
dependencies::{Direction, compute_dependencies, compute_dependency_spans},
};
use crate::mir::{engine, placeinfo::PlaceInfo};
mod analysis;
mod dependencies;
pub mod mutation;
mod recursive;
pub type FlowResults<'a, 'tcx> = engine::AnalysisResults<'tcx, FlowAnalysis<'a, 'tcx>>;
thread_local! {
pub(super) static BODY_STACK: RefCell<Vec<BodyId>> =
const { RefCell::new(Vec::new()) };
}
pub fn compute_flow<'a, 'tcx>(
tcx: TyCtxt<'tcx>,
body_id: BodyId,
body_with_facts: &'a BodyWithBorrowckFacts<'tcx>,
) -> FlowResults<'a, 'tcx> {
BODY_STACK.with(|body_stack| {
body_stack.borrow_mut().push(body_id);
debug!("{}", body_with_facts.body.to_string(tcx).unwrap());
let def_id = tcx.hir_body_owner_def_id(body_id).to_def_id();
let place_info = PlaceInfo::build(tcx, def_id, body_with_facts);
let location_domain = place_info.location_domain().clone();
let body = &body_with_facts.body;
let results = {
block_timer!("Flow");
let analysis = FlowAnalysis::new(tcx, def_id, body, place_info);
engine::iterate_to_fixpoint(tcx, body, location_domain, analysis)
};
if log::log_enabled!(log::Level::Info) {
let counts = body
.all_locations()
.flat_map(|loc| {
let state = results.state_at(loc);
state
.rows()
.map(|(_, locations)| locations.len())
.collect::<Vec<_>>()
})
.collect::<Vec<_>>();
let nloc = body.all_locations().count();
let np = counts.len();
let pavg = np as f64 / (nloc as f64);
let nl = counts.into_iter().sum::<usize>();
let lavg = nl as f64 / (nloc as f64);
log::info!(
"Over {nloc} locations, total number of place entries: {np} (avg {pavg:.0}/loc), total size of location sets: {nl} (avg {lavg:.0}/loc)",
);
}
if std::env::var("DUMP_MIR").is_ok()
&& BODY_STACK.with(|body_stack| body_stack.borrow().len() == 1)
{
todo!()
}
body_stack.borrow_mut().pop();
results
})
}