diff options
-rw-r--r-- | example-graphviz-ir.png | bin | 842576 -> 1343520 bytes | |||
-rw-r--r-- | src/codegen/mod.rs | 3 | ||||
-rw-r--r-- | src/ir/context.rs | 31 | ||||
-rw-r--r-- | src/ir/dot.rs | 53 | ||||
-rw-r--r-- | src/ir/function.rs | 14 | ||||
-rw-r--r-- | src/ir/item.rs | 29 | ||||
-rw-r--r-- | src/ir/item_kind.rs | 20 | ||||
-rw-r--r-- | src/ir/mod.rs | 1 | ||||
-rw-r--r-- | src/ir/module.rs | 12 | ||||
-rw-r--r-- | src/ir/ty.rs | 57 | ||||
-rw-r--r-- | src/ir/var.rs | 18 |
11 files changed, 192 insertions, 46 deletions
diff --git a/example-graphviz-ir.png b/example-graphviz-ir.png Binary files differindex c990f7e7..1e554a83 100644 --- a/example-graphviz-ir.png +++ b/example-graphviz-ir.png diff --git a/src/codegen/mod.rs b/src/codegen/mod.rs index 77f654e6..aab59946 100644 --- a/src/codegen/mod.rs +++ b/src/codegen/mod.rs @@ -10,6 +10,7 @@ use ir::annotations::FieldAccessorKind; use ir::comp::{Base, CompInfo, CompKind, Field, Method, MethodKind}; use ir::context::{BindgenContext, ItemId}; use ir::derive::{CanDeriveCopy, CanDeriveDebug, CanDeriveDefault}; +use ir::dot; use ir::enum_ty::{Enum, EnumVariant, EnumVariantValue}; use ir::function::{Function, FunctionSig}; use ir::int::IntKind; @@ -2502,7 +2503,7 @@ pub fn codegen(context: &mut BindgenContext) -> Vec<P<ast::Item>> { } if let Some(path) = context.options().emit_ir_graphviz.as_ref() { - match context.emit_ir_graphviz(path.clone()) { + match dot::write_dot_file(context, path) { Ok(()) => info!("Your dot file was generated successfully into: {}", path), Err(e) => error!("{}", e), } diff --git a/src/ir/context.rs b/src/ir/context.rs index 7383c09a..d2fb2bef 100644 --- a/src/ir/context.rs +++ b/src/ir/context.rs @@ -5,7 +5,7 @@ use super::int::IntKind; use super::item::{Item, ItemCanonicalPath, ItemSet}; use super::item_kind::ItemKind; use super::module::{Module, ModuleKind}; -use super::traversal::{self, Edge, ItemTraversal, Trace}; +use super::traversal::{self, Edge, ItemTraversal}; use super::ty::{FloatKind, TemplateDeclaration, Type, TypeKind}; use BindgenOptions; use cexpr; @@ -18,8 +18,6 @@ use std::cell::Cell; use std::collections::{HashMap, hash_map}; use std::collections::btree_map::{self, BTreeMap}; use std::fmt; -use std::fs::File; -use std::io::{self, Write}; use std::iter::IntoIterator; use syntax::ast::Ident; use syntax::codemap::{DUMMY_SP, Span}; @@ -1111,33 +1109,6 @@ impl<'ctx> BindgenContext<'ctx> { &self.options } - /// Output graphviz dot file. - pub fn emit_ir_graphviz(&self, path: String) -> io::Result<()> { - let file = try!(File::create(path)); - let mut dot_file = io::BufWriter::new(file); - writeln!(&mut dot_file, "digraph {{")?; - - let mut err: Option<io::Result<_>> = None; - - for (id, item) in self.items() { - writeln!(&mut dot_file, "{} {};", id.0, item.dot_attributes(self))?; - - item.trace(self, &mut |sub_id: ItemId, _edge_kind| { - match writeln!(&mut dot_file, "{} -> {};", id.0, sub_id.as_usize()) { - Ok(_) => {}, - Err(e) => err = Some(Err(e)), - } - }, &()); - - if err.is_some() { - return err.unwrap(); - } - } - - writeln!(&mut dot_file, "}}")?; - Ok(()) - } - /// Tokenizes a namespace cursor in order to get the name and kind of the /// namespace, fn tokenize_namespace(&self, diff --git a/src/ir/dot.rs b/src/ir/dot.rs new file mode 100644 index 00000000..b7a117bb --- /dev/null +++ b/src/ir/dot.rs @@ -0,0 +1,53 @@ +//! Generating Graphviz `dot` files from our IR. + +use std::fs::File; +use std::io::{self, Write}; +use std::path::Path; +use super::context::{BindgenContext, ItemId}; +use super::traversal::Trace; + +/// A trait for anything that can write attributes as `<table>` rows to a dot +/// file. +pub trait DotAttributes { + /// Write this thing's attributes to the given output. Each attribute must + /// be its own `<tr>...</tr>`. + fn dot_attributes<W>(&self, ctx: &BindgenContext, out: &mut W) -> io::Result<()> + where W: io::Write; +} + +/// Write a graphviz dot file containing our IR. +pub fn write_dot_file<P>(ctx: &BindgenContext, path: P) -> io::Result<()> + where P: AsRef<Path> +{ + let file = try!(File::create(path)); + let mut dot_file = io::BufWriter::new(file); + try!(writeln!(&mut dot_file, "digraph {{")); + + let mut err: Option<io::Result<_>> = None; + + for (id, item) in ctx.items() { + try!(writeln!(&mut dot_file, + r#"{} [fontname="courier", label=< <table border="0">"#, + id.as_usize())); + try!(item.dot_attributes(ctx, &mut dot_file)); + try!(writeln!(&mut dot_file, r#"</table> >];"#)); + + item.trace(ctx, &mut |sub_id: ItemId, _edge_kind| { + if err.is_some() { + return; + } + + match writeln!(&mut dot_file, "{} -> {};", id.as_usize(), sub_id.as_usize()) { + Ok(_) => {}, + Err(e) => err = Some(Err(e)), + } + }, &()); + + if let Some(err) = err { + return err; + } + } + + try!(writeln!(&mut dot_file, "}}")); + Ok(()) +} diff --git a/src/ir/function.rs b/src/ir/function.rs index 22b9c9b0..daa30b89 100644 --- a/src/ir/function.rs +++ b/src/ir/function.rs @@ -1,12 +1,14 @@ //! Intermediate representation for C/C++ functions and methods. use super::context::{BindgenContext, ItemId}; +use super::dot::DotAttributes; use super::item::Item; use super::traversal::{Trace, Tracer}; use super::ty::TypeKind; use clang; use clang_sys::CXCallingConv; use parse::{ClangItemParser, ClangSubItemParser, ParseError, ParseResult}; +use std::io; use syntax::abi; /// A function declaration, with a signature, arguments, and argument names. @@ -59,6 +61,18 @@ impl Function { } } +impl DotAttributes for Function { + fn dot_attributes<W>(&self, _ctx: &BindgenContext, out: &mut W) -> io::Result<()> + where W: io::Write + { + if let Some(ref mangled) = self.mangled_name { + try!(writeln!(out, "<tr><td>mangled name</td><td>{}</td></tr>", mangled)); + } + + Ok(()) + } +} + /// A function signature. #[derive(Debug)] pub struct FunctionSig { diff --git a/src/ir/item.rs b/src/ir/item.rs index 8f16a96f..bd401aba 100644 --- a/src/ir/item.rs +++ b/src/ir/item.rs @@ -3,6 +3,7 @@ use super::annotations::Annotations; use super::context::{BindgenContext, ItemId, PartialType}; use super::derive::{CanDeriveCopy, CanDeriveDebug, CanDeriveDefault}; +use super::dot::{DotAttributes}; use super::function::Function; use super::item_kind::ItemKind; use super::module::Module; @@ -15,6 +16,7 @@ use std::cell::{Cell, RefCell}; use std::collections::BTreeSet; use std::fmt::Write; use std::iter; +use std::io; /// A trait to get the canonical name from an item. /// @@ -372,20 +374,6 @@ impl Item { self.id } - /// Get this `Item`'s dot attributes. - pub fn dot_attributes(&self, ctx: &BindgenContext) -> String { - format!("[fontname=\"courier\", label=< \ - <table border=\"0\"> \ - <tr><td>ItemId({})</td></tr> \ - <tr><td>name</td><td>{}</td></tr> \ - <tr><td>kind</td><td>{}</td></tr> \ - </table> \ - >]", - self.id.as_usize(), - self.name(ctx).get(), - self.kind.kind_name()) - } - /// Get this `Item`'s parent's identifier. /// /// For the root module, the parent's ID is its own ID. @@ -928,6 +916,19 @@ impl Item { /// A set of items. pub type ItemSet = BTreeSet<ItemId>; +impl DotAttributes for Item { + fn dot_attributes<W>(&self, ctx: &BindgenContext, out: &mut W) -> io::Result<()> + where W: io::Write + { + try!(writeln!(out, + "<tr><td>{:?}</td></tr> + <tr><td>name</td><td>{}</td></tr>", + self.id, + self.name(ctx).get())); + self.kind.dot_attributes(ctx, out) + } +} + impl TemplateDeclaration for ItemId { fn template_params(&self, ctx: &BindgenContext) -> Option<Vec<ItemId>> { ctx.resolve_item_fallible(*self) diff --git a/src/ir/item_kind.rs b/src/ir/item_kind.rs index 3ff06731..6dfd6764 100644 --- a/src/ir/item_kind.rs +++ b/src/ir/item_kind.rs @@ -1,5 +1,8 @@ //! Different variants of an `Item` in our intermediate representation. +use std::io; +use super::context::BindgenContext; +use super::dot::DotAttributes; use super::function::Function; use super::module::Module; use super::ty::Type; @@ -39,7 +42,7 @@ impl ItemKind { ItemKind::Type(..) => "Type", ItemKind::Function(..) => "Function", ItemKind::Var(..) => "Var" - } + } } /// Is this a module? @@ -122,3 +125,18 @@ impl ItemKind { self.as_var().expect("Not a var") } } + +impl DotAttributes for ItemKind { + fn dot_attributes<W>(&self, ctx: &BindgenContext, out: &mut W) -> io::Result<()> + where W: io::Write + { + try!(writeln!(out, "<tr><td>kind</td><td>{}</td></tr>", self.kind_name())); + + match *self { + ItemKind::Module(ref module) => module.dot_attributes(ctx, out), + ItemKind::Type(ref ty) => ty.dot_attributes(ctx, out), + ItemKind::Function(ref func) => func.dot_attributes(ctx, out), + ItemKind::Var(ref var) => var.dot_attributes(ctx, out), + } + } +} diff --git a/src/ir/mod.rs b/src/ir/mod.rs index e624e46b..ba549c51 100644 --- a/src/ir/mod.rs +++ b/src/ir/mod.rs @@ -7,6 +7,7 @@ pub mod annotations; pub mod comp; pub mod context; pub mod derive; +pub mod dot; pub mod enum_ty; pub mod function; pub mod int; diff --git a/src/ir/module.rs b/src/ir/module.rs index 6b6c535b..6787e3f9 100644 --- a/src/ir/module.rs +++ b/src/ir/module.rs @@ -1,6 +1,8 @@ //! Intermediate representation for modules (AKA C++ namespaces). +use std::io; use super::context::{BindgenContext, ItemId}; +use super::dot::DotAttributes; use clang; use parse::{ClangSubItemParser, ParseError, ParseResult}; use parse_one; @@ -56,6 +58,16 @@ impl Module { } } +impl DotAttributes for Module { + fn dot_attributes<W>(&self, _ctx: &BindgenContext, out: &mut W) -> io::Result<()> + where W: io::Write + { + writeln!(out, + "<tr><td>ModuleKind</td><td>{:?}</td></tr>", + self.kind) + } +} + impl ClangSubItemParser for Module { fn parse(cursor: clang::Cursor, ctx: &mut BindgenContext) diff --git a/src/ir/ty.rs b/src/ir/ty.rs index c3ec4039..44a88744 100644 --- a/src/ir/ty.rs +++ b/src/ir/ty.rs @@ -3,6 +3,7 @@ use super::comp::CompInfo; use super::context::{BindgenContext, ItemId}; use super::derive::{CanDeriveCopy, CanDeriveDebug, CanDeriveDefault}; +use super::dot::DotAttributes; use super::enum_ty::Enum; use super::function::FunctionSig; use super::int::IntKind; @@ -12,6 +13,7 @@ use super::objc::ObjCInterface; use super::traversal::{Trace, Tracer}; use clang::{self, Cursor}; use parse::{ClangItemParser, ParseError, ParseResult}; +use std::io; use std::mem; /// Template declaration related methods. @@ -384,6 +386,61 @@ impl Type { } } +impl DotAttributes for Type { + fn dot_attributes<W>(&self, ctx: &BindgenContext, out: &mut W) -> io::Result<()> + where W: io::Write + { + if let Some(ref layout) = self.layout { + try!(writeln!(out, + "<tr><td>size</td><td>{}</td></tr> + <tr><td>align</td><td>{}</td></tr>", + layout.size, + layout.align)); + if layout.packed { + try!(writeln!(out, "<tr><td>packed</td><td>true</td></tr>")); + } + } + + if self.is_const { + try!(writeln!(out, "<tr><td>const</td><td>true</td></tr>")); + } + + self.kind.dot_attributes(ctx, out) + } +} + +impl DotAttributes for TypeKind { + fn dot_attributes<W>(&self, _ctx: &BindgenContext, out: &mut W) -> io::Result<()> + where W: io::Write + { + write!(out, + "<tr><td>TypeKind</td><td>{}</td></tr>", + match *self { + TypeKind::Void => "Void", + TypeKind::NullPtr => "NullPtr", + TypeKind::Comp(..) => "Comp", + TypeKind::Int(..) => "Int", + TypeKind::Float(..) => "Float", + TypeKind::Complex(..) => "Complex", + TypeKind::Alias(..) => "Alias", + TypeKind::TemplateAlias(..) => "TemplateAlias", + TypeKind::Array(..) => "Array", + TypeKind::Function(..) => "Function", + TypeKind::Enum(..) => "Enum", + TypeKind::Pointer(..) => "Pointer", + TypeKind::BlockPointer => "BlockPointer", + TypeKind::Reference(..) => "Reference", + TypeKind::TemplateInstantiation(..) => "TemplateInstantiation", + TypeKind::ResolvedTypeRef(..) => "ResolvedTypeRef", + TypeKind::Named => "Named", + TypeKind::ObjCInterface(..) => "ObjCInterface", + TypeKind::UnresolvedTypeRef(..) => { + unreachable!("there shouldn't be any more of these anymore") + } + }) + } +} + #[test] fn is_invalid_named_type_valid() { let ty = Type::new(Some("foo".into()), None, TypeKind::Named, false); diff --git a/src/ir/var.rs b/src/ir/var.rs index 6cfcdae7..c6d7a1c5 100644 --- a/src/ir/var.rs +++ b/src/ir/var.rs @@ -1,6 +1,7 @@ //! Intermediate representation of variables. use super::context::{BindgenContext, ItemId}; +use super::dot::DotAttributes; use super::function::cursor_mangling; use super::int::IntKind; use super::item::Item; @@ -8,6 +9,7 @@ use super::ty::{FloatKind, TypeKind}; use cexpr; use clang; use parse::{ClangItemParser, ClangSubItemParser, ParseError, ParseResult}; +use std::io; use std::num::Wrapping; /// The type for a constant variable. @@ -84,6 +86,22 @@ impl Var { } } +impl DotAttributes for Var { + fn dot_attributes<W>(&self, _ctx: &BindgenContext, out: &mut W) -> io::Result<()> + where W: io::Write + { + if self.is_const { + try!(writeln!(out, "<tr><td>const</td><td>true</td></tr>")); + } + + if let Some(ref mangled) = self.mangled_name { + try!(writeln!(out, "<tr><td>mangled name</td><td>{}</td></tr>", mangled)); + } + + Ok(()) + } +} + impl ClangSubItemParser for Var { fn parse(cursor: clang::Cursor, ctx: &mut BindgenContext) |