rapx/analysis/core/api_dep/
graph.rs1mod 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 }
119}