Skip to main content

rapx/analysis/alias/default/
graph.rs

1use super::MopFnAliasPairs;
2use crate::{
3    analysis::path::{
4        PathTree,
5        graph::{PathEnumerator, PathGraph},
6    },
7    analysis::points_to::graph::PtsGraph,
8    compat::FxHashMap,
9    graphs::cfg::CfgBlock,
10    utils::source::get_fn_name,
11};
12use rustc_middle::mir::Terminator;
13use rustc_middle::ty::TyCtxt;
14use rustc_span::{Span, def_id::DefId};
15use std::fmt;
16
17use super::value::Value;
18
19pub struct AliasGraph<'tcx> {
20    pub path_graph: PathGraph<'tcx>,
21    pub visit_times: usize,
22
23    /// Per-slot type info — kept for SafeDrop compatibility.
24    /// Indexed by value index = PtsGraph slot index.
25    pub values: Vec<Value>,
26
27    /// New unified PtsGraph for both MoP alias and SafeDrop.
28    pub pts_graph: PtsGraph,
29
30    /// Tracks Move operand destinations → source value indices.
31    /// Used by SafeDrop to propagate drop info through move chains.
32    pub owner_transfers: FxHashMap<usize, usize>,
33
34    pub ret_alias: MopFnAliasPairs,
35    pub arg_size: usize,
36    pub span: Span,
37}
38
39impl<'tcx> AliasGraph<'tcx> {
40    pub fn new(tcx: TyCtxt<'tcx>, def_id: DefId) -> AliasGraph<'tcx> {
41        let fn_name = get_fn_name(tcx, def_id);
42        rap_debug!("New an AliasGraph for: {:?}", fn_name);
43        let path_graph = PathGraph::new(tcx, def_id);
44        Self::from_path_graph(tcx, def_id, path_graph)
45    }
46
47    pub fn from_path_graph(
48        tcx: TyCtxt<'tcx>,
49        def_id: DefId,
50        path_graph: PathGraph<'tcx>,
51    ) -> AliasGraph<'tcx> {
52        let body = tcx.optimized_mir(def_id);
53        let locals = &body.local_decls;
54        let arg_size = body.arg_count;
55        let mut values = Vec::<Value>::new();
56        for local in locals.indices() {
57            let node = Value::new(local.as_usize(), local.as_usize());
58            values.push(node);
59        }
60        AliasGraph {
61            path_graph,
62            visit_times: 0,
63            values,
64            pts_graph: PtsGraph::new(),
65            owner_transfers: FxHashMap::default(),
66            ret_alias: MopFnAliasPairs::new(arg_size),
67            arg_size,
68            span: body.span,
69        }
70    }
71
72    pub fn def_id(&self) -> DefId {
73        self.path_graph.def_id()
74    }
75
76    pub fn tcx(&self) -> TyCtxt<'tcx> {
77        self.path_graph.tcx()
78    }
79
80    pub fn arg_size(&self) -> usize {
81        self.arg_size
82    }
83
84    pub fn span(&self) -> Span {
85        self.span
86    }
87
88    pub fn cfg_block(&self, index: usize) -> &CfgBlock {
89        self.path_graph.cfg_block(index)
90    }
91
92    pub fn terminator(&self, index: usize) -> Option<&Terminator<'tcx>> {
93        self.path_graph.terminator(index)
94    }
95
96    pub fn enumerate_paths(&self) -> PathTree {
97        let mut enumerator = PathEnumerator::new(&self.path_graph);
98        enumerator.enumerate_paths()
99    }
100
101    pub fn visit_times(&self) -> usize {
102        self.visit_times
103    }
104
105    pub fn increment_visit_times(&mut self) -> usize {
106        self.visit_times += 1;
107        self.visit_times
108    }
109
110    /// Drops the move edges into and out of a value that is being reassigned.
111    pub fn clear_owner_transfers(&mut self, value_idx: usize) {
112        self.owner_transfers
113            .retain(|&dest, &mut src| dest != value_idx && src != value_idx);
114    }
115
116    // ── Index translation: value index → PtsGraph slot index ──
117
118    pub fn value_to_slot_idx(&self, value_idx: usize) -> Option<usize> {
119        self.values.get(value_idx).and_then(|v| v.slot_idx)
120    }
121
122    pub fn get_alias_set(&self, e: usize) -> Option<Vec<usize>> {
123        let e_slot = self.value_to_slot_idx(e)?;
124        let mut result = vec![e];
125        for i in 0..self.values.len() {
126            if i == e {
127                continue;
128            }
129            if let Some(i_slot) = self.value_to_slot_idx(i) {
130                if self.pts_graph.may_alias(e_slot, i_slot) {
131                    result.push(i);
132                }
133            }
134        }
135        if result.len() > 1 { Some(result) } else { None }
136    }
137
138    // ── Value type queries (delegate to PtsGraph) ──
139
140    pub fn value_may_drop(&self, value_idx: usize) -> bool {
141        self.value_to_slot_idx(value_idx)
142            .map(|s| self.pts_graph.may_drop(s))
143            .unwrap_or(false)
144    }
145
146    pub fn value_is_ptr(&self, value_idx: usize) -> bool {
147        self.value_to_slot_idx(value_idx)
148            .map(|si| self.pts_graph.slot_is_ptr(si))
149            .unwrap_or(false)
150    }
151}
152
153impl<'tcx> std::fmt::Display for AliasGraph<'tcx> {
154    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
155        writeln!(f, "AliasGraph {{")?;
156        writeln!(f, "  def_id: {:?}", self.def_id())?;
157        writeln!(f, "  values: {:?}", self.values)?;
158        writeln!(f, "  cfg_blocks: {:?}", self.path_graph.cfg.blocks)?;
159        writeln!(f, "  disc_info: {:?}", self.path_graph.disc_info)?;
160        write!(f, "}}")
161    }
162}