]> git.lizzy.rs Git - rust.git/blob - src/librustc_ast_borrowck/cfg/graphviz.rs
Move the HIR cfg to `rustc_ast_borrowck`
[rust.git] / src / librustc_ast_borrowck / cfg / graphviz.rs
1 /// This module provides linkage between rustc::middle::graph and
2 /// libgraphviz traits.
3
4 use crate::cfg;
5 use rustc::hir;
6 use rustc::ty::TyCtxt;
7
8 pub(crate) type Node<'a> = (cfg::CFGIndex, &'a cfg::CFGNode);
9 pub(crate) type Edge<'a> = &'a cfg::CFGEdge;
10
11 pub struct LabelledCFG<'a, 'tcx> {
12     pub tcx: TyCtxt<'tcx>,
13     pub cfg: &'a cfg::CFG,
14     pub name: String,
15     /// `labelled_edges` controls whether we emit labels on the edges
16     pub labelled_edges: bool,
17 }
18
19 impl<'a, 'tcx> LabelledCFG<'a, 'tcx> {
20     fn local_id_to_string(&self, local_id: hir::ItemLocalId) -> String {
21         assert!(self.cfg.owner_def_id.is_local());
22         let hir_id = hir::HirId {
23             owner: self.tcx.hir().def_index_to_hir_id(self.cfg.owner_def_id.index).owner,
24             local_id
25         };
26         let s = self.tcx.hir().node_to_string(hir_id);
27
28         // Replacing newlines with \\l causes each line to be left-aligned,
29         // improving presentation of (long) pretty-printed expressions.
30         if s.contains("\n") {
31             let mut s = s.replace("\n", "\\l");
32             // Apparently left-alignment applies to the line that precedes
33             // \l, not the line that follows; so, add \l at end of string
34             // if not already present, ensuring last line gets left-aligned
35             // as well.
36             let mut last_two: Vec<_> =
37                 s.chars().rev().take(2).collect();
38             last_two.reverse();
39             if last_two != ['\\', 'l'] {
40                 s.push_str("\\l");
41             }
42             s
43         } else {
44             s
45         }
46     }
47 }
48
49 impl<'a, 'hir> dot::Labeller<'a> for LabelledCFG<'a, 'hir> {
50     type Node = Node<'a>;
51     type Edge = Edge<'a>;
52     fn graph_id(&'a self) -> dot::Id<'a> { dot::Id::new(&self.name[..]).unwrap() }
53
54     fn node_id(&'a self, &(i,_): &Node<'a>) -> dot::Id<'a> {
55         dot::Id::new(format!("N{}", i.node_id())).unwrap()
56     }
57
58     fn node_label(&'a self, &(i, n): &Node<'a>) -> dot::LabelText<'a> {
59         if i == self.cfg.entry {
60             dot::LabelText::LabelStr("entry".into())
61         } else if i == self.cfg.exit {
62             dot::LabelText::LabelStr("exit".into())
63         } else if n.data.id() == hir::DUMMY_ITEM_LOCAL_ID {
64             dot::LabelText::LabelStr("(dummy_node)".into())
65         } else {
66             let s = self.local_id_to_string(n.data.id());
67             dot::LabelText::EscStr(s.into())
68         }
69     }
70
71     fn edge_label(&self, e: &Edge<'a>) -> dot::LabelText<'a> {
72         let mut label = String::new();
73         if !self.labelled_edges {
74             return dot::LabelText::EscStr(label.into());
75         }
76         let mut put_one = false;
77         for (i, &id) in e.data.exiting_scopes.iter().enumerate() {
78             if put_one {
79                 label.push_str(",\\l");
80             } else {
81                 put_one = true;
82             }
83             let s = self.local_id_to_string(id);
84             label.push_str(&format!("exiting scope_{} {}",
85                                    i,
86                                    &s[..]));
87         }
88         dot::LabelText::EscStr(label.into())
89     }
90 }
91
92 impl<'a> dot::GraphWalk<'a> for &'a cfg::CFG {
93     type Node = Node<'a>;
94     type Edge = Edge<'a>;
95     fn nodes(&'a self) -> dot::Nodes<'a, Node<'a>> {
96         let v: Vec<_> = self.graph.enumerated_nodes().collect();
97         v.into()
98     }
99     fn edges(&'a self) -> dot::Edges<'a, Edge<'a>> {
100         self.graph.all_edges().iter().collect()
101     }
102     fn source(&'a self, edge: &Edge<'a>) -> Node<'a> {
103         let i = edge.source();
104         (i, self.graph.node(i))
105     }
106     fn target(&'a self, edge: &Edge<'a>) -> Node<'a> {
107         let i = edge.target();
108         (i, self.graph.node(i))
109     }
110 }
111
112 impl<'a, 'hir> dot::GraphWalk<'a> for LabelledCFG<'a, 'hir>
113 {
114     type Node = Node<'a>;
115     type Edge = Edge<'a>;
116     fn nodes(&'a self) -> dot::Nodes<'a, Node<'a>> { self.cfg.nodes() }
117     fn edges(&'a self) -> dot::Edges<'a, Edge<'a>> { self.cfg.edges() }
118     fn source(&'a self, edge: &Edge<'a>) -> Node<'a> { self.cfg.source(edge) }
119     fn target(&'a self, edge: &Edge<'a>) -> Node<'a> { self.cfg.target(edge) }
120 }