1 /// This module provides linkage between rustc::middle::graph and
2 /// libgraphviz traits.
4 // For clarity, rename the graphviz crate locally to dot.
11 pub type Node
<'a
> = (cfg
::CFGIndex
, &'a cfg
::CFGNode
);
12 pub type Edge
<'a
> = &'a cfg
::CFGEdge
;
14 pub struct LabelledCFG
<'a
, 'tcx
: 'a
> {
15 pub tcx
: TyCtxt
<'a
, 'tcx
, 'tcx
>,
16 pub cfg
: &'a cfg
::CFG
,
18 /// `labelled_edges` controls whether we emit labels on the edges
19 pub labelled_edges
: bool
,
22 impl<'a
, 'tcx
> LabelledCFG
<'a
, 'tcx
> {
23 fn local_id_to_string(&self, local_id
: hir
::ItemLocalId
) -> String
{
24 assert
!(self.cfg
.owner_def_id
.is_local());
25 let node_id
= self.tcx
.hir().hir_to_node_id(hir
::HirId
{
26 owner
: self.tcx
.hir().def_index_to_hir_id(self.cfg
.owner_def_id
.index
).owner
,
29 let s
= self.tcx
.hir().node_to_string(node_id
);
31 // Replacing newlines with \\l causes each line to be left-aligned,
32 // improving presentation of (long) pretty-printed expressions.
34 let mut s
= s
.replace("\n", "\\l");
35 // Apparently left-alignment applies to the line that precedes
36 // \l, not the line that follows; so, add \l at end of string
37 // if not already present, ensuring last line gets left-aligned
39 let mut last_two
: Vec
<_
> =
40 s
.chars().rev().take(2).collect();
42 if last_two
!= ['
\\'
, 'l'
] {
52 impl<'a
, 'hir
> dot
::Labeller
<'a
> for LabelledCFG
<'a
, 'hir
> {
55 fn graph_id(&'a
self) -> dot
::Id
<'a
> { dot::Id::new(&self.name[..]).unwrap() }
57 fn node_id(&'a
self, &(i
,_
): &Node
<'a
>) -> dot
::Id
<'a
> {
58 dot
::Id
::new(format
!("N{}", i
.node_id())).unwrap()
61 fn node_label(&'a
self, &(i
, n
): &Node
<'a
>) -> dot
::LabelText
<'a
> {
62 if i
== self.cfg
.entry
{
63 dot
::LabelText
::LabelStr("entry".into())
64 } else if i
== self.cfg
.exit
{
65 dot
::LabelText
::LabelStr("exit".into())
66 } else if n
.data
.id() == hir
::DUMMY_ITEM_LOCAL_ID
{
67 dot
::LabelText
::LabelStr("(dummy_node)".into())
69 let s
= self.local_id_to_string(n
.data
.id());
70 dot
::LabelText
::EscStr(s
.into())
74 fn edge_label(&self, e
: &Edge
<'a
>) -> dot
::LabelText
<'a
> {
75 let mut label
= String
::new();
76 if !self.labelled_edges
{
77 return dot
::LabelText
::EscStr(label
.into());
79 let mut put_one
= false;
80 for (i
, &id
) in e
.data
.exiting_scopes
.iter().enumerate() {
82 label
.push_str(",\\l");
86 let s
= self.local_id_to_string(id
);
87 label
.push_str(&format
!("exiting scope_{} {}",
91 dot
::LabelText
::EscStr(label
.into())
95 impl<'a
> dot
::GraphWalk
<'a
> for &'a cfg
::CFG
{
98 fn nodes(&'a
self) -> dot
::Nodes
<'a
, Node
<'a
>> {
99 let v
: Vec
<_
> = self.graph
.enumerated_nodes().collect();
102 fn edges(&'a
self) -> dot
::Edges
<'a
, Edge
<'a
>> {
103 self.graph
.all_edges().iter().collect()
105 fn source(&'a
self, edge
: &Edge
<'a
>) -> Node
<'a
> {
106 let i
= edge
.source();
107 (i
, self.graph
.node(i
))
109 fn target(&'a
self, edge
: &Edge
<'a
>) -> Node
<'a
> {
110 let i
= edge
.target();
111 (i
, self.graph
.node(i
))
115 impl<'a
, 'hir
> dot
::GraphWalk
<'a
> for LabelledCFG
<'a
, 'hir
>
117 type Node
= Node
<'a
>;
118 type Edge
= Edge
<'a
>;
119 fn nodes(&'a
self) -> dot
::Nodes
<'a
, Node
<'a
>> { self.cfg.nodes() }
120 fn edges(&'a
self) -> dot
::Edges
<'a
, Edge
<'a
>> { self.cfg.edges() }
121 fn source(&'a
self, edge
: &Edge
<'a
>) -> Node
<'a
> { self.cfg.source(edge) }
122 fn target(&'a
self, edge
: &Edge
<'a
>) -> Node
<'a
> { self.cfg.target(edge) }