use crate::analysis::{
Analysis,
path_analysis::graph::{PathEnumerator, PathGraph},
};
use crate::compat::FxHashMap;
use rustc_hir::{def::DefKind, def_id::DefId};
use rustc_middle::ty::TyCtxt;
use super::PathTree;
pub struct PathAnalyzer<'tcx> {
pub tcx: TyCtxt<'tcx>,
pub debug: bool,
pub paths: FxHashMap<DefId, PathTree>,
pub graphs: FxHashMap<DefId, PathGraph<'tcx>>,
}
impl<'tcx> PathAnalyzer<'tcx> {
pub fn new(tcx: TyCtxt<'tcx>, debug: bool) -> Self {
Self {
tcx,
debug,
paths: FxHashMap::default(),
graphs: FxHashMap::default(),
}
}
pub fn analyze(&mut self, def_id: DefId) -> Option<PathTree> {
self.analyze_repeat(def_id, 0)
}
pub fn analyze_repeat(&mut self, def_id: DefId, postfix_repeat: usize) -> Option<PathTree> {
if let Some(paths) = self.paths.get(&def_id) {
return Some(paths.clone());
}
if !self.tcx.is_mir_available(def_id) {
return None;
}
let mut graph = PathGraph::new(self.tcx, def_id);
graph.find_scc();
let mut enumerator = PathEnumerator::new(&graph);
let paths = enumerator.enumerate_paths_repeat(postfix_repeat);
self.graphs.insert(def_id, graph);
self.paths.insert(def_id, paths.clone());
Some(paths)
}
pub fn get_fn_paths(&self, def_id: DefId) -> Option<PathTree> {
self.paths.get(&def_id).cloned()
}
pub fn get_all_paths(&self) -> FxHashMap<DefId, PathTree> {
self.paths.clone()
}
pub fn analyze_all(&mut self) {
self.analyze_all_repeat(0);
}
pub fn analyze_all_repeat(&mut self, postfix_repeat: usize) {
for local_def_id in self.tcx.iter_local_def_id() {
if matches!(self.tcx.def_kind(local_def_id), DefKind::Fn) {
let def_id = local_def_id.to_def_id();
let _ = self.analyze_repeat(def_id, postfix_repeat);
}
}
}
pub fn run_with_repeat(&mut self, postfix_repeat: usize) {
self.analyze_all_repeat(postfix_repeat);
}
}
impl<'tcx> Analysis for PathAnalyzer<'tcx> {
fn name(&self) -> &'static str {
"Path Analysis"
}
fn run(&mut self) {
self.analyze_all();
}
fn reset(&mut self) {
self.paths.clear();
self.graphs.clear();
}
}