1use serde::{Deserialize, Serialize};
10
11use crate::cfg::types::{BlockId, CFGInfo, EdgeType};
12use crate::dfg::types::DFGInfo;
13
14#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
26pub struct ControlDependence {
27 pub condition_line: usize,
29 pub dependent_line: usize,
31 pub branch_type: BranchType,
33}
34
35#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
37pub enum BranchType {
38 True,
40 False,
42 Loop,
44 Exception,
46 Unconditional,
48}
49
50impl From<EdgeType> for BranchType {
51 fn from(edge_type: EdgeType) -> Self {
52 match edge_type {
53 EdgeType::True => BranchType::True,
54 EdgeType::False | EdgeType::Else => BranchType::False,
55 EdgeType::BackEdge | EdgeType::Loop | EdgeType::Iterate | EdgeType::Next => {
56 BranchType::Loop
57 }
58 EdgeType::Exception | EdgeType::ExceptionGroup => BranchType::Exception,
59 _ => BranchType::Unconditional,
60 }
61 }
62}
63
64#[derive(Debug, Clone, Serialize, Deserialize)]
71pub struct PDGInfo {
72 pub function_name: String,
74
75 pub cfg: CFGInfo,
77
78 pub dfg: DFGInfo,
80
81 pub control_deps: Vec<ControlDependence>,
89}
90
91impl PDGInfo {
92 pub fn new(cfg: CFGInfo, dfg: DFGInfo, control_deps: Vec<ControlDependence>) -> Self {
94 let function_name = cfg.function_name.clone();
95 Self {
96 function_name,
97 cfg,
98 dfg,
99 control_deps,
100 }
101 }
102
103 pub fn control_deps_for(&self, line: usize) -> Vec<usize> {
107 self.control_deps
108 .iter()
109 .filter(|dep| dep.dependent_line == line)
110 .map(|dep| dep.condition_line)
111 .collect()
112 }
113
114 pub fn lines_controlled_by(&self, condition_line: usize) -> Vec<usize> {
118 self.control_deps
119 .iter()
120 .filter(|dep| dep.condition_line == condition_line)
121 .map(|dep| dep.dependent_line)
122 .collect()
123 }
124
125 pub fn is_control_dependent(&self, line_a: usize, line_b: usize) -> bool {
127 self.control_deps
128 .iter()
129 .any(|dep| dep.dependent_line == line_a && dep.condition_line == line_b)
130 }
131
132 pub fn control_dep_count(&self) -> usize {
134 self.control_deps.len()
135 }
136
137 pub fn data_edge_count(&self) -> usize {
139 self.dfg.edges.len()
140 }
141
142 pub fn variables(&self) -> Vec<&str> {
144 self.dfg.variables()
145 }
146
147 pub fn block_for_line(&self, line: usize) -> Option<BlockId> {
149 self.cfg.block_for_line(line)
150 }
151
152 pub fn to_dict(&self) -> serde_json::Value {
154 serde_json::json!({
155 "function_name": self.function_name,
156 "control_deps": self.control_deps.len(),
157 "data_edges": self.dfg.edges.len(),
158 "cfg_blocks": self.cfg.blocks.len(),
159 "cfg_edges": self.cfg.edges.len(),
160 })
161 }
162}
163
164#[cfg(test)]
165mod tests {
166 use super::*;
167
168 fn create_test_control_dep() -> ControlDependence {
169 ControlDependence {
170 condition_line: 2,
171 dependent_line: 3,
172 branch_type: BranchType::True,
173 }
174 }
175
176 #[test]
177 fn test_branch_type_from_edge_type() {
178 assert_eq!(BranchType::from(EdgeType::True), BranchType::True);
179 assert_eq!(BranchType::from(EdgeType::False), BranchType::False);
180 assert_eq!(BranchType::from(EdgeType::Else), BranchType::False);
181 assert_eq!(BranchType::from(EdgeType::BackEdge), BranchType::Loop);
182 assert_eq!(BranchType::from(EdgeType::Loop), BranchType::Loop);
183 assert_eq!(BranchType::from(EdgeType::Exception), BranchType::Exception);
184 assert_eq!(
185 BranchType::from(EdgeType::Unconditional),
186 BranchType::Unconditional
187 );
188 }
189
190 #[test]
191 fn test_control_dependence_equality() {
192 let dep1 = create_test_control_dep();
193 let dep2 = create_test_control_dep();
194 assert_eq!(dep1, dep2);
195
196 let dep3 = ControlDependence {
197 condition_line: 2,
198 dependent_line: 4, branch_type: BranchType::True,
200 };
201 assert_ne!(dep1, dep3);
202 }
203}