112a9d9c8Sopenharmony_ci//! Generating Graphviz `dot` files from our IR.
212a9d9c8Sopenharmony_ci
312a9d9c8Sopenharmony_ciuse super::context::{BindgenContext, ItemId};
412a9d9c8Sopenharmony_ciuse super::traversal::Trace;
512a9d9c8Sopenharmony_ciuse std::fs::File;
612a9d9c8Sopenharmony_ciuse std::io::{self, Write};
712a9d9c8Sopenharmony_ciuse std::path::Path;
812a9d9c8Sopenharmony_ci
912a9d9c8Sopenharmony_ci/// A trait for anything that can write attributes as `<table>` rows to a dot
1012a9d9c8Sopenharmony_ci/// file.
1112a9d9c8Sopenharmony_cipub trait DotAttributes {
1212a9d9c8Sopenharmony_ci    /// Write this thing's attributes to the given output. Each attribute must
1312a9d9c8Sopenharmony_ci    /// be its own `<tr>...</tr>`.
1412a9d9c8Sopenharmony_ci    fn dot_attributes<W>(
1512a9d9c8Sopenharmony_ci        &self,
1612a9d9c8Sopenharmony_ci        ctx: &BindgenContext,
1712a9d9c8Sopenharmony_ci        out: &mut W,
1812a9d9c8Sopenharmony_ci    ) -> io::Result<()>
1912a9d9c8Sopenharmony_ci    where
2012a9d9c8Sopenharmony_ci        W: io::Write;
2112a9d9c8Sopenharmony_ci}
2212a9d9c8Sopenharmony_ci
2312a9d9c8Sopenharmony_ci/// Write a graphviz dot file containing our IR.
2412a9d9c8Sopenharmony_cipub fn write_dot_file<P>(ctx: &BindgenContext, path: P) -> io::Result<()>
2512a9d9c8Sopenharmony_ciwhere
2612a9d9c8Sopenharmony_ci    P: AsRef<Path>,
2712a9d9c8Sopenharmony_ci{
2812a9d9c8Sopenharmony_ci    let file = File::create(path)?;
2912a9d9c8Sopenharmony_ci    let mut dot_file = io::BufWriter::new(file);
3012a9d9c8Sopenharmony_ci    writeln!(&mut dot_file, "digraph {{")?;
3112a9d9c8Sopenharmony_ci
3212a9d9c8Sopenharmony_ci    let mut err: Option<io::Result<_>> = None;
3312a9d9c8Sopenharmony_ci
3412a9d9c8Sopenharmony_ci    for (id, item) in ctx.items() {
3512a9d9c8Sopenharmony_ci        let is_allowlisted = ctx.allowlisted_items().contains(&id);
3612a9d9c8Sopenharmony_ci
3712a9d9c8Sopenharmony_ci        writeln!(
3812a9d9c8Sopenharmony_ci            &mut dot_file,
3912a9d9c8Sopenharmony_ci            r#"{} [fontname="courier", color={}, label=< <table border="0" align="left">"#,
4012a9d9c8Sopenharmony_ci            id.as_usize(),
4112a9d9c8Sopenharmony_ci            if is_allowlisted { "black" } else { "gray" }
4212a9d9c8Sopenharmony_ci        )?;
4312a9d9c8Sopenharmony_ci        item.dot_attributes(ctx, &mut dot_file)?;
4412a9d9c8Sopenharmony_ci        writeln!(&mut dot_file, r#"</table> >];"#)?;
4512a9d9c8Sopenharmony_ci
4612a9d9c8Sopenharmony_ci        item.trace(
4712a9d9c8Sopenharmony_ci            ctx,
4812a9d9c8Sopenharmony_ci            &mut |sub_id: ItemId, edge_kind| {
4912a9d9c8Sopenharmony_ci                if err.is_some() {
5012a9d9c8Sopenharmony_ci                    return;
5112a9d9c8Sopenharmony_ci                }
5212a9d9c8Sopenharmony_ci
5312a9d9c8Sopenharmony_ci                match writeln!(
5412a9d9c8Sopenharmony_ci                    &mut dot_file,
5512a9d9c8Sopenharmony_ci                    "{} -> {} [label={:?}, color={}];",
5612a9d9c8Sopenharmony_ci                    id.as_usize(),
5712a9d9c8Sopenharmony_ci                    sub_id.as_usize(),
5812a9d9c8Sopenharmony_ci                    edge_kind,
5912a9d9c8Sopenharmony_ci                    if is_allowlisted { "black" } else { "gray" }
6012a9d9c8Sopenharmony_ci                ) {
6112a9d9c8Sopenharmony_ci                    Ok(_) => {}
6212a9d9c8Sopenharmony_ci                    Err(e) => err = Some(Err(e)),
6312a9d9c8Sopenharmony_ci                }
6412a9d9c8Sopenharmony_ci            },
6512a9d9c8Sopenharmony_ci            &(),
6612a9d9c8Sopenharmony_ci        );
6712a9d9c8Sopenharmony_ci
6812a9d9c8Sopenharmony_ci        if let Some(err) = err {
6912a9d9c8Sopenharmony_ci            return err;
7012a9d9c8Sopenharmony_ci        }
7112a9d9c8Sopenharmony_ci
7212a9d9c8Sopenharmony_ci        if let Some(module) = item.as_module() {
7312a9d9c8Sopenharmony_ci            for child in module.children() {
7412a9d9c8Sopenharmony_ci                writeln!(
7512a9d9c8Sopenharmony_ci                    &mut dot_file,
7612a9d9c8Sopenharmony_ci                    "{} -> {} [style=dotted, color=gray]",
7712a9d9c8Sopenharmony_ci                    item.id().as_usize(),
7812a9d9c8Sopenharmony_ci                    child.as_usize()
7912a9d9c8Sopenharmony_ci                )?;
8012a9d9c8Sopenharmony_ci            }
8112a9d9c8Sopenharmony_ci        }
8212a9d9c8Sopenharmony_ci    }
8312a9d9c8Sopenharmony_ci
8412a9d9c8Sopenharmony_ci    writeln!(&mut dot_file, "}}")?;
8512a9d9c8Sopenharmony_ci    Ok(())
8612a9d9c8Sopenharmony_ci}
87