rapx/analysis/core/dataflow/
debug.rs

1use 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            // only Nop and Const can be marker node and they only have one op
42            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                    // only exists for _a[_b] = (Use) value
59                    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                //label=xxx
75                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            //color=xxx
124            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        //edges
155        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}