1 // Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
11 //! This module provides linkage between rustc::middle::graph and
12 //! libgraphviz traits, specialized to attaching borrowck analysis
13 //! data to rendered labels.
15 pub use self::Variant
::*;
17 pub use rustc
::cfg
::graphviz
::{Node, Edge}
;
18 use rustc
::cfg
::graphviz
as cfg_dot
;
21 use borrowck
::{BorrowckCtxt, LoanPath}
;
23 use rustc
::cfg
::CFGIndex
;
24 use rustc
::middle
::dataflow
::{DataFlowOperator, DataFlowContext, EntryOrExit}
;
28 #[derive(Debug, Copy, Clone)]
36 pub fn short_name(&self) -> &'
static str {
45 pub struct DataflowLabeller
<'a
, 'tcx
: 'a
> {
46 pub inner
: cfg_dot
::LabelledCFG
<'a
, 'tcx
>,
47 pub variants
: Vec
<Variant
>,
48 pub borrowck_ctxt
: &'a BorrowckCtxt
<'a
, 'tcx
>,
49 pub analysis_data
: &'a borrowck
::AnalysisData
<'a
, 'tcx
>,
52 impl<'a
, 'tcx
> DataflowLabeller
<'a
, 'tcx
> {
53 fn dataflow_for(&self, e
: EntryOrExit
, n
: &Node
<'a
>) -> String
{
54 let id
= n
.1.data
.id();
55 debug
!("dataflow_for({:?}, id={}) {:?}", e
, id
, self.variants
);
56 let mut sets
= "".to_string();
57 let mut seen_one
= false;
58 for &variant
in &self.variants
{
59 if seen_one { sets.push_str(" "); }
else { seen_one = true; }
60 sets
.push_str(variant
.short_name());
62 sets
.push_str(&self.dataflow_for_variant(e
, n
, variant
));
67 fn dataflow_for_variant(&self, e
: EntryOrExit
, n
: &Node
, v
: Variant
) -> String
{
70 Loans
=> self.dataflow_loans_for(e
, cfgidx
),
71 Moves
=> self.dataflow_moves_for(e
, cfgidx
),
72 Assigns
=> self.dataflow_assigns_for(e
, cfgidx
),
76 fn build_set
<O
:DataFlowOperator
, F
>(&self,
79 dfcx
: &DataFlowContext
<'a
, 'tcx
, O
>,
80 mut to_lp
: F
) -> String
where
81 F
: FnMut(usize) -> Rc
<LoanPath
<'tcx
>>,
83 let mut saw_some
= false;
84 let mut set
= "{".to_string();
85 dfcx
.each_bit_for_node(e
, cfgidx
, |index
| {
86 let lp
= to_lp(index
);
90 let loan_str
= self.borrowck_ctxt
.loan_path_to_string(&lp
);
91 set
.push_str(&loan_str
[..]);
99 fn dataflow_loans_for(&self, e
: EntryOrExit
, cfgidx
: CFGIndex
) -> String
{
100 let dfcx
= &self.analysis_data
.loans
;
101 let loan_index_to_path
= |loan_index
| {
102 let all_loans
= &self.analysis_data
.all_loans
;
103 let l
: &borrowck
::Loan
= &all_loans
[loan_index
];
106 self.build_set(e
, cfgidx
, dfcx
, loan_index_to_path
)
109 fn dataflow_moves_for(&self, e
: EntryOrExit
, cfgidx
: CFGIndex
) -> String
{
110 let dfcx
= &self.analysis_data
.move_data
.dfcx_moves
;
111 let move_index_to_path
= |move_index
| {
112 let move_data
= &self.analysis_data
.move_data
.move_data
;
113 let moves
= move_data
.moves
.borrow();
114 let the_move
: &borrowck
::move_data
::Move
= &(*moves
)[move_index
];
115 move_data
.path_loan_path(the_move
.path
)
117 self.build_set(e
, cfgidx
, dfcx
, move_index_to_path
)
120 fn dataflow_assigns_for(&self, e
: EntryOrExit
, cfgidx
: CFGIndex
) -> String
{
121 let dfcx
= &self.analysis_data
.move_data
.dfcx_assign
;
122 let assign_index_to_path
= |assign_index
| {
123 let move_data
= &self.analysis_data
.move_data
.move_data
;
124 let assignments
= move_data
.var_assignments
.borrow();
125 let assignment
: &borrowck
::move_data
::Assignment
= &(*assignments
)[assign_index
];
126 move_data
.path_loan_path(assignment
.path
)
128 self.build_set(e
, cfgidx
, dfcx
, assign_index_to_path
)
132 impl<'a
, 'tcx
> dot
::Labeller
<'a
> for DataflowLabeller
<'a
, 'tcx
> {
133 type Node
= Node
<'a
>;
134 type Edge
= Edge
<'a
>;
135 fn graph_id(&'a
self) -> dot
::Id
<'a
> { self.inner.graph_id() }
136 fn node_id(&'a
self, n
: &Node
<'a
>) -> dot
::Id
<'a
> { self.inner.node_id(n) }
137 fn node_label(&'a
self, n
: &Node
<'a
>) -> dot
::LabelText
<'a
> {
138 let prefix
= self.dataflow_for(EntryOrExit
::Entry
, n
);
139 let suffix
= self.dataflow_for(EntryOrExit
::Exit
, n
);
140 let inner_label
= self.inner
.node_label(n
);
142 .prefix_line(dot
::LabelText
::LabelStr(prefix
.into_cow()))
143 .suffix_line(dot
::LabelText
::LabelStr(suffix
.into_cow()))
145 fn edge_label(&'a
self, e
: &Edge
<'a
>) -> dot
::LabelText
<'a
> { self.inner.edge_label(e) }
148 impl<'a
, 'tcx
> dot
::GraphWalk
<'a
> for DataflowLabeller
<'a
, 'tcx
> {
149 type Node
= Node
<'a
>;
150 type Edge
= Edge
<'a
>;
151 fn nodes(&'a
self) -> dot
::Nodes
<'a
, Node
<'a
>> { self.inner.nodes() }
152 fn edges(&'a
self) -> dot
::Edges
<'a
, Edge
<'a
>> { self.inner.edges() }
153 fn source(&'a
self, edge
: &Edge
<'a
>) -> Node
<'a
> { self.inner.source(edge) }
154 fn target(&'a
self, edge
: &Edge
<'a
>) -> Node
<'a
> { self.inner.target(edge) }