rapx/analysis/path_analysis/
default.rs1use crate::analysis::{
2 Analysis,
3 path_analysis::graph::{PathEnumerator, PathGraph},
4};
5use crate::compat::FxHashMap;
6use rustc_hir::{def::DefKind, def_id::DefId};
7use rustc_middle::ty::TyCtxt;
8
9use super::PathTree;
10
11pub struct PathAnalyzer<'tcx> {
14 pub tcx: TyCtxt<'tcx>,
15 pub debug: bool,
16 pub paths: FxHashMap<DefId, PathTree>,
17 pub graphs: FxHashMap<DefId, PathGraph<'tcx>>,
18}
19
20impl<'tcx> PathAnalyzer<'tcx> {
21 pub fn new(tcx: TyCtxt<'tcx>, debug: bool) -> Self {
22 Self {
23 tcx,
24 debug,
25 paths: FxHashMap::default(),
26 graphs: FxHashMap::default(),
27 }
28 }
29
30 pub fn analyze(&mut self, def_id: DefId) -> Option<PathTree> {
34 self.analyze_repeat(def_id, 0)
35 }
36
37 pub fn analyze_repeat(&mut self, def_id: DefId, postfix_repeat: usize) -> Option<PathTree> {
40 if let Some(paths) = self.paths.get(&def_id) {
41 return Some(paths.clone());
42 }
43
44 if !self.tcx.is_mir_available(def_id) {
45 return None;
46 }
47
48 let mut graph = PathGraph::new(self.tcx, def_id);
49 graph.find_scc();
50 let mut enumerator = PathEnumerator::new(&graph);
51 let paths = enumerator.enumerate_paths_repeat(postfix_repeat);
52
53 self.graphs.insert(def_id, graph);
54 self.paths.insert(def_id, paths.clone());
55 Some(paths)
56 }
57
58 pub fn get_fn_paths(&self, def_id: DefId) -> Option<PathTree> {
59 self.paths.get(&def_id).cloned()
60 }
61
62 pub fn get_all_paths(&self) -> FxHashMap<DefId, PathTree> {
63 self.paths.clone()
64 }
65
66 pub fn analyze_all(&mut self) {
68 self.analyze_all_repeat(0);
69 }
70
71 pub fn analyze_all_repeat(&mut self, postfix_repeat: usize) {
73 for local_def_id in self.tcx.iter_local_def_id() {
74 if matches!(self.tcx.def_kind(local_def_id), DefKind::Fn) {
75 let def_id = local_def_id.to_def_id();
76 let _ = self.analyze_repeat(def_id, postfix_repeat);
77 }
78 }
79 }
80
81 pub fn run_with_repeat(&mut self, postfix_repeat: usize) {
82 self.analyze_all_repeat(postfix_repeat);
83 }
84}
85
86impl<'tcx> Analysis for PathAnalyzer<'tcx> {
87 fn name(&self) -> &'static str {
88 "Path Analysis"
89 }
90
91 fn run(&mut self) {
92 self.analyze_all();
93 }
94
95 fn reset(&mut self) {
96 self.paths.clear();
97 self.graphs.clear();
98 }
99}