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