]> git.lizzy.rs Git - rust.git/blob - src/librustc_borrowck/graphviz.rs
Rollup merge of #57132 - daxpedda:master, r=steveklabnik
[rust.git] / src / librustc_borrowck / graphviz.rs
1 //! This module provides linkage between rustc::middle::graph and
2 //! libgraphviz traits, specialized to attaching borrowck analysis
3 //! data to rendered labels.
4
5 pub use self::Variant::*;
6
7 pub use rustc::cfg::graphviz::{Node, Edge};
8 use rustc::cfg::graphviz as cfg_dot;
9
10 use borrowck;
11 use borrowck::{BorrowckCtxt, LoanPath};
12 use dot;
13 use rustc::cfg::CFGIndex;
14 use dataflow::{DataFlowOperator, DataFlowContext, EntryOrExit};
15 use std::rc::Rc;
16
17 #[derive(Debug, Copy, Clone)]
18 pub enum Variant {
19     Loans,
20     Moves,
21     Assigns,
22 }
23
24 impl Variant {
25     pub fn short_name(&self) -> &'static str {
26         match *self {
27             Loans   => "loans",
28             Moves   => "moves",
29             Assigns => "assigns",
30         }
31     }
32 }
33
34 pub struct DataflowLabeller<'a, 'tcx: 'a> {
35     pub inner: cfg_dot::LabelledCFG<'a, 'tcx>,
36     pub variants: Vec<Variant>,
37     pub borrowck_ctxt: &'a BorrowckCtxt<'a, 'tcx>,
38     pub analysis_data: &'a borrowck::AnalysisData<'a, 'tcx>,
39 }
40
41 impl<'a, 'tcx> DataflowLabeller<'a, 'tcx> {
42     fn dataflow_for(&self, e: EntryOrExit, n: &Node<'a>) -> String {
43         let id = n.1.data.id();
44         debug!("dataflow_for({:?}, id={:?}) {:?}", e, id, self.variants);
45         let mut sets = String::new();
46         let mut seen_one = false;
47         for &variant in &self.variants {
48             if seen_one { sets.push_str(" "); } else { seen_one = true; }
49             sets.push_str(variant.short_name());
50             sets.push_str(": ");
51             sets.push_str(&self.dataflow_for_variant(e, n, variant));
52         }
53         sets
54     }
55
56     fn dataflow_for_variant(&self, e: EntryOrExit, n: &Node, v: Variant) -> String {
57         let cfgidx = n.0;
58         match v {
59             Loans   => self.dataflow_loans_for(e, cfgidx),
60             Moves   => self.dataflow_moves_for(e, cfgidx),
61             Assigns => self.dataflow_assigns_for(e, cfgidx),
62         }
63     }
64
65     fn build_set<O:DataFlowOperator, F>(&self,
66                                         e: EntryOrExit,
67                                         cfgidx: CFGIndex,
68                                         dfcx: &DataFlowContext<'a, 'tcx, O>,
69                                         mut to_lp: F) -> String where
70         F: FnMut(usize) -> Rc<LoanPath<'tcx>>,
71     {
72         let mut saw_some = false;
73         let mut set = "{".to_string();
74         dfcx.each_bit_for_node(e, cfgidx, |index| {
75             let lp = to_lp(index);
76             if saw_some {
77                 set.push_str(", ");
78             }
79             let loan_str = self.borrowck_ctxt.loan_path_to_string(&lp);
80             set.push_str(&loan_str);
81             saw_some = true;
82             true
83         });
84         set.push_str("}");
85         set
86     }
87
88     fn dataflow_loans_for(&self, e: EntryOrExit, cfgidx: CFGIndex) -> String {
89         let dfcx = &self.analysis_data.loans;
90         let loan_index_to_path = |loan_index| {
91             let all_loans = &self.analysis_data.all_loans;
92             let l: &borrowck::Loan = &all_loans[loan_index];
93             l.loan_path()
94         };
95         self.build_set(e, cfgidx, dfcx, loan_index_to_path)
96     }
97
98     fn dataflow_moves_for(&self, e: EntryOrExit, cfgidx: CFGIndex) -> String {
99         let dfcx = &self.analysis_data.move_data.dfcx_moves;
100         let move_index_to_path = |move_index| {
101             let move_data = &self.analysis_data.move_data.move_data;
102             let moves = move_data.moves.borrow();
103             let the_move: &borrowck::move_data::Move = &(*moves)[move_index];
104             move_data.path_loan_path(the_move.path)
105         };
106         self.build_set(e, cfgidx, dfcx, move_index_to_path)
107     }
108
109     fn dataflow_assigns_for(&self, e: EntryOrExit, cfgidx: CFGIndex) -> String {
110         let dfcx = &self.analysis_data.move_data.dfcx_assign;
111         let assign_index_to_path = |assign_index| {
112             let move_data = &self.analysis_data.move_data.move_data;
113             let assignments = move_data.var_assignments.borrow();
114             let assignment: &borrowck::move_data::Assignment = &(*assignments)[assign_index];
115             move_data.path_loan_path(assignment.path)
116         };
117         self.build_set(e, cfgidx, dfcx, assign_index_to_path)
118     }
119 }
120
121 impl<'a, 'tcx> dot::Labeller<'a> for DataflowLabeller<'a, 'tcx> {
122     type Node = Node<'a>;
123     type Edge = Edge<'a>;
124     fn graph_id(&'a self) -> dot::Id<'a> { self.inner.graph_id() }
125     fn node_id(&'a self, n: &Node<'a>) -> dot::Id<'a> { self.inner.node_id(n) }
126     fn node_label(&'a self, n: &Node<'a>) -> dot::LabelText<'a> {
127         let prefix = self.dataflow_for(EntryOrExit::Entry, n);
128         let suffix = self.dataflow_for(EntryOrExit::Exit, n);
129         let inner_label = self.inner.node_label(n);
130         inner_label
131             .prefix_line(dot::LabelText::LabelStr(prefix.into()))
132             .suffix_line(dot::LabelText::LabelStr(suffix.into()))
133     }
134     fn edge_label(&'a self, e: &Edge<'a>) -> dot::LabelText<'a> { self.inner.edge_label(e) }
135 }
136
137 impl<'a, 'tcx> dot::GraphWalk<'a> for DataflowLabeller<'a, 'tcx> {
138     type Node = Node<'a>;
139     type Edge = Edge<'a>;
140     fn nodes(&'a self) -> dot::Nodes<'a, Node<'a>> { self.inner.nodes() }
141     fn edges(&'a self) -> dot::Edges<'a, Edge<'a>> { self.inner.edges() }
142     fn source(&'a self, edge: &Edge<'a>) -> Node<'a> { self.inner.source(edge) }
143     fn target(&'a self, edge: &Edge<'a>) -> Node<'a> { self.inner.target(edge) }
144 }