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