neo_solidity/
callgraph.rs

1//! Call Graph Analysis
2//!
3//! Analyzes function call relationships.
4
5use std::collections::{HashMap, HashSet};
6
7/// Call graph node
8#[derive(Debug, Default)]
9pub struct CallNode {
10    pub callers: HashSet<String>,
11    pub callees: HashSet<String>,
12}
13
14/// Call graph
15#[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}