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