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 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: io::Write; 21} 22 23/// Write a graphviz dot file containing our IR. 24pub 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={:?}, color={}];", 56 id.as_usize(), 57 sub_id.as_usize(), 58 edge_kind, 59 if is_allowlisted { "black" } else { "gray" } 60 ) { 61 Ok(_) => {} 62 Err(e) => err = Some(Err(e)), 63 } 64 }, 65 &(), 66 ); 67 68 if let Some(err) = err { 69 return err; 70 } 71 72 if let Some(module) = item.as_module() { 73 for child in module.children() { 74 writeln!( 75 &mut dot_file, 76 "{} -> {} [style=dotted, color=gray]", 77 item.id().as_usize(), 78 child.as_usize() 79 )?; 80 } 81 } 82 } 83 84 writeln!(&mut dot_file, "}}")?; 85 Ok(()) 86} 87