]> git.proxmox.com Git - rustc.git/blame - src/librustc_data_structures/obligation_forest/graphviz.rs
New upstream version 1.47.0+dfsg1
[rustc.git] / src / librustc_data_structures / obligation_forest / graphviz.rs
CommitLineData
9fa01778 1use crate::obligation_forest::{ForestObligation, ObligationForest};
f035d41b 2use rustc_graphviz as dot;
0bf4aa26
XL
3use std::env::var_os;
4use std::fs::File;
74b04a01 5use std::io::BufWriter;
0bf4aa26
XL
6use std::path::Path;
7use std::sync::atomic::AtomicUsize;
8use std::sync::atomic::Ordering;
9
10impl<O: ForestObligation> ObligationForest<O> {
9fa01778
XL
11 /// Creates a graphviz representation of the obligation forest. Given a directory this will
12 /// create files with name of the format `<counter>_<description>.gv`. The counter is
0bf4aa26
XL
13 /// global and is maintained internally.
14 ///
15 /// Calling this will do nothing unless the environment variable
16 /// `DUMP_OBLIGATION_FOREST_GRAPHVIZ` is defined.
17 ///
18 /// A few post-processing that you might want to do make the forest easier to visualize:
19 ///
20 /// * `sed 's,std::[a-z]*::,,g'` — Deletes the `std::<package>::` prefix of paths.
21 /// * `sed 's,"Binder(TraitPredicate(<\(.*\)>)) (\([^)]*\))","\1 (\2)",'` — Transforms
22 /// `Binder(TraitPredicate(<predicate>))` into just `<predicate>`.
23 #[allow(dead_code)]
24 pub fn dump_graphviz<P: AsRef<Path>>(&self, dir: P, description: &str) {
25 static COUNTER: AtomicUsize = AtomicUsize::new(0);
26
27 if var_os("DUMP_OBLIGATION_FOREST_GRAPHVIZ").is_none() {
28 return;
29 }
30
31 let counter = COUNTER.fetch_add(1, Ordering::AcqRel);
32
33 let file_path = dir.as_ref().join(format!("{:010}_{}.gv", counter, description));
34
74b04a01 35 let mut gv_file = BufWriter::new(File::create(file_path).unwrap());
0bf4aa26
XL
36
37 dot::render(&self, &mut gv_file).unwrap();
38 }
39}
40
41impl<'a, O: ForestObligation + 'a> dot::Labeller<'a> for &'a ObligationForest<O> {
42 type Node = usize;
43 type Edge = (usize, usize);
44
9fa01778 45 fn graph_id(&self) -> dot::Id<'_> {
0bf4aa26
XL
46 dot::Id::new("trait_obligation_forest").unwrap()
47 }
48
9fa01778 49 fn node_id(&self, index: &Self::Node) -> dot::Id<'_> {
0bf4aa26
XL
50 dot::Id::new(format!("obligation_{}", index)).unwrap()
51 }
52
9fa01778 53 fn node_label(&self, index: &Self::Node) -> dot::LabelText<'_> {
0bf4aa26 54 let node = &self.nodes[*index];
74b04a01 55 let label = format!("{:?} ({:?})", node.obligation.as_cache_key(), node.state.get());
0bf4aa26
XL
56
57 dot::LabelText::LabelStr(label.into())
58 }
59
9fa01778 60 fn edge_label(&self, (_index_source, _index_target): &Self::Edge) -> dot::LabelText<'_> {
0bf4aa26
XL
61 dot::LabelText::LabelStr("".into())
62 }
63}
64
65impl<'a, O: ForestObligation + 'a> dot::GraphWalk<'a> for &'a ObligationForest<O> {
66 type Node = usize;
67 type Edge = (usize, usize);
68
9fa01778 69 fn nodes(&self) -> dot::Nodes<'_, Self::Node> {
0bf4aa26
XL
70 (0..self.nodes.len()).collect()
71 }
72
9fa01778 73 fn edges(&self) -> dot::Edges<'_, Self::Edge> {
0bf4aa26
XL
74 (0..self.nodes.len())
75 .flat_map(|i| {
76 let node = &self.nodes[i];
77
e1599b0c 78 node.dependents.iter().map(move |&d| (d, i))
0bf4aa26
XL
79 })
80 .collect()
81 }
82
83 fn source(&self, (s, _): &Self::Edge) -> Self::Node {
84 *s
85 }
86
87 fn target(&self, (_, t): &Self::Edge) -> Self::Node {
88 *t
89 }
90}