summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--example-graphviz-ir.pngbin842576 -> 1343520 bytes
-rw-r--r--src/codegen/mod.rs3
-rw-r--r--src/ir/context.rs31
-rw-r--r--src/ir/dot.rs53
-rw-r--r--src/ir/function.rs14
-rw-r--r--src/ir/item.rs29
-rw-r--r--src/ir/item_kind.rs20
-rw-r--r--src/ir/mod.rs1
-rw-r--r--src/ir/module.rs12
-rw-r--r--src/ir/ty.rs57
-rw-r--r--src/ir/var.rs18
11 files changed, 192 insertions, 46 deletions
diff --git a/example-graphviz-ir.png b/example-graphviz-ir.png
index c990f7e7..1e554a83 100644
--- a/example-graphviz-ir.png
+++ b/example-graphviz-ir.png
Binary files differ
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)