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