neo_solidity/
callgraph.rs1use std::collections::{HashMap, HashSet};
6
7#[derive(Debug, Default)]
9pub struct CallNode {
10 pub callers: HashSet<String>,
11 pub callees: HashSet<String>,
12}
13
14#[derive(Default)]
16pub struct CallGraph {
17 nodes: HashMap<String, CallNode>,
18}
19
20impl CallGraph {
21 pub fn new() -> Self {
22 Self::default()
23 }
24
25 pub fn add_call(&mut self, caller: &str, callee: &str) {
26 self.nodes
27 .entry(caller.to_string())
28 .or_default()
29 .callees
30 .insert(callee.to_string());
31 self.nodes
32 .entry(callee.to_string())
33 .or_default()
34 .callers
35 .insert(caller.to_string());
36 }
37
38 pub fn is_recursive(&self, func: &str) -> bool {
39 self.reachable(func, func, &mut HashSet::new())
40 }
41
42 fn reachable(&self, from: &str, to: &str, visited: &mut HashSet<String>) -> bool {
43 if !visited.insert(from.to_string()) {
44 return false;
45 }
46 if let Some(node) = self.nodes.get(from) {
47 if node.callees.contains(to) {
48 return true;
49 }
50 for callee in &node.callees {
51 if self.reachable(callee, to, visited) {
52 return true;
53 }
54 }
55 }
56 false
57 }
58}