rapx/analysis/core/dataflow/
debug.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
use std::fmt::Write;

use rustc_middle::mir::Local;
use rustc_middle::ty::TyCtxt;

use super::graph::{AggKind, Graph, GraphEdge, GraphNode, NodeOp};

fn escaped_string(s: String) -> String {
    s.replace("{", "\\{")
        .replace("}", "\\}")
        .replace("<", "\\<")
        .replace(">", "\\>")
        .replace("\"", "\\\"")
}

impl GraphEdge {
    pub fn to_dot_graph<'tcx>(&self) -> String {
        let mut attr = String::new();
        let mut dot = String::new();
        write!(
            attr,
            "label=\"{}\" ",
            escaped_string(format!("{}_{:?}", self.seq, self.op))
        )
        .unwrap();
        write!(dot, "{:?} -> {:?} [{}]", self.src, self.dst, attr).unwrap();
        dot
    }
}

impl GraphNode {
    pub fn to_dot_graph<'tcx>(
        &self,
        tcx: &TyCtxt<'tcx>,
        local: Local,
        color: Option<String>,
        is_marker: bool,
    ) -> String {
        let mut attr = String::new();
        let mut dot = String::new();
        if is_marker {
            // only Nop and Const can be marker node and they only have one op
            assert!(self.ops.len() == 1);
            match self.ops[0] {
                NodeOp::Nop => {
                    write!(attr, "label=\"{:?} ", local).unwrap();
                }
                NodeOp::Const(ref src_desc, ref src_ty) => {
                    write!(
                        attr,
                        "label=\"<f0> {:?} {} {} ",
                        local,
                        escaped_string(src_desc.clone()),
                        escaped_string(src_ty.clone()),
                    )
                    .unwrap();
                }
                NodeOp::Use => {
                    // only exists for _a[_b] =(Use) value
                    write!(attr, "label=\"{:?} ", local).unwrap();
                }
                _ => {
                    panic!("Wrong arm!  {:?} {:?}", local, self.ops[0]);
                }
            }
        } else {
            write!(attr, "label=\"<f0> {:?} ", local).unwrap();
        }
        let mut seq = 1;
        self.ops.iter().for_each(|op| {
            match op {
                //label=xxx
                NodeOp::Nop => {}
                NodeOp::Const(..) => {}
                NodeOp::Call(def_id) => {
                    let func_name = tcx.def_path_str(def_id);
                    write!(
                        attr,
                        "| <f{}> ({})fn {} ",
                        seq,
                        seq - 1,
                        escaped_string(func_name)
                    )
                    .unwrap();
                }
                NodeOp::Aggregate(agg_kind) => match agg_kind {
                    AggKind::Adt(def_id) => {
                        let agg_name = format!("{}::{{..}}", tcx.def_path_str(def_id));
                        write!(
                            attr,
                            "| <f{}> ({})Agg {} ",
                            seq,
                            seq - 1,
                            escaped_string(agg_name)
                        )
                        .unwrap();
                    }
                    AggKind::Closure(def_id) => {
                        let agg_name = tcx.def_path_str(def_id);
                        write!(
                            attr,
                            "| <f{}> ({})Clos {} ",
                            seq,
                            seq - 1,
                            escaped_string(agg_name)
                        )
                        .unwrap();
                    }
                    _ => {
                        write!(attr, "| <f{}> ({}){:?} ", seq, seq - 1, agg_kind).unwrap();
                    }
                },
                _ => {
                    write!(attr, "| <f{}> ({}){:?} ", seq, seq - 1, op).unwrap();
                }
            };
            seq += 1;
        });
        write!(attr, "\" ").unwrap();
        match color {
            //color=xxx
            None => {}
            Some(color) => {
                write!(attr, "color={} ", color).unwrap();
            }
        }
        if is_marker {
            write!(attr, "style=dashed ").unwrap();
        }
        write!(dot, "{:?} [{}]", local, attr).unwrap();
        dot
    }
}

impl Graph {
    pub fn to_dot_graph<'tcx>(&self, tcx: &TyCtxt<'tcx>) -> String {
        let mut dot = String::new();
        let name = tcx.def_path_str(self.def_id);

        writeln!(dot, "digraph \"{}\" {{", &name).unwrap();
        writeln!(dot, "    node [shape=record];").unwrap();
        for (local, node) in self.nodes.iter_enumerated() {
            let node_dot = if local <= Local::from_usize(self.argc) {
                node.to_dot_graph(tcx, local, Some(String::from("red")), false)
            } else if local < Local::from_usize(self.n_locals) {
                node.to_dot_graph(tcx, local, None, false)
            } else {
                node.to_dot_graph(tcx, local, None, true)
            };
            writeln!(dot, "    {}", node_dot).unwrap();
        }
        //edges
        for edge in self.edges.iter() {
            let edge_dot = edge.to_dot_graph();
            writeln!(dot, "    {}", edge_dot).unwrap();
        }
        writeln!(dot, "}}").unwrap();
        dot
    }
}