1 //! This module provides linkage between rustc::middle::graph and
2 //! libgraphviz traits, specialized to attaching borrowck analysis
3 //! data to rendered labels.
7 pub use rustc::cfg::graphviz::{Node, Edge};
8 use rustc::cfg::graphviz as cfg_dot;
10 use crate::borrowck::{self, BorrowckCtxt, LoanPath};
11 use crate::dataflow::{DataFlowOperator, DataFlowContext, EntryOrExit};
13 use rustc::cfg::CFGIndex;
16 #[derive(Debug, Copy, Clone)]
24 pub fn short_name(&self) -> &'static str {
33 pub struct DataflowLabeller<'a, 'tcx: 'a> {
34 pub inner: cfg_dot::LabelledCFG<'a, 'tcx>,
35 pub variants: Vec<Variant>,
36 pub borrowck_ctxt: &'a BorrowckCtxt<'a, 'tcx>,
37 pub analysis_data: &'a borrowck::AnalysisData<'tcx>,
40 impl<'a, 'tcx> DataflowLabeller<'a, 'tcx> {
41 fn dataflow_for(&self, e: EntryOrExit, n: &Node<'a>) -> String {
42 let id = n.1.data.id();
43 debug!("dataflow_for({:?}, id={:?}) {:?}", e, id, self.variants);
44 let mut sets = String::new();
45 let mut seen_one = false;
46 for &variant in &self.variants {
47 if seen_one { sets.push_str(" "); } else { seen_one = true; }
48 sets.push_str(variant.short_name());
50 sets.push_str(&self.dataflow_for_variant(e, n, variant));
55 fn dataflow_for_variant(&self, e: EntryOrExit, n: &Node<'_>, v: Variant) -> String {
58 Loans => self.dataflow_loans_for(e, cfgidx),
59 Moves => self.dataflow_moves_for(e, cfgidx),
60 Assigns => self.dataflow_assigns_for(e, cfgidx),
64 fn build_set<O: DataFlowOperator, F>(
68 dfcx: &DataFlowContext<'tcx, O>,
72 F: FnMut(usize) -> Rc<LoanPath<'tcx>>,
74 let mut saw_some = false;
75 let mut set = "{".to_string();
76 dfcx.each_bit_for_node(e, cfgidx, |index| {
77 let lp = to_lp(index);
81 let loan_str = self.borrowck_ctxt.loan_path_to_string(&lp);
82 set.push_str(&loan_str);
90 fn dataflow_loans_for(&self, e: EntryOrExit, cfgidx: CFGIndex) -> String {
91 let dfcx = &self.analysis_data.loans;
92 let loan_index_to_path = |loan_index| {
93 let all_loans = &self.analysis_data.all_loans;
94 let l: &borrowck::Loan<'_> = &all_loans[loan_index];
97 self.build_set(e, cfgidx, dfcx, loan_index_to_path)
100 fn dataflow_moves_for(&self, e: EntryOrExit, cfgidx: CFGIndex) -> String {
101 let dfcx = &self.analysis_data.move_data.dfcx_moves;
102 let move_index_to_path = |move_index| {
103 let move_data = &self.analysis_data.move_data.move_data;
104 let moves = move_data.moves.borrow();
105 let the_move: &borrowck::move_data::Move = &(*moves)[move_index];
106 move_data.path_loan_path(the_move.path)
108 self.build_set(e, cfgidx, dfcx, move_index_to_path)
111 fn dataflow_assigns_for(&self, e: EntryOrExit, cfgidx: CFGIndex) -> String {
112 let dfcx = &self.analysis_data.move_data.dfcx_assign;
113 let assign_index_to_path = |assign_index| {
114 let move_data = &self.analysis_data.move_data.move_data;
115 let assignments = move_data.var_assignments.borrow();
116 let assignment: &borrowck::move_data::Assignment = &(*assignments)[assign_index];
117 move_data.path_loan_path(assignment.path)
119 self.build_set(e, cfgidx, dfcx, assign_index_to_path)
123 impl<'a, 'tcx> dot::Labeller<'a> for DataflowLabeller<'a, 'tcx> {
124 type Node = Node<'a>;
125 type Edge = Edge<'a>;
126 fn graph_id(&'a self) -> dot::Id<'a> { self.inner.graph_id() }
127 fn node_id(&'a self, n: &Node<'a>) -> dot::Id<'a> { self.inner.node_id(n) }
128 fn node_label(&'a self, n: &Node<'a>) -> dot::LabelText<'a> {
129 let prefix = self.dataflow_for(EntryOrExit::Entry, n);
130 let suffix = self.dataflow_for(EntryOrExit::Exit, n);
131 let inner_label = self.inner.node_label(n);
133 .prefix_line(dot::LabelText::LabelStr(prefix.into()))
134 .suffix_line(dot::LabelText::LabelStr(suffix.into()))
136 fn edge_label(&'a self, e: &Edge<'a>) -> dot::LabelText<'a> { self.inner.edge_label(e) }
139 impl<'a, 'tcx> dot::GraphWalk<'a> for DataflowLabeller<'a, 'tcx> {
140 type Node = Node<'a>;
141 type Edge = Edge<'a>;
142 fn nodes(&'a self) -> dot::Nodes<'a, Node<'a>> { self.inner.nodes() }
143 fn edges(&'a self) -> dot::Edges<'a, Edge<'a>> { self.inner.edges() }
144 fn source(&'a self, edge: &Edge<'a>) -> Node<'a> { self.inner.source(edge) }
145 fn target(&'a self, edge: &Edge<'a>) -> Node<'a> { self.inner.target(edge) }