rapx/analysis/core/dataflow/
debug.rs1use std::fmt::Write;
2
3use rustc_middle::{mir::Local, ty::TyCtxt};
4
5use crate::analysis::core::dataflow::{graph::*, *};
6
7fn escaped_string(s: String) -> String {
8 s.replace("{", "\\{")
9 .replace("}", "\\}")
10 .replace("<", "\\<")
11 .replace(">", "\\>")
12 .replace("\"", "\\\"")
13}
14
15impl GraphEdge {
16 pub fn to_dot_graph<'tcx>(&self) -> String {
17 let mut attr = String::new();
18 let mut dot = String::new();
19 write!(
20 attr,
21 "label=\"{}\" ",
22 escaped_string(format!("{}_{:?}", self.seq, self.op))
23 )
24 .unwrap();
25 write!(dot, "{:?} -> {:?} [{}]", self.src, self.dst, attr).unwrap();
26 dot
27 }
28}
29
30impl GraphNode {
31 pub fn to_dot_graph<'tcx>(
32 &self,
33 tcx: &TyCtxt<'tcx>,
34 local: Local,
35 color: Option<String>,
36 is_marker: bool,
37 ) -> String {
38 let mut attr = String::new();
39 let mut dot = String::new();
40 if is_marker {
41 assert!(self.ops.len() == 1);
43 match self.ops[0] {
44 NodeOp::Nop => {
45 write!(attr, "label=\"{:?} ", local).unwrap();
46 }
47 NodeOp::Const(ref src_desc, ref src_ty) => {
48 write!(
49 attr,
50 "label=\"<f0> {:?} {} {} ",
51 local,
52 escaped_string(src_desc.clone()),
53 escaped_string(src_ty.clone()),
54 )
55 .unwrap();
56 }
57 NodeOp::Use => {
58 write!(attr, "label=\"{:?} ", local).unwrap();
60 }
61 NodeOp::Aggregate(_) => {
62 write!(attr, "label=\"{:?} ", local).unwrap();
63 }
64 _ => {
65 panic!("Wrong arm! {:?} {:?}", local, self.ops[0]);
66 }
67 }
68 } else {
69 write!(attr, "label=\"<f0> {:?} ", local).unwrap();
70 }
71 let mut seq = 1;
72 self.ops.iter().for_each(|op| {
73 match op {
74 NodeOp::Nop => {}
76 NodeOp::Const(..) => {}
77 NodeOp::Call(def_id) => {
78 let func_name = tcx.def_path_str(def_id);
79 write!(
80 attr,
81 "| <f{}> ({})fn {} ",
82 seq,
83 seq - 1,
84 escaped_string(func_name)
85 )
86 .unwrap();
87 }
88 NodeOp::Aggregate(agg_kind) => match agg_kind {
89 AggKind::Adt(def_id) => {
90 let agg_name = format!("{}::{{..}}", tcx.def_path_str(def_id));
91 write!(
92 attr,
93 "| <f{}> ({})Agg {} ",
94 seq,
95 seq - 1,
96 escaped_string(agg_name)
97 )
98 .unwrap();
99 }
100 AggKind::Closure(def_id) => {
101 let agg_name = tcx.def_path_str(def_id);
102 write!(
103 attr,
104 "| <f{}> ({})Clos {} ",
105 seq,
106 seq - 1,
107 escaped_string(agg_name)
108 )
109 .unwrap();
110 }
111 _ => {
112 write!(attr, "| <f{}> ({}){:?} ", seq, seq - 1, agg_kind).unwrap();
113 }
114 },
115 _ => {
116 write!(attr, "| <f{}> ({}){:?} ", seq, seq - 1, op).unwrap();
117 }
118 };
119 seq += 1;
120 });
121 write!(attr, "\" ").unwrap();
122 match color {
123 None => {}
125 Some(color) => {
126 write!(attr, "color={} ", color).unwrap();
127 }
128 }
129 if is_marker {
130 write!(attr, "style=dashed ").unwrap();
131 }
132 write!(dot, "{:?} [{}]", local, attr).unwrap();
133 dot
134 }
135}
136
137impl Graph {
138 pub fn to_dot_graph<'tcx>(&self, tcx: &TyCtxt<'tcx>) -> String {
139 let mut dot = String::new();
140 let name = tcx.def_path_str(self.def_id);
141
142 writeln!(dot, "digraph \"{}\" {{", &name).unwrap();
143 writeln!(dot, " node [shape=record];").unwrap();
144 for (local, node) in self.nodes.iter_enumerated() {
145 let node_dot = if local <= Local::from_usize(self.argc) {
146 node.to_dot_graph(tcx, local, Some(String::from("red")), false)
147 } else if local < Local::from_usize(self.n_locals) {
148 node.to_dot_graph(tcx, local, None, false)
149 } else {
150 node.to_dot_graph(tcx, local, None, true)
151 };
152 writeln!(dot, " {}", node_dot).unwrap();
153 }
154 for edge in self.edges.iter() {
156 let edge_dot = edge.to_dot_graph();
157 writeln!(dot, " {}", edge_dot).unwrap();
158 }
159 writeln!(dot, "}}").unwrap();
160 dot
161 }
162}