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