bindgen/ir/
dot.rs

1//! Generating Graphviz `dot` files from our IR.
2
3use super::context::{BindgenContext, ItemId};
4use super::traversal::Trace;
5use std::fs::File;
6use std::io::{self, Write};
7use std::path::Path;
8
9/// A trait for anything that can write attributes as `<table>` rows to a dot
10/// file.
11pub(crate) trait DotAttributes {
12    /// Write this thing's attributes to the given output. Each attribute must
13    /// be its own `<tr>...</tr>`.
14    fn dot_attributes<W>(
15        &self,
16        ctx: &BindgenContext,
17        out: &mut W,
18    ) -> io::Result<()>
19    where
20        W: Write;
21}
22
23/// Write a graphviz dot file containing our IR.
24pub(crate) fn write_dot_file<P>(ctx: &BindgenContext, path: P) -> io::Result<()>
25where
26    P: AsRef<Path>,
27{
28    let file = File::create(path)?;
29    let mut dot_file = io::BufWriter::new(file);
30    writeln!(&mut dot_file, "digraph {{")?;
31
32    let mut err: Option<io::Result<_>> = None;
33
34    for (id, item) in ctx.items() {
35        let is_allowlisted = ctx.allowlisted_items().contains(&id);
36
37        writeln!(
38            &mut dot_file,
39            r#"{} [fontname="courier", color={}, label=< <table border="0" align="left">"#,
40            id.as_usize(),
41            if is_allowlisted { "black" } else { "gray" }
42        )?;
43        item.dot_attributes(ctx, &mut dot_file)?;
44        writeln!(&mut dot_file, r#"</table> >];"#)?;
45
46        item.trace(
47            ctx,
48            &mut |sub_id: ItemId, edge_kind| {
49                if err.is_some() {
50                    return;
51                }
52
53                match writeln!(
54                    &mut dot_file,
55                    "{} -> {} [label={edge_kind:?}, color={}];",
56                    id.as_usize(),
57                    sub_id.as_usize(),
58                    if is_allowlisted { "black" } else { "gray" }
59                ) {
60                    Ok(_) => {}
61                    Err(e) => err = Some(Err(e)),
62                }
63            },
64            &(),
65        );
66
67        if let Some(err) = err {
68            return err;
69        }
70
71        if let Some(module) = item.as_module() {
72            for child in module.children() {
73                writeln!(
74                    &mut dot_file,
75                    "{} -> {} [style=dotted, color=gray]",
76                    item.id().as_usize(),
77                    child.as_usize()
78                )?;
79            }
80        }
81    }
82
83    writeln!(&mut dot_file, "}}")?;
84    Ok(())
85}