]>
Commit | Line | Data |
---|---|---|
1a4d82fc JJ |
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. | |
4 | // | |
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. | |
10 | ||
11 | //! This module provides linkage between rustc::middle::graph and | |
12 | //! libgraphviz traits, specialized to attaching borrowck analysis | |
13 | //! data to rendered labels. | |
14 | ||
15 | pub use self::Variant::*; | |
16 | ||
54a0048b SL |
17 | pub use rustc::cfg::graphviz::{Node, Edge}; |
18 | use rustc::cfg::graphviz as cfg_dot; | |
1a4d82fc JJ |
19 | |
20 | use borrowck; | |
21 | use borrowck::{BorrowckCtxt, LoanPath}; | |
22 | use dot; | |
54a0048b | 23 | use rustc::cfg::CFGIndex; |
1a4d82fc | 24 | use rustc::middle::dataflow::{DataFlowOperator, DataFlowContext, EntryOrExit}; |
1a4d82fc | 25 | use std::rc::Rc; |
9cc50fc6 | 26 | use dot::IntoCow; |
1a4d82fc | 27 | |
c34b1796 | 28 | #[derive(Debug, Copy, Clone)] |
1a4d82fc JJ |
29 | pub enum Variant { |
30 | Loans, | |
31 | Moves, | |
32 | Assigns, | |
33 | } | |
34 | ||
35 | impl Variant { | |
36 | pub fn short_name(&self) -> &'static str { | |
37 | match *self { | |
38 | Loans => "loans", | |
39 | Moves => "moves", | |
40 | Assigns => "assigns", | |
41 | } | |
42 | } | |
43 | } | |
44 | ||
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>, | |
50 | } | |
51 | ||
52 | impl<'a, 'tcx> DataflowLabeller<'a, 'tcx> { | |
53 | fn dataflow_for(&self, e: EntryOrExit, n: &Node<'a>) -> String { | |
c34b1796 | 54 | let id = n.1.data.id(); |
1a4d82fc JJ |
55 | debug!("dataflow_for({:?}, id={}) {:?}", e, id, self.variants); |
56 | let mut sets = "".to_string(); | |
57 | let mut seen_one = false; | |
85aaf69f | 58 | for &variant in &self.variants { |
1a4d82fc JJ |
59 | if seen_one { sets.push_str(" "); } else { seen_one = true; } |
60 | sets.push_str(variant.short_name()); | |
61 | sets.push_str(": "); | |
c34b1796 | 62 | sets.push_str(&self.dataflow_for_variant(e, n, variant)); |
1a4d82fc JJ |
63 | } |
64 | sets | |
65 | } | |
66 | ||
67 | fn dataflow_for_variant(&self, e: EntryOrExit, n: &Node, v: Variant) -> String { | |
68 | let cfgidx = n.0; | |
69 | match v { | |
70 | Loans => self.dataflow_loans_for(e, cfgidx), | |
71 | Moves => self.dataflow_moves_for(e, cfgidx), | |
72 | Assigns => self.dataflow_assigns_for(e, cfgidx), | |
73 | } | |
74 | } | |
75 | ||
76 | fn build_set<O:DataFlowOperator, F>(&self, | |
77 | e: EntryOrExit, | |
78 | cfgidx: CFGIndex, | |
79 | dfcx: &DataFlowContext<'a, 'tcx, O>, | |
80 | mut to_lp: F) -> String where | |
c34b1796 | 81 | F: FnMut(usize) -> Rc<LoanPath<'tcx>>, |
1a4d82fc JJ |
82 | { |
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); | |
87 | if saw_some { | |
88 | set.push_str(", "); | |
89 | } | |
7453a54e | 90 | let loan_str = self.borrowck_ctxt.loan_path_to_string(&lp); |
85aaf69f | 91 | set.push_str(&loan_str[..]); |
1a4d82fc JJ |
92 | saw_some = true; |
93 | true | |
94 | }); | |
95 | set.push_str("}"); | |
96 | set | |
97 | } | |
98 | ||
99 | fn dataflow_loans_for(&self, e: EntryOrExit, cfgidx: CFGIndex) -> String { | |
100 | let dfcx = &self.analysis_data.loans; | |
85aaf69f | 101 | let loan_index_to_path = |loan_index| { |
1a4d82fc JJ |
102 | let all_loans = &self.analysis_data.all_loans; |
103 | let l: &borrowck::Loan = &all_loans[loan_index]; | |
104 | l.loan_path() | |
105 | }; | |
106 | self.build_set(e, cfgidx, dfcx, loan_index_to_path) | |
107 | } | |
108 | ||
109 | fn dataflow_moves_for(&self, e: EntryOrExit, cfgidx: CFGIndex) -> String { | |
110 | let dfcx = &self.analysis_data.move_data.dfcx_moves; | |
85aaf69f | 111 | let move_index_to_path = |move_index| { |
1a4d82fc JJ |
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) | |
116 | }; | |
117 | self.build_set(e, cfgidx, dfcx, move_index_to_path) | |
118 | } | |
119 | ||
120 | fn dataflow_assigns_for(&self, e: EntryOrExit, cfgidx: CFGIndex) -> String { | |
121 | let dfcx = &self.analysis_data.move_data.dfcx_assign; | |
85aaf69f | 122 | let assign_index_to_path = |assign_index| { |
1a4d82fc JJ |
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) | |
127 | }; | |
128 | self.build_set(e, cfgidx, dfcx, assign_index_to_path) | |
129 | } | |
130 | } | |
131 | ||
54a0048b SL |
132 | impl<'a, 'tcx> dot::Labeller<'a> for DataflowLabeller<'a, 'tcx> { |
133 | type Node = Node<'a>; | |
134 | type Edge = Edge<'a>; | |
1a4d82fc JJ |
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> { | |
92a42be0 SL |
138 | let prefix = self.dataflow_for(EntryOrExit::Entry, n); |
139 | let suffix = self.dataflow_for(EntryOrExit::Exit, n); | |
1a4d82fc JJ |
140 | let inner_label = self.inner.node_label(n); |
141 | inner_label | |
142 | .prefix_line(dot::LabelText::LabelStr(prefix.into_cow())) | |
143 | .suffix_line(dot::LabelText::LabelStr(suffix.into_cow())) | |
144 | } | |
145 | fn edge_label(&'a self, e: &Edge<'a>) -> dot::LabelText<'a> { self.inner.edge_label(e) } | |
146 | } | |
147 | ||
54a0048b SL |
148 | impl<'a, 'tcx> dot::GraphWalk<'a> for DataflowLabeller<'a, 'tcx> { |
149 | type Node = Node<'a>; | |
150 | type Edge = Edge<'a>; | |
1a4d82fc JJ |
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) } | |
155 | } |