rapx/analysis/core/api_dep/
graph.rs

1mod dep_edge;
2mod dep_node;
3mod lifetime;
4mod ty_wrapper;
5
6use crate::utils::fs::rap_create_file;
7pub use dep_edge::DepEdge;
8pub use dep_node::{desc_str, DepNode};
9use petgraph::dot::{Config, Dot};
10use petgraph::graph::NodeIndex;
11use petgraph::Graph;
12use rustc_middle::ty::TyCtxt;
13use std::collections::HashMap;
14use std::io::Write;
15use std::path::Path;
16
17type InnerGraph<'tcx> = Graph<DepNode<'tcx>, DepEdge>;
18pub struct ApiDepGraph<'tcx> {
19    graph: InnerGraph<'tcx>,
20    node_indices: HashMap<DepNode<'tcx>, NodeIndex>,
21}
22
23pub struct Statistics {
24    pub api_count: usize,
25    pub type_count: usize,
26    pub generic_param_count: usize,
27    pub edge_cnt: usize,
28}
29
30impl<'tcx> ApiDepGraph<'tcx> {
31    pub fn new() -> ApiDepGraph<'tcx> {
32        ApiDepGraph {
33            graph: Graph::new(),
34            node_indices: HashMap::new(),
35        }
36    }
37
38    pub fn inner_graph(&self) -> &InnerGraph<'tcx> {
39        &self.graph
40    }
41
42    pub fn statistics(&self) -> Statistics {
43        let mut api_cnt = 0;
44        let mut ty_cnt = 0;
45        let mut generic_param_cnt = 0;
46        let mut edge_cnt = 0;
47
48        for node in self.graph.node_indices() {
49            match self.graph[node] {
50                DepNode::Api(_) => api_cnt += 1,
51                DepNode::Ty(_) => ty_cnt += 1,
52                DepNode::GenericParamDef(..) => generic_param_cnt += 1,
53            }
54        }
55
56        for edge in self.graph.edge_indices() {
57            edge_cnt += 1;
58        }
59
60        Statistics {
61            api_count: api_cnt,
62            type_count: ty_cnt,
63            generic_param_count: generic_param_cnt,
64            edge_cnt,
65        }
66    }
67
68    pub fn get_node(&mut self, node: DepNode<'tcx>) -> NodeIndex {
69        if let Some(node_index) = self.node_indices.get(&node) {
70            *node_index
71        } else {
72            let node_index = self.graph.add_node(node.clone());
73            self.node_indices.insert(node, node_index);
74            node_index
75        }
76    }
77
78    pub fn add_edge(&mut self, src: NodeIndex, dst: NodeIndex, edge: DepEdge) {
79        self.graph.add_edge(src, dst, edge);
80    }
81
82    pub fn add_edge_once(&mut self, src: NodeIndex, dst: NodeIndex, edge: DepEdge) {
83        if !self.graph.contains_edge(src, dst) {
84            self.graph.add_edge(src, dst, edge);
85        }
86    }
87
88    pub fn dump_to_dot<P: AsRef<Path>>(&self, path: P, tcx: TyCtxt<'tcx>) {
89        let get_edge_attr =
90            |graph: &Graph<DepNode<'tcx>, DepEdge>,
91             edge_ref: petgraph::graph::EdgeReference<DepEdge>| {
92                let color = match edge_ref.weight() {
93                    DepEdge::Arg(_) | DepEdge::Ret => "black",
94                    DepEdge::Fn2Generic => "grey",
95                };
96                format!("label=\"{}\", color = {}", edge_ref.weight(), color)
97            };
98        let get_node_attr = |graph: &Graph<DepNode<'tcx>, DepEdge>,
99                             node_ref: (NodeIndex, &DepNode<'tcx>)| {
100            format!("label={:?}, ", desc_str(node_ref.1.clone(), tcx))
101                + match node_ref.1 {
102                    DepNode::Api(_) => "color = blue",
103                    DepNode::Ty(_) => "color = red",
104                    DepNode::GenericParamDef(..) => "color = green",
105                }
106                + ", shape=box"
107        };
108
109        let dot = Dot::with_attr_getters(
110            &self.graph,
111            &[Config::NodeNoLabel, Config::EdgeNoLabel],
112            &get_edge_attr,
113            &get_node_attr,
114        );
115        let mut file = rap_create_file(path, "can not create dot file");
116        write!(&mut file, "{:?}", dot).expect("fail when writing data to dot file");
117        // println!("{:?}", dot);
118    }
119}