]> git.proxmox.com Git - rustc.git/blame - src/librustc_borrowck/graphviz.rs
Imported Upstream version 1.9.0+dfsg1
[rustc.git] / src / librustc_borrowck / graphviz.rs
CommitLineData
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
15pub use self::Variant::*;
16
54a0048b
SL
17pub use rustc::cfg::graphviz::{Node, Edge};
18use rustc::cfg::graphviz as cfg_dot;
1a4d82fc
JJ
19
20use borrowck;
21use borrowck::{BorrowckCtxt, LoanPath};
22use dot;
54a0048b 23use rustc::cfg::CFGIndex;
1a4d82fc 24use rustc::middle::dataflow::{DataFlowOperator, DataFlowContext, EntryOrExit};
1a4d82fc 25use std::rc::Rc;
9cc50fc6 26use dot::IntoCow;
1a4d82fc 27
c34b1796 28#[derive(Debug, Copy, Clone)]
1a4d82fc
JJ
29pub enum Variant {
30 Loans,
31 Moves,
32 Assigns,
33}
34
35impl 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
45pub 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
52impl<'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
132impl<'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
148impl<'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}