rapx/analysis/dataflow/
debug.rs

1use 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}