summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorEmilio Cobos Álvarez <ecoal95@gmail.com>2016-08-20 22:32:16 -0700
committerEmilio Cobos Álvarez <ecoal95@gmail.com>2016-09-16 11:34:07 -0700
commitcfdf15f5d04d4fbca3e7fcb46a1dd658ade973cd (patch)
treef7d2087332f4506bb836dce901bc181e5ffc7fba /src
parentbbd6b2c9919e02642a8874e5ceb2ba3b5c76adec (diff)
Rewrite the core of the binding generator.
TL;DR: The binding generator is a mess as of right now. At first it was funny (in a "this is challenging" sense) to improve on it, but this is not sustainable. The truth is that the current architecture of the binding generator is a huge pile of hacks, so these few days I've been working on rewriting it with a few goals. 1) Have the hacks as contained and identified as possible. They're sometimes needed because how clang exposes the AST, but ideally those hacks are well identified and don't interact randomly with each others. As an example, in the current bindgen when scanning the parameters of a function that references a struct clones all the struct information, then if the struct name changes (because we mangle it), everything breaks. 2) Support extending the bindgen output without having to deal with clang. The way I'm aiming to do this is separating completely the parsing stage from the code generation one, and providing a single id for each item the binding generator provides. 3) No more random mutation of the internal representation from anywhere. That means no more Rc<RefCell<T>>, no more random circular references, no more borrow_state... nothing. 4) No more deduplication of declarations before code generation. Current bindgen has a stage, called `tag_dup_decl`[1], that takes care of deduplicating declarations. That's completely buggy, and for C++ it's a complete mess, since we YOLO modify the world. I've managed to take rid of this using the clang canonical declaration, and the definition, to avoid scanning any type/item twice. 5) Code generation should not modify any internal data structure. It can lookup things, traverse whatever it needs, but not modifying randomly. 6) Each item should have a canonical name, and a single source of mangling logic, and that should be computed from the inmutable state, at code generation. I've put a few canonical_name stuff in the code generation phase, but it's still not complete, and should change if I implement namespaces. Improvements pending until this can land: 1) Add support for missing core stuff, mainly generating functions (note that we parse the signatures for types correctly though), bitfields, generating C++ methods. 2) Add support for the necessary features that were added to work around some C++ pitfalls, like opaque types, etc... 3) Add support for the sugar that Manish added recently. 4) Optionally (and I guess this can land without it, because basically nobody uses it since it's so buggy), bring back namespace support. These are not completely trivial, but I think I can do them quite easily with the current architecture. I'm putting the current state of affairs here as a request for comments... Any thoughts? Note that there are still a few smells I want to eventually re-redesign, like the ParseError::Recurse thing, but until that happens I'm way happier with this kind of architecture. I'm keeping the old `parser.rs` and `gen.rs` in tree just for reference while I code, but they will go away. [1]: https://github.com/Yamakaky/rust-bindgen/blob/master/src/gen.rs#L448
Diffstat (limited to 'src')
-rwxr-xr-xsrc/bin/bindgen.rs83
-rw-r--r--src/clang.rs179
-rw-r--r--src/clangll.rs6
-rw-r--r--src/codegen/helpers.rs113
-rw-r--r--src/codegen/mod.rs1904
-rw-r--r--src/gen.rs2364
-rw-r--r--src/hacks/mod.rs1
-rw-r--r--src/hacks/refcell.rs464
-rw-r--r--src/ir/annotations.rs141
-rw-r--r--src/ir/comp.rs718
-rw-r--r--src/ir/context.rs685
-rw-r--r--src/ir/enum_ty.rs110
-rw-r--r--src/ir/function.rs220
-rw-r--r--src/ir/int.rs30
-rw-r--r--src/ir/item.rs681
-rw-r--r--src/ir/item_kind.rs89
-rw-r--r--src/ir/layout.rs26
-rw-r--r--src/ir/mod.rs12
-rw-r--r--src/ir/module.rs52
-rw-r--r--src/ir/ty.rs537
-rw-r--r--src/ir/var.rs160
-rwxr-xr-xsrc/lib.rs224
-rw-r--r--src/parse.rs48
-rw-r--r--src/parser.rs1516
-rw-r--r--src/regex_set.rs58
-rw-r--r--src/types.rs882
26 files changed, 5894 insertions, 5409 deletions
diff --git a/src/bin/bindgen.rs b/src/bin/bindgen.rs
index 8c515131..1e92ee6d 100755
--- a/src/bin/bindgen.rs
+++ b/src/bin/bindgen.rs
@@ -2,6 +2,7 @@
#![crate_type = "bin"]
extern crate bindgen;
+extern crate env_logger;
#[macro_use]
extern crate docopt;
#[macro_use]
@@ -9,25 +10,12 @@ extern crate log;
extern crate clang_sys;
extern crate rustc_serialize;
-use bindgen::{Bindings, BindgenOptions, LinkType, Logger};
+use bindgen::{Bindings, BindgenOptions, LinkType};
use std::io;
use std::path;
use std::env;
use std::default::Default;
use std::fs;
-use std::process::exit;
-
-struct StdLogger;
-
-impl Logger for StdLogger {
- fn error(&self, msg: &str) {
- println!("{}", msg);
- }
-
- fn warn(&self, msg: &str) {
- println!("{}", msg);
- }
-}
const USAGE: &'static str = "
Usage:
@@ -40,6 +28,9 @@ Usage:
[--dtor-attr=<attr>...] \
[--opaque-type=<type>...] \
[--blacklist-type=<type>...] \
+ [--whitelist-type=<type>...] \
+ [--whitelist-function=<name>...] \
+ [--whitelist-var=<name>...] \
<input-header> \
[-- <clang-args>...]
@@ -95,15 +86,25 @@ Options:
ulonglong
slonglong
- --raw-line=<raw> TODO
- --dtor-attr=<attr> TODO
- --no-class-constants TODO
- --no-unstable-rust TODO
- --no-namespaced-constants TODO
- --no-bitfield-methods TODO
- --ignore-methods TODO
- --opaque-type=<type> TODO
- --blacklist-type=<type> TODO
+ --raw-line=<raw> Add a raw line at the beginning of the output.
+ --dtor-attr=<attr> Attributes to add to structures with destructor.
+ --no-class-constants Avoid generating class constants.
+ --no-unstable-rust Avoid generating unstable rust.
+ --no-namespaced-constants Avoid generating constants right under namespaces.
+ --no-bitfield-methods Avoid generating methods for bitfield access.
+ --ignore-methods Avoid generating all kind of methods.
+ --opaque-type=<type> Mark a type as opaque.
+ --blacklist-type=<type> Mark a type as hidden.
+ --whitelist-type=<type> Whitelist the type. If this set or any other
+ of the whitelisting sets is not empty, then
+ all the non-whitelisted types (or dependant)
+ won't be generated.
+ --whitelist-function=<regex> Whitelist all the free-standing functions
+ matching <regex>. Same behavior on emptyness
+ than the type whitelisting.
+ --whitelist-var=<regex> Whitelist all the free-standing variables
+ matching <regex>. Same behavior on emptyness
+ than the type whitelisting.
<clang-args> Options other than stated above are passed
directly through to clang.
@@ -134,6 +135,9 @@ struct Args {
flag_ignore_methods: bool,
flag_opaque_type: Vec<String>,
flag_blacklist_type: Vec<String>,
+ flag_whitelist_type: Vec<String>,
+ flag_whitelist_function: Vec<String>,
+ flag_whitelist_var: Vec<String>,
arg_clang_args: Vec<String>,
}
@@ -182,7 +186,10 @@ impl Into<ParseResult<(BindgenOptions, Box<io::Write>)>> for Args {
options.gen_bitfield_methods = !self.flag_no_bitfield_methods;
options.ignore_methods = self.flag_ignore_methods;
options.opaque_types.extend(self.flag_opaque_type.drain(..));
- options.blacklist_type.extend(self.flag_blacklist_type.drain(..));
+ options.hidden_types.extend(self.flag_blacklist_type.drain(..));
+ options.whitelisted_types.extend(self.flag_whitelist_type.drain(..));
+ options.whitelisted_functions.extend(self.flag_whitelist_function.drain(..));
+ options.whitelisted_vars.extend(self.flag_whitelist_var.drain(..));
options.clang_args.extend(self.arg_clang_args.drain(..));
options.clang_args.push(self.arg_input_header);
@@ -191,6 +198,13 @@ impl Into<ParseResult<(BindgenOptions, Box<io::Write>)>> for Args {
}
pub fn main() {
+ log::set_logger(|max_log_level| {
+ use env_logger::Logger;
+ let env_logger = Logger::new();
+ max_log_level.set(env_logger.filter());
+ Box::new(env_logger)
+ }).expect("Failed to set logger.");
+
let mut bind_args: Vec<_> = env::args().collect();
if let Some(clang) = clang_sys::support::Clang::find(None) {
@@ -217,24 +231,13 @@ pub fn main() {
.and_then(|d| d.argv(bind_args.iter()).decode())
.unwrap_or_else(|e| e.exit());
- let logger = StdLogger;
let result: ParseResult<_> = args.into();
let (options, out) = result.unwrap_or_else(|msg| {
- logger.error(&msg);
- exit(-1);
+ panic!("Failed to generate_bindings: {:?}", msg);
});
- match Bindings::generate(&options, Some(&logger as &Logger), None) {
- Ok(bindings) => match bindings.write(out) {
- Ok(()) => (),
- Err(e) => {
- logger.error(&format!("Unable to write bindings to file. {}", e));
- exit(-1);
- }
- },
- Err(()) => {
- logger.error("Failed to generate bindings".into());
- exit(-1);
- }
- }
+ let bindings = Bindings::generate(options, None)
+ .expect("Unable to generate bindings");
+ bindings.write(out)
+ .expect("Unable to write bindings to file.");
}
diff --git a/src/clang.rs b/src/clang.rs
index f8a68e12..5618007b 100644
--- a/src/clang.rs
+++ b/src/clang.rs
@@ -15,9 +15,24 @@ pub struct Cursor {
x: CXCursor
}
+impl fmt::Debug for Cursor {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ write!(fmt, "Cursor({} kind: {}, loc: {})",
+ self.spelling(), kind_to_str(self.kind()), self.location())
+ }
+}
+
pub type CursorVisitor<'s> = for<'a, 'b> FnMut(&'a Cursor, &'b Cursor) -> Enum_CXChildVisitResult + 's;
impl Cursor {
+ pub fn is_declaration(&self) -> bool {
+ unsafe { clang_isDeclaration(self.kind()) != 0 }
+ }
+
+ pub fn null() -> Self {
+ Cursor { x: unsafe { clang_getNullCursor() } }
+ }
+
// common
pub fn spelling(&self) -> String {
unsafe {
@@ -43,18 +58,71 @@ impl Cursor {
}
}
+ pub fn fallible_semantic_parent(&self) -> Option<Cursor> {
+ let sp = self.semantic_parent();
+ if sp == *self || !sp.is_valid() {
+ return None;
+ }
+ Some(sp)
+ }
+
pub fn semantic_parent(&self) -> Cursor {
unsafe {
Cursor { x: clang_getCursorSemanticParent(self.x) }
}
}
+ pub fn num_template_args(&self) -> c_int {
+ unsafe {
+ clang_Cursor_getNumTemplateArguments(self.x)
+ }
+ }
+
+
+ /// This function gets the translation unit cursor. Note that we shouldn't
+ /// create a TranslationUnit struct here, because bindgen assumes there will
+ /// only be one of them alive at a time, and dispose it on drop. That can
+ /// change if this would be required, but I think we can survive fine
+ /// without it.
+ pub fn translation_unit(&self) -> Cursor {
+ assert!(self.is_valid());
+ unsafe {
+ let tu = clang_Cursor_getTranslationUnit(self.x);
+ let cursor = Cursor {
+ x: clang_getTranslationUnitCursor(tu),
+ };
+ assert!(cursor.is_valid());
+ cursor
+ }
+ }
+
+ pub fn is_toplevel(&self) -> bool {
+ let mut semantic_parent = self.semantic_parent();
+
+ while semantic_parent.kind() == CXCursor_Namespace ||
+ semantic_parent.kind() == CXCursor_NamespaceAlias ||
+ semantic_parent.kind() == CXCursor_NamespaceRef
+ {
+ semantic_parent = semantic_parent.semantic_parent();
+ }
+
+ let tu = self.translation_unit();
+ // Yes, the second can happen with, e.g., macro definitions.
+ semantic_parent == tu || semantic_parent == tu.semantic_parent()
+ }
+
pub fn kind(&self) -> Enum_CXCursorKind {
unsafe {
clang_getCursorKind(self.x)
}
}
+ pub fn is_anonymous(&self) -> bool {
+ unsafe {
+ clang_Cursor_isAnonymous(self.x) != 0
+ }
+ }
+
pub fn is_template(&self) -> bool {
self.specialized().is_valid()
}
@@ -77,10 +145,11 @@ impl Cursor {
}
}
- pub fn raw_comment(&self) -> String {
- unsafe {
+ pub fn raw_comment(&self) -> Option<String> {
+ let s = unsafe {
String_ { x: clang_Cursor_getRawCommentText(self.x) }.to_string()
- }
+ };
+ if s.is_empty() { None } else { Some(s) }
}
pub fn comment(&self) -> Comment {
@@ -165,12 +234,18 @@ impl Cursor {
}
}
- pub fn enum_val(&self) -> i64 {
+ pub fn enum_val_signed(&self) -> i64 {
unsafe {
clang_getEnumConstantDeclValue(self.x) as i64
}
}
+ pub fn enum_val_unsigned(&self) -> u64 {
+ unsafe {
+ clang_getEnumConstantDeclUnsignedValue(self.x) as u64
+ }
+ }
+
// typedef
pub fn typedef_type(&self) -> Type {
unsafe {
@@ -195,7 +270,7 @@ impl Cursor {
pub fn args(&self) -> Vec<Cursor> {
unsafe {
let num = self.num_args() as usize;
- let mut args = vec!();
+ let mut args = vec![];
for i in 0..num {
args.push(Cursor { x: clang_Cursor_getArgument(self.x, i as c_uint) });
}
@@ -235,6 +310,12 @@ impl Cursor {
}
}
+ pub fn method_is_const(&self) -> bool {
+ unsafe {
+ clang_CXXMethod_isConst(self.x) != 0
+ }
+ }
+
pub fn method_is_virtual(&self) -> bool {
unsafe {
clang_CXXMethod_isVirtual(self.x) != 0
@@ -274,29 +355,40 @@ impl PartialEq for Cursor {
clang_equalCursors(self.x, other.x) == 1
}
}
-
- fn ne(&self, other: &Cursor) -> bool {
- !self.eq(other)
- }
}
impl Eq for Cursor {}
impl Hash for Cursor {
fn hash<H: Hasher>(&self, state: &mut H) {
- self.x.kind.hash(state);
- self.x.xdata.hash(state);
- self.x.data[0].hash(state);
- self.x.data[1].hash(state);
- self.x.data[2].hash(state);
+ unsafe { clang_hashCursor(self.x) }.hash(state)
}
}
// type
+#[derive(Clone, Hash)]
pub struct Type {
x: CXType
}
+impl PartialEq for Type {
+ fn eq(&self, other: &Self) -> bool {
+ unsafe {
+ clang_equalTypes(self.x, other.x) != 0
+ }
+ }
+}
+
+impl Eq for Type {}
+
+impl fmt::Debug for Type {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ write!(fmt, "Type({}, kind: {}, decl: {:?}, canon: {:?})",
+ self.spelling(), type_to_str(self.kind()), self.declaration(),
+ self.declaration().canonical())
+ }
+}
+
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub enum LayoutError {
Invalid,
@@ -358,7 +450,7 @@ impl Type {
pub fn is_const(&self) -> bool {
unsafe {
- clang_isConstQualifiedType(self.x) == 1
+ clang_isConstQualifiedType(self.x) != 0
}
}
@@ -378,6 +470,24 @@ impl Type {
}
}
+ pub fn fallible_align(&self) -> Result<usize, LayoutError> {
+ unsafe {
+ let val = clang_Type_getAlignOf(self.x);
+ if val < 0 {
+ Err(LayoutError::from(val as i32))
+ } else {
+ Ok(val as usize)
+ }
+ }
+ }
+
+ pub fn fallible_layout(&self) -> Result<::ir::layout::Layout, LayoutError> {
+ use ir::layout::Layout;
+ let size = try!(self.fallible_size());
+ let align = try!(self.fallible_align());
+ Ok(Layout::new(size, align))
+ }
+
pub fn align(&self) -> usize {
unsafe {
let val = clang_Type_getAlignOf(self.x);
@@ -427,7 +537,7 @@ impl Type {
// function
pub fn is_variadic(&self) -> bool {
unsafe {
- clang_isFunctionTypeVariadic(self.x) == 1
+ clang_isFunctionTypeVariadic(self.x) != 0
}
}
@@ -581,21 +691,25 @@ pub struct Index {
}
impl Index {
- pub fn create(pch: bool, diag: bool) -> Index {
+ pub fn new(pch: bool, diag: bool) -> Index {
unsafe {
Index { x: clang_createIndex(pch as c_int, diag as c_int) }
}
}
+}
- pub fn dispose(&self) {
+impl fmt::Debug for Index {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ write!(fmt, "Index {{ }}")
+ }
+}
+
+impl Drop for Index {
+ fn drop(&mut self) {
unsafe {
clang_disposeIndex(self.x);
}
}
-
- pub fn is_null(&self) -> bool {
- self.x.is_null()
- }
}
// Token
@@ -609,6 +723,12 @@ pub struct TranslationUnit {
x: CXTranslationUnit
}
+impl fmt::Debug for TranslationUnit {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ write!(fmt, "TranslationUnit {{ }}")
+ }
+}
+
impl TranslationUnit {
pub fn parse(ix: &Index, file: &str, cmd_args: &[String],
unsaved: &[UnsavedFile], opts: ::libc::c_uint) -> TranslationUnit {
@@ -655,12 +775,6 @@ impl TranslationUnit {
}
}
- pub fn dispose(&self) {
- unsafe {
- clang_disposeTranslationUnit(self.x);
- }
- }
-
pub fn is_null(&self) -> bool {
self.x.is_null()
}
@@ -687,6 +801,15 @@ impl TranslationUnit {
}
}
+impl Drop for TranslationUnit {
+ fn drop(&mut self) {
+ unsafe {
+ clang_disposeTranslationUnit(self.x);
+ }
+ }
+}
+
+
// Diagnostic
pub struct Diagnostic {
x: CXDiagnostic
diff --git a/src/clangll.rs b/src/clangll.rs
index b94356bc..47f41ff1 100644
--- a/src/clangll.rs
+++ b/src/clangll.rs
@@ -428,7 +428,7 @@ pub const CXCallingConv_X86_64SysV: c_uint = 11;
pub const CXCallingConv_Invalid: c_uint = 100;
pub const CXCallingConv_Unexposed: c_uint = 200;
#[repr(C)]
-#[derive(Copy, Clone)]
+#[derive(Copy, Clone, Hash)]
pub struct CXType {
pub kind: Enum_CXTypeKind,
pub data: [*mut c_void; 2],
@@ -1076,6 +1076,7 @@ extern "C" {
pub fn clang_Cursor_getNumArguments(C: CXCursor) -> c_int;
pub fn clang_Cursor_getArgument(C: CXCursor, i: c_uint) ->
CXCursor;
+ pub fn clang_Cursor_getNumTemplateArguments(T: CXCursor) -> c_int;
pub fn clang_Cursor_getTemplateArgumentKind(C: CXCursor, i: c_uint) ->
CXTemplateArgumentKind;
pub fn clang_Cursor_getTemplateArgumentValue(C: CXCursor, i: c_uint) ->
@@ -1148,6 +1149,7 @@ extern "C" {
pieceIndex: c_uint,
options: c_uint) ->
CXSourceRange;
+ pub fn clang_Cursor_getOffsetOfField(C: CXCursor) -> c_longlong;
pub fn clang_getCursorDisplayName(arg1: CXCursor) -> CXString;
pub fn clang_getCursorReferenced(arg1: CXCursor) -> CXCursor;
pub fn clang_getCursorDefinition(arg1: CXCursor) -> CXCursor;
@@ -1168,6 +1170,7 @@ extern "C" {
pub fn clang_Cursor_getMangling(C: CXCursor) -> CXString;
pub fn clang_Cursor_getParsedComment(C: CXCursor) -> CXComment;
pub fn clang_Cursor_getModule(C: CXCursor) -> CXModule;
+ pub fn clang_Cursor_isAnonymous(C: CXCursor) -> c_uint;
pub fn clang_Module_getASTFile(Module: CXModule) -> CXFile;
pub fn clang_Module_getParent(Module: CXModule) -> CXModule;
pub fn clang_Module_getName(Module: CXModule) -> CXString;
@@ -1241,6 +1244,7 @@ extern "C" {
pub fn clang_FullComment_getAsHTML(Comment: CXComment) -> CXString;
pub fn clang_FullComment_getAsXML(Comment: CXComment) -> CXString;
pub fn clang_CXXMethod_isPureVirtual(C: CXCursor) -> c_uint;
+ pub fn clang_CXXMethod_isConst(C: CXCursor) -> c_uint;
pub fn clang_CXXMethod_isStatic(C: CXCursor) -> c_uint;
pub fn clang_CXXMethod_isVirtual(C: CXCursor) -> c_uint;
pub fn clang_CXXField_isMutable(C: CXCursor) -> c_uint;
diff --git a/src/codegen/helpers.rs b/src/codegen/helpers.rs
new file mode 100644
index 00000000..e2fc1120
--- /dev/null
+++ b/src/codegen/helpers.rs
@@ -0,0 +1,113 @@
+/// Helpers for code generation that don't need macro expansion.
+
+use aster;
+use ir::layout::Layout;
+use syntax::ast;
+use syntax::codemap::respan;
+use syntax::ptr::P;
+
+
+pub mod attributes {
+ use aster;
+ use syntax::ast;
+
+ pub fn repr(which: &str) -> ast::Attribute {
+ aster::AstBuilder::new().attr().list("repr").words(&[which]).build()
+ }
+
+ pub fn repr_list(which_ones: &[&str]) -> ast::Attribute {
+ aster::AstBuilder::new().attr().list("repr").words(which_ones).build()
+ }
+
+ pub fn derives(which_ones: &[&str]) -> ast::Attribute {
+ aster::AstBuilder::new().attr().list("derive").words(which_ones).build()
+ }
+
+ pub fn inline() -> ast::Attribute {
+ aster::AstBuilder::new().attr().word("inline")
+ }
+
+ pub fn doc(comment: &str) -> ast::Attribute {
+ aster::AstBuilder::new().attr().doc(comment)
+ }
+
+ pub fn link_name(name: &str) -> ast::Attribute {
+ aster::AstBuilder::new().attr().name_value("link_name").str(name)
+ }
+}
+
+/// Generates a proper type for a field or type with a given `Layout`, that is,
+/// a type with the correct size and alignment restrictions.
+pub struct BlobTyBuilder {
+ layout: Layout,
+}
+
+impl BlobTyBuilder {
+ pub fn new(layout: Layout) -> Self {
+ BlobTyBuilder {
+ layout: layout,
+ }
+ }
+
+ pub fn build(self) -> P<ast::Ty> {
+ use std::cmp;
+
+ let ty_name = match self.layout.align {
+ 8 => "u64",
+ 4 => "u32",
+ 2 => "u16",
+ 1 | _ => "u8",
+ };
+ let data_len = if ty_name == "u8" {
+ self.layout.size
+ } else {
+ self.layout.size / cmp::max(self.layout.align, 1)
+ };
+
+ let inner_ty = aster::AstBuilder::new().ty().path().id(ty_name).build();
+ if data_len == 1 {
+ inner_ty
+ } else {
+ ArrayTyBuilder::new().with_len(data_len).build(inner_ty)
+ }
+ }
+}
+
+pub struct ArrayTyBuilder {
+ len: usize,
+}
+
+impl ArrayTyBuilder {
+ pub fn new() -> Self {
+ ArrayTyBuilder {
+ len: 0,
+ }
+ }
+
+ pub fn with_len(mut self, len: usize) -> Self {
+ self.len = len;
+ self
+ }
+
+ pub fn build(self, ty: P<ast::Ty>) -> P<ast::Ty> {
+ use syntax::codemap::DUMMY_SP;
+ let size =
+ ast::LitKind::Int(self.len as u64,
+ ast::LitIntType::Unsigned(ast::UintTy::Us));
+ let size = ast::ExprKind::Lit(P(respan(DUMMY_SP, size)));
+ let array_kind = ast::TyKind::FixedLengthVec(ty,
+ P(ast::Expr {
+ id: ast::DUMMY_NODE_ID,
+ node: size,
+ span: DUMMY_SP,
+ attrs: ast::ThinVec::new(),
+ })
+ );
+
+ P(ast::Ty {
+ id: ast::DUMMY_NODE_ID,
+ node: array_kind,
+ span: DUMMY_SP,
+ })
+ }
+}
diff --git a/src/codegen/mod.rs b/src/codegen/mod.rs
new file mode 100644
index 00000000..62cebf46
--- /dev/null
+++ b/src/codegen/mod.rs
@@ -0,0 +1,1904 @@
+mod helpers;
+
+use self::helpers::{attributes, ArrayTyBuilder, BlobTyBuilder};
+
+use ir::context::BindgenContext;
+use ir::item::{Item, ItemId, ItemCanonicalName, ItemCanonicalPath};
+use ir::ty::{Type, TypeKind};
+use ir::int::IntKind;
+use ir::module::Module;
+use ir::var::Var;
+use ir::enum_ty::Enum;
+use ir::function::{Function, FunctionSig};
+use ir::item_kind::ItemKind;
+use ir::comp::{CompKind, CompInfo, Field, Method};
+use ir::layout::Layout;
+use ir::annotations::FieldAccessorKind;
+
+use std::ops;
+use std::mem;
+use std::collections::BTreeSet;
+use std::collections::HashSet;
+use std::collections::hash_map::{HashMap, Entry};
+
+use syntax::abi::Abi;
+use syntax::ast;
+use syntax::codemap::{Span, respan};
+use syntax::ptr::P;
+use aster;
+
+fn root_import(ctx: &BindgenContext) -> P<ast::Item> {
+ assert!(ctx.options().enable_cxx_namespaces, "Somebody messed it up");
+ let root = ctx.root_module().canonical_name(ctx);
+ let root_ident = ctx.rust_ident(&root);
+ quote_item!(ctx.ext_cx(), use $root_ident;).unwrap()
+}
+
+struct CodegenResult {
+ items: Vec<P<ast::Item>>,
+ saw_union: bool,
+ items_seen: HashSet<ItemId>,
+ /// The set of generated function names, needed because in C/C++ is legal to
+ /// do something like:
+ ///
+ /// ```
+ /// extern "C" {
+ /// void foo();
+ /// }
+ ///
+ /// extern "C" {
+ /// void foo();
+ /// }
+ /// ```
+ ///
+ /// Being these two different declarations.
+ functions_seen: HashSet<String>,
+}
+
+impl CodegenResult {
+ fn new() -> Self {
+ CodegenResult {
+ items: vec![],
+ saw_union: false,
+ items_seen: Default::default(),
+ functions_seen: Default::default(),
+ }
+ }
+
+ fn saw_union(&mut self) {
+ self.saw_union = true;
+ }
+
+ fn seen(&self, item: ItemId) -> bool {
+ self.items_seen.contains(&item)
+ }
+
+ fn set_seen(&mut self, item: ItemId) {
+ self.items_seen.insert(item);
+ }
+
+ fn seen_function(&self, name: &str) -> bool {
+ self.functions_seen.contains(name)
+ }
+
+ fn saw_function(&mut self, name: &str) {
+ self.functions_seen.insert(name.into());
+ }
+
+ fn inner<F>(&mut self, cb: F) -> Vec<P<ast::Item>>
+ where F: FnOnce(&mut Self)
+ {
+ let mut new = Self::new();
+
+ cb(&mut new);
+
+ self.saw_union |= new.saw_union;
+
+ new.items
+ }
+}
+
+impl ops::Deref for CodegenResult {
+ type Target = Vec<P<ast::Item>>;
+
+ fn deref(&self) -> &Self::Target {
+ &self.items
+ }
+}
+
+impl ops::DerefMut for CodegenResult {
+ fn deref_mut(&mut self) -> &mut Self::Target {
+ &mut self.items
+ }
+}
+
+struct ForeignModBuilder {
+ inner: ast::ForeignMod,
+}
+
+impl ForeignModBuilder {
+ fn new(abi: Abi) -> Self {
+ ForeignModBuilder {
+ inner: ast::ForeignMod {
+ abi: abi,
+ items: vec![],
+ }
+ }
+ }
+
+ fn with_foreign_item(mut self, item: ast::ForeignItem) -> Self {
+ self.inner.items.push(item);
+ self
+ }
+
+ #[allow(dead_code)]
+ fn with_foreign_items<I>(mut self, items: I) -> Self
+ where I: IntoIterator<Item=ast::ForeignItem>
+ {
+ self.inner.items.extend(items.into_iter());
+ self
+ }
+
+ fn build(self, ctx: &BindgenContext) -> P<ast::Item> {
+ use syntax::codemap::DUMMY_SP;
+ P(ast::Item {
+ ident: ctx.rust_ident(""),
+ id: ast::DUMMY_NODE_ID,
+ node: ast::ItemKind::ForeignMod(self.inner),
+ vis: ast::Visibility::Public,
+ attrs: vec![],
+ span: DUMMY_SP,
+ })
+ }
+}
+
+/// A trait to convert a rust type into a pointer, optionally const, to the same
+/// type.
+///
+/// This is done due to aster's lack of pointer builder, I guess I should PR
+/// there.
+trait ToPtr {
+ fn to_ptr(self, is_const: bool, span: Span) -> P<ast::Ty>;
+}
+
+impl ToPtr for P<ast::Ty> {
+ fn to_ptr(self, is_const: bool, span: Span) -> Self {
+ let ty = ast::TyKind::Ptr(ast::MutTy {
+ ty: self,
+ mutbl: if is_const {
+ ast::Mutability::Immutable
+ } else {
+ ast::Mutability::Mutable
+ }
+ });
+ P(ast::Ty {
+ id: ast::DUMMY_NODE_ID,
+ node: ty,
+ span: span,
+ })
+ }
+}
+
+trait CodeGenerator {
+ /// Extra information from the caller.
+ type Extra;
+
+ fn codegen(&self,
+ ctx: &BindgenContext,
+ result: &mut CodegenResult,
+ extra: &Self::Extra);
+}
+
+impl CodeGenerator for Item {
+ type Extra = ();
+
+ fn codegen(&self,
+ ctx: &BindgenContext,
+ result: &mut CodegenResult,
+ _extra: &()) {
+ if self.is_hidden(ctx) || result.seen(self.id()) {
+ return;
+ }
+
+ result.set_seen(self.id());
+
+ match *self.kind() {
+ ItemKind::Module(ref module) => {
+ if !ctx.options().enable_cxx_namespaces && self.id() == ctx.root_module() {
+ return;
+ }
+
+ module.codegen(ctx, result, self);
+ },
+ ItemKind::Function(ref fun) => {
+ if !ctx.options().ignore_functions {
+ fun.codegen(ctx, result, self);
+ }
+ },
+ ItemKind::Var(ref var) => {
+ var.codegen(ctx, result, self);
+ },
+ ItemKind::Type(ref ty) => {
+ ty.codegen(ctx, result, self);
+ }
+ }
+ }
+}
+
+impl CodeGenerator for Module {
+ type Extra = Item;
+
+ fn codegen(&self,
+ ctx: &BindgenContext,
+ result: &mut CodegenResult,
+ item: &Item) {
+ if !ctx.options().enable_cxx_namespaces {
+ for child in self.children() {
+ ctx.resolve_item(*child).codegen(ctx, result, &());
+ }
+ return;
+ }
+
+ let inner_items = result.inner(|result| {
+ result.push(root_import(ctx));
+ for child in self.children() {
+ ctx.resolve_item(*child).codegen(ctx, result, &());
+ }
+ });
+
+ let module = ast::ItemKind::Mod(ast::Mod {
+ inner: ctx.span(),
+ items: inner_items,
+ });
+
+ let name = item.canonical_name(ctx);
+ let item = aster::AstBuilder::new().item().pub_()
+ .build_item_kind(name, module);
+
+ result.push(item);
+ }
+}
+
+impl CodeGenerator for Var {
+ type Extra = Item;
+ fn codegen(&self,
+ ctx: &BindgenContext,
+ result: &mut CodegenResult,
+ item: &Item) {
+ let name = item.canonical_name(ctx);
+ let ty = self.ty().to_rust_ty(ctx);
+
+ if let Some(val) = self.val() {
+ let const_item = aster::AstBuilder::new().item().pub_().const_(name)
+ .expr().int(val).build(ty);
+ result.push(const_item)
+ } else {
+ let mut attrs = vec![];
+ if let Some(mangled) = self.mangled_name() {
+ attrs.push(attributes::link_name(mangled));
+ } else if name != self.name() {
+ attrs.push(attributes::link_name(self.name()));
+ }
+
+ let item = ast::ForeignItem {
+ ident: ctx.rust_ident_raw(&name),
+ attrs: attrs,
+ node: ast::ForeignItemKind::Static(ty, !self.is_const()),
+ id: ast::DUMMY_NODE_ID,
+ span: ctx.span(),
+ vis: ast::Visibility::Public,
+ };
+
+ let item = ForeignModBuilder::new(Abi::C)
+ .with_foreign_item(item)
+ .build(ctx);
+ result.push(item);
+ }
+ }
+}
+
+impl CodeGenerator for Type {
+ type Extra = Item;
+
+ fn codegen(&self,
+ ctx: &BindgenContext,
+ result: &mut CodegenResult,
+ item: &Item) {
+ match *self.kind() {
+ TypeKind::Void |
+ TypeKind::NullPtr |
+ TypeKind::Int(..) |
+ TypeKind::Float(..) |
+ TypeKind::Array(..) |
+ TypeKind::Pointer(..) |
+ TypeKind::Reference(..) |
+ TypeKind::TemplateRef(..) |
+ TypeKind::Function(..) |
+ TypeKind::ResolvedTypeRef(..) |
+ TypeKind::Named(..) => {
+ // These items don't need code generation, they only need to be
+ // converted to rust types in fields, arguments, and such.
+ return;
+ }
+ TypeKind::Comp(ref ci) => ci.codegen(ctx, result, item),
+ TypeKind::Alias(ref spelling, inner) => {
+ let inner_item = ctx.resolve_item(inner);
+ let name = item.canonical_name(ctx);
+
+ // Try to catch the common pattern:
+ //
+ // typedef struct foo { ... } foo;
+ //
+ // here.
+ //
+ if inner_item.canonical_name(ctx) == name {
+ return;
+ }
+
+ // If this is a known named type, disallow generating anything
+ // for it too.
+ if utils::type_from_named(ctx, spelling, inner).is_some() {
+ return;
+ }
+
+ let mut applicable_template_args = item.applicable_template_args(ctx);
+ let inner_rust_type = if item.is_opaque(ctx) {
+ applicable_template_args.clear();
+ // Pray if there's no layout.
+ let layout = self.layout(ctx).unwrap_or_else(Layout::zero);
+ BlobTyBuilder::new(layout).build()
+ } else {
+ inner_item.to_rust_ty(ctx)
+ };
+
+ let rust_name = ctx.rust_ident(&name);
+ let mut typedef = aster::AstBuilder::new().item().pub_();
+
+ if let Some(comment) = item.comment() {
+ typedef = typedef.attr().doc(comment);
+ }
+
+ let mut generics = typedef.type_(rust_name).generics();
+ for template_arg in applicable_template_args.iter() {
+ let template_arg = ctx.resolve_type(*template_arg);
+ if template_arg.is_named() {
+ let name = template_arg.name().unwrap();
+ if name.contains("typename ") {
+ error!("Item contained `typename`'d template param: {:?}", item);
+ return;
+ }
+ generics = generics.ty_param_id(template_arg.name().unwrap());
+ }
+ }
+
+ let typedef = generics.build().build_ty(inner_rust_type);
+ result.push(typedef)
+ }
+ TypeKind::Enum(ref ei) => ei.codegen(ctx, result, item),
+ ref u @ TypeKind::UnresolvedTypeRef(..)
+ => unreachable!("Should have been resolved after parsing {:?}!", u),
+ }
+ }
+}
+
+struct Vtable<'a> {
+ item_id: ItemId,
+ #[allow(dead_code)]
+ methods: &'a [Method],
+ #[allow(dead_code)]
+ base_classes: &'a [ItemId],
+}
+
+impl<'a> Vtable<'a> {
+ fn new(item_id: ItemId, methods: &'a [Method], base_classes: &'a [ItemId]) -> Self {
+ Vtable {
+ item_id: item_id,
+ methods: methods,
+ base_classes: base_classes,
+ }
+ }
+}
+
+impl<'a> CodeGenerator for Vtable<'a> {
+ type Extra = Item;
+
+ fn codegen(&self,
+ ctx: &BindgenContext,
+ result: &mut CodegenResult,
+ item: &Item) {
+ assert_eq!(item.id(), self.item_id);
+ // For now, generate an empty struct, later we should generate function
+ // pointers and whatnot.
+ let vtable = aster::AstBuilder::new().item().pub_()
+ .with_attr(attributes::repr("C"))
+ .struct_(self.canonical_name(ctx))
+ .build();
+ result.push(vtable);
+ }
+}
+
+impl<'a> ItemCanonicalName for Vtable<'a> {
+ fn canonical_name(&self, _ctx: &BindgenContext) -> String {
+ format!("bindgen_vtable_{}", self.item_id)
+ }
+}
+
+impl<'a> ItemToRustTy for Vtable<'a> {
+ fn to_rust_ty(&self, ctx: &BindgenContext) -> P<ast::Ty> {
+ aster::ty::TyBuilder::new().id(self.canonical_name(ctx))
+ }
+}
+
+struct Bitfield<'a> {
+ index: usize,
+ fields: Vec<&'a Field>,
+}
+
+impl<'a> Bitfield<'a> {
+ fn new(index: usize, fields: Vec<&'a Field>) -> Self {
+ Bitfield {
+ index: index,
+ fields: fields,
+ }
+ }
+
+ fn codegen_fields(self,
+ ctx: &BindgenContext,
+ fields: &mut Vec<ast::StructField>,
+ methods: &mut Vec<ast::ImplItem>) {
+ use aster::struct_field::StructFieldBuilder;
+ use std::cmp;
+ let mut total_width = self.fields.iter()
+ .fold(0u32, |acc, f| acc + f.bitfield().unwrap());
+
+ if !total_width.is_power_of_two() || total_width < 8 {
+ total_width = cmp::max(8, total_width.next_power_of_two());
+ }
+ debug_assert_eq!(total_width % 8, 0);
+ let total_width_in_bytes = total_width as usize / 8;
+
+ let bitfield_type =
+ BlobTyBuilder::new(Layout::new(total_width_in_bytes, total_width_in_bytes)).build();
+ let field_name = format!("_bitfield_{}", self.index);
+ let field_ident = ctx.ext_cx().ident_of(&field_name);
+ let field = StructFieldBuilder::named(&field_name).pub_()
+ .build_ty(bitfield_type.clone());
+ fields.push(field);
+
+
+ let mut offset = 0;
+ for field in self.fields {
+ let width = field.bitfield().unwrap();
+ let field_name = field.name()
+ .map(ToOwned::to_owned)
+ .unwrap_or_else(|| format!("at_offset_{}", offset));
+
+ let field_item = ctx.resolve_item(field.ty());
+ let field_ty_layout = field_item.kind().expect_type()
+ .layout(ctx)
+ .expect("Bitfield without layout? Gah!");
+
+ let field_type = field_item.to_rust_ty(ctx);
+ let int_type = BlobTyBuilder::new(field_ty_layout).build();
+
+ let getter_name = ctx.ext_cx().ident_of(&field_name);
+ let setter_name = ctx.ext_cx().ident_of(&format!("set_{}", &field_name));
+ let mask = ((1usize << width) - 1) << offset;
+ // The transmute is unfortunate, but it's needed for enums in
+ // bitfields.
+ let item = quote_item!(ctx.ext_cx(),
+ impl X {
+ #[inline]
+ pub fn $getter_name(&self) -> $field_type {
+ unsafe {
+ ::std::mem::transmute(
+ ((self.$field_ident & ($mask as $bitfield_type)) >> $offset)
+ as $int_type)
+ }
+ }
+
+ #[inline]
+ pub fn $setter_name(&mut self, val: $field_type) {
+ self.$field_ident &= !($mask as $bitfield_type);
+ self.$field_ident |= (val as $int_type as $bitfield_type << $offset) & ($mask as $bitfield_type);
+ }
+ }
+ ).unwrap();
+
+ let items = match item.unwrap().node {
+ ast::ItemKind::Impl(_, _, _, _, _, items) => items,
+ _ => unreachable!(),
+ };
+
+ methods.extend(items.into_iter());
+ offset += width;
+ }
+ }
+}
+
+impl CodeGenerator for CompInfo {
+ type Extra = Item;
+
+ fn codegen(&self,
+ ctx: &BindgenContext,
+ result: &mut CodegenResult,
+ item: &Item) {
+ use aster::struct_field::StructFieldBuilder;
+ // Don't output classes with template parameters that aren't types, and
+ // also don't output template specializations, neither total or partial.
+ //
+ // TODO: Generate layout tests for template specializations, yay!
+ if self.has_non_type_template_params() || self.is_template_specialization() {
+ return;
+ }
+
+ let applicable_template_args = item.applicable_template_args(ctx);
+
+ let mut attributes = vec![];
+ let mut needs_clone_impl = false;
+ if let Some(comment) = item.comment() {
+ attributes.push(attributes::doc(comment));
+ }
+ if self.packed() {
+ attributes.push(attributes::repr_list(&["C", "packed"]));
+ } else {
+ attributes.push(attributes::repr("C"));
+ }
+
+ let mut derives = vec![];
+ let ty = item.expect_type();
+ if ty.can_derive_debug(ctx) {
+ derives.push("Debug");
+ }
+
+ if ty.can_derive_copy(ctx) && !item.annotations().disallow_copy() {
+ derives.push("Copy");
+ if !applicable_template_args.is_empty() {
+ // FIXME: This requires extra logic if you have a big array in a
+ // templated struct. The reason for this is that the magic:
+ // fn clone(&self) -> Self { *self }
+ // doesn't work for templates.
+ //
+ // It's not hard to fix though.
+ derives.push("Clone");
+ } else {
+ needs_clone_impl = true;
+ }
+ }
+
+ if !derives.is_empty() {
+ attributes.push(attributes::derives(&derives))
+ }
+
+ let mut template_args_used = vec![false; applicable_template_args.len()];
+ let canonical_name = item.canonical_name(ctx);
+ let builder = aster::AstBuilder::new().item().pub_()
+ .with_attrs(attributes)
+ .struct_(&canonical_name);
+
+ // Generate the vtable from the method list if appropriate.
+ // TODO: I don't know how this could play with virtual methods that are
+ // not in the list of methods found by us, we'll see. Also, could the
+ // order of the vtable pointers vary?
+ //
+ // FIXME: Once we generate proper vtables, we need to codegen the
+ // vtable, but *not* generate a field for it in the case that
+ // needs_explicit_vtable is false but has_vtable is true.
+ //
+ // Also, we need to generate the vtable in such a way it "inherits" from
+ // the parent too.
+ let mut fields = vec![];
+ if self.needs_explicit_vtable(ctx) {
+ let vtable = Vtable::new(item.id(),
+ self.methods(),
+ self.base_members());
+ vtable.codegen(ctx, result, item);
+
+ let vtable_type = vtable.to_rust_ty(ctx).to_ptr(true, ctx.span());
+
+ let vtable_field = StructFieldBuilder::named("vtable_").pub_()
+ .build_ty(vtable_type);
+
+ fields.push(vtable_field);
+ }
+
+ for (i, base) in self.base_members().iter().enumerate() {
+ let base_ty = ctx.resolve_type(*base);
+ // NB: We won't include unsized types in our base chain because they
+ // would contribute to our size given the dummy field we insert for
+ // unsized types.
+ //
+ // NB: Canonical type is here because it could be inheriting from a
+ // typedef, for example, and the lack of `unwrap()` is because we
+ // can inherit from a template parameter, yes.
+ if base_ty.is_unsized(ctx) {
+ continue;
+ }
+
+ for (i, ty) in applicable_template_args.iter().enumerate() {
+ if base_ty.signature_contains_named_type(ctx, ctx.resolve_type(*ty)) {
+ template_args_used[i] = true;
+ }
+ }
+
+ let inner = base.to_rust_ty(ctx);
+ let field_name = if i == 0 {
+ "_base".into()
+ } else {
+ format!("_base_{}", i)
+ };
+
+ let field = StructFieldBuilder::named(field_name)
+ .pub_().build_ty(inner);
+ fields.push(field);
+ }
+
+ let is_union = self.kind() == CompKind::Union;
+ if is_union {
+ result.saw_union();
+ }
+
+ let layout = item.kind().expect_type().layout(ctx);
+
+ let mut current_bitfield_width = None;
+ let mut current_bitfield_layout: Option<Layout> = None;
+ let mut current_bitfield_fields = vec![];
+ let mut bitfield_count = 0;
+ let struct_fields = self.fields();
+ let fields_should_be_private = item.annotations()
+ .private_fields()
+ .unwrap_or(false);
+ let struct_accessor_kind = item.annotations()
+ .accessor_kind()
+ .unwrap_or(FieldAccessorKind::None);
+
+ let mut methods = vec![];
+ let mut anonymous_field_count = 0;
+ for field in struct_fields {
+ debug_assert_eq!(current_bitfield_width.is_some(),
+ current_bitfield_layout.is_some());
+ debug_assert_eq!(current_bitfield_width.is_some(),
+ !current_bitfield_fields.is_empty());
+
+ let field_ty = ctx.resolve_type(field.ty());
+
+ // Try to catch a bitfield contination early.
+ if let (Some(ref mut bitfield_width), Some(width)) = (current_bitfield_width, field.bitfield()) {
+ let layout = current_bitfield_layout.unwrap();
+ debug!("Testing bitfield continuation {} {} {:?}",
+ *bitfield_width, width, layout);
+ if *bitfield_width + width <= (layout.size * 8) as u32 {
+ *bitfield_width += width;
+ current_bitfield_fields.push(field);
+ continue;
+ }
+ }
+
+ // Flush the current bitfield.
+ if current_bitfield_width.is_some() {
+ debug_assert!(!current_bitfield_fields.is_empty());
+ let bitfield_fields =
+ mem::replace(&mut current_bitfield_fields, vec![]);
+ bitfield_count += 1;
+ Bitfield::new(bitfield_count, bitfield_fields)
+ .codegen_fields(ctx, &mut fields, &mut methods);
+ current_bitfield_width = None;
+ current_bitfield_layout = None;
+ }
+ debug_assert!(current_bitfield_fields.is_empty());
+
+ if let Some(width) = field.bitfield() {
+ let layout = field_ty.layout(ctx)
+ .expect("Bitfield type without layout?");
+ current_bitfield_width = Some(width);
+ current_bitfield_layout = Some(layout);
+ current_bitfield_fields.push(field);
+ continue;
+ }
+
+ for (i, ty) in applicable_template_args.iter().enumerate() {
+ if field_ty.signature_contains_named_type(ctx, ctx.resolve_type(*ty)) {
+ template_args_used[i] = true;
+ }
+ }
+
+ let ty = field.ty().to_rust_ty(ctx);
+
+ let ty = if is_union {
+ quote_ty!(ctx.ext_cx(), __BindgenUnionField<$ty>)
+ } else {
+ ty
+ };
+
+ let mut attrs = vec![];
+ if let Some(comment) = field.comment() {
+ attrs.push(attributes::doc(comment));
+ }
+ let field_name = match field.name() {
+ Some(name) => ctx.rust_mangle(name).into_owned(),
+ None => {
+ anonymous_field_count += 1;
+ format!("__bindgen_anon_{}", anonymous_field_count)
+ }
+ };
+
+ let is_private = field.annotations()
+ .private_fields()
+ .unwrap_or(fields_should_be_private);
+
+ let accessor_kind = field.annotations()
+ .accessor_kind()
+ .unwrap_or(struct_accessor_kind);
+
+ let mut field = StructFieldBuilder::named(&field_name);
+
+ if !is_private {
+ field = field.pub_();
+ }
+
+ let field = field.with_attrs(attrs)
+ .build_ty(ty.clone());
+
+ fields.push(field);
+
+ // TODO: Factor the following code out, please!
+ if accessor_kind == FieldAccessorKind::None {
+ continue;
+ }
+
+ let getter_name =
+ ctx.rust_ident_raw(&format!("get_{}", field_name));
+ let mutable_getter_name =
+ ctx.rust_ident_raw(&format!("get_{}_mut", field_name));
+ let field_name = ctx.rust_ident_raw(&field_name);
+
+ let accessor_methods_impl = match accessor_kind {
+ FieldAccessorKind::None => unreachable!(),
+ FieldAccessorKind::Regular => {
+ quote_item!(ctx.ext_cx(),
+ impl X {
+ #[inline]
+ pub fn $getter_name(&self) -> &$ty {
+ &self.$field_name
+ }
+
+ #[inline]
+ pub fn $mutable_getter_name(&mut self) -> &mut $ty {
+ &mut self.$field_name
+ }
+ }
+ )
+ }
+ FieldAccessorKind::Unsafe => {
+ quote_item!(ctx.ext_cx(),
+ impl X {
+ #[inline]
+ pub unsafe fn $getter_name(&self) -> &$ty {
+ &self.$field_name
+ }
+
+ #[inline]
+ pub unsafe fn $mutable_getter_name(&mut self) -> &mut $ty {
+ &mut self.$field_name
+ }
+ }
+ )
+ }
+ FieldAccessorKind::Immutable => {
+ quote_item!(ctx.ext_cx(),
+ impl X {
+ #[inline]
+ pub fn $getter_name(&self) -> &$ty {
+ &self.$field_name
+ }
+ }
+ )
+ }
+ };
+
+ match accessor_methods_impl.unwrap().node {
+ ast::ItemKind::Impl(_, _, _, _, _, ref items)
+ => methods.extend(items.clone()),
+ _ => unreachable!()
+ }
+ }
+
+ // Flush the last bitfield if any.
+ //
+ // FIXME: Reduce duplication with the loop above.
+ // FIXME: May need to pass current_bitfield_layout too.
+ if current_bitfield_width.is_some() {
+ debug_assert!(!current_bitfield_fields.is_empty());
+ let bitfield_fields = mem::replace(&mut current_bitfield_fields, vec![]);
+ bitfield_count += 1;
+ Bitfield::new(bitfield_count, bitfield_fields)
+ .codegen_fields(ctx, &mut fields, &mut methods);
+ }
+ debug_assert!(current_bitfield_fields.is_empty());
+
+ if is_union {
+ let layout = layout.expect("Unable to get layout information?");
+ let ty = BlobTyBuilder::new(layout).build();
+ let field = StructFieldBuilder::named("bindgen_union_field").pub_()
+ .build_ty(ty);
+ fields.push(field);
+ }
+
+ // Yeah, sorry about that.
+ if item.is_opaque(ctx) {
+ fields.clear();
+ methods.clear();
+ for i in 0..template_args_used.len() {
+ template_args_used[i] = false;
+ }
+
+ match layout {
+ Some(l) => {
+ let ty = BlobTyBuilder::new(l).build();
+ let field = StructFieldBuilder::named("_bindgen_opaque_blob").pub_()
+ .build_ty(ty);
+ fields.push(field);
+ }
+ None => {
+ warn!("Opaque type without layout! Expect dragons!");
+ }
+ }
+ }
+
+ // C requires every struct to be addressable, so what C compilers do is
+ // making the struct 1-byte sized.
+ //
+ // NOTE: This check is conveniently here to avoid the dummy fields we
+ // may add for unused template parameters.
+ if self.is_unsized(ctx) {
+ let ty = BlobTyBuilder::new(Layout::new(1, 1)).build();
+ let field = StructFieldBuilder::named("_address").pub_()
+ .build_ty(ty);
+ fields.push(field);
+ }
+
+ // Append any extra template arguments that nobody has used so far.
+ for (i, ty) in applicable_template_args.iter().enumerate() {
+ if !template_args_used[i] {
+ let name = ctx.resolve_type(*ty).name().unwrap();
+ let ident = ctx.rust_ident(name);
+ let field =
+ StructFieldBuilder::named(format!("_phantom_{}", i)).pub_()
+ .build_ty(quote_ty!(ctx.ext_cx(), ::std::marker::PhantomData<$ident>));
+ fields.push(field)
+ }
+ }
+
+
+ let mut generics = aster::AstBuilder::new().generics();
+ for template_arg in applicable_template_args.iter() {
+ // Take into account that here only arrive named types, not
+ // template specialisations that would need to be
+ // instantiated.
+ //
+ // TODO: Add template args from the parent, here and in
+ // `to_rust_ty`!!
+ let template_arg = ctx.resolve_type(*template_arg);
+ generics = generics.ty_param_id(template_arg.name().unwrap());
+ }
+
+ let generics = generics.build();
+
+ let rust_struct = builder.with_generics(generics.clone())
+ .with_fields(fields).build();
+ result.push(rust_struct);
+
+ // Generate the inner types and all that stuff.
+ //
+ // TODO: In the future we might want to be smart, and use nested
+ // modules, and whatnot.
+ for ty in self.inner_types() {
+ let child_item = ctx.resolve_item(*ty);
+ // assert_eq!(child_item.parent_id(), item.id());
+ child_item.codegen(ctx, result, &());
+ }
+
+ // NOTE: Some unexposed attributes (like alignment attributes) may
+ // affect layout, so we're bad and pray to the gods for avoid sending
+ // all the tests to shit when parsing things like max_align_t.
+ if self.found_unknown_attr() {
+ warn!("Type {} has an unkown attribute that may affect layout", canonical_name);
+ }
+ if applicable_template_args.is_empty() && !self.found_unknown_attr() {
+ for var in self.inner_vars() {
+ ctx.resolve_item(*var).codegen(ctx, result, &());
+ }
+
+ if let Some(layout) = layout {
+ let fn_name =
+ ctx.rust_ident_raw(&format!("bindgen_test_layout_{}", canonical_name));
+ let ident = ctx.rust_ident_raw(&canonical_name);
+ let size_of_expr =
+ quote_expr!(ctx.ext_cx(), ::std::mem::size_of::<$ident>());
+ let align_of_expr =
+ quote_expr!(ctx.ext_cx(), ::std::mem::align_of::<$ident>());
+ let size = layout.size;
+ let align = layout.align;
+ let item = quote_item!(ctx.ext_cx(),
+ #[test]
+ fn $fn_name() {
+ assert_eq!($size_of_expr, $size);
+ assert_eq!($align_of_expr, $align);
+ }).unwrap();
+ result.push(item);
+ }
+
+ let mut method_names = Default::default();
+ for method in self.methods() {
+ method.codegen_method(ctx, &mut methods, &mut method_names, result, item);
+ }
+ }
+
+ // NB: We can't use to_rust_ty here since for opaque types this tries to
+ // use the specialization knowledge to generate a blob field.
+ let ty_for_impl = aster::AstBuilder::new().ty().path().id(&canonical_name).build();
+ if needs_clone_impl {
+ let impl_ = quote_item!(ctx.ext_cx(),
+ impl X {
+ fn clone(&self) -> Self { *self }
+ }
+ );
+
+ let impl_ = match impl_.unwrap().node {
+ ast::ItemKind::Impl(_, _, _, _, _, ref items) => items.clone(),
+ _ => unreachable!(),
+ };
+
+ let clone_impl =
+ aster::AstBuilder::new().item().impl_()
+ .trait_().id("Clone").build()
+ .with_generics(generics.clone())
+ .with_items(impl_)
+ .build_ty(ty_for_impl.clone());
+
+ result.push(clone_impl);
+ }
+
+ if !methods.is_empty() {
+ let methods =
+ aster::AstBuilder::new().item().impl_()
+ .with_generics(generics)
+ .with_items(methods)
+ .build_ty(ty_for_impl);
+ result.push(methods);
+ }
+ }
+}
+
+trait MethodCodegen {
+ fn codegen_method(&self,
+ ctx: &BindgenContext,
+ methods: &mut Vec<ast::ImplItem>,
+ method_names: &mut HashMap<String, usize>,
+ result: &mut CodegenResult,
+ parent: &Item);
+}
+
+impl MethodCodegen for Method {
+ fn codegen_method(&self,
+ ctx: &BindgenContext,
+ methods: &mut Vec<ast::ImplItem>,
+ method_names: &mut HashMap<String, usize>,
+ result: &mut CodegenResult,
+ _parent: &Item) {
+ if ctx.options().ignore_methods {
+ return;
+ }
+
+ if self.is_virtual() {
+ return; // FIXME
+ }
+ // First of all, output the actual function.
+ ctx.resolve_item(self.signature()).codegen(ctx, result, &());
+
+ let function_item = ctx.resolve_item(self.signature());
+ let function = function_item.expect_function();
+ let mut name = function.name().to_owned();
+ let signature_item = ctx.resolve_item(function.signature());
+ let signature = match *signature_item.expect_type().kind() {
+ TypeKind::Function(ref sig) => sig,
+ _ => panic!("How in the world?"),
+ };
+
+ let count = {
+ let mut count = method_names.entry(name.clone())
+ .or_insert(0);
+ *count += 1;
+ *count - 1
+ };
+
+ if count != 0 {
+ name.push_str(&count.to_string());
+ }
+
+ let function_name = function_item.canonical_name(ctx);
+ let mut fndecl = utils::rust_fndecl_from_signature(ctx, signature_item).unwrap();
+ if !self.is_static() {
+ let mutability = if self.is_const() {
+ ast::Mutability::Immutable
+ } else {
+ ast::Mutability::Mutable
+ };
+
+ assert!(!fndecl.inputs.is_empty());
+ // FIXME: use aster here.
+ fndecl.inputs[0] = ast::Arg {
+ ty: P(ast::Ty {
+ id: ast::DUMMY_NODE_ID,
+ node: ast::TyKind::Rptr(None, ast::MutTy {
+ ty: P(ast::Ty {
+ id: ast::DUMMY_NODE_ID,
+ node: ast::TyKind::ImplicitSelf,
+ span: ctx.span()
+ }),
+ mutbl: mutability,
+ }),
+ span: ctx.span(),
+ }),
+ pat: P(ast::Pat {
+ id: ast::DUMMY_NODE_ID,
+ node: ast::PatKind::Ident(ast::BindingMode::ByValue(ast::Mutability::Immutable),
+ respan(ctx.span(), ctx.ext_cx().ident_of("self")),
+ None),
+ span: ctx.span(),
+ }),
+ id: ast::DUMMY_NODE_ID,
+ };
+ }
+
+ let sig = ast::MethodSig {
+ unsafety: ast::Unsafety::Unsafe,
+ abi: Abi::Rust,
+ decl: P(fndecl.clone()),
+ generics: ast::Generics::default(),
+ constness: respan(ctx.span(), ast::Constness::NotConst),
+ };
+
+ // TODO: We need to keep in sync the argument names, so we should unify
+ // this with the other loop that decides them.
+ let mut unnamed_arguments = 0;
+ let mut exprs = signature.argument_types().iter().map(|&(ref name, _ty)| {
+ let arg_name = match *name {
+ Some(ref name) => ctx.rust_mangle(name).into_owned(),
+ None => {
+ unnamed_arguments += 1;
+ format!("arg{}", unnamed_arguments)
+ }
+ };
+ aster::expr::ExprBuilder::new().id(arg_name)
+ }).collect::<Vec<_>>();
+
+ if !self.is_static() {
+ assert!(!exprs.is_empty());
+ exprs[0] = if self.is_const() {
+ quote_expr!(ctx.ext_cx(), &*self)
+ } else {
+ quote_expr!(ctx.ext_cx(), &mut *self)
+ };
+ };
+
+ let call = aster::expr::ExprBuilder::new().call()
+ .id(function_name)
+ .with_args(exprs)
+ .build();
+
+ let block = ast::Block {
+ stmts: vec![
+ ast::Stmt {
+ id: ast::DUMMY_NODE_ID,
+ node: ast::StmtKind::Expr(call),
+ span: ctx.span(),
+ }
+ ],
+ id: ast::DUMMY_NODE_ID,
+ rules: ast::BlockCheckMode::Default,
+ span: ctx.span(),
+ };
+
+ let mut attrs = vec![];
+ attrs.push(attributes::inline());
+
+ let item = ast::ImplItem {
+ id: ast::DUMMY_NODE_ID,
+ ident: ctx.ext_cx().ident_of(&name),
+ vis: ast::Visibility::Public,
+ attrs: attrs,
+ node: ast::ImplItemKind::Method(sig, P(block)),
+ defaultness: ast::Defaultness::Final,
+ span: ctx.span(),
+ };
+
+ methods.push(item);
+ }
+}
+
+impl CodeGenerator for Enum {
+ type Extra = Item;
+
+ fn codegen(&self,
+ ctx: &BindgenContext,
+ result: &mut CodegenResult,
+ item: &Item) {
+ use ir::enum_ty::EnumVariantValue;
+
+ let name = item.canonical_name(ctx);
+ let layout = item.expect_type().layout(ctx);
+
+ let repr = self.repr().map(|repr| ctx.resolve_type(repr));
+ let repr = match repr {
+ Some(repr) => match *repr.canonical_type(ctx).kind() {
+ TypeKind::Int(int_kind) => int_kind,
+ _ => panic!("Unexpected type as enum repr"),
+ },
+ None => {
+ warn!("Guessing type of enum! Forward declarations of enums shouldn't be legal!");
+ IntKind::Int
+ }
+ };
+
+ let signed = repr.is_signed();
+ let size = layout.map(|l| l.size).unwrap_or(0);
+ let repr_name = match (signed, size) {
+ (true, 1) => "i8",
+ (false, 1) => "u8",
+ (true, 2) => "i16",
+ (false, 2) => "u16",
+ (true, 4) => "i32",
+ (false, 4) => "u32",
+ (true, 8) => "i64",
+ (false, 8) => "u64",
+ _ => {
+ warn!("invalid enum decl: signed: {}, size: {}", signed, size);
+ "i32"
+ }
+ };
+
+ let mut builder = aster::AstBuilder::new().item().pub_();
+
+ // FIXME: Rust forbids repr with empty enums. Remove this condition when
+ // this is allowed.
+ if !self.variants().is_empty() {
+ builder = builder.with_attr(attributes::repr(repr_name));
+ }
+
+ if let Some(comment) = item.comment() {
+ builder = builder.with_attr(attributes::doc(comment));
+ }
+
+ let derives =
+ attributes::derives(&["Debug", "Copy", "Clone", "PartialEq", "Eq", "Hash"]);
+
+ builder = builder.with_attr(derives);
+
+ let mut builder = builder.enum_(&name);
+
+ fn add_constant(enum_: &Type,
+ // Only to avoid recomputing every time.
+ enum_canonical_name: &str,
+ // May be the same as "variant" if it's because the enum
+ // is unnamed and we still haven't seen the value.
+ variant_name: &str,
+ referenced_name: &str,
+ enum_rust_ty: P<ast::Ty>,
+ result: &mut CodegenResult) {
+ let constant_name = if enum_.name().is_some() {
+ format!("{}_{}", enum_canonical_name, variant_name)
+ } else {
+ variant_name.into()
+ };
+
+ let constant = aster::AstBuilder::new().item().pub_()
+ .const_(constant_name)
+ .expr().path()
+ .ids(&[&*enum_canonical_name, referenced_name])
+ .build().build(enum_rust_ty);
+ result.push(constant);
+ }
+
+ // A map where we keep a value -> variant relation.
+ let mut seen_values = HashMap::<_, String>::new();
+ let enum_ty = item.expect_type();
+ let enum_rust_ty = item.to_rust_ty(ctx);
+ for variant in self.variants().iter() {
+ match seen_values.entry(variant.val()) {
+ Entry::Occupied(ref entry) => {
+ let existing_variant_name = entry.get();
+ let variant_name = ctx.rust_mangle(variant.name());
+ add_constant(enum_ty, &name, &*variant_name,
+ existing_variant_name, enum_rust_ty.clone(),
+ result);
+ }
+ Entry::Vacant(entry) => {
+ let expr = aster::AstBuilder::new().expr();
+ let expr = match variant.val() {
+ EnumVariantValue::Signed(val) => expr.int(val),
+ EnumVariantValue::Unsigned(val) => expr.uint(val),
+ };
+ let variant_name = ctx.rust_mangle(variant.name());
+ builder = builder.with_variant_(ast::Variant_ {
+ name: ctx.rust_ident(&*variant_name),
+ attrs: vec![],
+ data: ast::VariantData::Unit(ast::DUMMY_NODE_ID),
+ disr_expr: Some(expr),
+ });
+
+ // If it's an unnamed enum, we also generate a constant so
+ // it can be properly accessed.
+ if enum_ty.name().is_none() {
+ // NB: if we want to do this for other kind of nested
+ // enums we can probably mangle the name.
+ if item.is_toplevel(ctx) {
+ add_constant(enum_ty, &name, &variant_name,
+ &variant_name, enum_rust_ty.clone(),
+ result);
+ }
+ }
+
+ entry.insert(variant_name.into_owned());
+ }
+ }
+ }
+
+
+ result.push(builder.build());
+ }
+}
+
+trait ToRustTy {
+ type Extra;
+
+ fn to_rust_ty(&self, ctx: &BindgenContext, extra: &Self::Extra) -> P<ast::Ty>;
+}
+
+trait ItemToRustTy {
+ fn to_rust_ty(&self, ctx: &BindgenContext) -> P<ast::Ty>;
+}
+
+// Convenience implementation.
+impl ItemToRustTy for ItemId {
+ fn to_rust_ty(&self, ctx: &BindgenContext) -> P<ast::Ty> {
+ ctx.resolve_item(*self).to_rust_ty(ctx)
+ }
+}
+
+impl ItemToRustTy for Item {
+ fn to_rust_ty(&self, ctx: &BindgenContext) -> P<ast::Ty> {
+ self.kind().expect_type().to_rust_ty(ctx, self)
+ }
+}
+
+fn raw_type(ctx: &BindgenContext, name: &str) -> P<ast::Ty> {
+ let ident = ctx.rust_ident_raw(&name);
+ quote_ty!(ctx.ext_cx(), ::std::os::raw::$ident)
+}
+
+impl ToRustTy for Type {
+ type Extra = Item;
+
+ fn to_rust_ty(&self, ctx: &BindgenContext, item: &Item) -> P<ast::Ty> {
+ macro_rules! raw {
+ ($ty: ident) => {
+ raw_type(ctx, stringify!($ty))
+ }
+ }
+ match *self.kind() {
+ TypeKind::Void => raw!(c_void),
+ // TODO: we should do something smart with nullptr, or maybe *const
+ // c_void is enough?
+ TypeKind::NullPtr => quote_ty!(ctx.ext_cx(), *const ::std::os::raw::c_void),
+ TypeKind::Int(ik) => {
+ match ik {
+ IntKind::Bool => aster::ty::TyBuilder::new().bool(),
+ IntKind::Char => raw!(c_char),
+ IntKind::UChar => raw!(c_uchar),
+ IntKind::Short => raw!(c_short),
+ IntKind::UShort => raw!(c_ushort),
+ IntKind::Int => raw!(c_int),
+ IntKind::UInt => raw!(c_uint),
+ IntKind::Long => raw!(c_long),
+ IntKind::ULong => raw!(c_ulong),
+ IntKind::LongLong => raw!(c_longlong),
+ IntKind::ULongLong => raw!(c_ulonglong),
+ IntKind::U16 => aster::ty::TyBuilder::new().u16(),
+ IntKind::U32 => aster::ty::TyBuilder::new().u32(),
+ }
+ }
+ TypeKind::Float(fk) => {
+ use ir::ty::FloatKind;
+ // TODO: we probably should just take the type layout into
+ // account?
+ match fk {
+ FloatKind::Float => aster::ty::TyBuilder::new().f32(),
+ FloatKind::Double |
+ FloatKind::LongDouble => aster::ty::TyBuilder::new().f64(),
+ }
+ }
+ TypeKind::Function(ref fs) => {
+ let ty = fs.to_rust_ty(ctx, item);
+ aster::AstBuilder::new().ty().option().build(ty)
+ }
+ TypeKind::Array(item, len) => {
+ let inner = item.to_rust_ty(ctx);
+ ArrayTyBuilder::new().with_len(len).build(inner)
+ }
+ TypeKind::Enum(..) => {
+ let path = item.canonical_path(ctx);
+ aster::AstBuilder::new().ty().path().ids(path).build()
+ }
+ TypeKind::TemplateRef(inner, ref template_args) => {
+ // PS: Sorry for the duplication here.
+ let mut inner_ty = inner.to_rust_ty(ctx).unwrap();
+
+ if let ast::TyKind::Path(_, ref mut path) = inner_ty.node {
+ path.segments.last_mut().unwrap().parameters =
+ ast::PathParameters::AngleBracketed(
+ ast::AngleBracketedParameterData {
+ lifetimes: vec![],
+ types: P::from_vec(template_args.iter().map(|arg| {
+ arg.to_rust_ty(ctx)
+ }).collect()),
+ bindings: P::from_vec(vec![]),
+ }
+ );
+ }
+
+ P(inner_ty)
+ }
+ TypeKind::ResolvedTypeRef(inner) => inner.to_rust_ty(ctx),
+ TypeKind::Alias(ref spelling, inner) => {
+ if item.is_opaque(ctx) {
+ // Pray if there's no available layout.
+ let layout = self.layout(ctx).unwrap_or_else(Layout::zero);
+ BlobTyBuilder::new(layout).build()
+ } else if let Some(ty) = utils::type_from_named(ctx, spelling, inner) {
+ ty
+ } else {
+ utils::build_templated_path(item, ctx, true)
+ }
+ }
+ TypeKind::Comp(ref info) => {
+ if item.is_opaque(ctx) || info.has_non_type_template_params() {
+ return match self.layout(ctx) {
+ Some(layout) => {
+ BlobTyBuilder::new(layout).build()
+ }
+ None => {
+ warn!("Couldn't compute layout for a type with non \
+ template params or opaque, expect dragons!");
+ aster::AstBuilder::new().ty().unit()
+ }
+ }
+ }
+
+ utils::build_templated_path(item, ctx, false)
+ }
+ TypeKind::Pointer(inner) |
+ TypeKind::Reference(inner) => {
+ let inner = ctx.resolve_item(inner);
+ inner.to_rust_ty(ctx).to_ptr(inner.expect_type().is_const(), ctx.span())
+ }
+ TypeKind::Named(..) => {
+ let name = item.canonical_name(ctx);
+ let ident = ctx.rust_ident(&name);
+ quote_ty!(ctx.ext_cx(), $ident)
+ }
+ ref u @ TypeKind::UnresolvedTypeRef(..)
+ => unreachable!("Should have been resolved after parsing {:?}!", u),
+ }
+ }
+}
+
+impl ToRustTy for FunctionSig {
+ type Extra = Item;
+
+ fn to_rust_ty(&self, ctx: &BindgenContext, _item: &Item) -> P<ast::Ty> {
+ // TODO: we might want to consider ignoring the reference return value.
+ let return_item = ctx.resolve_item(self.return_type());
+ let ret = if let TypeKind::Void = *return_item.kind().expect_type().kind() {
+ ast::FunctionRetTy::Default(ctx.span())
+ } else {
+ ast::FunctionRetTy::Ty(return_item.to_rust_ty(ctx))
+ };
+
+ let mut unnamed_arguments = 0;
+ let arguments = self.argument_types().iter().map(|&(ref name, ty)| {
+ let arg_item = ctx.resolve_item(ty);
+ let arg_ty = arg_item.kind().expect_type();
+
+ // From the C90 standard (http://c0x.coding-guidelines.com/6.7.5.3.html)
+ // 1598 - A declaration of a parameter as “array of type” shall be
+ // adjusted to “qualified pointer to type”, where the type qualifiers
+ // (if any) are those specified within the [ and ] of the array type
+ // derivation.
+ let arg_ty = if let TypeKind::Array(t, _) = *arg_ty.kind() {
+ t.to_rust_ty(ctx).to_ptr(arg_ty.is_const(), ctx.span())
+ } else {
+ arg_item.to_rust_ty(ctx)
+ };
+
+ let arg_name = match *name {
+ Some(ref name) => ctx.rust_mangle(name).into_owned(),
+ None => {
+ unnamed_arguments += 1;
+ format!("arg{}", unnamed_arguments)
+ }
+ };
+
+ assert!(!arg_name.is_empty());
+
+ ast::Arg {
+ ty: arg_ty,
+ pat: aster::AstBuilder::new().pat().id(arg_name),
+ id: ast::DUMMY_NODE_ID,
+ }
+ }).collect::<Vec<_>>();
+
+ let decl = P(ast::FnDecl {
+ inputs: arguments,
+ output: ret,
+ variadic: self.is_variadic(),
+ });
+
+ let fnty = ast::TyKind::BareFn(P(ast::BareFnTy {
+ unsafety: ast::Unsafety::Unsafe,
+ abi: self.abi(),
+ lifetimes: vec![],
+ decl: decl,
+ }));
+
+ P(ast::Ty {
+ id: ast::DUMMY_NODE_ID,
+ node: fnty,
+ span: ctx.span(),
+ })
+ }
+}
+
+impl CodeGenerator for Function {
+ type Extra = Item;
+
+ fn codegen(&self,
+ ctx: &BindgenContext,
+ result: &mut CodegenResult,
+ item: &Item) {
+ let name = self.name();
+ let canonical_name = item.canonical_name(ctx);
+
+ // TODO: Maybe warn here if there's a type/argument mismatch, or
+ // something?
+ if result.seen_function(&canonical_name) {
+ return;
+ }
+ result.saw_function(&canonical_name);
+
+ let signature_item = ctx.resolve_item(self.signature());
+ let signature = signature_item.kind().expect_type();
+ let signature = match *signature.kind() {
+ TypeKind::Function(ref sig) => sig,
+ _ => panic!("How?"),
+ };
+
+ let fndecl = utils::rust_fndecl_from_signature(ctx, signature_item);
+
+ let mut attributes = vec![];
+
+ if let Some(comment) = item.comment() {
+ attributes.push(attributes::doc(comment));
+ }
+
+ if let Some(mangled) = self.mangled_name() {
+ attributes.push(attributes::link_name(mangled));
+ } else if name != canonical_name {
+ attributes.push(attributes::link_name(name));
+ }
+
+ let foreign_item_kind =
+ ast::ForeignItemKind::Fn(fndecl, ast::Generics::default());
+
+ let foreign_item =
+ ast::ForeignItem {
+ ident: ctx.rust_ident_raw(&canonical_name),
+ attrs: attributes,
+ node: foreign_item_kind,
+ id: ast::DUMMY_NODE_ID,
+ span: ctx.span(),
+ vis: ast::Visibility::Public,
+ };
+
+ let item = ForeignModBuilder::new(signature.abi())
+ .with_foreign_item(foreign_item)
+ .build(ctx);
+
+ result.push(item);
+ }
+}
+
+type ItemSet = BTreeSet<ItemId>;
+
+trait TypeCollector {
+ type Extra;
+
+ fn collect_types(&self,
+ context: &BindgenContext,
+ types: &mut ItemSet,
+ extra: &Self::Extra);
+}
+
+impl TypeCollector for ItemId {
+ type Extra = ();
+
+ fn collect_types(&self,
+ context: &BindgenContext,
+ types: &mut ItemSet,
+ extra: &()) {
+ context.resolve_item(*self).collect_types(context, types, extra);
+ }
+}
+
+impl TypeCollector for Item {
+ type Extra = ();
+
+ fn collect_types(&self,
+ context: &BindgenContext,
+ types: &mut ItemSet,
+ _extra: &()) {
+ if self.is_hidden(context) || types.contains(&self.id()) {
+ return;
+ }
+
+ match *self.kind() {
+ ItemKind::Type(ref ty) => {
+ types.insert(self.id());
+ if !self.is_opaque(context) {
+ ty.collect_types(context, types, self);
+ }
+ }
+ _ => {}, // FIXME.
+ }
+ }
+}
+
+impl TypeCollector for Type {
+ type Extra = Item;
+
+ fn collect_types(&self,
+ context: &BindgenContext,
+ types: &mut ItemSet,
+ item: &Item) {
+ match *self.kind() {
+ TypeKind::Pointer(inner) |
+ TypeKind::Reference(inner) |
+ TypeKind::Array(inner, _) |
+ TypeKind::Alias(_, inner) |
+ TypeKind::Named(_, Some(inner)) |
+ TypeKind::ResolvedTypeRef(inner)
+ => inner.collect_types(context, types, &()),
+
+ TypeKind::TemplateRef(inner, ref template_args) => {
+ inner.collect_types(context, types, &());
+ for item in template_args {
+ item.collect_types(context, types, &());
+ }
+ }
+ TypeKind::Comp(ref ci) => ci.collect_types(context, types, item),
+ TypeKind::Function(ref sig) => {
+ sig.collect_types(context, types, item)
+ }
+ // FIXME: Pending types!
+ ref other @ _ => {
+ debug!("Ignoring: {:?}", other);
+ },
+ }
+ }
+}
+
+impl TypeCollector for FunctionSig {
+ type Extra = Item;
+
+ fn collect_types(&self,
+ context: &BindgenContext,
+ types: &mut ItemSet,
+ _item: &Item) {
+ self.return_type().collect_types(context, types, &());
+
+ for &(_, ty) in self.argument_types() {
+ ty.collect_types(context, types, &());
+ }
+ }
+}
+
+impl TypeCollector for CompInfo {
+ type Extra = Item;
+
+ fn collect_types(&self,
+ context: &BindgenContext,
+ types: &mut ItemSet,
+ item: &Item) {
+ if let Some(template) = self.specialized_template() {
+ template.collect_types(context, types, &());
+ }
+
+ let applicable_template_args = item.applicable_template_args(context);
+ for arg in applicable_template_args {
+ arg.collect_types(context, types, &());
+ }
+
+ for base in self.base_members() {
+ base.collect_types(context, types, &());
+ }
+
+ for field in self.fields() {
+ field.ty().collect_types(context, types, &());
+ }
+
+ for ty in self.inner_types() {
+ ty.collect_types(context, types, &());
+ }
+
+ // FIXME(emilio): Methods, VTable?
+ }
+}
+
+pub fn codegen(context: &mut BindgenContext) -> Vec<P<ast::Item>> {
+ context.gen(|context| {
+ let mut result = CodegenResult::new();
+
+ debug!("codegen: {:?}", context.options());
+
+ // If the whitelisted types and functions sets are empty, just generate
+ // everything.
+ if context.options().whitelisted_types.is_empty() &&
+ context.options().whitelisted_functions.is_empty() &&
+ context.options().whitelisted_vars.is_empty() {
+ for (_item_id, item) in context.items() {
+ // Non-toplevel item parents are the responsible one for generating
+ // them.
+ if item.is_toplevel(context) {
+ item.codegen(context, &mut result, &());
+ }
+ }
+ } else {
+ // Recursively collect all the types dependent on the whitelisted
+ // types, then generate them.
+ //
+ // FIXME(emilio): This pass is probably slow, but it can't be faster
+ // than docopt anyway :)
+ let mut items = ItemSet::new();
+ for (_item_id, item) in context.items() {
+ // FIXME(emilio): This probably should look only at whether the
+ // parent is a module.
+ if !item.is_toplevel(context) {
+ continue;
+ }
+
+ let name = item.canonical_name(context);
+ match *item.kind() {
+ ItemKind::Type(ref ty) => {
+ if context.options().whitelisted_types.matches(&name) {
+ item.collect_types(context, &mut items, &());
+ }
+ // Unnamed top-level enums are special and we whitelist
+ // them via the whitelisted_vars filter, since they're
+ // effectively top-level constants, and there's no way
+ // for them to be referenced consistently.
+ if let TypeKind::Enum(ref enum_) = *ty.kind() {
+ if ty.name().is_none() {
+ if enum_.variants().iter().any(|variant| {
+ context.options().whitelisted_vars.matches(&variant.name())
+ }) {
+ item.collect_types(context, &mut items, &());
+ }
+ }
+ }
+ }
+ ItemKind::Function(ref fun) => {
+ if context.options().whitelisted_functions.matches(&name) {
+ items.insert(item.id());
+ fun.signature().collect_types(context, &mut items, &());
+ }
+ }
+ ItemKind::Var(ref var) => {
+ if context.options().whitelisted_vars.matches(&name) {
+ items.insert(item.id());
+ var.ty().collect_types(context, &mut items, &());
+ }
+ }
+ ItemKind::Module(..) => {}
+ }
+ }
+
+ fn contains_parent(ctx: &BindgenContext, types: &ItemSet, id: ItemId) -> bool {
+ let item = ctx.resolve_item(id);
+ let mut last = id;
+ let mut current = item.parent_id();
+
+ while last != current {
+ if types.contains(&current) {
+ return true;
+ }
+ last = current;
+ current = ctx.resolve_item(current).parent_id();
+ }
+
+ false
+ }
+
+ for item_id in items.iter() {
+ let item = context.resolve_item(*item_id);
+ if item.is_toplevel(context) || !contains_parent(context, &items, *item_id) {
+ item.codegen(context, &mut result, &());
+ }
+ }
+ }
+ let saw_union = result.saw_union;
+ let mut result = result.items;
+ if saw_union {
+ utils::prepend_union_types(context, &mut result);
+ }
+ result
+ })
+}
+
+mod utils {
+ use ir::context::BindgenContext;
+ use ir::item::{Item, ItemCanonicalPath, ItemId};
+ use ir::ty::TypeKind;
+ use syntax::ast;
+ use syntax::ptr::P;
+ use std::mem;
+ use super::ItemToRustTy;
+ use aster;
+
+ pub fn prepend_union_types(ctx: &BindgenContext, result: &mut Vec<P<ast::Item>>) {
+ let union_field_decl = quote_item!(ctx.ext_cx(),
+ #[derive(Debug)]
+ #[repr(C)]
+ pub struct __BindgenUnionField<T>(::std::marker::PhantomData<T>);
+ ).unwrap();
+
+ let union_field_impl = quote_item!(&ctx.ext_cx(),
+ impl<T> __BindgenUnionField<T> {
+ #[inline]
+ pub fn new() -> Self {
+ __BindgenUnionField(::std::marker::PhantomData)
+ }
+
+ #[inline]
+ pub unsafe fn as_ref(&self) -> &T {
+ ::std::mem::transmute(self)
+ }
+
+ #[inline]
+ pub unsafe fn as_mut(&mut self) -> &mut T {
+ ::std::mem::transmute(self)
+ }
+ }
+ ).unwrap();
+
+ let union_field_default_impl = quote_item!(&ctx.ext_cx(),
+ impl<T> ::std::default::Default for __BindgenUnionField<T> {
+ #[inline]
+ fn default() -> Self {
+ Self::new()
+ }
+ }
+ ).unwrap();
+
+ let union_field_clone_impl = quote_item!(&ctx.ext_cx(),
+ impl<T> ::std::clone::Clone for __BindgenUnionField<T> {
+ #[inline]
+ fn clone(&self) -> Self {
+ Self::new()
+ }
+ }
+ ).unwrap();
+
+ let union_field_copy_impl = quote_item!(&ctx.ext_cx(),
+ impl<T> ::std::marker::Copy for __BindgenUnionField<T> {}
+ ).unwrap();
+
+ let items = vec![
+ union_field_decl, union_field_impl,
+ union_field_default_impl,
+ union_field_clone_impl,
+ union_field_copy_impl,
+ ];
+
+ let old_items = mem::replace(result, items);
+ result.extend(old_items.into_iter());
+ }
+
+
+ pub fn build_templated_path(item: &Item, ctx: &BindgenContext, only_named: bool) -> P<ast::Ty> {
+ let path = item.canonical_path(ctx);
+
+ let builder = aster::AstBuilder::new().ty().path();
+ let template_args = if only_named {
+ item.applicable_template_args(ctx).iter().filter(|arg| {
+ ctx.resolve_type(**arg).is_named()
+ }).map(|arg| {
+ arg.to_rust_ty(ctx)
+ }).collect::<Vec<_>>()
+ } else {
+ item.applicable_template_args(ctx).iter().map(|arg| {
+ arg.to_rust_ty(ctx)
+ }).collect::<Vec<_>>()
+ };
+
+ // XXX: I suck at aster.
+ if path.len() == 1 {
+ return builder.segment(&path[0])
+ .with_tys(template_args).build().build();
+ }
+
+ let mut builder = builder.id(&path[0]);
+ for (i, segment) in path.iter().skip(1).enumerate() {
+ // Take into account the skip(1)
+ builder = if i == path.len() - 2 {
+ // XXX Extra clone courtesy of the borrow checker.
+ builder.segment(&segment)
+ .with_tys(template_args.clone()).build()
+ } else {
+ builder.segment(&segment).build()
+ }
+ }
+
+ builder.build()
+ }
+
+ fn primitive_ty(ctx: &BindgenContext, name: &str) -> P<ast::Ty> {
+ let ident = ctx.rust_ident_raw(&name);
+ quote_ty!(ctx.ext_cx(), $ident)
+ }
+
+ pub fn type_from_named(ctx: &BindgenContext,
+ name: &str,
+ _inner: ItemId) -> Option<P<ast::Ty>> {
+ // FIXME: We could use the inner item to check this is really a
+ // primitive type but, who the heck overrides these anyway?
+ macro_rules! ty {
+ ($which:ident) => {{
+ primitive_ty(ctx, stringify!($which))
+ }}
+ }
+ Some(match name {
+ "int8_t" => ty!(i8),
+ "uint8_t" => ty!(u8),
+ "int16_t" => ty!(i16),
+ "uint16_t" => ty!(u16),
+ "int32_t" => ty!(i32),
+ "uint32_t" => ty!(u32),
+ "int64_t" => ty!(i64),
+ "uint64_t" => ty!(u64),
+
+ "uintptr_t" |
+ "size_t" => ty!(usize),
+
+ "intptr_t" |
+ "ptrdiff_t" |
+ "ssize_t" => ty!(isize),
+ _ => return None,
+ })
+ }
+
+ pub fn rust_fndecl_from_signature(ctx: &BindgenContext, sig: &Item) -> P<ast::FnDecl> {
+ use codegen::ToRustTy;
+
+ let signature = sig.kind().expect_type();
+ let signature = match *signature.kind() {
+ TypeKind::Function(ref sig) => sig,
+ _ => panic!("How?"),
+ };
+
+ let decl_ty = signature.to_rust_ty(ctx, sig);
+ match decl_ty.unwrap().node {
+ ast::TyKind::BareFn(bare_fn) => bare_fn.unwrap().decl,
+ _ => panic!("How did this happen exactly?"),
+ }
+ }
+}
diff --git a/src/gen.rs b/src/gen.rs
deleted file mode 100644
index eab4478a..00000000
--- a/src/gen.rs
+++ /dev/null
@@ -1,2364 +0,0 @@
-use std;
-use hacks::refcell::RefCell;
-use std::vec::Vec;
-use std::rc::Rc;
-use std::collections::HashMap;
-use syntax::abi::Abi;
-use syntax::ast;
-use syntax::codemap::{Span, respan, ExpnInfo, NameAndSpan, MacroBang};
-use syntax::ext::base;
-use syntax::ext::build::AstBuilder;
-use syntax::ext::expand::ExpansionConfig;
-use syntax::ext::quote::rt::ToTokens;
-use syntax::feature_gate::Features;
-use syntax::parse;
-use syntax::parse::token::{InternedString, intern};
-use syntax::attr::mk_attr_id;
-use syntax::ptr::P;
-use syntax::print::pprust::tts_to_string;
-
-use super::BindgenOptions;
-use super::LinkType;
-use parser::Accessor;
-use types::*;
-use aster;
-
-struct GenCtx<'r> {
- ext_cx: base::ExtCtxt<'r>,
- options: BindgenOptions,
- span: Span,
- module_map: ModuleMap,
- current_module_id: ModuleId,
- saw_union: bool,
-}
-
-impl<'r> GenCtx<'r> {
- fn full_path_for_module(&self, id: ModuleId) -> Vec<String> {
- if !self.options.enable_cxx_namespaces {
- return vec![];
- }
-
- let mut ret = vec![];
-
- let mut current_id = Some(id);
- while let Some(current) = current_id {
- let module = &self.module_map.get(&current).unwrap();
- ret.push(module.name.clone());
- current_id = module.parent_id;
- }
-
- if self.current_module_id == ROOT_MODULE_ID {
- ret.pop(); // The root module doens'n need a root:: in the pattern
- }
-
- ret.reverse();
- ret
- }
-
- fn current_module_mut(&mut self) -> &mut Module {
- let id = self.current_module_id;
- self.module_map.get_mut(&id).expect("Module not found!")
- }
-}
-
-fn first<A, B>((val, _): (A, B)) -> A {
- val
-}
-
-fn ref_eq<T>(thing: &T, other: &T) -> bool {
- (thing as *const T) == (other as *const T)
-}
-
-fn rust_id(ctx: &GenCtx, name: &str) -> (String, bool) {
- let token = parse::token::Ident(ctx.ext_cx.ident_of(name));
- if token.is_any_keyword() ||
- name.contains("@") ||
- name.contains("?") ||
- name.contains("$") ||
- "bool" == name
- {
- let mut s = name.to_owned();
- s = s.replace("@", "_");
- s = s.replace("?", "_");
- s = s.replace("$", "_");
- s.push_str("_");
- (s, true)
- } else {
- (name.to_owned(), false)
- }
-}
-
-fn rust_type_id(ctx: &GenCtx, name: &str) -> String {
- match name {
- "bool" | "uint" | "u8" | "u16" |
- "u32" | "f32" | "f64" | "i8" |
- "i16" | "i32" | "i64" | "Self" |
- "str" => {
- let mut s = name.to_owned();
- s.push_str("_");
- s
- }
- "int8_t" => "i8".to_owned(),
- "uint8_t" => "u8".to_owned(),
- "int16_t" => "i16".to_owned(),
- "uint16_t" => "u16".to_owned(),
- "int32_t" => "i32".to_owned(),
- "uint32_t" => "u32".to_owned(),
- "int64_t" => "i64".to_owned(),
- "uint64_t" => "u64".to_owned(),
- "uintptr_t"
- | "size_t" => "usize".to_owned(),
- "intptr_t"
- | "ptrdiff_t"
- | "ssize_t" => "isize".to_owned(),
- _ => first(rust_id(ctx, name))
- }
-}
-
-fn comp_name(ctx: &GenCtx, kind: CompKind, name: &str) -> String {
- match kind {
- CompKind::Struct => struct_name(ctx, name),
- CompKind::Union => union_name(ctx, name),
- }
-}
-
-fn struct_name(ctx: &GenCtx, name: &str) -> String {
- if ctx.options.rename_types {
- format!("Struct_{}", name)
- } else {
- name.to_owned()
- }
-}
-
-fn union_name(ctx: &GenCtx, name: &str) -> String {
- if ctx.options.rename_types {
- format!("Union_{}", name)
- } else {
- name.to_owned()
- }
-}
-
-fn enum_name(ctx: &GenCtx, name: &str) -> String {
- if ctx.options.rename_types {
- format!("Enum_{}", name)
- } else {
- name.to_owned()
- }
-}
-
-fn gen_unmangle_method(ctx: &mut GenCtx,
- v: &VarInfo,
- counts: &mut HashMap<String, isize>,
- self_kind: Option<ast::Mutability>)
- -> ast::ImplItem {
- let mut fndecl;
- let mut args = vec![];
-
- if let Some(mutability) = self_kind {
- let selfexpr = match mutability {
- ast::Mutability::Immutable => quote_expr!(&ctx.ext_cx, &*self),
- ast::Mutability::Mutable => quote_expr!(&ctx.ext_cx, &mut *self),
- };
- args.push(selfexpr);
- }
-
- match v.ty {
- TFuncPtr(ref sig) => {
- fndecl = cfuncty_to_rs(ctx,
- &*sig.ret_ty, sig.args.as_slice(),
- false);
- let mut unnamed: usize = 0;
- let iter = if !args.is_empty() {
- sig.args[1..].iter()
- } else {
- sig.args.iter()
- };
- for &(ref n, _) in iter {
- let argname = if n.is_empty() {
- unnamed += 1;
- format!("arg{}", unnamed)
- } else {
- first(rust_id(ctx, &n))
- };
- let expr = aster::AstBuilder::new().expr().path()
- .segment(&argname).build().build();
- args.push(expr);
- }
- },
- _ => unreachable!()
- };
-
-
- if let Some(mutability) = self_kind {
- assert!(!fndecl.inputs.is_empty());
- fndecl.inputs[0] = ast::Arg {
- ty: P(ast::Ty {
- id: ast::DUMMY_NODE_ID,
- node: ast::TyKind::Rptr(None, ast::MutTy {
- ty: P(ast::Ty {
- id: ast::DUMMY_NODE_ID,
- node: ast::TyKind::ImplicitSelf,
- span: ctx.span
- }),
- mutbl: mutability,
- }),
- span: ctx.span,
- }),
- pat: P(ast::Pat {
- id: ast::DUMMY_NODE_ID,
- node: ast::PatKind::Ident(ast::BindingMode::ByValue(ast::Mutability::Immutable),
- respan(ctx.span, ctx.ext_cx.ident_of("self")),
- None),
- span: ctx.span,
- }),
- id: ast::DUMMY_NODE_ID,
- };
- }
-
- let sig = ast::MethodSig {
- unsafety: ast::Unsafety::Unsafe,
- abi: Abi::Rust,
- decl: P(fndecl),
- generics: ast::Generics::default(),
- constness: ast::Constness::NotConst,
- };
-
- let mangled_rs = first(rust_id(ctx, &v.mangled));
- let call = P(ast::Expr {
- id: ast::DUMMY_NODE_ID,
- node: ast::ExprKind::Call(
- P(ast::Expr {
- id: ast::DUMMY_NODE_ID,
- node: ast::ExprKind::Path(None, ast::Path {
- span: ctx.span,
- global: false,
- segments: vec![ast::PathSegment {
- identifier: ctx.ext_cx.ident_of(&mangled_rs),
- parameters: ast::PathParameters::none()
- }]
- }),
- span: ctx.span,
- attrs: ast::ThinVec::new(),
- }),
- args
- ),
- span: ctx.span,
- attrs: ast::ThinVec::new(),
- });
-
- let block = ast::Block {
- stmts: vec![
- ast::Stmt {
- id: ast::DUMMY_NODE_ID,
- node: ast::StmtKind::Expr(call),
- span: ctx.span,
- }
- ],
- id: ast::DUMMY_NODE_ID,
- rules: ast::BlockCheckMode::Default,
- span: ctx.span
- };
-
- let mut name = v.name.clone();
- let mut count = 0;
- match counts.get(&v.name) {
- Some(x) => {
- count = *x;
- name.push_str(&x.to_string());
- },
- None => ()
- }
- count += 1;
- counts.insert(v.name.clone(), count);
-
- let mut attrs = mk_doc_attr(ctx, &v.comment);
- attrs.push(respan(ctx.span, ast::Attribute_ {
- id: mk_attr_id(),
- style: ast::AttrStyle::Outer,
- value: P(respan(ctx.span, ast::MetaItemKind::Word(InternedString::new("inline")))),
- is_sugared_doc: false
- }));
-
- let name = first(rust_id(ctx, &name));
-
- ast::ImplItem {
- id: ast::DUMMY_NODE_ID,
- ident: ctx.ext_cx.ident_of(&name),
- vis: ast::Visibility::Public,
- attrs: attrs,
- node: ast::ImplItemKind::Method(sig, P(block)),
- defaultness: ast::Defaultness::Final,
- span: ctx.span
- }
-}
-
-pub fn gen_mods(links: &[(String, LinkType)],
- map: ModuleMap,
- options: BindgenOptions,
- span: Span) -> Vec<P<ast::Item>> {
- // Create a dummy ExtCtxt. We only need this for string interning and that uses TLS.
- let mut features = Features::new();
- features.quote = true;
-
- let cfg = ExpansionConfig::default("xxx".to_owned());
- let sess = parse::ParseSess::new();
- let mut loader = base::DummyMacroLoader;
- let mut ctx = GenCtx {
- ext_cx: base::ExtCtxt::new(&sess, vec![], cfg, &mut loader),
- options: options,
- span: span,
- module_map: map,
- current_module_id: ROOT_MODULE_ID,
- saw_union: false,
- };
-
- ctx.ext_cx.bt_push(ExpnInfo {
- call_site: ctx.span,
- callee: NameAndSpan {
- format: MacroBang(intern("")),
- allow_internal_unstable: false,
- span: None
- }
- });
-
- if let Some(root_mod) = gen_mod(&mut ctx, ROOT_MODULE_ID, links, span) {
- // Move out of the pointer so we can mutate it
- let mut root_mod_item = root_mod.and_then(|item| item);
-
- gen_union_field_definitions_if_necessary(&mut ctx, &mut root_mod_item);
-
- if !ctx.options.enable_cxx_namespaces {
- match root_mod_item.node {
- // XXX This clone might be really expensive, but doing:
- ast::ItemKind::Mod(root) => {
- return root.items;
- }
- _ => unreachable!(),
- }
- }
-
- let ident = root_mod_item.ident;
- let root_export = quote_item!(&ctx.ext_cx, pub use $ident::*;).unwrap();
-
- vec![root_export, P(root_mod_item)]
- } else {
- vec![]
- }
-}
-
-fn gen_mod(mut ctx: &mut GenCtx,
- module_id: ModuleId,
- links: &[(String, LinkType)],
- span: Span) -> Option<P<ast::Item>> {
-
- // XXX avoid this clone
- let module = ctx.module_map.get(&module_id).unwrap().clone();
-
- // Import just the root to minimise name conflicts
- let mut globals = if module_id != ROOT_MODULE_ID {
- // XXX Pass this previously instead of looking it up always?
- let root_ident = ctx.ext_cx.ident_of(&ctx.module_map.get(&ROOT_MODULE_ID).unwrap().name);
- let root_use = quote_item!(&ctx.ext_cx, use $root_ident;).unwrap();
- vec![root_use]
- } else {
- vec![]
- };
-
- ctx.current_module_id = module_id;
-
- globals.extend(gen_globals(&mut ctx, links, &module.globals).into_iter());
-
- globals.extend(module.children_ids.iter().filter_map(|id| {
- gen_mod(ctx, *id, links, span.clone())
- }));
-
- if !globals.is_empty() {
- Some(P(ast::Item {
- ident: ctx.ext_cx.ident_of(&module.name),
- attrs: vec![],
- id: ast::DUMMY_NODE_ID,
- node: ast::ItemKind::Mod(ast::Mod {
- inner: span,
- items: globals,
- }),
- vis: ast::Visibility::Public,
- span: span.clone(),
- }))
- } else {
- None
- }
-}
-
-fn gen_global(mut ctx: &mut GenCtx,
- g: Global,
- defs: &mut Vec<P<ast::Item>>) {
- match g {
- GType(ti) => {
- let t = ti.borrow().clone();
- defs.extend(ctypedef_to_rs(&mut ctx, t).into_iter())
- },
- GCompDecl(ci) => {
- let mut c = ci.borrow().clone();
- let name = comp_name(&ctx, c.kind, &c.name);
- // Use the reference template if any
- while let Some(TComp(ref_template)) = c.ref_template.clone() {
- if c.name != ref_template.borrow().name {
- break;
- }
- c = ref_template.borrow().clone();
- }
- if !c.args.is_empty() &&
- !c.args.iter().any(|a| a.name().map(|name| name.is_empty()).unwrap_or(true)) {
- defs.extend(comp_to_rs(&mut ctx, &name, c).into_iter());
- } else {
- defs.push(opaque_to_rs(&mut ctx, &name, c.layout()));
- }
- },
- GComp(ci) => {
- let c = ci.borrow().clone();
- let name = comp_name(&ctx, c.kind, &c.name);
- defs.extend(comp_to_rs(&mut ctx, &name, c).into_iter())
- },
- GEnumDecl(ei) => {
- let e = ei.borrow().clone();
- let name = enum_name(&ctx, &e.name);
- let dummy = EnumItem::new("_BindgenOpaqueEnum".to_owned(), "".to_owned(), 0);
-
- defs.extend(cenum_to_rs(&mut ctx, &name, e.kind, e.comment, &[dummy], e.layout).into_iter())
- },
- GEnum(ei) => {
- let e = ei.borrow().clone();
- let name = enum_name(&ctx, &e.name);
- defs.extend(cenum_to_rs(&mut ctx, &name, e.kind, e.comment, &e.items, e.layout).into_iter())
- },
- GVar(vi) => {
- let v = vi.borrow();
- let ty = cty_to_rs(&mut ctx, &v.ty, v.is_const, true);
- defs.push(const_to_rs(&mut ctx, &v.name, v.val.unwrap(), ty));
- },
- _ => { }
- }
-}
-
-fn gen_globals(mut ctx: &mut GenCtx,
- links: &[(String, LinkType)],
- globs: &[Global]) -> Vec<P<ast::Item>> {
- let uniq_globs = tag_dup_decl(globs);
-
- let mut fs = vec![];
- let mut vs = vec![];
- let mut gs = vec![];
- for g in uniq_globs.into_iter() {
- match g {
- GOther => {}
- GFunc(_) => fs.push(g),
- GVar(_) => {
- let is_int_const = {
- match g {
- GVar(ref vi) => {
- let v = vi.borrow();
- v.is_const && v.val.is_some()
- }
- _ => unreachable!()
- }
- };
- if is_int_const {
- gs.push(g);
- } else {
- vs.push(g);
- }
- }
- _ => gs.push(g)
- }
- }
-
- let mut defs = vec![];
- gs = remove_redundant_decl(gs);
-
- for mut g in gs.into_iter() {
- if let Some(substituted) = ctx.current_module_mut().translations.remove(&g.name()) {
- match (substituted.layout(), g.layout()) {
- (Some(l), Some(lg)) if l.size == lg.size => {},
- (None, None) => {},
- _ => {
- warn!("warning: substituted type for {} does not match its size", g.name());
- }
- }
- g = substituted;
- }
-
- gen_global(ctx, g, &mut defs);
- }
-
- let mut pending_translations = std::mem::replace(&mut ctx.current_module_mut().translations, HashMap::new());
- for (name, g) in pending_translations.drain() {
- warn!("warning: generating definition for not found type: {}", name);
- gen_global(ctx, g, &mut defs);
- }
-
- let vars: Vec<_> = vs.into_iter().map(|v| {
- match v {
- GVar(vi) => {
- let v = vi.borrow();
- cvar_to_rs(&mut ctx, v.name.clone(), v.mangled.clone(), &v.ty, v.is_const)
- },
- _ => unreachable!()
- }
- }).collect();
-
- let mut unmangle_count: HashMap<String, isize> = HashMap::new();
- let funcs = {
- let func_list = fs.into_iter().map(|f| {
- match f {
- GFunc(vi) => {
- let v = vi.borrow();
- match v.ty {
- TFuncPtr(ref sig) => {
- let mut name = v.name.clone();
- let mut count = 0;
- match unmangle_count.get(&v.name) {
- Some(x) => {
- count = *x;
- name.push_str(&x.to_string());
- },
- None => ()
- }
- count += 1;
- unmangle_count.insert(v.name.clone(), count);
-
- let decl = cfunc_to_rs(&mut ctx, name, v.mangled.clone(), v.comment.clone(),
- &*sig.ret_ty, &sig.args[..],
- sig.is_variadic, ast::Visibility::Public);
- (sig.abi, decl)
- }
- _ => unreachable!()
- }
- },
- _ => unreachable!()
- }
- });
-
- let mut map: HashMap<Abi, Vec<_>> = HashMap::new();
- for (abi, func) in func_list {
- map.entry(abi).or_insert(vec![]).push(func);
- }
- map
- };
-
- if !vars.is_empty() {
- defs.push(mk_extern(&mut ctx, links, vars, Abi::C));
- }
-
- for (abi, funcs) in funcs.into_iter() {
- defs.push(mk_extern(&mut ctx, &links, funcs, abi));
- }
-
- //let attrs = vec!(mk_attr_list(&mut ctx, "allow", ["dead_code", "non_camel_case_types", "uppercase_variables"]));
-
- defs
-}
-
-fn mk_extern(ctx: &GenCtx, links: &[(String, LinkType)],
- foreign_items: Vec<ast::ForeignItem>,
- abi: Abi) -> P<ast::Item> {
- let attrs: Vec<_> = links.iter().map(|&(ref l, ref k)| {
- let k = match *k {
- LinkType::Default => None,
- LinkType::Static => Some("static"),
- LinkType::Framework => Some("framework")
- };
- let link_name = P(respan(ctx.span, ast::MetaItemKind::NameValue(
- InternedString::new("name"),
- respan(ctx.span, ast::LitKind::Str(intern(l).as_str(), ast::StrStyle::Cooked))
- )));
- let link_args = match k {
- None => vec!(link_name),
- Some(ref k) => vec!(link_name, P(respan(ctx.span, ast::MetaItemKind::NameValue(
- InternedString::new("kind"),
- respan(ctx.span, ast::LitKind::Str(intern(k).as_str(), ast::StrStyle::Cooked))
- ))))
- };
- respan(ctx.span, ast::Attribute_ {
- id: mk_attr_id(),
- style: ast::AttrStyle::Outer,
- value: P(respan(ctx.span, ast::MetaItemKind::List(
- InternedString::new("link"),
- link_args)
- )),
- is_sugared_doc: false
- })
- }).collect();
-
- let mut items = vec![];
- items.extend(foreign_items.into_iter());
- let ext = ast::ItemKind::ForeignMod(ast::ForeignMod {
- abi: abi,
- items: items
- });
-
- P(ast::Item {
- ident: ctx.ext_cx.ident_of(""),
- attrs: attrs,
- id: ast::DUMMY_NODE_ID,
- node: ext,
- vis: ast::Visibility::Inherited,
- span: ctx.span
- })
-}
-
-fn mk_impl(_ctx: &GenCtx, ty: P<ast::Ty>,
- items: Vec<ast::ImplItem>)
- -> P<ast::Item> {
- aster::AstBuilder::new().item().impl_().with_items(items).build_ty(ty)
-}
-
-fn remove_redundant_decl(gs: Vec<Global>) -> Vec<Global> {
- fn check_decl(a: &Global, ty: &Type) -> bool {
- match *a {
- GComp(ref ci1) => match *ty {
- TComp(ref ci2) => {
- ref_eq(ci1, ci2) && ci1.borrow().name.is_empty()
- },
- _ => false
- },
- GEnum(ref ei1) => match *ty {
- TEnum(ref ei2) => {
- ref_eq(ei1, ei2) && ei1.borrow().name.is_empty()
- },
- _ => false
- },
- _ => false
- }
- }
-
- let typedefs: Vec<Type> = gs.iter().filter_map(|g|
- match *g {
- GType(ref ti) => Some(ti.borrow().ty.clone()),
- _ => None
- }
- ).collect();
-
- gs.into_iter().filter(|g|
- !typedefs.iter().any(|t| check_decl(g, t))
- ).collect()
-}
-
-fn tag_dup_decl(gs: &[Global]) -> Vec<Global> {
- fn check(name1: &str, name2: &str) -> bool {
- !name1.is_empty() && name1 == name2
- }
-
- fn check_dup(g1: &Global, g2: &Global) -> bool {
- match (g1, g2) {
- (&GType(ref ti1), &GType(ref ti2)) => {
- let a = ti1.borrow();
- let b = ti2.borrow();
- check(&a.name, &b.name)
- },
- (&GComp(ref ci1), &GComp(ref ci2)) => {
- let a = ci1.borrow();
- let b = ci2.borrow();
- check(&a.name, &b.name)
- },
- (&GCompDecl(ref ci1), &GCompDecl(ref ci2)) => {
- let a = ci1.borrow();
- let b = ci2.borrow();
- check(&a.name, &b.name)
- },
- (&GEnum(ref ei1), &GEnum(ref ei2)) => {
- let a = ei1.borrow();
- let b = ei2.borrow();
- check(&a.name, &b.name)
- },
- (&GEnumDecl(ref ei1), &GEnumDecl(ref ei2)) => {
- let a = ei1.borrow();
- let b = ei2.borrow();
- check(&a.name, &b.name)
- },
- (&GVar(ref vi1), &GVar(ref vi2)) => {
- let a = vi1.borrow();
- let b = vi2.borrow();
- check(&a.name, &b.name) &&
- check(&a.mangled, &b.mangled)
- },
- (&GFunc(ref vi1), &GFunc(ref vi2)) => {
- let a = vi1.borrow();
- let b = vi2.borrow();
- check(&a.name, &b.name) &&
- check(&a.mangled, &b.mangled)
- },
- _ => false
- }
- }
-
- fn check_opaque_dup(g1: &Global, g2: &Global) -> bool {
- match (g1, g2) {
- (&GCompDecl(ref ci1), &GComp(ref ci2)) => {
- let a = ci1.borrow();
- let b = ci2.borrow();
- check(&a.name, &b.name)
- },
- (&GEnumDecl(ref ei1), &GEnum(ref ei2)) => {
- let a = ei1.borrow();
- let b = ei2.borrow();
- check(&a.name, &b.name)
- },
- _ => false,
- }
- }
-
- if gs.is_empty() {
- return vec![];
- }
-
- let mut step: Vec<Global> = vec![];
- step.push(gs[0].clone());
-
- for (i, _gsi) in gs.iter().enumerate().skip(1) {
- let mut dup = false;
- for j in 0..i {
- if i == j {
- continue;
- }
- if check_dup(&gs[i], &gs[j]) {
- dup = true;
- break;
- }
- }
- if !dup {
- step.push(gs[i].clone());
- }
- }
-
- let len = step.len();
- let mut res: Vec<Global> = vec![];
- for i in 0..len {
- let mut dup = false;
- match &step[i] {
- &GCompDecl(_) | &GEnumDecl(_) => {
- for j in 0..len {
- if i == j {
- continue;
- }
- if check_opaque_dup(&step[i], &step[j]) {
- dup = true;
- break;
- }
- }
- },
- _ => (),
- }
-
- if !dup {
- res.push(step[i].clone());
- }
- }
-
- res
-}
-
-fn ctypedef_to_rs(ctx: &mut GenCtx, ty: TypeInfo) -> Vec<P<ast::Item>> {
- fn mk_item(ctx: &GenCtx, name: &str, comment: &str, ty: &Type) -> P<ast::Item> {
- let rust_name = rust_type_id(ctx, name);
- let rust_ty = if cty_is_translatable(ty) {
- cty_to_rs(ctx, ty, true, true)
- } else {
- cty_to_rs(ctx, &TVoid, true, true)
- };
- aster::AstBuilder::new().item().pub_()
- .with_attrs(mk_doc_attr(ctx, comment))
- .type_(&rust_name).build_ty(P(rust_ty))
- }
-
- if ty.hide {
- return vec![];
- }
-
- if ty.opaque {
- return mk_opaque_struct(ctx, &ty.name, &ty.layout);
- }
-
- let item = match ty.ty {
- TComp(ref ci) => {
- assert!(!ci.borrow().name.is_empty());
- mk_item(ctx, &ty.name, &ty.comment, &ty.ty)
- },
- TEnum(ref ei) => {
- assert!(!ei.borrow().name.is_empty());
- mk_item(ctx, &ty.name, &ty.comment, &ty.ty)
- },
- _ => mk_item(ctx, &ty.name, &ty.comment, &ty.ty),
- };
-
- vec![item]
-}
-
-fn comp_to_rs(ctx: &mut GenCtx, name: &str, ci: CompInfo)
- -> Vec<P<ast::Item>> {
- if ci.hide {
- return vec![];
- }
-
- if ci.opaque {
- let name = first(rust_id(ctx, &ci.name));
- return mk_opaque_struct(ctx, &name, &ci.layout());
- }
-
- if ci.has_non_type_template_params ||
- ci.args.iter().any(|f| f == &TVoid) {
- return vec![];
- }
-
- let mut template_args_used = vec![false; ci.args.len()];
-
- match ci.kind {
- CompKind::Struct => cstruct_to_rs(ctx, name, ci, &mut template_args_used),
- CompKind::Union => cunion_to_rs(ctx, name, ci, &mut template_args_used),
- }
-}
-
-fn comp_attrs(ctx: &GenCtx, ci: &CompInfo, name: &str, extra: &mut Vec<P<ast::Item>>) -> Vec<ast::Attribute> {
- let mut attrs = mk_doc_attr(ctx, &ci.comment);
- attrs.push(mk_repr_attr(ctx, &ci.layout()));
- let mut derives = vec![];
-
- if ci.can_derive_debug() && ctx.options.derive_debug {
- derives.push("Debug");
- }
-
- if ci.has_destructor() {
- for attr in ctx.options.dtor_attrs.iter() {
- let attr = ctx.ext_cx.ident_of(attr);
- attrs.push(quote_attr!(&ctx.ext_cx, #[$attr]));
- }
- }
-
- if ci.can_derive_copy() {
- derives.push("Copy");
-
- // TODO: make mk_clone_impl work for template arguments,
- // meanwhile just fallback to deriving.
- if ci.args.is_empty() {
- extra.push(mk_clone_impl(ctx, name));
- } else {
- derives.push("Clone");
- }
- }
-
- if !derives.is_empty() {
- attrs.push(mk_deriving_attr(ctx, &derives));
- }
-
- attrs
-}
-
-fn gen_accessors(ctx: &mut GenCtx, name: &str, ty: &ast::Ty, accessor: Accessor,
- methods: &mut Vec<ast::ImplItem>) {
- if accessor == Accessor::None {
- return;
- }
- let ident = ctx.ext_cx.ident_of(&format!("{}", name));
- let mutable_getter_name = ctx.ext_cx.ident_of(&format!("get_{}_mut", name));
- let getter_name = ctx.ext_cx.ident_of(&format!("get_{}", name));
- let imp = match accessor {
- Accessor::Regular => quote_item!(&ctx.ext_cx,
- impl X {
- #[inline]
- pub fn $getter_name(&self) -> & $ty {
- & self.$ident
- }
- pub fn $mutable_getter_name(&mut self) -> &mut $ty {
- &mut self.$ident
- }
- }
- ),
- Accessor::Unsafe => quote_item!(&ctx.ext_cx,
- impl X {
- #[inline]
- pub unsafe fn $getter_name(&self) -> & $ty {
- & self.$ident
- }
- pub unsafe fn $mutable_getter_name(&mut self) -> &mut $ty {
- &mut self.$ident
- }
- }
- ),
- Accessor::Immutable => quote_item!(&ctx.ext_cx,
- impl X {
- #[inline]
- pub fn $getter_name(&self) -> & $ty {
- & self.$ident
- }
- }
- ),
- _ => return
- };
- match imp.unwrap().node {
- ast::ItemKind::Impl(_, _, _, _, _, ref items) => methods.extend(items.clone()),
- _ => unreachable!()
- }
-}
-
-fn add_extra_template_fields_if_needed(ctx: &GenCtx,
- template_args: &[Type],
- template_args_used: &[bool],
- fields: &mut Vec<ast::StructField>) {
- let mut phantom_count = 0;
- for (i, arg) in template_args.iter().enumerate() {
- if template_args_used[i] {
- continue;
- }
-
- let f_name = format!("_phantom{}", phantom_count);
- phantom_count += 1;
- let inner_type = P(cty_to_rs(ctx, &arg, true, false));
-
- fields.push(ast::StructField {
- span: ctx.span,
- ident: Some(ctx.ext_cx.ident_of(&f_name)),
- vis: ast::Visibility::Public,
- id: ast::DUMMY_NODE_ID,
- ty: quote_ty!(&ctx.ext_cx, ::std::marker::PhantomData<$inner_type>),
- attrs: vec![],
- });
- }
-}
-
-fn cstruct_to_rs(ctx: &mut GenCtx, name: &str, ci: CompInfo,
- template_args_used: &mut [bool]) -> Vec<P<ast::Item>> {
- let layout = ci.layout();
- let members = &ci.members;
- let template_args = &ci.args;
- let methodlist = &ci.methods;
- let mut fields = vec![];
- let mut methods = vec![];
- // Nested composites may need to emit declarations and implementations as
- // they are encountered. The declarations end up in 'extra' and are emitted
- // after the current struct.
- let mut extra = vec![];
- let mut unnamed: u32 = 0;
- let mut bitfields: u32 = 0;
-
- let id = rust_type_id(ctx, name);
- let id_ty = P(mk_ty(ctx, false, &[id.clone()]));
-
- if ci.has_vtable {
- let mut vffields = vec![];
- let base_vftable = match members.get(0) {
- Some(&CompMember::Field(FieldInfo { ty: TComp(ref ci2), .. })) => {
- let ci2 = ci2.borrow();
- if ci2.has_vtable {
- Some(format!("_vftable_{}", ci2.name))
- } else {
- None
- }
- },
- _ => None,
- };
-
- if let Some(ref base) = base_vftable {
- let field = ast::StructField {
- span: ctx.span,
- vis: ast::Visibility::Public,
- ident: Some(ctx.ext_cx.ident_of("_base")),
- id: ast::DUMMY_NODE_ID,
- ty: P(mk_ty(ctx, false, &[base.clone()])),
- attrs: vec![],
- };
- vffields.push(field);
- }
-
- let mut counts: HashMap<String, isize> = HashMap::new();
- for vm in ci.vmethods.iter() {
- let ty = match vm.ty {
- TFuncPtr(ref sig) => {
- let decl = cfuncty_to_rs(ctx, &*sig.ret_ty, sig.args.as_slice(), sig.is_variadic);
- mk_fn_proto_ty(ctx, &decl, sig.abi)
- },
- _ => unreachable!()
- };
-
- let mut name = vm.name.clone();
- let mut count = 0;
- match counts.get(&vm.name) {
- Some(x) => {
- count = *x;
- name.push_str(&x.to_string());
- },
- None => ()
- }
- count += 1;
- counts.insert(vm.name.clone(), count);
-
- let name = first(rust_id(ctx, &name));
-
- vffields.push(ast::StructField {
- span: ctx.span,
- vis: ast::Visibility::Public,
- ident: Some(ctx.ext_cx.ident_of(&name)),
- id: ast::DUMMY_NODE_ID,
- ty: P(ty),
- attrs: vec![],
- });
- }
-
- // FIXME: rustc actually generates tons of warnings
- // due to an empty repr(C) type, so we just generate
- // a dummy field with pointer-alignment to supress it.
- if vffields.is_empty() {
- vffields.push(mk_blob_field(ctx, "_bindgen_empty_ctype_warning_fix",
- &Layout::new(::std::mem::size_of::<*mut ()>(), ::std::mem::align_of::<*mut ()>())));
- }
-
- let vf_name = format!("_vftable_{}", name);
- let item = aster::AstBuilder::new().item()
- .with_attr(mk_repr_attr(ctx, &layout))
- .pub_()
- .struct_(&vf_name)
- .with_fields(vffields).build();
-
- extra.push(item);
-
- if base_vftable.is_none() {
- let vf_type = mk_ty(ctx, false, &[vf_name]);
- fields.push(ast::StructField {
- span: ctx.span,
- ident: Some(ctx.ext_cx.ident_of("_vftable")),
- vis: ast::Visibility::Public,
- id: ast::DUMMY_NODE_ID,
- ty: P(mk_ptrty(ctx, &vf_type, true)),
- attrs: vec![]
- });
- }
- }
-
- let mut anon_enum_count = 0;
- let mut setters = vec![];
-
- for m in members.iter() {
- match *m {
- CompMember::Enum(ref ei) => {
- let empty_name = ei.borrow().name.is_empty();
- if empty_name {
- ei.borrow_mut().name = format!("{}_enum{}", name, anon_enum_count);
- anon_enum_count += 1;
- }
-
- let e = ei.borrow().clone();
- extra.extend(cenum_to_rs(ctx, &e.name, e.kind, e.comment, &e.items, e.layout).into_iter());
- }
- CompMember::Field(ref f) => {
- let f_name = match f.bitfields {
- Some(_) => {
- bitfields += 1;
- format!("_bitfield_{}", bitfields)
- }
- None => rust_type_id(ctx, &f.name)
- };
-
- let is_translatable = cty_is_translatable(&f.ty);
- if !is_translatable || f.ty.is_opaque() {
- if !is_translatable {
- warn!("{}::{} not translatable, void: {}", ci.name, f.name, f.ty == TVoid);
- }
- if let Some(layout) = f.ty.layout() {
- fields.push(mk_blob_field(ctx, &f_name, &layout));
- }
- continue;
- }
-
- if ctx.options.gen_bitfield_methods {
- let mut offset: u32 = 0;
- if let Some(ref bitfields) = f.bitfields {
- for &(ref bf_name, bf_size) in bitfields.iter() {
- setters.extend(gen_bitfield_methods(ctx, &f_name, bf_name, &f.ty, offset as usize, bf_size).into_iter());
- offset += bf_size;
- }
- setters.push(gen_fullbitfield_method(ctx, &f_name, &f.ty, bitfields))
- }
- }
-
- // If the member is not a template argument, it needs the full path.
- let mut needs_full_path = true;
- for (index, arg) in template_args.iter().enumerate() {
- let used = f.ty.signature_contains_type(arg);
-
- if used {
- template_args_used[index] = true;
- needs_full_path = *arg == f.ty || match f.ty {
- TPtr(ref t, _, _, _) => **t != *arg,
- TArray(ref t, _, _) => **t != *arg,
- _ => true,
- };
- break;
- }
- }
-
- let rust_ty = P(cty_to_rs(ctx, &f.ty, f.bitfields.is_none(), needs_full_path));
-
- // Wrap mutable fields in a Cell/UnsafeCell
- let rust_ty = if f.mutable {
- if !f.ty.can_derive_copy() {
- quote_ty!(&ctx.ext_cx, ::std::cell::UnsafeCell<$rust_ty>)
- // We can only wrap in a cell for non-copiable types, since
- // Cell<T>: Clone, but not Copy.
- //
- // It's fine though, since mutating copiable types is trivial
- // and doesn't make a lot of sense marking fields as `mutable`.
- } else if !ci.can_derive_copy() {
- quote_ty!(&ctx.ext_cx, ::std::cell::Cell<$rust_ty>)
- } else {
- rust_ty
- }
- } else {
- rust_ty
- };
- let vis = if f.private {
- ast::Visibility::Inherited
- } else {
- ast::Visibility::Public
- };
- gen_accessors(ctx, &f_name, &rust_ty, f.accessor, &mut methods);
- let field = ast::StructField {
- span: ctx.span,
- ident: Some(ctx.ext_cx.ident_of(&f_name)),
- vis: vis,
- id: ast::DUMMY_NODE_ID,
- ty: rust_ty,
- attrs: mk_doc_attr(ctx, &f.comment)
- };
- fields.push(field);
- }
- CompMember::Comp(ref rc_c) => {
- let name_is_empty = rc_c.borrow().name.is_empty();
-
- if name_is_empty {
- let c = rc_c.borrow();
- unnamed += 1;
- let field_name = format!("_bindgen_data_{}_", unnamed);
- fields.push(mk_blob_field(ctx, &field_name, &c.layout()));
- methods.extend(gen_comp_methods(ctx, &field_name, 0, c.kind, &c.members, &mut extra).into_iter());
- } else {
- let name = comp_name(&ctx, rc_c.borrow().kind, &rc_c.borrow().name);
- extra.extend(comp_to_rs(ctx, &name, rc_c.borrow().clone()).into_iter());
- }
- }
- }
- }
-
- add_extra_template_fields_if_needed(ctx, template_args,
- template_args_used,
- &mut fields);
-
- if !setters.is_empty() {
- extra.push(mk_impl(ctx, id_ty.clone(), setters));
- }
-
- let field_count = fields.len();
- let variant_data = if fields.is_empty() {
- ast::VariantData::Unit(ast::DUMMY_NODE_ID)
- } else {
- ast::VariantData::Struct(fields, ast::DUMMY_NODE_ID)
- };
-
- let ty_params = mk_ty_params(ctx, &template_args);
-
- let def = ast::ItemKind::Struct(
- variant_data,
- ast::Generics {
- lifetimes: vec![],
- ty_params: P::from_vec(ty_params),
- where_clause: ast::WhereClause {
- id: ast::DUMMY_NODE_ID,
- predicates: vec![]
- }
- }
- );
-
- let attrs = comp_attrs(&ctx, &ci, name, &mut extra);
-
- let struct_def = ast::Item {
- ident: ctx.ext_cx.ident_of(&id),
- attrs: attrs,
- id: ast::DUMMY_NODE_ID,
- node: def,
- vis: ast::Visibility::Public,
- span: ctx.span
- };
-
- let mut items = vec![P(struct_def)];
- if !methods.is_empty() {
- items.push(mk_impl(ctx, id_ty.clone(), methods));
- }
-
- // Template args have incomplete type in general
- //
- // XXX if x is a class without members, C++ still will report
- // sizeof(x) == 1, since it requires to be adressable.
- //
- // We maybe should add a dummy byte if it's the case, but...
- // That could play wrong with inheritance.
- //
- // So for now don't generate a test if the struct/class is empty
- // or has only empty bases.
- if ci.args.is_empty() && field_count > 0 &&
- (ci.has_nonempty_base || ci.base_members < field_count) {
- extra.push(mk_test_fn(ctx, name, &layout));
- }
-
- items.extend(extra.into_iter());
-
- let mut mangledlist = vec![];
- let mut unmangledlist = vec![];
- let mut unmangle_count: HashMap<String, isize> = HashMap::new();
- for v in methodlist {
- let v = v.clone();
- match v.ty {
- TFuncPtr(ref sig) => {
- let name = v.mangled.clone();
- let explicit_self = if v.is_static {
- None
- } else if v.is_const {
- Some(ast::Mutability::Immutable)
- } else {
- Some(ast::Mutability::Mutable)
- };
- unmangledlist.push(gen_unmangle_method(ctx, &v, &mut unmangle_count, explicit_self));
- mangledlist.push(cfunc_to_rs(ctx, name, String::new(), String::new(),
- &*sig.ret_ty, sig.args.as_slice(),
- sig.is_variadic, ast::Visibility::Inherited));
- }
- _ => unreachable!()
- }
- }
- if !mangledlist.is_empty() {
- items.push(mk_extern(ctx, &[], mangledlist, Abi::C));
- items.push(mk_impl(ctx, id_ty, unmangledlist));
- }
-
- if !ci.vars.is_empty() && template_args.is_empty() {
- let vars = ci.vars.into_iter().map(|v| {
- let vi = v.varinfo();
- let v = vi.borrow_mut();
- let mut var_name = v.name.clone();
- if !v.mangled.is_empty() {
- var_name = format!("{}_consts_{}", name, v.name);
- }
- cvar_to_rs(ctx, var_name, v.mangled.clone(), &v.ty, v.is_const)
- }).collect();
-
- items.push(mk_extern(ctx, &[], vars, Abi::C));
- }
- items
-}
-
-fn opaque_to_rs(ctx: &mut GenCtx, name: &str, _layout: Layout) -> P<ast::Item> {
- // XXX can't repr(C) an empty enum
- let id = rust_type_id(ctx, name);
- let ident = ctx.ext_cx.ident_of(&id);
- quote_item!(&ctx.ext_cx, pub enum $ident {}).unwrap()
-}
-
-fn cunion_to_rs(ctx: &mut GenCtx, name: &str, ci: CompInfo,
- template_args_used: &mut [bool]) -> Vec<P<ast::Item>> {
- const UNION_DATA_FIELD_NAME: &'static str = "_bindgen_data_";
-
- ctx.saw_union = true;
-
- let members = &ci.members;
- let layout = ci.layout();
-
- fn mk_item(ctx: &GenCtx, name: &str, item: ast::ItemKind, vis:
- ast::Visibility, attrs: Vec<ast::Attribute>) -> P<ast::Item> {
- P(ast::Item {
- ident: ctx.ext_cx.ident_of(name),
- attrs: attrs,
- id: ast::DUMMY_NODE_ID,
- node: item,
- vis: vis,
- span: ctx.span
- })
- }
-
- let tmp_ci = Rc::new(RefCell::new(ci.clone()));
- let union = TComp(tmp_ci);
-
-
- // Nested composites may need to emit declarations and implementations as
- // they are encountered. The declarations end up in 'extra' and are emitted
- // after the current union.
- let mut extra = vec![];
-
- fn mk_union_field(ctx: &GenCtx, name: &str, ty: ast::Ty) -> ast::StructField {
- let field_ty = if !ctx.options.enable_cxx_namespaces ||
- ctx.current_module_id == ROOT_MODULE_ID {
- quote_ty!(&ctx.ext_cx, __BindgenUnionField<$ty>)
- } else {
- quote_ty!(&ctx.ext_cx, root::__BindgenUnionField<$ty>)
- };
-
- ast::StructField {
- span: ctx.span,
- ident: Some(ctx.ext_cx.ident_of(name)),
- vis: ast::Visibility::Public,
- id: ast::DUMMY_NODE_ID,
- ty: field_ty,
- attrs: vec![],
- }
- }
-
- let mut fields =
- members.iter().flat_map(|member| {
- if let CompMember::Field(ref f) = *member {
- let mut needs_full_path = true;
- for (index, arg) in ci.args.iter().enumerate() {
- let used = f.ty.signature_contains_type(arg);
-
- if used {
- template_args_used[index] = true;
- needs_full_path = *arg == f.ty || match f.ty {
- TPtr(ref t, _, _, _) => **t != *arg,
- TArray(ref t, _, _) => **t != *arg,
- _ => true,
- };
- break;
- }
- }
-
- let cty = cty_to_rs(ctx, &f.ty, false, needs_full_path);
- Some(mk_union_field(ctx, &f.name, cty))
- } else {
- None
- }
- }).collect::<Vec<_>>();
-
- fields.push(mk_blob_field(ctx, UNION_DATA_FIELD_NAME, &layout));
-
- add_extra_template_fields_if_needed(ctx, &ci.args,
- template_args_used,
- &mut fields);
-
- let ty_params = mk_ty_params(ctx, &ci.args);
-
- let generics = ast::Generics {
- lifetimes: vec![],
- ty_params: P::from_vec(ty_params),
- where_clause: ast::WhereClause {
- id: ast::DUMMY_NODE_ID,
- predicates: vec![]
- }
- };
-
- // TODO: use aster here.
- let def = ast::ItemKind::Struct(
- ast::VariantData::Struct(fields, ast::DUMMY_NODE_ID),
- generics.clone()
- );
-
- let union_id = rust_type_id(ctx, name);
-
- let union_attrs = comp_attrs(&ctx, &ci, name, &mut extra);
-
- if ci.args.is_empty() {
- extra.push(mk_test_fn(ctx, &name, &layout));
- }
-
- let union_def = mk_item(ctx, &union_id, def, ast::Visibility::Public, union_attrs);
- let union_impl = ast::ItemKind::Impl(
- ast::Unsafety::Normal,
- ast::ImplPolarity::Positive,
- generics,
- None,
- P(cty_to_rs(ctx, &union, true, true)),
- gen_comp_methods(ctx, UNION_DATA_FIELD_NAME, 0, CompKind::Union, &members, &mut extra),
- );
- let mut items = vec!(
- union_def,
- mk_item(ctx, "", union_impl, ast::Visibility::Inherited, vec![])
- );
-
- items.extend(extra.into_iter());
- items
-}
-
-fn const_to_rs(ctx: &mut GenCtx, name: &str, val: i64, val_ty: ast::Ty) -> P<ast::Item> {
- let id = first(rust_id(ctx, name));
- aster::AstBuilder::new().item().pub_().const_(&id)
- .expr().int(val)
- .ty().build(P(val_ty))
-}
-
-fn enum_size_to_unsigned_max_value(size: usize) -> u64 {
- match size {
- 1 => std::u8::MAX as u64,
- 2 => std::u16::MAX as u64,
- 4 => std::u32::MAX as u64,
- 8 => std::u64::MAX,
- _ => unreachable!("invalid enum size: {}", size)
- }
-}
-
-fn enum_size_to_rust_type_name(signed: bool, size: usize) -> &'static str {
- match (signed, size) {
- (true, 1) => "i8",
- (false, 1) => "u8",
- (true, 2) => "i16",
- (false, 2) => "u16",
- (true, 4) => "i32",
- (false, 4) => "u32",
- (true, 8) => "i64",
- (false, 8) => "u64",
- _ => {
- warn!("invalid enum decl: signed: {}, size: {}", signed, size);
- "i32"
- }
- }
-}
-
-fn cenum_value_to_int_lit(ctx: &mut GenCtx,
- enum_is_signed: bool,
- size: usize,
- value: i64) -> P<ast::Expr> {
- if enum_is_signed {
- if value == std::i64::MIN {
- let lit = ast::LitKind::Int(std::u64::MAX, ast::LitIntType::Unsuffixed);
- ctx.ext_cx.expr_lit(ctx.span, lit)
- } else {
- let lit = ast::LitKind::Int(value.abs() as u64, ast::LitIntType::Unsuffixed);
- let expr = ctx.ext_cx.expr_lit(ctx.span, lit);
- if value < 0 {
- ctx.ext_cx.expr(ctx.span, ast::ExprKind::Unary(ast::UnOp::Neg, expr))
- } else {
- expr
- }
- }
- } else {
- let u64_value = value as u64 & enum_size_to_unsigned_max_value(size);
- let int_lit = ast::LitKind::Int(u64_value, ast::LitIntType::Unsuffixed);
- ctx.ext_cx.expr_lit(ctx.span, int_lit)
- }
-}
-
-fn cenum_to_rs(ctx: &mut GenCtx,
- name: &str,
- kind: IKind,
- comment: String,
- enum_items: &[EnumItem],
- layout: Layout) -> Vec<P<ast::Item>> {
- let enum_name = ctx.ext_cx.ident_of(name);
- let enum_ty = ctx.ext_cx.ty_ident(ctx.span, enum_name);
- let enum_is_signed = kind.is_signed();
- let enum_repr = enum_size_to_rust_type_name(enum_is_signed, layout.size);
-
- let mut items = vec![];
-
- if !ctx.options.rust_enums {
- items.push(ctx.ext_cx.item_ty(ctx.span,
- enum_name,
- ctx.ext_cx.ty_ident(ctx.span,
- ctx.ext_cx.ident_of(enum_repr))));
- for item in enum_items {
- let value = cenum_value_to_int_lit(ctx, enum_is_signed, layout.size, item.val);
- let name = first(rust_id(ctx, &item.name));
- items.push(ctx.ext_cx.item_const(ctx.span, ctx.ext_cx.ident_of(&name), enum_ty.clone(), value));
- }
- return items;
- }
-
- let mut variants = vec![];
- let mut found_values = HashMap::new();
- for item in enum_items {
- let name = first(rust_id(ctx, &item.name));
- let name = ctx.ext_cx.ident_of(&name);
- if let Some(orig) = found_values.get(&item.val) {
- let value = ctx.ext_cx.expr_path(
- ctx.ext_cx.path(ctx.span, vec![enum_name, *orig]));
- items.push(P(ast::Item {
- ident: name,
- attrs: vec![],
- id: ast::DUMMY_NODE_ID,
- node: ast::ItemKind::Const(enum_ty.clone(), value),
- vis: ast::Visibility::Public,
- span: ctx.span,
- }));
- continue;
- }
-
- found_values.insert(item.val, name);
- let value = cenum_value_to_int_lit(
- ctx, enum_is_signed, layout.size, item.val);
-
- variants.push(respan(ctx.span, ast::Variant_ {
- name: name,
- attrs: vec![],
- data: ast::VariantData::Unit(ast::DUMMY_NODE_ID),
- disr_expr: Some(value),
- }));
- }
-
- let enum_repr = InternedString::new(enum_repr);
-
- let repr_arg = ctx.ext_cx.meta_word(ctx.span, enum_repr);
- let repr_list = ctx.ext_cx.meta_list(ctx.span, InternedString::new("repr"), vec![repr_arg]);
-
- let mut attrs = mk_doc_attr(ctx, &comment);
- attrs.push(respan(ctx.span, ast::Attribute_ {
- id: mk_attr_id(),
- style: ast::AttrStyle::Outer,
- value: repr_list,
- is_sugared_doc: false,
- }));
-
- attrs.push(if ctx.options.derive_debug {
- mk_deriving_attr(ctx, &["Debug", "Copy", "Clone", "Eq", "PartialEq", "Hash"])
- } else {
- mk_deriving_attr(ctx, &["Copy", "Clone", "Eq", "PartialEq", "Hash"])
- });
-
- items.push(P(ast::Item {
- ident: enum_name,
- attrs: attrs,
- id: ast::DUMMY_NODE_ID,
- node: ast::ItemKind::Enum(ast::EnumDef { variants: variants }, ast::Generics::default()),
- vis: ast::Visibility::Public,
- span: ctx.span,
- }));
-
- items
-}
-
-/// Generates accessors for fields in nested structs and unions which must be
-/// represented in Rust as an untyped array. This process may generate
-/// declarations and implementations that must be placed at the root level.
-/// These are emitted into `extra`.
-fn gen_comp_methods(ctx: &mut GenCtx, data_field: &str, data_offset: usize,
- kind: CompKind, members: &[CompMember],
- extra: &mut Vec<P<ast::Item>>) -> Vec<ast::ImplItem> {
- let mk_field_method = |ctx: &mut GenCtx, f: &FieldInfo, offset: usize| {
- // TODO: Implement bitfield accessors
- if f.bitfields.is_some() { return None; }
-
- let f_name = first(rust_id(ctx, &f.name));
- let ret_ty = P(cty_to_rs(ctx, &TPtr(Box::new(f.ty.clone()), false, false, Layout::zero()), true, true));
-
- // When the offset is zero, generate slightly prettier code.
- let method = {
- let impl_str = format!(r"
- impl X {{
- pub unsafe fn {}(&mut self) -> {} {{
- let raw: *mut u8 = ::std::mem::transmute(&self.{});
- ::std::mem::transmute(raw.offset({}))
- }}
- }}
- ", f_name, tts_to_string(&ret_ty.to_tokens(&ctx.ext_cx)[..]), data_field, offset);
-
- parse::new_parser_from_source_str(ctx.ext_cx.parse_sess(),
- ctx.ext_cx.cfg(), "".to_string(), impl_str).parse_item().unwrap().unwrap()
- };
-
- method.and_then(|i| {
- match i.node {
- ast::ItemKind::Impl(_, _, _, _, _, mut items) => {
- items.pop()
- }
- _ => unreachable!("impl parsed to something other than impl")
- }
- })
- };
-
- let mut offset = data_offset;
- let mut methods = vec![];
- for m in members.into_iter() {
- let advance_by = match *m {
- CompMember::Field(ref f) => {
- if ctx.options.gen_bitfield_methods {
- methods.extend(mk_field_method(ctx, f, offset).into_iter());
- }
- f.ty.size()
- }
- CompMember::Comp(ref rc_c) => {
- let c = rc_c.borrow();
- let name = comp_name(&ctx, c.kind, &c.name);
- extra.extend(comp_to_rs(ctx, &name, c.clone()).into_iter());
- c.layout().size
- }
- CompMember::Enum(_) => 0
- };
- match kind {
- CompKind::Struct => { offset += advance_by; }
- CompKind::Union => { }
- }
- }
- methods
-}
-
-fn type_for_bitfield_width(ctx: &mut GenCtx, width: u32, is_arg: bool) -> ast::Ty {
- let input_type = if width > 16 {
- "u32"
- } else if width > 8 {
- "u16"
- } else if width > 1 {
- "u8"
- } else {
- if is_arg {
- "bool"
- } else {
- "u8"
- }
- };
- mk_ty(ctx, false, &[input_type.to_owned()])
-}
-
-fn gen_bitfield_methods(ctx: &mut GenCtx, bindgen_name: &str,
- field_name: &str, field_type: &Type,
- offset: usize, width: u32) -> Vec<ast::ImplItem> {
- let input_type = type_for_bitfield_width(ctx, width, true);
- let width = width as usize;
-
- let field_type = cty_to_rs(ctx, field_type, false, true);
-
- let real_field_name = if field_name.is_empty() {
- format!("at_offset_{}", offset)
- } else {
- field_name.into()
- };
-
-
- let bindgen_ident = ctx.ext_cx.ident_of(bindgen_name);
- let setter_name = ctx.ext_cx.ident_of(&format!("set_{}", real_field_name));
- let getter_name = ctx.ext_cx.ident_of(&real_field_name);
-
- let mask = ((1usize << width) - 1) << offset;
- let item = quote_item!(&ctx.ext_cx,
- impl X {
- #[inline]
- pub fn $getter_name(&self) -> $field_type {
- (self.$bindgen_ident & ($mask as $field_type)) >> $offset
- }
-
- #[inline]
- pub fn $setter_name(&mut self, val: $input_type) {
- self.$bindgen_ident &= !($mask as $field_type);
- self.$bindgen_ident |= (val as $field_type << $offset) & ($mask as $field_type);
- }
- }
- ).unwrap();
-
- match item.node {
- ast::ItemKind::Impl(_, _, _, _, _, ref items) => items.clone(),
- _ => unreachable!()
- }
-}
-
-fn gen_fullbitfield_method(ctx: &mut GenCtx, bindgen_name: &String,
- bitfield_type: &Type, bitfields: &[(String, u32)]) -> ast::ImplItem {
- let field_type = cty_to_rs(ctx, bitfield_type, false, true);
- let mut args = vec![];
- let mut unnamed: usize = 0;
- for &(ref name, width) in bitfields.iter() {
- let ident = if name.is_empty() {
- unnamed += 1;
- let dummy = format!("unnamed_bitfield{}", unnamed);
- ctx.ext_cx.ident_of(&dummy)
- } else {
- ctx.ext_cx.ident_of(name)
- };
- args.push(ast::Arg {
- ty: P(type_for_bitfield_width(ctx, width, true)),
- pat: P(ast::Pat {
- id: ast::DUMMY_NODE_ID,
- node: ast::PatKind::Ident(
- ast::BindingMode::ByValue(ast::Mutability::Immutable),
- respan(ctx.span, ident),
- None
- ),
- span: ctx.span
- }),
- id: ast::DUMMY_NODE_ID,
- });
- }
-
- let fndecl = ast::FnDecl {
- inputs: args,
- output: ast::FunctionRetTy::Ty(P(field_type.clone())),
- variadic: false
- };
-
- let mut offset = 0;
-
- let mut exprs = quote_expr!(&ctx.ext_cx, 0);
-
- let mut unnamed: usize = 0;
- for &(ref name, width) in bitfields.iter() {
- let name_ident = if name.is_empty() {
- unnamed += 1;
- let dummy = format!("unnamed_bitfield{}", unnamed);
- ctx.ext_cx.ident_of(&dummy)
- } else {
- ctx.ext_cx.ident_of(name)
- };
- exprs = quote_expr!(&ctx.ext_cx,
- $exprs | (($name_ident as $field_type) << $offset)
- );
-
- offset += width;
- }
-
- let block = ast::Block {
- stmts: vec![
- ast::Stmt {
- id: ast::DUMMY_NODE_ID,
- node: ast::StmtKind::Expr(exprs),
- span: ctx.span,
- }
- ],
- id: ast::DUMMY_NODE_ID,
- rules: ast::BlockCheckMode::Default,
- span: ctx.span
- };
-
- let mut attrs = vec![];
-
- let node = ast::ImplItemKind::Method(
- ast::MethodSig {
- unsafety: ast::Unsafety::Normal,
- abi: Abi::Rust,
- decl: P(fndecl),
- generics: ast::Generics::default(),
- constness: if ctx.options.unstable_rust {
- ast::Constness::Const
- } else {
- attrs.push(quote_attr!(&ctx.ext_cx, #[inline]));
- ast::Constness::NotConst
- },
- }, P(block)
- );
-
- ast::ImplItem {
- id: ast::DUMMY_NODE_ID,
- ident: ctx.ext_cx.ident_of(&format!("new{}", bindgen_name)),
- vis: ast::Visibility::Public,
- attrs: attrs,
- node: node,
- span: ctx.span,
- defaultness: ast::Defaultness::Final,
- }
-}
-
-fn mk_blob_field(ctx: &GenCtx, name: &str, layout: &Layout) -> ast::StructField {
- let ty_name = match layout.align {
- 8 => "u64",
- 4 => "u32",
- 2 => "u16",
- 1 | _ => "u8",
- };
- let data_len = if ty_name == "u8" { layout.size } else { layout.size / layout.align };
-
- let base_ty = mk_ty(ctx, false, &[ty_name.to_owned()]);
- let data_ty = if data_len == 1 {
- P(base_ty)
- } else {
- P(mk_arrty(ctx, &base_ty, data_len))
- };
- ast::StructField {
- span: ctx.span,
- vis: ast::Visibility::Public,
- ident: Some(ctx.ext_cx.ident_of(name)),
- id: ast::DUMMY_NODE_ID,
- ty: data_ty,
- attrs: vec![]
- }
-}
-
-fn mk_link_name_attr(ctx: &GenCtx, name: String) -> ast::Attribute {
- let lit = respan(ctx.span, ast::LitKind::Str(intern(&name).as_str(), ast::StrStyle::Cooked));
- let attr_val = P(respan(ctx.span, ast::MetaItemKind::NameValue(
- InternedString::new("link_name"), lit
- )));
- let attr = ast::Attribute_ {
- id: mk_attr_id(),
- style: ast::AttrStyle::Outer,
- value: attr_val,
- is_sugared_doc: false
- };
- respan(ctx.span, attr)
-}
-
-fn mk_repr_attr(ctx: &GenCtx, layout: &Layout) -> ast::Attribute {
- let mut values = vec!(P(respan(ctx.span, ast::MetaItemKind::Word(InternedString::new("C")))));
- if layout.packed {
- values.push(P(respan(ctx.span, ast::MetaItemKind::Word(InternedString::new("packed")))));
- }
- let attr_val = P(respan(ctx.span, ast::MetaItemKind::List(
- InternedString::new("repr"),
- values
- )));
-
- respan(ctx.span, ast::Attribute_ {
- id: mk_attr_id(),
- style: ast::AttrStyle::Outer,
- value: attr_val,
- is_sugared_doc: false
- })
-}
-
-// NB: This requires that the type you implement it for also
-// implements Copy.
-//
-// Implements std::clone::Clone using dereferencing.
-//
-// This is to bypass big arrays not implementing clone,
-// but implementing copy due to hacks inside rustc's internals.
-fn mk_clone_impl(ctx: &GenCtx, ty_name: &str) -> P<ast::Item> {
- let impl_str = format!(r"
- impl ::std::clone::Clone for {} {{
- fn clone(&self) -> Self {{ *self }}
- }}
- ", ty_name);
-
- parse::new_parser_from_source_str(ctx.ext_cx.parse_sess(),
- ctx.ext_cx.cfg(), "".to_owned(), impl_str).parse_item().unwrap().unwrap()
-}
-
-fn mk_deriving_attr(ctx: &GenCtx, attrs: &[&'static str]) -> ast::Attribute {
- let attr_val = P(respan(ctx.span, ast::MetaItemKind::List(
- InternedString::new("derive"),
- attrs.iter().map(|attr| {
- P(respan(ctx.span, ast::MetaItemKind::Word(InternedString::new(attr))))
- }).collect()
- )));
-
- respan(ctx.span, ast::Attribute_ {
- id: mk_attr_id(),
- style: ast::AttrStyle::Outer,
- value: attr_val,
- is_sugared_doc: false
- })
-}
-
-fn mk_doc_attr(ctx: &GenCtx, doc: &str) -> Vec<ast::Attribute> {
- if doc.is_empty() {
- return vec![];
- }
-
- let attr_val = P(respan(ctx.span, ast::MetaItemKind::NameValue(
- InternedString::new("doc"),
- respan(ctx.span, ast::LitKind::Str(intern(doc).as_str(), ast::StrStyle::Cooked))
- )));
-
- vec!(respan(ctx.span, ast::Attribute_ {
- id: mk_attr_id(),
- style: ast::AttrStyle::Outer,
- value: attr_val,
- is_sugared_doc: true
- }))
-}
-
-fn cvar_to_rs(ctx: &mut GenCtx, name: String,
- mangled: String, ty: &Type,
- is_const: bool) -> ast::ForeignItem {
- let (rust_name, was_mangled) = rust_id(ctx, &name);
-
- let mut attrs = vec![];
- if !mangled.is_empty() {
- attrs.push(mk_link_name_attr(ctx, mangled));
- } else if was_mangled {
- attrs.push(mk_link_name_attr(ctx, name));
- }
-
- let val_ty = P(cty_to_rs(ctx, ty, true, true));
-
- ast::ForeignItem {
- ident: ctx.ext_cx.ident_of(&rust_name),
- attrs: attrs,
- node: ast::ForeignItemKind::Static(val_ty, !is_const),
- id: ast::DUMMY_NODE_ID,
- span: ctx.span,
- vis: ast::Visibility::Public,
- }
-}
-
-fn cfuncty_to_rs(ctx: &GenCtx,
- rty: &Type,
- aty: &[(String, Type)],
- var: bool) -> ast::FnDecl {
-
- let ret = match *rty {
- TVoid => ast::FunctionRetTy::Default(ctx.span),
- // Disable references in returns for now
- TPtr(ref t, is_const, _, ref layout) =>
- ast::FunctionRetTy::Ty(P(cty_to_rs(ctx, &TPtr(t.clone(), is_const, false, layout.clone()), true, true))),
- _ => ast::FunctionRetTy::Ty(P(cty_to_rs(ctx, rty, true, true)))
- };
-
- let mut unnamed: usize = 0;
- let args: Vec<ast::Arg> = aty.iter().map(|arg| {
- let (ref n, ref t) = *arg;
-
- let arg_name = if n.is_empty() {
- unnamed += 1;
- format!("arg{}", unnamed)
- } else {
- first(rust_id(ctx, &n))
- };
-
- // From the C90 standard (http://c0x.coding-guidelines.com/6.7.5.3.html)
- // 1598 - A declaration of a parameter as “array of type” shall be
- // adjusted to “qualified pointer to type”, where the type qualifiers
- // (if any) are those specified within the [ and ] of the array type
- // derivation.
- let arg_ty = P(match *t {
- TArray(ref typ, _, l) => cty_to_rs(ctx, &TPtr(typ.clone(), false, false, l), true, true),
- _ => cty_to_rs(ctx, t, true, true),
- });
-
- ast::Arg {
- ty: arg_ty,
- pat: P(ast::Pat {
- id: ast::DUMMY_NODE_ID,
- node: ast::PatKind::Ident(
- ast::BindingMode::ByValue(ast::Mutability::Immutable),
- respan(ctx.span, ctx.ext_cx.ident_of(&arg_name)),
- None
- ),
- span: ctx.span
- }),
- id: ast::DUMMY_NODE_ID,
- }
- }).collect();
-
- let var = !args.is_empty() && var;
- ast::FnDecl {
- inputs: args,
- output: ret,
- variadic: var
- }
-}
-
-fn cfunc_to_rs(ctx: &mut GenCtx,
- name: String,
- mangled: String,
- comment: String,
- rty: &Type,
- aty: &[(String, Type)],
- var: bool,
- vis: ast::Visibility) -> ast::ForeignItem {
- let var = !aty.is_empty() && var;
- let decl = ast::ForeignItemKind::Fn(
- P(cfuncty_to_rs(ctx, rty, aty, var)),
- ast::Generics::default()
- );
-
- let (rust_name, was_mangled) = rust_id(ctx, &name);
-
- let mut attrs = mk_doc_attr(ctx, &comment);
- if !mangled.is_empty() {
- attrs.push(mk_link_name_attr(ctx, mangled));
- } else if was_mangled {
- attrs.push(mk_link_name_attr(ctx, name));
- }
-
- ast::ForeignItem {
- ident: ctx.ext_cx.ident_of(&rust_name),
- attrs: attrs,
- node: decl,
- id: ast::DUMMY_NODE_ID,
- span: ctx.span,
- vis: vis,
- }
-}
-
-fn cty_to_rs(ctx: &GenCtx, ty: &Type, allow_bool: bool, use_full_path: bool) -> ast::Ty {
- let prefix = vec!["std".to_owned(), "os".to_owned(), "raw".to_owned()];
- let raw = |fragment: &str| {
- let mut path = prefix.clone();
- path.push(fragment.to_owned());
- path
- };
-
- match *ty {
- TVoid => mk_ty(ctx, true, &raw("c_void")),
- TInt(i, ref layout) => match i {
- IBool => {
- let ty_name = match layout.size {
- 1 if allow_bool => "bool",
- 2 => "u16",
- 4 => "u32",
- 8 => "u64",
- _ => "u8",
- };
- mk_ty(ctx, false, &[ty_name.to_owned()])
- },
- ISChar => mk_ty(ctx, true, &raw("c_char")),
- IUChar => mk_ty(ctx, true, &raw("c_uchar")),
- IInt => mk_ty(ctx, true, &raw("c_int")),
- IUInt => mk_ty(ctx, true, &raw("c_uint")),
- IShort => mk_ty(ctx, true, &raw("c_short")),
- IUShort => mk_ty(ctx, true, &raw("c_ushort")),
- ILong => mk_ty(ctx, true, &raw("c_long")),
- IULong => mk_ty(ctx, true, &raw("c_ulong")),
- ILongLong => mk_ty(ctx, true, &raw("c_longlong")),
- IULongLong => mk_ty(ctx, true, &raw("c_ulonglong"))
- },
- TFloat(f, _) => match f {
- FFloat => mk_ty(ctx, false, &["f32".to_owned()]),
- FDouble => mk_ty(ctx, false, &["f64".to_owned()])
- },
- TPtr(ref t, is_const, _is_ref, _) => {
- let id = cty_to_rs(ctx, &**t, allow_bool, use_full_path);
- mk_ptrty(ctx, &id, is_const)
- },
- TArray(ref t, s, _) => {
- let ty = cty_to_rs(ctx, &**t, allow_bool, use_full_path);
- mk_arrty(ctx, &ty, s)
- },
- TFuncPtr(ref sig) => {
- let decl = cfuncty_to_rs(ctx, &*sig.ret_ty, &sig.args[..], sig.is_variadic);
- mk_fnty(ctx, &decl, sig.abi)
- },
- TFuncProto(ref sig) => {
- let decl = cfuncty_to_rs(ctx, &*sig.ret_ty, &sig.args[..], sig.is_variadic);
- mk_fn_proto_ty(ctx, &decl, sig.abi)
- },
- TNamed(ref ti) => {
- let id = rust_type_id(ctx, &ti.borrow().name);
-
- if use_full_path {
- let mut path = ctx.full_path_for_module(ti.borrow().module_id);
- path.push(id);
- mk_ty(ctx, false, &path)
- } else {
- mk_ty(ctx, false, &[id])
- }
- },
- TComp(ref ci) => {
- let c = ci.borrow();
- let id = comp_name(&ctx, c.kind, &c.name);
-
- let args = c.args.iter().map(|gt| {
- P(cty_to_rs(ctx, gt, allow_bool, false))
- }).collect();
-
- if use_full_path {
- let mut path = ctx.full_path_for_module(c.module_id());
- path.push(id);
- mk_ty_args(ctx, false, &path, args)
- } else {
- mk_ty_args(ctx, false, &[id], args)
- }
- },
- TEnum(ref ei) => {
- let e = ei.borrow();
- let id = enum_name(&ctx, &e.name);
-
- if use_full_path {
- let mut path = ctx.full_path_for_module(e.module_id);
- path.push(id);
- mk_ty(ctx, false, &path)
- } else {
- mk_ty(ctx, false, &[id])
- }
- }
- }
-}
-
-fn cty_is_translatable(ty: &Type) -> bool {
- match *ty {
- TVoid => false,
- TArray(ref t, _, _) => {
- cty_is_translatable(&**t)
- },
- TComp(ref ci) => {
- let c = ci.borrow();
- !c.args.iter().any(|gt| gt == &TVoid) && !c.has_non_type_template_params
- },
- _ => true,
- }
-}
-
-fn mk_ty(ctx: &GenCtx, global: bool, segments: &[String]) -> ast::Ty {
- mk_ty_args(ctx, global, segments, vec![])
-}
-
-fn mk_ty_args(ctx: &GenCtx, global: bool, segments: &[String], args: Vec<P<ast::Ty>>) -> ast::Ty {
- let segment_count = segments.len();
- let ty = ast::TyKind::Path(
- None,
- ast::Path {
- span: ctx.span,
- global: global,
- segments: segments.iter().enumerate().map(|(i, s)| {
- ast::PathSegment {
- identifier: ctx.ext_cx.ident_of(s),
- parameters: ast::PathParameters::AngleBracketed(ast::AngleBracketedParameterData {
- lifetimes: vec![],
- types: if i == segment_count - 1 { P::from_vec(args.clone()) } else { P::new() },
- bindings: P::new(),
- }),
- }
- }).collect()
- },
- );
-
- ast::Ty {
- id: ast::DUMMY_NODE_ID,
- node: ty,
- span: ctx.span
- }
-}
-
-fn mk_ptrty(ctx: &GenCtx, base: &ast::Ty, is_const: bool) -> ast::Ty {
- let ty = ast::TyKind::Ptr(ast::MutTy {
- ty: P(base.clone()),
- mutbl: if is_const { ast::Mutability::Immutable } else { ast::Mutability::Mutable }
- });
-
- ast::Ty {
- id: ast::DUMMY_NODE_ID,
- node: ty,
- span: ctx.span
- }
-}
-
-#[allow(dead_code)]
-fn mk_refty(ctx: &mut GenCtx, base: &ast::Ty, is_const: bool) -> ast::Ty {
- let ty = ast::TyKind::Rptr(
- None,
- ast::MutTy {
- ty: P(base.clone()),
- mutbl: if is_const { ast::Mutability::Immutable } else { ast::Mutability::Mutable }
- }
- );
-
- ast::Ty {
- id: ast::DUMMY_NODE_ID,
- node: ty,
- span: ctx.span
- }
-}
-
-fn mk_arrty(ctx: &GenCtx, base: &ast::Ty, n: usize) -> ast::Ty {
- let int_lit = ast::LitKind::Int(n as u64, ast::LitIntType::Unsigned(ast::UintTy::Us));
- let sz = ast::ExprKind::Lit(P(respan(ctx.span, int_lit)));
- let ty = ast::TyKind::FixedLengthVec(
- P(base.clone()),
- P(ast::Expr {
- id: ast::DUMMY_NODE_ID,
- node: sz,
- span: ctx.span,
- attrs: ast::ThinVec::new(),
- })
- );
-
- ast::Ty {
- id: ast::DUMMY_NODE_ID,
- node: ty,
- span: ctx.span
- }
-}
-
-fn mk_fn_proto_ty(ctx: &GenCtx,
- decl: &ast::FnDecl,
- abi: Abi) -> ast::Ty {
- let fnty = ast::TyKind::BareFn(P(ast::BareFnTy {
- unsafety: ast::Unsafety::Unsafe,
- abi: abi,
- lifetimes: vec![],
- decl: P(decl.clone())
- }));
-
- ast::Ty {
- id: ast::DUMMY_NODE_ID,
- node: fnty,
- span: ctx.span,
- }
-}
-
-fn mk_fnty(ctx: &GenCtx, decl: &ast::FnDecl, abi: Abi) -> ast::Ty {
- let fnty = ast::TyKind::BareFn(P(ast::BareFnTy {
- unsafety: ast::Unsafety::Unsafe,
- abi: abi,
- lifetimes: vec![],
- decl: P(decl.clone())
- }));
-
- let segs = vec![
- ast::PathSegment {
- identifier: ctx.ext_cx.ident_of("std"),
- parameters: ast::PathParameters::AngleBracketed(ast::AngleBracketedParameterData {
- lifetimes: vec![],
- types: P::new(),
- bindings: P::new(),
- }),
- },
- ast::PathSegment {
- identifier: ctx.ext_cx.ident_of("option"),
- parameters: ast::PathParameters::AngleBracketed(ast::AngleBracketedParameterData {
- lifetimes: vec![],
- types: P::new(),
- bindings: P::new(),
- }),
- },
- ast::PathSegment {
- identifier: ctx.ext_cx.ident_of("Option"),
- parameters: ast::PathParameters::AngleBracketed(ast::AngleBracketedParameterData {
- lifetimes: vec![],
- types: P::from_vec(vec![
- P(ast::Ty {
- id: ast::DUMMY_NODE_ID,
- node: fnty,
- span: ctx.span
- })
- ]),
- bindings: P::new(),
- }),
- }
- ];
-
- ast::Ty {
- id: ast::DUMMY_NODE_ID,
- node: ast::TyKind::Path(
- None,
- ast::Path {
- span: ctx.span,
- global: true,
- segments: segs
- },
- ),
- span: ctx.span
- }
-}
-
-fn mk_test_fn(ctx: &GenCtx, name: &str, layout: &Layout) -> P<ast::Item> {
- let size = layout.size;
- let align = layout.align;
- let struct_name = ctx.ext_cx.ident_of(name);
-
- let fn_name = ctx.ext_cx.ident_of(&format!("bindgen_test_layout_{}", name));
-
- let size_of_expr = quote_expr!(&ctx.ext_cx, ::std::mem::size_of::<$struct_name>());
- let align_of_expr = quote_expr!(&ctx.ext_cx, ::std::mem::align_of::<$struct_name>());
- let item = quote_item!(&ctx.ext_cx,
- #[test]
- fn $fn_name() {
- assert_eq!($size_of_expr, $size);
- assert_eq!($align_of_expr, $align);
- }).unwrap();
- item
-}
-
-fn mk_opaque_struct(ctx: &GenCtx, name: &str, layout: &Layout) -> Vec<P<ast::Item>> {
- let blob_field = mk_blob_field(ctx, "_bindgen_opaque_blob", layout);
- let variant_data = if layout.size == 0 {
- ast::VariantData::Unit(ast::DUMMY_NODE_ID)
- } else {
- ast::VariantData::Struct(vec![blob_field], ast::DUMMY_NODE_ID)
- };
-
- let def = ast::ItemKind::Struct(
- variant_data,
- ast::Generics {
- lifetimes: vec![],
- ty_params: P::new(),
- where_clause: ast::WhereClause {
- id: ast::DUMMY_NODE_ID,
- predicates: vec![]
- }
- }
- );
-
- let struct_decl = P(ast::Item {
- ident: ctx.ext_cx.ident_of(&name),
- attrs: vec![mk_repr_attr(ctx, layout)],
- id: ast::DUMMY_NODE_ID,
- node: def,
- vis: ast::Visibility::Public,
- span: ctx.span
- });
-
- let mut ret = vec![struct_decl];
-
- // The test should always be correct but...
- if *layout != Layout::zero() {
- ret.push(mk_test_fn(ctx, &name, layout));
- }
-
- ret
-}
-
-/// Generates a vector of rust's ty params from a list of types
-fn mk_ty_params(ctx: &GenCtx, template_args: &[Type]) -> Vec<ast::TyParam> {
- template_args.iter().map(|gt| {
- let name = match *gt {
- TNamed(ref ti) => {
- ctx.ext_cx.ident_of(&ti.borrow().name)
- },
- _ => ctx.ext_cx.ident_of("")
- };
- ast::TyParam {
- ident: name,
- id: ast::DUMMY_NODE_ID,
- bounds: P::new(),
- default: None,
- span: ctx.span
- }
- }).collect()
-}
-
-fn gen_union_field_definitions_if_necessary(ctx: &mut GenCtx, mut root_mod: &mut ast::Item) {
- if !ctx.saw_union {
- return;
- }
-
- let union_field_decl = quote_item!(&ctx.ext_cx,
- #[derive(Copy, Debug)]
- #[repr(C)]
- pub struct __BindgenUnionField<T>(::std::marker::PhantomData<T>);
- ).unwrap();
-
- let union_field_impl = quote_item!(&ctx.ext_cx,
- impl<T> __BindgenUnionField<T> {
- #[inline]
- pub fn new() -> Self {
- __BindgenUnionField(::std::marker::PhantomData)
- }
-
- #[inline]
- pub unsafe fn as_ref(&self) -> &T {
- ::std::mem::transmute(self)
- }
-
- #[inline]
- pub unsafe fn as_mut(&mut self) -> &mut T {
- ::std::mem::transmute(self)
- }
- }
- ).unwrap();
-
- let union_field_default_impl = quote_item!(&ctx.ext_cx,
- impl<T> ::std::default::Default for __BindgenUnionField<T> {
- #[inline]
- fn default() -> Self {
- Self::new()
- }
- }
- ).unwrap();
-
- let union_field_clone_impl = quote_item!(&ctx.ext_cx,
- impl<T> ::std::clone::Clone for __BindgenUnionField<T> {
- #[inline]
- fn clone(&self) -> Self {
- Self::new()
- }
- }
- ).unwrap();
-
- let items = vec![union_field_decl, union_field_impl, union_field_default_impl, union_field_clone_impl];
- match root_mod.node {
- ast::ItemKind::Mod(ref mut root) => {
- let old_items = std::mem::replace(&mut root.items, items);
- root.items.extend(old_items.into_iter());
- }
- _ => unreachable!(),
- }
-}
diff --git a/src/hacks/mod.rs b/src/hacks/mod.rs
deleted file mode 100644
index 79339002..00000000
--- a/src/hacks/mod.rs
+++ /dev/null
@@ -1 +0,0 @@
-pub mod refcell;
diff --git a/src/hacks/refcell.rs b/src/hacks/refcell.rs
deleted file mode 100644
index 408e95d4..00000000
--- a/src/hacks/refcell.rs
+++ /dev/null
@@ -1,464 +0,0 @@
-// Copyright 2012-2014 The Rust Project Developers.
-// See http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! A fork of std::cell::RefCell that makes `as_unsafe_cell` usable on stable Rust.
-//!
-//! FIXME(https://github.com/rust-lang/rust/issues/27708): Remove this
-//! (revert commit f7f81e0ed0b62402db291e28a9bb16f7194ebf78 / PR #11835)
-//! when `std::cell::RefCell::as_unsafe_cell` is in Rust’s stable channel.
-
-#![allow(unsafe_code, dead_code)]
-
-use std::cell::{UnsafeCell, Cell};
-use std::cmp::Ordering;
-use std::ops::{Deref, DerefMut};
-
-/// A fork of std::cell::RefCell that makes `as_unsafe_cell` usable on stable Rust.
-///
-/// FIXME(https://github.com/rust-lang/rust/issues/27708): Remove this
-/// (revert commit f7f81e0ed0b62402db291e28a9bb16f7194ebf78 / PR #11835)
-/// when `std::cell::RefCell::as_unsafe_cell` is in Rust’s stable channel.
-#[derive(Debug)]
-pub struct RefCell<T: ?Sized> {
- borrow: Cell<BorrowFlag>,
- value: UnsafeCell<T>,
-}
-type BorrowFlag = usize;
-
-/// An enumeration of values returned from the `state` method on a `RefCell<T>`.
-#[derive(Copy, Clone, PartialEq, Eq, Debug)]
-pub enum BorrowState {
- /// The cell is currently being read, there is at least one active `borrow`.
- Reading,
- /// The cell is currently being written to, there is an active `borrow_mut`.
- Writing,
- /// There are no outstanding borrows on this cell.
- Unused,
-}
-
-// Values [1, MAX-1] represent the number of `Ref` active
-// (will not outgrow its range since `usize` is the size of the address space)
-const UNUSED: BorrowFlag = 0;
-const WRITING: BorrowFlag = !0;
-
-impl<T> RefCell<T> {
- /// Creates a new `RefCell` containing `value`.
- ///
- /// # Examples
- ///
- /// ```
- /// use std::cell::RefCell;
- ///
- /// let c = RefCell::new(5);
- /// ```
- #[inline]
- pub fn new(value: T) -> RefCell<T> {
- RefCell {
- value: UnsafeCell::new(value),
- borrow: Cell::new(UNUSED),
- }
- }
-
- /// Consumes the `RefCell`, returning the wrapped value.
- ///
- /// # Examples
- ///
- /// ```
- /// use std::cell::RefCell;
- ///
- /// let c = RefCell::new(5);
- ///
- /// let five = c.into_inner();
- /// ```
- #[inline]
- pub fn into_inner(self) -> T {
- // Since this function takes `self` (the `RefCell`) by value, the
- // compiler statically verifies that it is not currently borrowed.
- // Therefore the following assertion is just a `debug_assert!`.
- debug_assert!(self.borrow.get() == UNUSED);
- unsafe { self.value.into_inner() }
- }
-}
-
-impl<T: ?Sized> RefCell<T> {
- /// Query the current state of this `RefCell`
- ///
- /// The returned value can be dispatched on to determine if a call to
- /// `borrow` or `borrow_mut` would succeed.
- #[inline]
- pub fn borrow_state(&self) -> BorrowState {
- match self.borrow.get() {
- WRITING => BorrowState::Writing,
- UNUSED => BorrowState::Unused,
- _ => BorrowState::Reading,
- }
- }
-
- /// Immutably borrows the wrapped value.
- ///
- /// The borrow lasts until the returned `Ref` exits scope. Multiple
- /// immutable borrows can be taken out at the same time.
- ///
- /// # Panics
- ///
- /// Panics if the value is currently mutably borrowed.
- ///
- /// # Examples
- ///
- /// ```
- /// use std::cell::RefCell;
- ///
- /// let c = RefCell::new(5);
- ///
- /// let borrowed_five = c.borrow();
- /// let borrowed_five2 = c.borrow();
- /// ```
- ///
- /// An example of panic:
- ///
- /// ```
- /// use std::cell::RefCell;
- /// use std::thread;
- ///
- /// let result = thread::spawn(move || {
- /// let c = RefCell::new(5);
- /// let m = c.borrow_mut();
- ///
- /// let b = c.borrow(); // this causes a panic
- /// }).join();
- ///
- /// assert!(result.is_err());
- /// ```
- #[inline]
- pub fn borrow(&self) -> Ref<T> {
- match BorrowRef::new(&self.borrow) {
- Some(b) => Ref {
- value: unsafe { &*self.value.get() },
- borrow: b,
- },
- None => panic!("RefCell<T> already mutably borrowed"),
- }
- }
-
- /// Mutably borrows the wrapped value.
- ///
- /// The borrow lasts until the returned `RefMut` exits scope. The value
- /// cannot be borrowed while this borrow is active.
- ///
- /// # Panics
- ///
- /// Panics if the value is currently borrowed.
- ///
- /// # Examples
- ///
- /// ```
- /// use std::cell::RefCell;
- ///
- /// let c = RefCell::new(5);
- ///
- /// *c.borrow_mut() = 7;
- ///
- /// assert_eq!(*c.borrow(), 7);
- /// ```
- ///
- /// An example of panic:
- ///
- /// ```
- /// use std::cell::RefCell;
- /// use std::thread;
- ///
- /// let result = thread::spawn(move || {
- /// let c = RefCell::new(5);
- /// let m = c.borrow();
- ///
- /// let b = c.borrow_mut(); // this causes a panic
- /// }).join();
- ///
- /// assert!(result.is_err());
- /// ```
- #[inline]
- pub fn borrow_mut(&self) -> RefMut<T> {
- match BorrowRefMut::new(&self.borrow) {
- Some(b) => RefMut {
- value: unsafe { &mut *self.value.get() },
- borrow: b,
- },
- None => panic!("RefCell<T> already borrowed"),
- }
- }
-
- /// Returns a reference to the underlying `UnsafeCell`.
- ///
- /// This can be used to circumvent `RefCell`'s safety checks.
- ///
- /// This function is `unsafe` because `UnsafeCell`'s field is public.
- #[inline]
- pub unsafe fn as_unsafe_cell(&self) -> &UnsafeCell<T> {
- &self.value
- }
-
- /// Returns a mutable reference to the underlying data.
- ///
- /// This call borrows `RefCell` mutably (at compile-time) so there is no
- /// need for dynamic checks.
- #[inline]
- pub fn get_mut(&mut self) -> &mut T {
- unsafe {
- &mut *self.value.get()
- }
- }
-}
-
-unsafe impl<T: ?Sized> Send for RefCell<T> where T: Send {}
-
-impl<T: Clone> Clone for RefCell<T> {
- #[inline]
- fn clone(&self) -> RefCell<T> {
- RefCell::new(self.borrow().clone())
- }
-}
-
-impl<T: Default> Default for RefCell<T> {
- #[inline]
- fn default() -> RefCell<T> {
- RefCell::new(Default::default())
- }
-}
-
-impl<T: ?Sized + PartialEq> PartialEq for RefCell<T> {
- #[inline]
- fn eq(&self, other: &RefCell<T>) -> bool {
- *self.borrow() == *other.borrow()
- }
-}
-
-impl<T: ?Sized + Eq> Eq for RefCell<T> {}
-
-impl<T: ?Sized + PartialOrd> PartialOrd for RefCell<T> {
- #[inline]
- fn partial_cmp(&self, other: &RefCell<T>) -> Option<Ordering> {
- self.borrow().partial_cmp(&*other.borrow())
- }
-
- #[inline]
- fn lt(&self, other: &RefCell<T>) -> bool {
- *self.borrow() < *other.borrow()
- }
-
- #[inline]
- fn le(&self, other: &RefCell<T>) -> bool {
- *self.borrow() <= *other.borrow()
- }
-
- #[inline]
- fn gt(&self, other: &RefCell<T>) -> bool {
- *self.borrow() > *other.borrow()
- }
-
- #[inline]
- fn ge(&self, other: &RefCell<T>) -> bool {
- *self.borrow() >= *other.borrow()
- }
-}
-
-impl<T: ?Sized + Ord> Ord for RefCell<T> {
- #[inline]
- fn cmp(&self, other: &RefCell<T>) -> Ordering {
- self.borrow().cmp(&*other.borrow())
- }
-}
-
-struct BorrowRef<'b> {
- borrow: &'b Cell<BorrowFlag>,
-}
-
-impl<'b> BorrowRef<'b> {
- #[inline]
- fn new(borrow: &'b Cell<BorrowFlag>) -> Option<BorrowRef<'b>> {
- match borrow.get() {
- WRITING => None,
- b => {
- borrow.set(b + 1);
- Some(BorrowRef { borrow: borrow })
- },
- }
- }
-}
-
-impl<'b> Drop for BorrowRef<'b> {
- #[inline]
- fn drop(&mut self) {
- let borrow = self.borrow.get();
- debug_assert!(borrow != WRITING && borrow != UNUSED);
- self.borrow.set(borrow - 1);
- }
-}
-
-impl<'b> Clone for BorrowRef<'b> {
- #[inline]
- fn clone(&self) -> BorrowRef<'b> {
- // Since this Ref exists, we know the borrow flag
- // is not set to WRITING.
- let borrow = self.borrow.get();
- debug_assert!(borrow != UNUSED);
- // Prevent the borrow counter from overflowing.
- assert!(borrow != WRITING);
- self.borrow.set(borrow + 1);
- BorrowRef { borrow: self.borrow }
- }
-}
-
-/// Wraps a borrowed reference to a value in a `RefCell` box.
-/// A wrapper type for an immutably borrowed value from a `RefCell<T>`.
-///
-/// See the [module-level documentation](index.html) for more.
-pub struct Ref<'b, T: ?Sized + 'b> {
- value: &'b T,
- borrow: BorrowRef<'b>,
-}
-
-impl<'b, T: ?Sized> Deref for Ref<'b, T> {
- type Target = T;
-
- #[inline]
- fn deref(&self) -> &T {
- self.value
- }
-}
-
-impl<'b, T: ?Sized> Ref<'b, T> {
- /// Copies a `Ref`.
- ///
- /// The `RefCell` is already immutably borrowed, so this cannot fail.
- ///
- /// This is an associated function that needs to be used as
- /// `Ref::clone(...)`. A `Clone` implementation or a method would interfere
- /// with the widespread use of `r.borrow().clone()` to clone the contents of
- /// a `RefCell`.
- #[inline]
- pub fn clone(orig: &Ref<'b, T>) -> Ref<'b, T> {
- Ref {
- value: orig.value,
- borrow: orig.borrow.clone(),
- }
- }
-
- /// Make a new `Ref` for a component of the borrowed data.
- ///
- /// The `RefCell` is already immutably borrowed, so this cannot fail.
- ///
- /// This is an associated function that needs to be used as `Ref::map(...)`.
- /// A method would interfere with methods of the same name on the contents
- /// of a `RefCell` used through `Deref`.
- ///
- /// # Example
- ///
- /// ```
- /// use std::cell::{RefCell, Ref};
- ///
- /// let c = RefCell::new((5, 'b'));
- /// let b1: Ref<(u32, char)> = c.borrow();
- /// let b2: Ref<u32> = Ref::map(b1, |t| &t.0);
- /// assert_eq!(*b2, 5)
- /// ```
- #[inline]
- pub fn map<U: ?Sized, F>(orig: Ref<'b, T>, f: F) -> Ref<'b, U>
- where F: FnOnce(&T) -> &U
- {
- Ref {
- value: f(orig.value),
- borrow: orig.borrow,
- }
- }
-}
-
-impl<'b, T: ?Sized> RefMut<'b, T> {
- /// Make a new `RefMut` for a component of the borrowed data, e.g. an enum
- /// variant.
- ///
- /// The `RefCell` is already mutably borrowed, so this cannot fail.
- ///
- /// This is an associated function that needs to be used as
- /// `RefMut::map(...)`. A method would interfere with methods of the same
- /// name on the contents of a `RefCell` used through `Deref`.
- ///
- /// # Example
- ///
- /// ```
- /// use std::cell::{RefCell, RefMut};
- ///
- /// let c = RefCell::new((5, 'b'));
- /// {
- /// let b1: RefMut<(u32, char)> = c.borrow_mut();
- /// let mut b2: RefMut<u32> = RefMut::map(b1, |t| &mut t.0);
- /// assert_eq!(*b2, 5);
- /// *b2 = 42;
- /// }
- /// assert_eq!(*c.borrow(), (42, 'b'));
- /// ```
- #[inline]
- pub fn map<U: ?Sized, F>(orig: RefMut<'b, T>, f: F) -> RefMut<'b, U>
- where F: FnOnce(&mut T) -> &mut U
- {
- RefMut {
- value: f(orig.value),
- borrow: orig.borrow,
- }
- }
-}
-
-struct BorrowRefMut<'b> {
- borrow: &'b Cell<BorrowFlag>,
-}
-
-impl<'b> Drop for BorrowRefMut<'b> {
- #[inline]
- fn drop(&mut self) {
- let borrow = self.borrow.get();
- debug_assert!(borrow == WRITING);
- self.borrow.set(UNUSED);
- }
-}
-
-impl<'b> BorrowRefMut<'b> {
- #[inline]
- fn new(borrow: &'b Cell<BorrowFlag>) -> Option<BorrowRefMut<'b>> {
- match borrow.get() {
- UNUSED => {
- borrow.set(WRITING);
- Some(BorrowRefMut { borrow: borrow })
- },
- _ => None,
- }
- }
-}
-
-/// A wrapper type for a mutably borrowed value from a `RefCell<T>`.
-///
-/// See the [module-level documentation](index.html) for more.
-pub struct RefMut<'b, T: ?Sized + 'b> {
- value: &'b mut T,
- borrow: BorrowRefMut<'b>,
-}
-
-impl<'b, T: ?Sized> Deref for RefMut<'b, T> {
- type Target = T;
-
- #[inline]
- fn deref(&self) -> &T {
- self.value
- }
-}
-
-impl<'b, T: ?Sized> DerefMut for RefMut<'b, T> {
- #[inline]
- fn deref_mut(&mut self) -> &mut T {
- self.value
- }
-}
diff --git a/src/ir/annotations.rs b/src/ir/annotations.rs
new file mode 100644
index 00000000..cc61dbfd
--- /dev/null
+++ b/src/ir/annotations.rs
@@ -0,0 +1,141 @@
+use clang;
+
+#[derive(Copy, PartialEq, Clone, Debug)]
+pub enum FieldAccessorKind {
+ None,
+ Regular,
+ Unsafe,
+ Immutable,
+}
+
+/// Annotations for a given item, or a field.
+#[derive(Clone, PartialEq, Debug)]
+pub struct Annotations {
+ /// Whether this item is marked as opaque. Only applies to types.
+ opaque: bool,
+ /// Whether this item should be hidden from the output. Only applies to
+ /// types.
+ hide: bool,
+ /// Whether this type should be replaced by another. The name must be the
+ /// canonical name that that type would get.
+ use_instead_of: Option<String>,
+ /// Manually disable deriving copy/clone on this type. Only applies to
+ /// struct or union types.
+ disallow_copy: bool,
+ /// Whether fields should be marked as private or not. You can set this on
+ /// structs (it will apply to all the fields), or individual fields.
+ private_fields: Option<bool>,
+ /// The kind of accessor this field will have. Also can be applied to
+ /// structs so all the fields inside share it by default.
+ accessor_kind: Option<FieldAccessorKind>,
+}
+
+fn parse_accessor(s: &str) -> FieldAccessorKind {
+ match s {
+ "false" => FieldAccessorKind::None,
+ "unsafe" => FieldAccessorKind::Unsafe,
+ "immutable" => FieldAccessorKind::Immutable,
+ _ => FieldAccessorKind::Regular,
+ }
+}
+
+impl Default for Annotations {
+ fn default() -> Self {
+ Annotations {
+ opaque: false,
+ hide: false,
+ use_instead_of: None,
+ disallow_copy: false,
+ private_fields: None,
+ accessor_kind: None
+ }
+ }
+}
+
+impl Annotations {
+ pub fn new(cursor: &clang::Cursor) -> Option<Annotations> {
+ let mut anno = Annotations::default();
+ let mut matched_one = false;
+ anno.parse(&cursor.comment(), &mut matched_one);
+
+ if matched_one {
+ Some(anno)
+ } else {
+ None
+ }
+ }
+
+ pub fn hide(&self) -> bool {
+ self.hide
+ }
+
+ pub fn opaque(&self) -> bool {
+ self.opaque
+ }
+
+ /// For a given type, indicates the type it should replace.
+ ///
+ /// For example, in the following code:
+ ///
+ /// ```cpp
+ ///
+ /// /** <div rustbindgen replaces="Bar"></div> */
+ /// struct Foo { int x; };
+ ///
+ /// struct Bar { char foo; };
+ /// ```
+ ///
+ /// the generated code would look something like:
+ ///
+ /// ```rust
+ /// /** <div rustbindgen replaces="Bar"></div> */
+ /// struct Bar {
+ /// int x;
+ /// };
+ /// ```
+ ///
+ /// That is, code for `Foo` is used to generate `Bar`.
+ pub fn use_instead_of(&self) -> Option<&str> {
+ self.use_instead_of.as_ref().map(|s| &**s)
+ }
+
+ pub fn disallow_copy(&self) -> bool {
+ self.disallow_copy
+ }
+
+ pub fn private_fields(&self) -> Option<bool> {
+ self.private_fields
+ }
+
+ pub fn accessor_kind(&self) -> Option<FieldAccessorKind> {
+ self.accessor_kind
+ }
+
+ fn parse(&mut self, comment: &clang::Comment, matched: &mut bool) {
+ use clangll::CXComment_HTMLStartTag;
+ if comment.kind() == CXComment_HTMLStartTag &&
+ comment.get_tag_name() == "div" &&
+ comment.get_num_tag_attrs() > 1 &&
+ comment.get_tag_attr_name(0) == "rustbindgen" {
+ *matched = true;
+ for i in 0..comment.get_num_tag_attrs() {
+ let value = comment.get_tag_attr_value(i);
+ let name = comment.get_tag_attr_name(i);
+ match name.as_str() {
+ "opaque" => self.opaque = true,
+ "hide" => self.hide = true,
+ "nocopy" => self.disallow_copy = true,
+ "replaces" => self.use_instead_of = Some(value),
+ "private" => self.private_fields = Some(value != "false"),
+ "accessor"
+ => self.accessor_kind = Some(parse_accessor(&value)),
+ _ => {},
+ }
+ }
+ }
+
+ for i in 0..comment.num_children() {
+ self.parse(&comment.get_child(i), matched);
+ }
+ }
+}
diff --git a/src/ir/comp.rs b/src/ir/comp.rs
new file mode 100644
index 00000000..1e6bf555
--- /dev/null
+++ b/src/ir/comp.rs
@@ -0,0 +1,718 @@
+use super::annotations::Annotations;
+use super::context::BindgenContext;
+use super::context::TypeResolver;
+use super::layout::Layout;
+use super::item::{Item, ItemId};
+use super::ty::{Type, RUST_DERIVE_IN_ARRAY_LIMIT};
+use std::cell::Cell;
+use std::cmp;
+use parse::{ClangItemParser, ParseError};
+use clang;
+
+#[derive(Debug, Copy, Clone, PartialEq)]
+pub enum CompKind {
+ Struct,
+ Union,
+}
+
+#[derive(Debug, Copy, Clone, PartialEq)]
+pub enum MethodKind {
+ Static,
+ Normal,
+ Virtual,
+}
+
+/// A struct representing a C++ method, either static, normal, or virtual.
+#[derive(Debug)]
+pub struct Method {
+ kind: MethodKind,
+ /// The signature of the method. Take into account this is not a `Type`
+ /// item, but a `Function` one.
+ ///
+ /// This is tricky and probably this field should be renamed.
+ signature: ItemId,
+ is_const: bool,
+}
+
+impl Method {
+ fn new(kind: MethodKind, signature: ItemId, is_const: bool) -> Self {
+ Method {
+ kind: kind,
+ signature: signature,
+ is_const: is_const,
+ }
+ }
+
+ pub fn kind(&self) -> MethodKind {
+ self.kind
+ }
+
+ pub fn is_virtual(&self) -> bool {
+ self.kind == MethodKind::Virtual
+ }
+
+ pub fn is_static(&self) -> bool {
+ self.kind == MethodKind::Static
+ }
+
+ pub fn signature(&self) -> ItemId {
+ self.signature
+ }
+
+ pub fn is_const(&self) -> bool {
+ self.is_const
+ }
+}
+
+/// A struct representing a C++ field.
+#[derive(Clone, Debug)]
+pub struct Field {
+ /// The name of the field, empty if it's an unnamed bitfield width.
+ name: Option<String>,
+ /// The inner type.
+ ty: ItemId,
+ /// The doc comment on the field if any.
+ comment: Option<String>,
+ /// Annotations for this field, or the default.
+ annotations: Annotations,
+ /// If this field is a bitfield, and how many bits does it contain if it is.
+ bitfield: Option<u32>,
+ /// If the C++ field is marked as `mutable`
+ mutable: bool,
+}
+
+impl Field {
+ pub fn new(name: Option<String>,
+ ty: ItemId,
+ comment: Option<String>,
+ annotations: Option<Annotations>,
+ bitfield: Option<u32>,
+ mutable: bool) -> Field {
+ Field {
+ name: name,
+ ty: ty,
+ comment: comment,
+ annotations: annotations.unwrap_or_default(),
+ bitfield: bitfield,
+ mutable: mutable,
+ }
+ }
+
+ pub fn name(&self) -> Option<&str> {
+ self.name.as_ref().map(|n| &**n)
+ }
+
+ pub fn ty(&self) -> ItemId {
+ self.ty
+ }
+
+ pub fn comment(&self) -> Option<&str> {
+ self.comment.as_ref().map(|c| &**c)
+ }
+
+ pub fn bitfield(&self) -> Option<u32> {
+ self.bitfield
+ }
+
+ pub fn is_mutable(&self) -> bool {
+ self.mutable
+ }
+
+ pub fn annotations(&self) -> &Annotations {
+ &self.annotations
+ }
+}
+
+
+#[derive(Debug)]
+pub struct CompInfo {
+ /// Whether this is a struct or a union.
+ kind: CompKind,
+ /// The members of this struct or union.
+ fields: Vec<Field>,
+ /// The template parameters of this class. These are non-concrete, and
+ /// should always be a Type(TypeKind::Named(name)), but still they need to
+ /// be registered with an unique type id in the context.
+ template_args: Vec<ItemId>,
+ /// The method declarations inside this class, if in C++ mode.
+ methods: Vec<Method>,
+ /// Vector of classes this one inherits from.
+ base_members: Vec<ItemId>,
+ /// The parent reference template if any.
+ ref_template: Option<ItemId>,
+ /// The inner types that were declared inside this class, in something like:
+ ///
+ /// class Foo {
+ /// typedef int FooTy;
+ /// struct Bar {
+ /// int baz;
+ /// };
+ /// }
+ ///
+ /// static Foo::Bar const = {3};
+ inner_types: Vec<ItemId>,
+ /// Set of static constants declared inside this class.
+ inner_vars: Vec<ItemId>,
+ /// Whether this type should generate an vtable (TODO: Should be able to
+ /// look at the virtual methods and ditch this field).
+ has_vtable: bool,
+ /// Whether this type has destructor.
+ has_destructor: bool,
+ /// Whether this type has a base type with more than one member.
+ ///
+ /// TODO: We should be able to compute this.
+ has_nonempty_base: bool,
+ /// If this type has a template parameter which is not a type (e.g.: a size_t)
+ has_non_type_template_params: bool,
+ /// Whether this struct layout is packed.
+ packed: bool,
+ /// Whether this struct is anonymous.
+ is_anonymous: bool,
+ /// Used to know if we've found an opaque attribute that could cause us to
+ /// generate a type with invalid layout. This is explicitly used to avoid us
+ /// generating bad alignments when parsing types like max_align_t.
+ ///
+ /// It's not clear what the behavior should be here, if generating the item
+ /// and pray, or behave as an opaque type.
+ found_unknown_attr: bool,
+ /// Used to detect if we've run in a can_derive_debug cycle while cycling
+ /// around the template arguments.
+ detect_derive_debug_cycle: Cell<bool>,
+ /// Used to detect if we've run in a has_destructor cycle while cycling
+ /// around the template arguments.
+ detect_has_destructor_cycle: Cell<bool>,
+}
+
+impl CompInfo {
+ pub fn new(kind: CompKind) -> Self {
+ CompInfo {
+ kind: kind,
+ fields: vec![],
+ template_args: vec![],
+ methods: vec![],
+ base_members: vec![],
+ ref_template: None,
+ inner_types: vec![],
+ inner_vars: vec![],
+ has_vtable: false,
+ has_destructor: false,
+ has_nonempty_base: false,
+ has_non_type_template_params: false,
+ packed: false,
+ is_anonymous: false,
+ found_unknown_attr: false,
+ detect_derive_debug_cycle: Cell::new(false),
+ detect_has_destructor_cycle: Cell::new(false),
+ }
+ }
+
+ pub fn can_derive_debug(&self, type_resolver: &TypeResolver, layout: Option<Layout>) -> bool {
+ // We can reach here recursively via template parameters of a member,
+ // for example.
+ if self.detect_derive_debug_cycle.get() {
+ warn!("Derive debug cycle detected!");
+ return true;
+ }
+
+ if self.kind == CompKind::Union {
+ let layout = layout.unwrap_or_else(Layout::zero);
+ let size_divisor = cmp::max(1, layout.align);
+ return layout.size / size_divisor <= RUST_DERIVE_IN_ARRAY_LIMIT;
+ }
+
+ self.detect_derive_debug_cycle.set(true);
+
+ let can_derive_debug =
+ self.template_args.iter().all(|ty| {
+ type_resolver.resolve_type(*ty)
+ .can_derive_debug(type_resolver)
+ }) &&
+ self.fields.iter().all(|field| {
+ type_resolver.resolve_type(field.ty)
+ .can_derive_debug(type_resolver)
+ });
+
+ self.detect_derive_debug_cycle.set(false);
+
+ can_derive_debug
+ }
+
+ pub fn is_unsized(&self, type_resolver: &TypeResolver) -> bool {
+ !self.has_vtable(type_resolver) && self.fields.is_empty() &&
+ self.base_members.iter().all(|base| {
+ type_resolver
+ .resolve_type(*base)
+ .canonical_type(type_resolver)
+ .is_unsized(type_resolver)
+ }) &&
+ self.ref_template.map_or(true, |template| {
+ type_resolver.resolve_type(template).is_unsized(type_resolver)
+ })
+ }
+
+ pub fn has_destructor(&self, type_resolver: &TypeResolver) -> bool {
+ if self.detect_has_destructor_cycle.get() {
+ warn!("Cycle detected looking for destructors");
+ // Assume no destructor, since we don't have an explicit one.
+ return false;
+ }
+
+ self.detect_has_destructor_cycle.set(true);
+
+ let has_destructor = self.has_destructor || match self.kind {
+ CompKind::Union => false,
+ CompKind::Struct => {
+ // NB: We can't rely on a type with type parameters
+ // not having destructor.
+ //
+ // This is unfortunate, but...
+ self.ref_template.as_ref().map_or(false, |t| {
+ type_resolver.resolve_type(*t).has_destructor(type_resolver)
+ }) ||
+ self.template_args.iter().any(|t| {
+ type_resolver.resolve_type(*t).has_destructor(type_resolver)
+ }) ||
+ self.base_members.iter().any(|t| {
+ type_resolver.resolve_type(*t).has_destructor(type_resolver)
+ }) ||
+ self.fields.iter().any(|field| {
+ type_resolver.resolve_type(field.ty)
+ .has_destructor(type_resolver)
+ })
+ }
+ };
+
+ self.detect_has_destructor_cycle.set(false);
+
+ has_destructor
+ }
+
+ pub fn can_derive_copy(&self, type_resolver: &TypeResolver) -> bool {
+ // NOTE: Take into account that while unions in C and C++ are copied by
+ // default, the may have an explicit destructor in C++, so we can't
+ // defer this check just for the union case.
+ if self.has_destructor(type_resolver) {
+ return false;
+ }
+
+ match self.kind {
+ CompKind::Union => true,
+ CompKind::Struct => {
+ // With template args, use a safe subset of the types,
+ // since copyability depends on the types itself.
+ self.ref_template.as_ref().map_or(true, |t| {
+ type_resolver.resolve_type(*t).can_derive_copy(type_resolver)
+ }) &&
+ self.base_members.iter().all(|t| {
+ type_resolver.resolve_type(*t).can_derive_copy(type_resolver)
+ }) &&
+ self.fields.iter().all(|field| {
+ type_resolver.resolve_type(field.ty)
+ .can_derive_copy(type_resolver)
+ })
+ }
+ }
+ }
+
+ pub fn is_template_specialization(&self) -> bool {
+ self.ref_template.is_some()
+ }
+
+ pub fn specialized_template(&self) -> Option<ItemId> {
+ self.ref_template
+ }
+
+ // Computes the layout of this type.
+ //
+ // This is called as a fallback under some circumstances where LLVM doesn't
+ // give us the correct layout.
+ // If we're a union without known layout, we try to compute it from our
+ // members. This is not ideal, but clang fails to report the size for
+ // these kind of unions, see test/headers/template_union.hpp
+ pub fn layout(&self, type_resolver: &TypeResolver) -> Option<Layout> {
+ use std::cmp;
+
+ // We can't do better than clang here, sorry.
+ if self.kind == CompKind::Struct {
+ return None;
+ }
+
+ let mut max_size = 0;
+ let mut max_align = 0;
+ for field in &self.fields {
+ let field_layout = type_resolver.resolve_type(field.ty)
+ .layout(type_resolver);
+
+ if let Some(layout) = field_layout {
+ max_size = cmp::max(max_size, layout.size);
+ max_align = cmp::max(max_align, layout.align);
+ }
+ }
+
+ Some(Layout::new(max_size, max_align))
+ }
+
+ pub fn fields(&self) -> &[Field] {
+ &self.fields
+ }
+
+ pub fn template_args(&self) -> &[ItemId] {
+ &self.template_args
+ }
+
+ pub fn has_non_type_template_params(&self) -> bool {
+ self.has_non_type_template_params
+ }
+
+ pub fn has_vtable(&self, type_resolver: &TypeResolver) -> bool {
+ self.has_vtable || self.base_members().iter().any(|base| {
+ type_resolver
+ .resolve_type(*base)
+ .has_vtable(type_resolver)
+ }) || self.ref_template.map_or(false, |template| {
+ type_resolver.resolve_type(template).has_vtable(type_resolver)
+ })
+ }
+
+ pub fn methods(&self) -> &[Method] {
+ &self.methods
+ }
+
+ pub fn kind(&self) -> CompKind {
+ self.kind
+ }
+
+ pub fn base_members(&self) -> &[ItemId] {
+ &self.base_members
+ }
+
+ pub fn from_ty(potential_id: ItemId,
+ ty: &clang::Type,
+ location: Option<clang::Cursor>,
+ ctx: &mut BindgenContext) -> Result<Self, ParseError> {
+ use clangll::*;
+ // Sigh... For class templates we want the location, for
+ // specialisations, we want the declaration... So just try both.
+ //
+ // TODO: Yeah, this code reads really bad.
+ let mut cursor = ty.declaration();
+ let mut kind = Self::kind_from_cursor(&cursor);
+ if kind.is_err() {
+ if let Some(location) = location {
+ kind = Self::kind_from_cursor(&location);
+ cursor = location;
+ }
+ }
+
+ let kind = try!(kind);
+
+ debug!("CompInfo::from_ty({:?}, {:?})", kind, cursor);
+
+
+ let mut ci = CompInfo::new(kind);
+ ci.is_anonymous = cursor.is_anonymous();
+ ci.template_args = match ty.num_template_args() {
+ // In forward declarations and not specializations, etc, they are in
+ // the ast, we'll meet them in CXCursor_TemplateTypeParameter
+ -1 => vec![],
+ len => {
+ let mut list = Vec::with_capacity(len as usize);
+ for i in 0..len {
+ let arg_type = ty.template_arg_type(i);
+ if arg_type.kind() != CXType_Invalid {
+ let type_id =
+ Item::from_ty_or_ref(arg_type, None, None, ctx);
+
+ list.push(type_id);
+ } else {
+ ci.has_non_type_template_params = true;
+ warn!("warning: Template parameter is not a type");
+ }
+ }
+
+ list
+ }
+ };
+
+ ci.ref_template = Item::parse(cursor.specialized(), None, ctx).ok();
+
+ let mut maybe_anonymous_struct_field = None;
+ cursor.visit(|cur, _other| {
+ if cur.kind() != CXCursor_FieldDecl {
+ if let Some((ty, ref _clang_ty)) = maybe_anonymous_struct_field {
+ let field = Field::new(None, ty, None, None, None, false);
+ ci.fields.push(field);
+ }
+ maybe_anonymous_struct_field = None;
+ }
+
+ match cur.kind() {
+ CXCursor_FieldDecl => {
+ match maybe_anonymous_struct_field.take() {
+ Some((ty, clang_ty)) => {
+ let mut used = false;
+ cur.visit(|child, _| {
+ if child.cur_type() == clang_ty {
+ used = true;
+ }
+ CXChildVisit_Continue
+ });
+ if !used {
+ let field = Field::new(None, ty, None, None, None, false);
+ ci.fields.push(field);
+ }
+ },
+ None => {}
+ }
+
+ let bit_width = cur.bit_width();
+ let field_type =
+ Item::from_ty_or_ref(cur.cur_type(), Some(*cur), Some(potential_id), ctx);
+ let comment = cur.raw_comment();
+ let annotations = Annotations::new(cur);
+ let name = cur.spelling();
+ let is_mutable = cursor.is_mutable_field();
+
+ // Name can be empty if there are bitfields, for example,
+ // see tests/headers/struct_with_bitfields.h
+ assert!(!name.is_empty() || bit_width.is_some(),
+ "Empty field name?");
+
+ let name = if name.is_empty() { None } else { Some(name) };
+
+ let field = Field::new(name, field_type, comment,
+ annotations, bit_width, is_mutable);
+ ci.fields.push(field);
+
+ // No we look for things like attributes and stuff.
+ cur.visit(|cur, _| {
+ if cur.kind() == CXCursor_UnexposedAttr {
+ ci.found_unknown_attr = true;
+ }
+ CXChildVisit_Continue
+ });
+
+ }
+ CXCursor_UnexposedAttr => {
+ ci.found_unknown_attr = true;
+ }
+ CXCursor_EnumDecl |
+ CXCursor_TypeAliasDecl |
+ CXCursor_TypedefDecl |
+ CXCursor_StructDecl |
+ CXCursor_UnionDecl |
+ CXCursor_ClassTemplate |
+ CXCursor_ClassDecl => {
+ let inner = Item::parse(*cur, Some(potential_id), ctx)
+ .expect("Inner ClassDecl");
+ if !ci.inner_types.contains(&inner) {
+ ci.inner_types.push(inner);
+ }
+ // A declaration of an union or a struct without name could
+ // also be an unnamed field, unfortunately.
+ if cur.spelling().is_empty() && cur.kind() != CXCursor_EnumDecl {
+ maybe_anonymous_struct_field = Some((inner, cur.cur_type()));
+ }
+ }
+ CXCursor_PackedAttr => {
+ ci.packed = true;
+ }
+ CXCursor_TemplateTypeParameter => {
+ // Yes! You can arrive here with an empty template parameter
+ // name! Awesome, isn't it?
+ //
+ // see tests/headers/empty_template_param_name.hpp
+ if cur.spelling().is_empty() {
+ return CXChildVisit_Continue;
+ }
+
+ let default_type =
+ Item::from_ty(&cur.cur_type(), Some(*cur), Some(potential_id), ctx).ok();
+
+ let param = Item::named_type(cur.spelling(), default_type, potential_id, ctx);
+ ci.template_args.push(param);
+ }
+ CXCursor_CXXBaseSpecifier => {
+ if !ci.has_vtable {
+ ci.has_vtable = cur.is_virtual_base();
+ }
+ let type_id = Item::from_ty(&cur.cur_type(), None, None, ctx)
+ .expect("BaseSpecifier");
+ ci.base_members.push(type_id);
+ }
+ CXCursor_CXXMethod => {
+ let is_virtual = cur.method_is_virtual();
+ let is_static = cur.method_is_static();
+ debug_assert!(!(is_static && is_virtual), "How?");
+
+ if !ci.has_vtable {
+ ci.has_vtable = is_virtual;
+ }
+
+ let linkage = cur.linkage();
+ if linkage != CXLinkage_External {
+ return CXChildVisit_Continue;
+ }
+
+ if cur.access_specifier() == CX_CXXPrivate {
+ return CXChildVisit_Continue;
+ }
+
+ let visibility = cur.visibility();
+ if visibility != CXVisibility_Default {
+ return CXChildVisit_Continue;
+ }
+
+ if cur.is_inlined_function() {
+ return CXChildVisit_Continue;
+ }
+
+ let spelling = cur.spelling();
+ if spelling.starts_with("operator") {
+ return CXChildVisit_Continue;
+ }
+
+ // This used to not be here, but then I tried generating
+ // stylo bindings with this (without path filters), and
+ // cried a lot with a method in gfx/Point.h
+ // (ToUnknownPoint), that somehow was causing the same type
+ // to be inserted in the map two times.
+ //
+ // I couldn't make a reduced test case, but anyway...
+ // Methods of template functions not only use to be inlined,
+ // but also instantiated, and we wouldn't be able to call
+ // them, so just bail out.
+ if !ci.template_args.is_empty() {
+ return CXChildVisit_Continue;
+ }
+
+ // NB: This gets us an owned `Function`, not a `FunctionSig`.
+ let method_signature = Item::parse(*cur, Some(potential_id), ctx)
+ .expect("CXXMethod");
+ let is_const = cur.method_is_const();
+ let method_kind = if is_static {
+ MethodKind::Static
+ } else if is_virtual {
+ MethodKind::Virtual
+ } else {
+ MethodKind::Normal
+ };
+ ci.methods.push(Method::new(method_kind, method_signature, is_const));
+ }
+ CXCursor_Destructor => {
+ if cur.method_is_virtual() {
+ // FIXME: Push to the method list?
+ ci.has_vtable = true;
+ }
+ ci.has_destructor = true;
+ }
+ CXCursor_NonTypeTemplateParameter => {
+ ci.has_non_type_template_params = true;
+ }
+ CXCursor_VarDecl => {
+ let linkage = cur.linkage();
+ if linkage != CXLinkage_External && linkage != CXLinkage_UniqueExternal {
+ return CXChildVisit_Continue;
+ }
+
+ let visibility = cur.visibility();
+ if visibility != CXVisibility_Default {
+ return CXChildVisit_Continue;
+ }
+
+ let item = Item::parse(*cur, Some(potential_id), ctx)
+ .expect("VarDecl");
+ ci.inner_vars.push(item);
+ }
+ // Intentionally not handled
+ CXCursor_CXXAccessSpecifier |
+ CXCursor_CXXFinalAttr |
+ CXCursor_Constructor |
+ CXCursor_FunctionTemplate |
+ CXCursor_ConversionFunction => {}
+ _ => {
+ warn!("unhandled composite member `{}` (kind {}) in `{}` ({})",
+ cur.spelling(), cur.kind(), cursor.spelling(),
+ cur.location());
+ }
+ }
+ CXChildVisit_Continue
+ });
+
+ if let Some((ty, _)) = maybe_anonymous_struct_field {
+ let field = Field::new(None, ty, None, None, None, false);
+ ci.fields.push(field);
+ }
+
+ Ok(ci)
+ }
+
+ fn kind_from_cursor(cursor: &clang::Cursor) -> Result<CompKind, ParseError> {
+ use clangll::*;
+ Ok(match cursor.kind() {
+ CXCursor_UnionDecl => CompKind::Union,
+ CXCursor_ClassDecl |
+ CXCursor_StructDecl => CompKind::Struct,
+ CXCursor_ClassTemplatePartialSpecialization |
+ CXCursor_ClassTemplate => {
+ match cursor.template_kind() {
+ CXCursor_UnionDecl => CompKind::Union,
+ _ => CompKind::Struct,
+ }
+ }
+ _ => {
+ warn!("Unknown kind for comp type: {:?}", cursor);
+ return Err(ParseError::Continue);
+ }
+ })
+ }
+
+ pub fn signature_contains_named_type(&self,
+ type_resolver: &TypeResolver,
+ ty: &Type) -> bool {
+ // We don't generate these, so rather don't make the codegen step to
+ // think we got it covered.
+ if self.has_non_type_template_params() {
+ return false;
+ }
+ self.template_args.iter().any(|arg| {
+ type_resolver.resolve_type(*arg)
+ .signature_contains_named_type(type_resolver, ty)
+ })
+ }
+
+ pub fn inner_types(&self) -> &[ItemId] {
+ &self.inner_types
+ }
+
+ pub fn inner_vars(&self) -> &[ItemId] {
+ &self.inner_vars
+ }
+
+ pub fn found_unknown_attr(&self) -> bool {
+ self.found_unknown_attr
+ }
+
+ pub fn packed(&self) -> bool {
+ self.packed
+ }
+
+ /// Returns whether this type needs an explicit vtable because it has
+ /// virtual methods and none of its base classes has already a vtable.
+ pub fn needs_explicit_vtable(&self, type_resolver: &TypeResolver) -> bool {
+ self.has_vtable(type_resolver) && !self.base_members.iter().any(|base| {
+ // NB: Ideally, we could rely in all these types being `comp`, and
+ // life would be beautiful.
+ //
+ // Unfortunately, given the way we implement --match-pat, and also
+ // that you can inherit from templated types, we need to handle
+ // other cases here too.
+ type_resolver
+ .resolve_type(*base)
+ .canonical_type(type_resolver)
+ .as_comp().map_or(false, |ci| {
+ ci.has_vtable(type_resolver)
+ })
+ })
+ }
+}
diff --git a/src/ir/context.rs b/src/ir/context.rs
new file mode 100644
index 00000000..5ddedda0
--- /dev/null
+++ b/src/ir/context.rs
@@ -0,0 +1,685 @@
+use super::ty::{Type, TypeKind, FloatKind};
+use super::item::{Item, ItemCanonicalName, ItemId};
+use super::item_kind::ItemKind;
+use super::int::IntKind;
+use super::module::Module;
+use clang::{self, Cursor};
+use std::borrow::{Cow, Borrow};
+use std::collections::btree_map::{self, BTreeMap};
+use std::collections::{HashSet, HashMap};
+use std::fmt;
+use syntax::ast::Ident;
+use syntax::codemap::{DUMMY_SP, Span};
+use syntax::ext::base::ExtCtxt;
+use parse::ClangItemParser;
+use BindgenOptions;
+
+// This is just convenience to avoid creating a manual debug impl for the
+// context.
+struct GenContext<'ctx>(ExtCtxt<'ctx>);
+
+impl<'ctx> fmt::Debug for GenContext <'ctx> {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ write!(fmt, "GenContext {{ ... }}")
+ }
+}
+
+/// A context used during parsing and generation of structs.
+#[derive(Debug)]
+pub struct BindgenContext<'ctx> {
+ /// The map of all the items parsed so far.
+ ///
+ /// It's a BTreeMap because we want the keys to be sorted to have consistent
+ /// output.
+ items: BTreeMap<ItemId, Item>,
+
+ /// Clang cursor to type map. This is needed to be able to associate types
+ /// with item ids during parsing.
+ ///
+ /// The cursor used for storage is the definition cursor.
+ types: HashMap<Cursor, ItemId>,
+
+ /// A cursor to module map. Similar reason than above.
+ modules: HashMap<Cursor, ItemId>,
+
+ /// The root module, this is guaranteed to be an item of kind Module.
+ root_module: ItemId,
+
+ /// Current module being traversed.
+ current_module: ItemId,
+
+ /// A stack with the current type declarations and types we're parsing. This
+ /// is needed to avoid infinite recursion when parsing a type like:
+ ///
+ /// struct c { struct c* next; };
+ ///
+ /// This means effectively, that a type has a potential ID before knowing if
+ /// it's a correct type. But that's not important in practice.
+ ///
+ /// We could also use the `types` HashMap, but my intention with it is that
+ /// only valid types and declarations end up there, and this could
+ /// potentially break that assumption.
+ ///
+ /// FIXME: Should not be public, though... meh.
+ pub currently_parsed_types: Vec<(Cursor, ItemId)>,
+
+ /// A HashSet with all the already parsed macro names. This is done to avoid
+ /// hard errors while parsing duplicated macros.
+ parsed_macros: HashSet<String>,
+
+ /// The active replacements collected from replaces="xxx" annotations.
+ replacements: HashMap<String, ItemId>,
+
+ collected_typerefs: bool,
+
+ /// Dummy structures for code generation.
+ gen_ctx: Option<&'ctx GenContext<'ctx>>,
+ span: Span,
+
+ /// The clang index for parsing.
+ index: clang::Index,
+
+ /// The translation unit for parsing.
+ translation_unit: clang::TranslationUnit,
+
+ /// The options given by the user via cli or other medium.
+ options: BindgenOptions,
+}
+
+impl<'ctx> BindgenContext<'ctx> {
+ pub fn new(options: BindgenOptions) -> Self {
+ use clangll;
+
+ let index = clang::Index::new(false, true);
+
+ let translation_unit =
+ clang::TranslationUnit::parse(&index, "", &options.clang_args, &[],
+ clangll::CXTranslationUnit_DetailedPreprocessingRecord);
+
+ let root_module = Self::build_root_module();
+ let mut me = BindgenContext {
+ items: Default::default(),
+ types: Default::default(),
+ modules: Default::default(),
+ root_module: root_module.id(),
+ current_module: root_module.id(),
+ currently_parsed_types: vec![],
+ parsed_macros: Default::default(),
+ replacements: Default::default(),
+ collected_typerefs: false,
+ gen_ctx: None,
+ span: DUMMY_SP,
+ index: index,
+ translation_unit: translation_unit,
+ options: options,
+ };
+
+ me.add_item(root_module, None, None);
+
+ me
+ }
+
+ pub fn add_item(&mut self,
+ item: Item,
+ declaration: Option<Cursor>,
+ location: Option<Cursor>) {
+ use clangll::{CXCursor_ClassTemplate, CXCursor_ClassTemplatePartialSpecialization};
+ debug!("BindgenContext::add_item({:?}, declaration: {:?}, loc: {:?}", item, declaration, location);
+ debug_assert!(declaration.is_some() || !item.kind().is_type() ||
+ item.kind().expect_type().is_builtin_or_named(),
+ "Adding a type without declaration?");
+
+ let id = item.id();
+ let is_type = item.kind().is_type();
+ let old_item = self.items.insert(id, item);
+ assert!(old_item.is_none(), "Inserted type twice?");
+
+ if is_type && declaration.is_some() {
+ let declaration = declaration.unwrap();
+ debug_assert_eq!(declaration, declaration.canonical());
+ if declaration.is_valid() {
+ let old = self.types.insert(declaration, id);
+ debug_assert_eq!(old, None);
+ } else if location.is_some() &&
+ (location.unwrap().kind() == CXCursor_ClassTemplate ||
+ location.unwrap().kind() == CXCursor_ClassTemplatePartialSpecialization) {
+ let old = self.types.insert(location.unwrap().canonical(), id);
+ debug_assert_eq!(old, None);
+ } else {
+ // This could happen, for example, with types like `int*` or
+ // similar.
+ //
+ // Fortunately, we don't care about those types being
+ // duplicated, so we can just ignore them.
+ debug!("Invalid declaration {:?} found for type {:?}",
+ declaration, self.items.get(&id).unwrap().kind().expect_type());
+ }
+ }
+ }
+
+ // TODO: Move all this syntax crap to other part of the code.
+ pub fn ext_cx(&self) -> &ExtCtxt<'ctx> {
+ &self.gen_ctx.expect("Not in gen phase").0
+ }
+
+ pub fn span(&self) -> Span {
+ self.span
+ }
+
+ /// Mangles a name so it doesn't conflict with any keyword.
+ pub fn rust_mangle<'a>(&self, name: &'a str) -> Cow<'a, str> {
+ use syntax::parse::token;
+ let ident = self.rust_ident_raw(&name);
+ let token = token::Ident(ident);
+ if token.is_any_keyword() ||
+ name.contains("@") ||
+ name.contains("?") ||
+ name.contains("$") ||
+ "bool" == name
+ {
+ let mut s = name.to_owned();
+ s = s.replace("@", "_");
+ s = s.replace("?", "_");
+ s = s.replace("$", "_");
+ s.push_str("_");
+ return Cow::Owned(s)
+ }
+ Cow::Borrowed(name)
+ }
+
+ /// Returns a mangled name as a rust identifier.
+ pub fn rust_ident(&self, name: &str) -> Ident {
+ self.rust_ident_raw(&self.rust_mangle(name))
+ }
+
+ pub fn rust_ident_raw<S>(&self, name: &S) -> Ident
+ where S: Borrow<str>,
+ {
+ self.ext_cx().ident_of(name.borrow())
+ }
+
+ pub fn items<'a>(&'a self) -> btree_map::Iter<'a, ItemId, Item> {
+ self.items.iter()
+ }
+
+ pub fn collected_typerefs(&self) -> bool {
+ self.collected_typerefs
+ }
+
+ fn collect_typerefs(&mut self) -> Vec<(ItemId, clang::Type, Option<clang::Cursor>)> {
+ debug_assert!(!self.collected_typerefs);
+ self.collected_typerefs = true;
+ let mut typerefs = vec![];
+ for (id, ref mut item) in &mut self.items {
+ let kind = item.kind();
+ let ty = match kind.as_type() {
+ Some(ty) => ty,
+ None => continue,
+ };
+
+ match *ty.kind() {
+ TypeKind::UnresolvedTypeRef(ref ty, loc) => {
+ typerefs.push((*id, ty.clone(), loc));
+ }
+ _ => {},
+ };
+ }
+ typerefs
+ }
+
+ fn resolve_typerefs(&mut self) {
+ let typerefs = self.collect_typerefs();
+
+ for (id, ty, loc) in typerefs {
+ let _resolved = {
+ let resolved = Item::from_ty(&ty, loc, None, self)
+ .expect("What happened?");
+ let mut item = self.items.get_mut(&id).unwrap();
+
+ *item.kind_mut().as_type_mut().unwrap().kind_mut() =
+ TypeKind::ResolvedTypeRef(resolved);
+ resolved
+ };
+
+ // Something in the STL is trolling me. I don't need this assertion
+ // right now, but worth investigating properly once this lands.
+ //
+ // debug_assert!(self.items.get(&resolved).is_some(), "How?");
+ }
+ }
+
+ fn process_replacements(&mut self) {
+ if self.replacements.is_empty() {
+ return;
+ }
+
+ // FIXME: This is linear, but the replaces="xxx" annotation was already
+ // there, and for better or worse it's useful, sigh...
+ //
+ // We leverage the ResolvedTypeRef thing, though, which is cool :P.
+
+ let mut replacements = vec![];
+
+ for (id, item) in self.items.iter() {
+ let ty = match item.kind().as_type() {
+ Some(ty) => ty,
+ None => continue,
+ };
+
+ // canonical_name calls are expensive.
+ let ci = match ty.as_comp() {
+ Some(ci) => ci,
+ None => continue,
+ };
+
+ if ci.is_template_specialization() {
+ continue;
+ }
+
+ if let Some(replacement) = self.replacements.get(&item.canonical_name(self)) {
+ if replacement != id {
+ // We set this just after parsing the annotation. It's
+ // very unlikely, but this can happen.
+ if self.items.get(replacement).is_some() {
+ replacements.push((*id, *replacement));
+ }
+ }
+ }
+ }
+
+ for (id, replacement) in replacements {
+ let mut item = self.items.get_mut(&id).unwrap();
+ *item.kind_mut().as_type_mut().unwrap().kind_mut() =
+ TypeKind::ResolvedTypeRef(replacement);
+ }
+ }
+
+ // Enters in the generation phase.
+ pub fn gen<F, Out>(&mut self, cb: F) -> Out
+ where F: FnOnce(&Self) -> Out
+ {
+ use syntax::ext::expand::ExpansionConfig;
+ use syntax::codemap::{ExpnInfo, MacroBang, NameAndSpan};
+ use syntax::ext::base;
+ use syntax::parse;
+ use std::mem;
+
+ let cfg = ExpansionConfig::default("xxx".to_owned());
+ let sess = parse::ParseSess::new();
+ let mut loader = base::DummyMacroLoader;
+ let mut ctx =
+ GenContext(base::ExtCtxt::new(&sess, vec![], cfg, &mut loader));
+
+ ctx.0.bt_push(ExpnInfo {
+ call_site: self.span,
+ callee: NameAndSpan {
+ format: MacroBang(parse::token::intern("")),
+ allow_internal_unstable: false,
+ span: None
+ }
+ });
+
+ // FIXME: This is evil, we should move code generation to use a wrapper
+ // of BindgenContext instead, I guess. Even though we know it's fine
+ // because we remove it before the end of this function.
+ self.gen_ctx = Some(unsafe { mem::transmute(&ctx) });
+
+ self.resolve_typerefs();
+ self.process_replacements();
+
+ let ret = cb(self);
+ self.gen_ctx = None;
+ ret
+ }
+
+ // This deserves a comment. Builtin types don't get a valid declaration, so
+ // we can't add it to the cursor->type map.
+ //
+ // That being said, they're not generated anyway, and are few, so the
+ // duplication and special-casing is fine.
+ //
+ // If at some point we care about the memory here, probably a map TypeKind
+ // -> builtin type ItemId would be the best to improve that.
+ fn add_builtin_item(&mut self, item: Item) {
+ debug_assert!(item.kind().is_type());
+ let id = item.id();
+ let old_item = self.items.insert(id, item);
+ assert!(old_item.is_none(), "Inserted type twice?");
+ }
+
+ fn build_root_module() -> Item {
+ let module = Module::new(Some("root".into()));
+ let id = ItemId::next();
+ Item::new(id, None, None, id, ItemKind::Module(module))
+ }
+
+ pub fn root_module(&self) -> ItemId {
+ self.root_module
+ }
+
+ pub fn resolve_type(&self, type_id: ItemId) -> &Type {
+ self.items.get(&type_id).unwrap().kind().expect_type()
+ }
+
+ pub fn safe_resolve_type(&self, type_id: ItemId) -> Option<&Type> {
+ self.items.get(&type_id).map(|t| t.kind().expect_type())
+ }
+
+ pub fn resolve_item_fallible(&self, item_id: ItemId) -> Option<&Item> {
+ self.items.get(&item_id)
+ }
+
+ pub fn resolve_item(&self, item_id: ItemId) -> &Item {
+ match self.items.get(&item_id) {
+ Some(item) => item,
+ None => panic!("Not an item: {:?}", item_id),
+ }
+ }
+
+ pub fn current_module(&self) -> ItemId {
+ self.current_module
+ }
+
+ /// This is one of the hackiest methods in all the parsing code. This method
+ /// is used to allow having templates with another argument names instead of
+ /// the canonical ones.
+ ///
+ /// This is surprisingly difficult to do with libclang, due to the fact that
+ /// partial template specializations don't provide explicit template
+ /// argument information.
+ ///
+ /// The only way to do this as far as I know, is inspecting manually the
+ /// AST, looking for TypeRefs inside. This, unfortunately, doesn't work for
+ /// more complex cases, see the comment on the assertion below.
+ ///
+ /// To see an example of what this handles:
+ ///
+ /// ```
+ /// template<typename T>
+ /// class Incomplete {
+ /// T p;
+ /// };
+ ///
+ /// template<typename U>
+ /// class Foo {
+ /// Incomplete<U> bar;
+ /// };
+ /// ```
+ fn build_template_wrapper(&mut self,
+ wrapping: ItemId,
+ parent_id: ItemId,
+ ty: &clang::Type,
+ location: clang::Cursor) -> ItemId {
+ use clangll::*;
+ let mut args = vec![];
+ let mut found_invalid_template_ref = false;
+ let self_id = ItemId::next();
+ location.visit(|c, _| {
+ if c.kind() == CXCursor_TemplateRef &&
+ c.cur_type().kind() == CXType_Invalid {
+ found_invalid_template_ref = true;
+ }
+ if c.kind() == CXCursor_TypeRef {
+ let new_ty =
+ Item::from_ty_or_ref(c.cur_type(), Some(*c), Some(self_id), self);
+ args.push(new_ty);
+ }
+ CXChildVisit_Continue
+ });
+
+ let item = {
+ let wrapping_type = self.resolve_type(wrapping);
+ let old_args = match *wrapping_type.kind() {
+ TypeKind::Comp(ref ci) => ci.template_args(),
+ _ => panic!("how?"),
+ };
+ // The following assertion actually fails with partial template
+ // specialization. But as far as I know there's no way at all to
+ // grab the specialized types from neither the AST or libclang.
+ //
+ // This flaw was already on the old parser, but I now think it has
+ // no clear solution.
+ //
+ // For an easy example in which there's no way at all of getting the
+ // `int` type, except manually parsing the spelling:
+ //
+ // template<typename T, typename U>
+ // class Incomplete {
+ // T d;
+ // U p;
+ // };
+ //
+ // template<typename U>
+ // class Foo {
+ // Incomplete<U, int> bar;
+ // };
+ //
+ // debug_assert_eq!(old_args.len(), args.len());
+ //
+ // That being said, this is not so common, so just error! and hope
+ // for the best, returning the previous type, who knows.
+ if old_args.len() != args.len() {
+ error!("Found partial template specialization, expect dragons!");
+ return wrapping;
+ }
+
+ let type_kind = TypeKind::TemplateRef(wrapping, args);
+ let name = ty.spelling();
+ let name = if name.is_empty() { None } else { Some(name) };
+ let ty = Type::new(name, ty.fallible_layout().ok(), type_kind, ty.is_const());
+ Item::new(self_id, None, None, parent_id, ItemKind::Type(ty))
+ };
+
+ // Bypass all the validations in add_item explicitly.
+ self.items.insert(self_id, item);
+ self_id
+ }
+
+ /// Looks up for an already resolved type, either because it's builtin, or
+ /// because we already have it in the map.
+ pub fn builtin_or_resolved_ty(&mut self,
+ parent_id: Option<ItemId>,
+ ty: &clang::Type,
+ location: Option<clang::Cursor>) -> Option<ItemId> {
+ use clangll::{CXCursor_ClassTemplate, CXCursor_ClassTemplatePartialSpecialization};
+ debug!("builtin_or_resolved_ty: {:?}, {:?}, {:?}", ty, location, parent_id);
+ let mut declaration = ty.declaration();
+ if !declaration.is_valid() {
+ if let Some(location) = location {
+ if location.kind() == CXCursor_ClassTemplate ||
+ location.kind() == CXCursor_ClassTemplatePartialSpecialization {
+ declaration = location;
+ }
+ }
+ }
+ let canonical_declaration = declaration.canonical();
+ if canonical_declaration.is_valid() {
+ // First lookup to see if we already have it resolved.
+ let id = self.types.get(&canonical_declaration).map(|id| *id);
+ if let Some(id) = id {
+ debug!("Already resolved ty {:?}, {:?}, {:?} {:?}",
+ id, declaration, ty, location);
+ // If the declaration existed, we *might* be done, but it's not
+ // the case for class templates, where the template arguments
+ // may vary.
+ //
+ // In this case, we create a TemplateRef with the new template
+ // arguments, pointing to the canonical template.
+ //
+ // Note that we only do it if parent_id is some, and we have a
+ // location for building the new arguments, the template
+ // argument names don't matter in the global context.
+ if (declaration.kind() == CXCursor_ClassTemplate ||
+ declaration.kind() == CXCursor_ClassTemplatePartialSpecialization) &&
+ *ty != canonical_declaration.cur_type() &&
+ location.is_some() && parent_id.is_some() {
+ return Some(
+ self.build_template_wrapper(id, parent_id.unwrap(), ty,
+ location.unwrap()));
+ }
+
+ return Some(self.build_ty_wrapper(id, parent_id, ty));
+ }
+ }
+
+ debug!("Not resolved, maybe builtin?");
+
+ // Else, build it.
+ self.build_builtin_ty(ty, declaration)
+ }
+
+ // This is unfortunately a lot of bloat, but is needed to properly track
+ // constness et. al.
+ //
+ // We should probably make the constness tracking separate, so it doesn't
+ // bloat that much, but hey, we already bloat the heck out of builtin types.
+ fn build_ty_wrapper(&mut self,
+ wrapped_id: ItemId,
+ parent_id: Option<ItemId>,
+ ty: &clang::Type) -> ItemId {
+ let id = ItemId::next();
+ let spelling = ty.spelling();
+ let is_const = ty.is_const();
+ let layout = ty.fallible_layout().ok();
+ let type_kind = TypeKind::ResolvedTypeRef(wrapped_id);
+ let ty = Type::new(Some(spelling), layout, type_kind, is_const);
+ let item = Item::new(id, None, None,
+ parent_id.unwrap_or(self.current_module), ItemKind::Type(ty));
+ self.add_builtin_item(item);
+ id
+ }
+
+ fn build_builtin_ty(&mut self,
+ ty: &clang::Type,
+ _declaration: Cursor) -> Option<ItemId> {
+ use clangll::*;
+ let type_kind = match ty.kind() {
+ CXType_NullPtr => TypeKind::NullPtr,
+ CXType_Void => TypeKind::Void,
+ CXType_Bool => TypeKind::Int(IntKind::Bool),
+ CXType_Int => TypeKind::Int(IntKind::Int),
+ CXType_UInt => TypeKind::Int(IntKind::UInt),
+ CXType_SChar |
+ CXType_Char_S => TypeKind::Int(IntKind::Char),
+ CXType_UChar |
+ CXType_Char_U => TypeKind::Int(IntKind::UChar),
+ CXType_Short => TypeKind::Int(IntKind::Short),
+ CXType_UShort => TypeKind::Int(IntKind::UShort),
+ CXType_WChar |
+ CXType_Char16 => TypeKind::Int(IntKind::U16),
+ CXType_Char32 => TypeKind::Int(IntKind::U32),
+ CXType_Long => TypeKind::Int(IntKind::Long),
+ CXType_ULong => TypeKind::Int(IntKind::ULong),
+ CXType_LongLong => TypeKind::Int(IntKind::LongLong),
+ CXType_ULongLong => TypeKind::Int(IntKind::ULongLong),
+ CXType_Float => TypeKind::Float(FloatKind::Float),
+ CXType_Double => TypeKind::Float(FloatKind::Double),
+ CXType_LongDouble => TypeKind::Float(FloatKind::LongDouble),
+ _ => return None,
+ };
+
+ let spelling = ty.spelling();
+ let is_const = ty.is_const();
+ let layout = ty.fallible_layout().ok();
+ let ty = Type::new(Some(spelling), layout, type_kind, is_const);
+ let id = ItemId::next();
+ let item = Item::new(id, None, None, self.root_module, ItemKind::Type(ty));
+ self.add_builtin_item(item);
+ Some(id)
+ }
+
+ pub fn translation_unit(&self) -> &clang::TranslationUnit {
+ &self.translation_unit
+ }
+
+ pub fn parsed_macro(&self, macro_name: &str) -> bool {
+ self.parsed_macros.contains(macro_name)
+ }
+
+ pub fn note_parsed_macro(&mut self, macro_name: String) {
+ debug_assert!(!self.parsed_macros.contains(&macro_name));
+ self.parsed_macros.insert(macro_name);
+ }
+
+ pub fn in_codegen_phase(&self) -> bool {
+ self.gen_ctx.is_some()
+ }
+
+ /// This is a bit of a hack, but it's done so using the replaces="xxx"
+ /// annotation implies hide in the other type.
+ pub fn replace(&mut self, name: &str, potential_ty: ItemId) {
+ self.replacements.insert(name.into(), potential_ty);
+ }
+
+ pub fn hidden_by_name(&self, name: &str) -> bool {
+ debug_assert!(self.in_codegen_phase(),
+ "You're not supposed to call this yet");
+ self.options.hidden_types.contains(name)
+ }
+
+ pub fn opaque_by_name(&self, name: &str) -> bool {
+ debug_assert!(self.in_codegen_phase(),
+ "You're not supposed to call this yet");
+ self.options.opaque_types.contains(name)
+ }
+
+ pub fn options(&self) -> &BindgenOptions {
+ &self.options
+ }
+
+ /// Given a CXCursor_Namespace cursor, return the item id of the
+ /// corresponding module, or create one on the fly.
+ pub fn module(&mut self, cursor: clang::Cursor) -> ItemId {
+ use clangll::*;
+ assert!(cursor.kind() == CXCursor_Namespace, "Be a nice person");
+ let cursor = cursor.canonical();
+ let module_id = match self.modules.get(&cursor) {
+ Some(id) => return *id,
+ None => ItemId::next(),
+ };
+
+ let module_name = self.translation_unit
+ .tokens(&cursor).and_then(|tokens| {
+ if tokens.len() <= 1 {
+ None
+ } else {
+ match &*tokens[1].spelling {
+ "{" => None,
+ s => Some(s.to_owned()),
+ }
+ }
+ });
+
+ let module = Module::new(module_name);
+ let module = Item::new(module_id, None, None, self.current_module,
+ ItemKind::Module(module));
+
+ self.add_item(module, None, None);
+
+ module_id
+ }
+
+ pub fn with_module<F>(&mut self, module_id: ItemId, cb: F)
+ where F: FnOnce(&mut Self, &mut Vec<ItemId>)
+ {
+ debug_assert!(self.resolve_item(module_id).kind().is_module(), "Wat");
+
+ let previous_id = self.current_module;
+ self.current_module = module_id;
+
+ let mut children = vec![];
+ cb(self, &mut children);
+
+ self.items.get_mut(&module_id).unwrap()
+ .as_module_mut().expect("Not a module?")
+ .children_mut().extend(children.into_iter());
+
+ self.current_module = previous_id;
+ }
+}
+
+/// This was originally a type that only exposes the resolve_type operation to
+/// its consumers.
+///
+/// Later a made resolve_type public, so... meh. It should go away soon.
+pub type TypeResolver<'ctx> = BindgenContext<'ctx>;
diff --git a/src/ir/enum_ty.rs b/src/ir/enum_ty.rs
new file mode 100644
index 00000000..c85ee07a
--- /dev/null
+++ b/src/ir/enum_ty.rs
@@ -0,0 +1,110 @@
+use super::item::{Item, ItemId};
+use super::ty::TypeKind;
+use super::context::BindgenContext;
+use parse::{ClangItemParser, ParseError};
+use clang;
+
+#[derive(Debug)]
+pub struct Enum {
+ /// The representation used for this enum.
+ /// Should be an IntKind type.
+ ///
+ /// It's None if the enum is a forward declaration and isn't defined
+ /// anywhere else, see tests/headers/func_ptr_in_struct.h
+ repr: Option<ItemId>,
+ /// The different variants, with explicit values.
+ variants: Vec<EnumVariant>,
+}
+
+impl Enum {
+ pub fn new(repr: Option<ItemId>, variants: Vec<EnumVariant>) -> Self {
+ Enum {
+ repr: repr,
+ variants: variants,
+ }
+ }
+
+ pub fn repr(&self) -> Option<ItemId> {
+ self.repr
+ }
+
+ pub fn variants(&self) -> &[EnumVariant] {
+ &self.variants
+ }
+
+ pub fn from_ty(ty: &clang::Type,
+ ctx: &mut BindgenContext) -> Result<Self, ParseError> {
+ use clangll::*;
+ if ty.kind() != CXType_Enum {
+ return Err(ParseError::Continue);
+ }
+
+ let declaration = ty.declaration().canonical();
+ let repr = Item::from_ty(&declaration.enum_type(), None, None, ctx).ok();
+ let mut variants = vec![];
+
+ let is_signed = match repr {
+ Some(repr) => {
+ let repr_type = ctx.resolve_type(repr);
+ match *repr_type.canonical_type(ctx).kind() {
+ TypeKind::Int(ref int_kind) => int_kind.is_signed(),
+ ref other => panic!("Since when enums can be non-integers? {:?}", other),
+ }
+ }
+ // Assume signedness since the default type by the C standard is an
+ // int.
+ None => true,
+ };
+
+ declaration.visit(|cursor, _| {
+ if cursor.kind() == CXCursor_EnumConstantDecl {
+ let name = cursor.spelling();
+ let comment = cursor.raw_comment();
+ let val = if is_signed {
+ EnumVariantValue::Signed(cursor.enum_val_signed())
+ } else {
+ EnumVariantValue::Unsigned(cursor.enum_val_unsigned())
+ };
+ variants.push(EnumVariant::new(name, comment, val));
+ }
+ CXChildVisit_Continue
+ });
+
+ Ok(Enum::new(repr, variants))
+ }
+}
+
+/// A single enum variant, to be contained only in an enum.
+#[derive(Debug)]
+pub struct EnumVariant {
+ /// The name of the variant.
+ name: String,
+ /// An optional doc comment.
+ comment: Option<String>,
+ /// The integer value of the variant.
+ val: EnumVariantValue,
+}
+
+#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
+pub enum EnumVariantValue {
+ Signed(i64),
+ Unsigned(u64),
+}
+
+impl EnumVariant {
+ pub fn new(name: String, comment: Option<String>, val: EnumVariantValue) -> Self {
+ EnumVariant {
+ name: name,
+ comment: comment,
+ val: val,
+ }
+ }
+
+ pub fn name(&self) -> &str {
+ &self.name
+ }
+
+ pub fn val(&self) -> EnumVariantValue {
+ self.val
+ }
+}
diff --git a/src/ir/function.rs b/src/ir/function.rs
new file mode 100644
index 00000000..b95ac57b
--- /dev/null
+++ b/src/ir/function.rs
@@ -0,0 +1,220 @@
+use super::item::{Item, ItemId};
+use super::ty::TypeKind;
+use super::context::BindgenContext;
+use syntax::abi;
+use clang;
+use clangll::Enum_CXCallingConv;
+use parse::{ClangItemParser, ClangSubItemParser, ParseError, ParseResult};
+
+/// A function declaration , with a signature, arguments, and argument names.
+///
+/// The argument names vector must be the same length as the ones in the
+/// signature.
+#[derive(Debug)]
+pub struct Function {
+ name: String,
+ /// The mangled name, that is, the symbol.
+ mangled_name: Option<String>,
+ /// The id pointing to the current function signature.
+ signature: ItemId,
+ /// The doc comment on the function, if any.
+ comment: Option<String>,
+}
+
+impl Function {
+ pub fn new(name: String,
+ mangled_name: Option<String>,
+ sig: ItemId,
+ comment: Option<String>) -> Self {
+ Function {
+ name: name,
+ mangled_name: mangled_name,
+ signature: sig,
+ comment: comment,
+ }
+ }
+
+ pub fn name(&self) -> &str {
+ &self.name
+ }
+
+ pub fn mangled_name(&self) -> Option<&str> {
+ self.mangled_name.as_ref().map(|n| &**n)
+ }
+
+ pub fn signature(&self) -> ItemId {
+ self.signature
+ }
+}
+
+/// A function signature.
+#[derive(Debug)]
+pub struct FunctionSig {
+ /// The return type of the function.
+ return_type: ItemId,
+ /// The type of the arguments, optionally with the name of the argument when
+ /// declared.
+ argument_types: Vec<(Option<String>, ItemId)>,
+ /// Whether this function is variadic.
+ is_variadic: bool,
+ /// The abi of this function.
+ abi: abi::Abi,
+}
+
+fn get_abi(cc: Enum_CXCallingConv) -> abi::Abi {
+ use clangll::*;
+ match cc {
+ CXCallingConv_Default => abi::Abi::C,
+ CXCallingConv_C => abi::Abi::C,
+ CXCallingConv_X86StdCall => abi::Abi::Stdcall,
+ CXCallingConv_X86FastCall => abi::Abi::Fastcall,
+ CXCallingConv_AAPCS => abi::Abi::Aapcs,
+ CXCallingConv_X86_64Win64 => abi::Abi::Win64,
+ other => panic!("unsupported calling convention: {}", other),
+ }
+}
+
+pub fn cursor_mangling(cursor: &clang::Cursor) -> Option<String> {
+ let mut mangling = cursor.mangling();
+
+ // Try to undo backend linkage munging (prepended _, generally)
+ if cfg!(target_os = "macos") {
+ mangling.remove(0);
+ }
+
+ if mangling.is_empty() { None } else { Some(mangling) }
+}
+
+impl FunctionSig {
+ pub fn new(return_type: ItemId,
+ arguments: Vec<(Option<String>, ItemId)>,
+ is_variadic: bool,
+ abi: abi::Abi) -> Self {
+ FunctionSig {
+ return_type: return_type,
+ argument_types: arguments,
+ is_variadic: is_variadic,
+ abi: abi,
+ }
+ }
+
+ pub fn from_ty(ty: &clang::Type,
+ cursor: &clang::Cursor,
+ ctx: &mut BindgenContext) -> Result<Self, ParseError> {
+ use clangll::*;
+ debug!("FunctionSig::from_ty {:?} {:?}", ty, cursor);
+
+ // Don't parse operatorxx functions in C++
+ let spelling = cursor.spelling();
+ if spelling.starts_with("operator") {
+ return Err(ParseError::Continue);
+ }
+
+ let cursor = if cursor.is_valid() {
+ *cursor
+ } else {
+ ty.declaration()
+ };
+ let mut args: Vec<_> = match cursor.kind() {
+ CXCursor_FunctionDecl |
+ CXCursor_CXXMethod => {
+ // For CXCursor_FunctionDecl, cursor.args() is the reliable way
+ // to get parameter names and types.
+ cursor.args().iter().map(|arg| {
+ let arg_ty = arg.cur_type();
+ let name = arg.spelling();
+ let name = if name.is_empty() { None } else { Some(name) };
+ let ty = Item::from_ty(&arg_ty, Some(*arg), None, ctx)
+ .expect("Argument?");
+ (name, ty)
+ }).collect()
+ }
+ _ => {
+ // For non-CXCursor_FunctionDecl, visiting the cursor's children
+ // is the only reliable way to get parameter names.
+ let mut args = vec![];
+ cursor.visit(|c, _| {
+ if c.kind() == CXCursor_ParmDecl {
+ let ty = Item::from_ty(&c.cur_type(), Some(*c), None, ctx)
+ .expect("ParmDecl?");
+ let name = c.spelling();
+ let name = if name.is_empty() { None } else { Some(name) };
+ args.push((name, ty));
+ }
+ CXChildVisit_Continue
+ });
+ args
+ }
+ };
+
+ if cursor.kind() == CXCursor_CXXMethod {
+ let is_const = cursor.method_is_const();
+ let is_virtual = cursor.method_is_virtual();
+ let is_static = cursor.method_is_static();
+ if !is_static && !is_virtual {
+ let class = Item::parse(cursor.semantic_parent(), None, ctx)
+ .expect("Expected to parse the class");
+ let ptr = Item::builtin_type(TypeKind::Pointer(class), is_const, ctx);
+ args.insert(0, (Some("this".into()), ptr));
+ } else if is_virtual {
+ let void = Item::builtin_type(TypeKind::Void, false, ctx);
+ let ptr = Item::builtin_type(TypeKind::Pointer(void), false, ctx);
+ args.insert(0, (Some("this".into()), ptr));
+ }
+ }
+
+ let ret = try!(Item::from_ty(&ty.ret_type(), None, None, ctx));
+ let abi = get_abi(ty.call_conv());
+
+ Ok(Self::new(ret, args, ty.is_variadic(), abi))
+ }
+
+ pub fn return_type(&self) -> ItemId {
+ self.return_type
+ }
+
+ pub fn argument_types(&self) -> &[(Option<String>, ItemId)] {
+ &self.argument_types
+ }
+
+ pub fn abi(&self) -> abi::Abi {
+ self.abi
+ }
+
+ pub fn is_variadic(&self) -> bool {
+ // Clang reports some functions as variadic when they *might* be
+ // variadic. We do the argument check because rust doesn't codegen well
+ // variadic functions without an initial argument.
+ self.is_variadic && !self.argument_types.is_empty()
+ }
+}
+
+impl ClangSubItemParser for Function {
+ fn parse(cursor: clang::Cursor,
+ context: &mut BindgenContext) -> Result<ParseResult<Self>, ParseError> {
+ use clangll::*;
+ match cursor.kind() {
+ CXCursor_FunctionDecl |
+ CXCursor_CXXMethod => {},
+ _ => return Err(ParseError::Continue),
+ };
+
+ debug!("Function::parse({:?}, {:?})", cursor, cursor.cur_type());
+
+ // Grab the signature using Item::from_ty.
+ let sig = try!(Item::from_ty(&cursor.cur_type(), Some(cursor), None, context));
+
+ let name = cursor.spelling();
+ assert!(!name.is_empty(), "Empty function name?");
+
+ let mut mangled_name = cursor_mangling(&cursor);
+ if mangled_name.as_ref() == Some(&name) {
+ mangled_name = None;
+ }
+
+ let comment = cursor.raw_comment();
+
+ let function = Self::new(name, mangled_name, sig, comment);
+ Ok(ParseResult::New(function, Some(cursor)))
+ }
+}
diff --git a/src/ir/int.rs b/src/ir/int.rs
new file mode 100644
index 00000000..d2769b77
--- /dev/null
+++ b/src/ir/int.rs
@@ -0,0 +1,30 @@
+#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
+pub enum IntKind {
+ Bool,
+ Char,
+ UChar,
+ Short,
+ UShort,
+ Int,
+ UInt,
+ Long,
+ ULong,
+ LongLong,
+ ULongLong,
+ U16, // For Char16 and Wchar
+ U32, // For Char32
+ // Though now we're at it we could add equivalents for the rust types...
+}
+
+impl IntKind {
+ pub fn is_signed(&self) -> bool {
+ use self::IntKind::*;
+ match *self {
+ Bool | UChar | UShort |
+ UInt | ULong | ULongLong | U16 | U32 => false,
+
+ Char | Short | Int |
+ Long | LongLong => true,
+ }
+ }
+}
diff --git a/src/ir/item.rs b/src/ir/item.rs
new file mode 100644
index 00000000..c9ac71a4
--- /dev/null
+++ b/src/ir/item.rs
@@ -0,0 +1,681 @@
+use super::context::BindgenContext;
+use super::item_kind::ItemKind;
+use super::ty::{Type, TypeKind};
+use super::function::Function;
+use super::module::Module;
+use super::annotations::Annotations;
+use std::fmt;
+use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
+use parse::{ClangItemParser, ClangSubItemParser, ParseError, ParseResult};
+use clang;
+use clangll;
+
+/// A trait to get the canonical name from an item.
+///
+/// This is the trait that will eventually isolate all the logic related to name
+/// mangling and that kind of stuff.
+///
+/// This assumes no nested paths, at some point I'll have to make it a more
+/// complex thing.
+///
+/// This name is required to be safe for Rust, that is, is not expected to
+/// return any rust keyword from here.
+pub trait ItemCanonicalName {
+ fn canonical_name(&self, ctx: &BindgenContext) -> String;
+}
+
+/// The same, but specifies the path that needs to be followed to reach an item.
+///
+/// To contrast with canonical_name, here's an example:
+///
+/// ```
+/// namespace foo {
+/// const BAR = 3;
+/// }
+/// ```
+///
+/// For bar, the canonical path is foo::BAR, while the canonical name is just
+/// BAR.
+pub trait ItemCanonicalPath {
+ fn canonical_path(&self, ctx: &BindgenContext) -> Vec<String>;
+}
+
+/// A single identifier for an item.
+///
+/// TODO: Build stronger abstractions on top of this, like TypeId(ItemId), ...
+#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
+pub struct ItemId(usize);
+
+impl fmt::Display for ItemId {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ try!(write!(fmt, "_bindgen_id_"));
+ self.0.fmt(fmt)
+ }
+}
+
+pub static NEXT_ITEM_ID: AtomicUsize = ATOMIC_USIZE_INIT;
+
+impl ItemId {
+ pub fn next() -> Self {
+ ItemId(NEXT_ITEM_ID.fetch_add(1, Ordering::Relaxed))
+ }
+}
+
+// Pure convenience
+impl ItemCanonicalName for ItemId {
+ fn canonical_name(&self, ctx: &BindgenContext) -> String {
+ debug_assert!(ctx.in_codegen_phase(),
+ "You're not supposed to call this yet");
+ ctx.resolve_item(*self).canonical_name(ctx)
+ }
+}
+
+impl ItemCanonicalPath for ItemId {
+ fn canonical_path(&self, ctx: &BindgenContext) -> Vec<String> {
+ debug_assert!(ctx.in_codegen_phase(),
+ "You're not supposed to call this yet");
+ ctx.resolve_item(*self).canonical_path(ctx)
+ }
+}
+
+#[derive(Debug)]
+pub struct Item {
+ /// This item's id.
+ id: ItemId,
+ /// A doc comment over the item, if any.
+ comment: Option<String>,
+ /// Annotations extracted from the doc comment, or the default ones
+ /// otherwise.
+ annotations: Annotations,
+ /// An item's parent id. This will most likely be a class where this item
+ /// was declared, or a module, etc.
+ ///
+ /// All the items have a parent, except the root module, in which case the
+ /// parent id is its own id.
+ parent_id: ItemId,
+ /// The item kind.
+ kind: ItemKind,
+}
+
+impl Item {
+ pub fn new(id: ItemId,
+ comment: Option<String>,
+ annotations: Option<Annotations>,
+ parent_id: ItemId,
+ kind: ItemKind) -> Self {
+ debug_assert!(id != parent_id || kind.is_module());
+ Item {
+ id: id,
+ parent_id: parent_id,
+ comment: comment,
+ annotations: annotations.unwrap_or_default(),
+ kind: kind,
+ }
+ }
+
+ pub fn id(&self) -> ItemId {
+ self.id
+ }
+
+ pub fn parent_id(&self) -> ItemId {
+ self.parent_id
+ }
+
+ pub fn comment(&self) -> Option<&str> {
+ self.comment.as_ref().map(|c| &**c)
+ }
+
+ pub fn kind(&self) -> &ItemKind {
+ &self.kind
+ }
+
+ pub fn kind_mut(&mut self) -> &mut ItemKind {
+ &mut self.kind
+ }
+
+ pub fn is_toplevel(&self, ctx: &BindgenContext) -> bool {
+ // FIXME: Workaround for some types falling behind when parsing weird
+ // stl classes, for example.
+ if ctx.options().enable_cxx_namespaces &&
+ self.kind().is_module() &&
+ self.id() != ctx.root_module() {
+ return false;
+ }
+
+ let mut parent = self.parent_id;
+ loop {
+ let parent_item = match ctx.resolve_item_fallible(parent) {
+ Some(item) => item,
+ None => return false,
+ };
+
+ if parent_item.id() == ctx.root_module() {
+ return true;
+ } else if ctx.options().enable_cxx_namespaces || !parent_item.kind().is_module() {
+ return false;
+ }
+
+ parent = parent_item.parent_id();
+ }
+ }
+
+ pub fn expect_type(&self) -> &Type {
+ self.kind().expect_type()
+ }
+
+ pub fn expect_function(&self) -> &Function {
+ self.kind().expect_function()
+ }
+
+ pub fn applicable_template_args(&self, ctx: &BindgenContext) -> Vec<ItemId> {
+ let ty = match *self.kind() {
+ ItemKind::Type(ref ty) => ty,
+ _ => return vec![],
+ };
+
+ fn parent_contains(ctx: &BindgenContext,
+ parent_template_args: &[ItemId],
+ item: ItemId) -> bool {
+ let item_ty = ctx.resolve_type(item);
+ parent_template_args.iter().any(|parent_item| {
+ let parent_ty = ctx.resolve_type(*parent_item);
+ match (parent_ty.kind(), item_ty.kind()) {
+ (&TypeKind::Named(ref n, _), &TypeKind::Named(ref i, _)) => n == i,
+ _ => false,
+ }
+ })
+ }
+
+ match *ty.kind() {
+ TypeKind::Named(..) => vec![self.id()],
+ TypeKind::Array(inner, _) |
+ TypeKind::Pointer(inner) |
+ TypeKind::Reference(inner) |
+ TypeKind::Alias(_, inner) |
+ TypeKind::ResolvedTypeRef(inner) => {
+ ctx.resolve_item(inner).applicable_template_args(ctx)
+ }
+ // XXX Is this completely correct? Partial template specialization
+ // is hard anyways, sigh...
+ TypeKind::TemplateRef(_, ref args) => {
+ args.clone()
+ }
+ // In a template specialization we've got all we want.
+ TypeKind::Comp(ref ci) if ci.is_template_specialization() => {
+ ci.template_args().iter().cloned().collect()
+ }
+ TypeKind::Comp(ref ci) => {
+ let mut parent_template_args =
+ ctx.resolve_item(self.parent_id())
+ .applicable_template_args(ctx);
+
+ for ty in ci.template_args() {
+ if !parent_contains(ctx, &parent_template_args, *ty) {
+ parent_template_args.push(*ty);
+ }
+ }
+
+ parent_template_args
+ }
+ _ => vec![],
+ }
+ }
+
+ fn is_module(&self) -> bool {
+ match self.kind {
+ ItemKind::Module(..) => true,
+ _ => false,
+ }
+ }
+
+ pub fn annotations(&self) -> &Annotations {
+ &self.annotations
+ }
+
+ /// Whether this item should be hidden, either due to annotations, or due to
+ /// other kind of configuration.
+ pub fn is_hidden(&self, ctx: &BindgenContext) -> bool {
+ debug_assert!(ctx.in_codegen_phase(),
+ "You're not supposed to call this yet");
+ self.annotations.hide() ||
+ ctx.hidden_by_name(&self.real_canonical_name(ctx, false))
+ }
+
+ pub fn is_opaque(&self, ctx: &BindgenContext) -> bool {
+ debug_assert!(ctx.in_codegen_phase(),
+ "You're not supposed to call this yet");
+ self.annotations.opaque() ||
+ ctx.opaque_by_name(&self.real_canonical_name(ctx, false))
+ }
+
+ /// Get the canonical name without taking into account the replaces
+ /// annotation.
+ fn real_canonical_name(&self, ctx: &BindgenContext, count_namespaces: bool) -> String {
+ let base_name = match *self.kind() {
+ ItemKind::Type(ref ty) => {
+ match *ty.kind() {
+ // If we're a template specialization, our name is our parent's
+ TypeKind::Comp(ref ci) if ci.is_template_specialization() => {
+ return ci.specialized_template().unwrap().canonical_name(ctx);
+ },
+ // Same as above
+ TypeKind::ResolvedTypeRef(inner) |
+ TypeKind::TemplateRef(inner, _) => {
+ return inner.canonical_name(ctx);
+ }
+ // If we're a named type, we don't need to mangle it, and we
+ // should be able to assert we're not top level.
+ TypeKind::Named(ref name, _) => {
+ return name.to_owned();
+ }
+ _ => {}
+ }
+
+ ty.name().map(ToOwned::to_owned)
+ .unwrap_or_else(|| format!("_bindgen_ty{}", self.id()))
+ }
+ ItemKind::Function(ref fun) => {
+ let mut base = fun.name().to_owned();
+
+ // We might need to deduplicate if we're a method.
+ let parent = ctx.resolve_item(self.parent_id());
+ if let ItemKind::Type(ref ty) = *parent.kind() {
+ if let TypeKind::Comp(ref ci) = *ty.kind() {
+ let mut count = 0;
+ let mut found = false;
+ for method in ci.methods() {
+ if method.signature() == self.id() {
+ found = true;
+ break;
+ }
+ let fun = ctx.resolve_item(method.signature())
+ .expect_function();
+ if fun.name() == base {
+ count += 1;
+ }
+ }
+
+ assert!(found, "Method not found?");
+ if count != 0 {
+ base.push_str(&count.to_string());
+ }
+ }
+ }
+ base
+ }
+ ItemKind::Var(ref var) => {
+ var.name().to_owned()
+ }
+ ItemKind::Module(ref module) => {
+ module.name().map(ToOwned::to_owned)
+ .unwrap_or_else(|| format!("_bindgen_mod{}", self.id()))
+ }
+ };
+
+ let parent = ctx.resolve_item(self.parent_id());
+ let parent_is_namespace = parent.is_module();
+ if self.is_toplevel(ctx) || (parent_is_namespace && count_namespaces) {
+ return ctx.rust_mangle(&base_name).into_owned();
+ }
+
+ // TODO: allow modification of the mangling functions, maybe even per
+ // item type?
+ format!("{}_{}", parent.canonical_name(ctx), base_name)
+ }
+
+ pub fn as_module_mut(&mut self) -> Option<&mut Module> {
+ match self.kind {
+ ItemKind::Module(ref mut module) => Some(module),
+ _ => None,
+ }
+ }
+}
+
+impl ClangItemParser for Item {
+ fn builtin_type(kind: TypeKind, is_const: bool, ctx: &mut BindgenContext) -> ItemId {
+ // Feel free to add more here, I'm just lazy.
+ match kind {
+ TypeKind::Void |
+ TypeKind::Int(..) |
+ TypeKind::Pointer(..) |
+ TypeKind::Float(..) => {},
+ _ => panic!("Unsupported builtin type"),
+ }
+
+ let ty = Type::new(None, None, kind, is_const);
+ let id = ItemId::next();
+ let module = ctx.root_module();
+ ctx.add_item(Item::new(id, None, None, module, ItemKind::Type(ty)),
+ None, None);
+ id
+ }
+
+
+ fn parse(cursor: clang::Cursor,
+ parent_id: Option<ItemId>,
+ context: &mut BindgenContext) -> Result<ItemId, ParseError> {
+ use ir::function::Function;
+ use ir::module::Module;
+ use ir::var::Var;
+
+ if !cursor.is_valid() {
+ return Err(ParseError::Continue);
+ }
+
+ let comment = cursor.raw_comment();
+ let annotations = Annotations::new(&cursor);
+
+ // FIXME: The current_module logic is not really accurate. We should be
+ // able to index modules by their Cursor, and locate the proper module
+ // for a given item.
+ //
+ // We don't support modules properly though, so there's no rush for
+ // this.
+ let current_module = context.current_module();
+ macro_rules! try_parse {
+ ($what:ident) => {
+ match $what::parse(cursor, context) {
+ Ok(ParseResult::New(item, declaration)) => {
+ let id = ItemId::next();
+ context.add_item(Item::new(id, comment, annotations,
+ parent_id.unwrap_or(current_module),
+ ItemKind::$what(item)),
+ declaration,
+ Some(cursor));
+ return Ok(id);
+ }
+ Ok(ParseResult::AlreadyResolved(id)) => {
+ return Ok(id);
+ }
+ Err(ParseError::Recurse) => return Err(ParseError::Recurse),
+ Err(ParseError::Continue) => {},
+ }
+ }
+ }
+
+ try_parse!(Module);
+
+ // NOTE: Is extremely important to parse functions and vars **before**
+ // types. Otherwise we can parse a function declaration as a type
+ // (which is legal), and lose functions to generate.
+ //
+ // In general, I'm not totally confident this split between
+ // ItemKind::Function and TypeKind::FunctionSig is totally worth it, but
+ // I guess we can try.
+ try_parse!(Function);
+ try_parse!(Var);
+
+ // Types are sort of special, so to avoid parsing template classes
+ // twice, handle them separately.
+ {
+ let definition = cursor.definition();
+ let applicable_cursor = if definition.is_valid() {
+ definition
+ } else {
+ cursor
+ };
+ match Self::from_ty(&applicable_cursor.cur_type(),
+ Some(applicable_cursor), parent_id, context)
+ {
+ Ok(ty) => return Ok(ty),
+ Err(ParseError::Recurse) => return Err(ParseError::Recurse),
+ Err(ParseError::Continue) => {},
+ }
+ }
+
+ // Guess how does clang treat extern "C" blocks?
+ if cursor.kind() == clangll::CXCursor_UnexposedDecl {
+ Err(ParseError::Recurse)
+ } else {
+ error!("Unhandled cursor kind: {}", ::clang::kind_to_str(cursor.kind()));
+ Err(ParseError::Continue)
+ }
+ }
+
+ fn from_ty_or_ref(ty: clang::Type,
+ location: Option<clang::Cursor>,
+ parent_id: Option<ItemId>,
+ context: &mut BindgenContext) -> ItemId {
+ debug!("from_ty_or_ref: {:?}, {:?}, {:?}", ty, location, parent_id);
+
+ if context.collected_typerefs() {
+ debug!("refs already collected, resolving directly");
+ return Self::from_ty(&ty, location, parent_id, context)
+ .expect("Unable to resolve type");
+ }
+
+ if let Some(ty) = context.builtin_or_resolved_ty(parent_id, &ty, location) {
+ debug!("{:?} already resolved: {:?}", ty, location);
+ return ty;
+ }
+
+ debug!("New unresolved type reference: {:?}, {:?}", ty, location);
+
+ let is_const = ty.is_const();
+ let kind = TypeKind::UnresolvedTypeRef(ty, location);
+ let id = ItemId::next();
+ let current_module = context.current_module();
+ context.add_item(Item::new(id, None, None,
+ parent_id.unwrap_or(current_module),
+ ItemKind::Type(Type::new(None, None, kind, is_const))),
+ Some(clang::Cursor::null()),
+ None);
+ id
+ }
+
+
+ fn from_ty(ty: &clang::Type,
+ location: Option<clang::Cursor>,
+ parent_id: Option<ItemId>,
+ context: &mut BindgenContext) -> Result<ItemId, ParseError> {
+ Self::from_ty_with_id(ItemId::next(), ty, location, parent_id, context)
+ }
+
+ fn from_ty_with_id(id: ItemId,
+ ty: &clang::Type,
+ location: Option<clang::Cursor>,
+ parent_id: Option<ItemId>,
+ context: &mut BindgenContext) -> Result<ItemId, ParseError> {
+ use clangll::*;
+
+ let decl = {
+ let decl = ty.declaration();
+ let definition = decl.definition();
+ if definition.is_valid() {
+ definition
+ } else {
+ decl
+ }
+ };
+
+ let comment =
+ decl.raw_comment()
+ .or_else(|| location.as_ref().and_then(|l| l.raw_comment()));
+ let annotations =
+ Annotations::new(&decl)
+ .or_else(|| location.as_ref().and_then(|l| Annotations::new(l)));
+
+ if let Some(ref replaced) = annotations.as_ref().and_then(|a| a.use_instead_of()) {
+ context.replace(replaced, id);
+ }
+
+ if let Some(ty) = context.builtin_or_resolved_ty(parent_id, ty, location) {
+ return Ok(ty);
+ }
+
+ // First, check we're not recursing.
+ let mut valid_decl = decl.kind() != CXCursor_NoDeclFound;
+ let declaration_to_look_for = if valid_decl {
+ decl.canonical()
+ } else if location.is_some() && location.unwrap().kind() == CXCursor_ClassTemplate {
+ valid_decl = true;
+ location.unwrap()
+ } else {
+ decl
+ };
+
+ if valid_decl {
+ if let Some(&(_, item_id)) = context.currently_parsed_types.iter().find(|&&(d, _)| d == declaration_to_look_for) {
+ debug!("Avoiding recursion parsing type: {:?}", ty);
+ return Ok(item_id);
+ }
+ }
+
+ let current_module = context.current_module();
+ if valid_decl {
+ context.currently_parsed_types.push((declaration_to_look_for, id));
+ }
+
+ let result = Type::from_clang_ty(id, ty, location, parent_id, context);
+ let ret = match result {
+ Ok(ParseResult::AlreadyResolved(ty)) => Ok(ty),
+ Ok(ParseResult::New(item, declaration)) => {
+ context.add_item(Item::new(id, comment, annotations,
+ parent_id.unwrap_or(current_module),
+ ItemKind::Type(item)),
+ declaration,
+ location);
+ Ok(id)
+ }
+ Err(ParseError::Continue) => Err(ParseError::Continue),
+ Err(ParseError::Recurse) => {
+ debug!("Item::from_ty recursing in the ast");
+ let mut result = Err(ParseError::Recurse);
+ if let Some(ref location) = location {
+ // Need to pop here, otherwise we'll get stuck.
+ //
+ // TODO: Find a nicer interface, really. Also, the
+ // declaration_to_look_for suspiciously shares a lot of
+ // logic with ir::context, so we should refactor that.
+ if valid_decl {
+ let (popped_decl, _) = context.currently_parsed_types.pop().unwrap();
+ assert_eq!(popped_decl, declaration_to_look_for);
+ }
+
+ location.visit(|cur, _other| {
+ use clangll::*;
+ result = Item::from_ty_with_id(id, ty, Some(*cur), parent_id, context);
+ match result {
+ Ok(..) => CXChildVisit_Break,
+ Err(ParseError::Recurse) => CXChildVisit_Recurse,
+ Err(ParseError::Continue) => CXChildVisit_Continue,
+ }
+ });
+
+ if valid_decl {
+ context.currently_parsed_types.push((declaration_to_look_for, id));
+ }
+ }
+ // If we have recursed into the AST all we know, and we still
+ // haven't found what we've got, let's
+ // just make a named type.
+ //
+ // This is what happens with some template members, for example.
+ //
+ // FIXME: Maybe we should restrict this to things with parent?
+ // It's harmless, but if we restrict that, then
+ // tests/headers/nsStyleAutoArray.hpp crashes.
+ if let Err(ParseError::Recurse) = result {
+ Ok(Self::named_type_with_id(id, ty.spelling(),
+ None,
+ parent_id.unwrap_or(context.current_module()),
+ context))
+ } else {
+ result
+ }
+ }
+ };
+
+ if valid_decl {
+ let (popped_decl, _) = context.currently_parsed_types.pop().unwrap();
+ assert_eq!(popped_decl, declaration_to_look_for);
+ }
+
+ ret
+ }
+
+ /// A named type is a template parameter, e.g., the "T" in Foo<T>. They're
+ /// always local so it's the only exception when there's no declaration for
+ /// a type.
+ ///
+ /// It must have an id, and must not be the current module id. Ideally we
+ /// could assert the parent id is a Comp(..) type, but that info isn't
+ /// available yet.
+ fn named_type_with_id<S>(id: ItemId,
+ name: S,
+ default: Option<ItemId>,
+ parent_id: ItemId,
+ context: &mut BindgenContext) -> ItemId
+ where S: Into<String>
+ {
+ // see tests/headers/const_tparam.hpp
+ // and tests/headers/variadic_tname.hpp
+ let name = name.into().replace("const ", "").replace(".", "");
+
+ context.add_item(Item::new(id, None, None, parent_id,
+ ItemKind::Type(Type::named(name, default))),
+ None,
+ None);
+
+ id
+ }
+
+ fn named_type<S>(name: S,
+ default: Option<ItemId>,
+ parent_id: ItemId,
+ context: &mut BindgenContext) -> ItemId
+ where S: Into<String>
+ {
+ Self::named_type_with_id(ItemId::next(), name, default, parent_id, context)
+ }
+}
+
+impl ItemCanonicalName for Item {
+ fn canonical_name(&self, ctx: &BindgenContext) -> String {
+ debug_assert!(ctx.in_codegen_phase(),
+ "You're not supposed to call this yet");
+ if let Some(other_canon_type) = self.annotations.use_instead_of() {
+ return other_canon_type.to_owned();
+ }
+ self.real_canonical_name(ctx, ctx.options().enable_cxx_namespaces)
+ }
+}
+
+impl ItemCanonicalPath for Item {
+ fn canonical_path(&self, ctx: &BindgenContext) -> Vec<String> {
+ if !ctx.options().enable_cxx_namespaces {
+ return vec![self.canonical_name(ctx)];
+ }
+
+ if self.id() == ctx.root_module() {
+ match self.kind {
+ ItemKind::Module(ref module) => {
+ return vec![module.name().unwrap().into()]
+ }
+ _ => panic!("Something has wrong horribly wrong"),
+ }
+ }
+
+ // TODO: This duplicates too much logic with real_canonical_name.
+ if let ItemKind::Type(ref ty) = *self.kind() {
+ match *ty.kind() {
+ TypeKind::Comp(ref ci) if ci.is_template_specialization() => {
+ return ci.specialized_template().unwrap().canonical_path(ctx);
+ },
+ TypeKind::ResolvedTypeRef(inner) |
+ TypeKind::TemplateRef(inner, _) => {
+ return inner.canonical_path(ctx);
+ }
+ TypeKind::Named(ref name, _) => {
+ return vec![name.clone()];
+ }
+ _ => {}
+ }
+ }
+
+ let mut parent_path = self.parent_id().canonical_path(&ctx);
+ parent_path.push(self.real_canonical_name(ctx, true));
+
+ parent_path
+ }
+}
diff --git a/src/ir/item_kind.rs b/src/ir/item_kind.rs
new file mode 100644
index 00000000..b6f317a7
--- /dev/null
+++ b/src/ir/item_kind.rs
@@ -0,0 +1,89 @@
+use super::function::Function;
+use super::module::Module;
+use super::ty::Type;
+use super::var::Var;
+
+/// A item we parse and translate.
+#[derive(Debug)]
+pub enum ItemKind {
+ /// A module, created implicitly once (the root module), or via C++
+ /// namespaces.
+ Module(Module),
+
+ /// A type declared in any of the multiple ways it can be declared.
+ Type(Type),
+
+ /// A function or method declaration.
+ Function(Function),
+ /// A variable declaration, most likely a static.
+ Var(Var),
+}
+
+impl ItemKind {
+ pub fn as_module(&self) -> Option<&Module> {
+ match *self {
+ ItemKind::Module(ref module) => Some(module),
+ _ => None,
+ }
+ }
+
+ pub fn is_module(&self) -> bool {
+ self.as_module().is_some()
+ }
+
+ pub fn expect_module(&self) -> &Module {
+ self.as_module().expect("Not a module")
+ }
+
+ pub fn as_function(&self) -> Option<&Function> {
+ match *self {
+ ItemKind::Function(ref func) => Some(func),
+ _ => None,
+ }
+ }
+
+ pub fn is_function(&self) -> bool {
+ self.as_function().is_some()
+ }
+
+ pub fn expect_function(&self) -> &Function {
+ self.as_function().expect("Not a function")
+ }
+
+ pub fn as_type(&self) -> Option<&Type> {
+ match *self {
+ ItemKind::Type(ref ty) => Some(ty),
+ _ => None,
+ }
+ }
+
+ pub fn as_type_mut(&mut self) -> Option<&mut Type> {
+ match *self {
+ ItemKind::Type(ref mut ty) => Some(ty),
+ _ => None,
+ }
+ }
+
+ pub fn is_type(&self) -> bool {
+ self.as_type().is_some()
+ }
+
+ pub fn expect_type(&self) -> &Type {
+ self.as_type().expect("Not a type")
+ }
+
+ pub fn as_var(&self) -> Option<&Var> {
+ match *self {
+ ItemKind::Var(ref v) => Some(v),
+ _ => None,
+ }
+ }
+
+ pub fn is_var(&self) -> bool {
+ self.as_var().is_some()
+ }
+
+ pub fn expect_var(&self) -> &Var {
+ self.as_var().expect("Not a var")
+ }
+}
diff --git a/src/ir/layout.rs b/src/ir/layout.rs
new file mode 100644
index 00000000..d672ebea
--- /dev/null
+++ b/src/ir/layout.rs
@@ -0,0 +1,26 @@
+
+/// A type that represents the struct layout of a type.
+#[derive(Debug, Clone, Copy)]
+pub struct Layout {
+ pub size: usize,
+ pub align: usize,
+ pub packed: bool,
+}
+
+impl Layout {
+ pub fn new(size: usize, align: usize) -> Self {
+ Layout {
+ size: size,
+ align: align,
+ packed: false,
+ }
+ }
+
+ pub fn is_zero(&self) -> bool {
+ self.size == 0 && self.align == 0
+ }
+
+ pub fn zero() -> Self {
+ Self::new(0, 0)
+ }
+}
diff --git a/src/ir/mod.rs b/src/ir/mod.rs
new file mode 100644
index 00000000..07ac3059
--- /dev/null
+++ b/src/ir/mod.rs
@@ -0,0 +1,12 @@
+pub mod annotations;
+pub mod comp;
+pub mod context;
+pub mod enum_ty;
+pub mod function;
+pub mod int;
+pub mod item;
+pub mod item_kind;
+pub mod layout;
+pub mod module;
+pub mod ty;
+pub mod var;
diff --git a/src/ir/module.rs b/src/ir/module.rs
new file mode 100644
index 00000000..77fee5ef
--- /dev/null
+++ b/src/ir/module.rs
@@ -0,0 +1,52 @@
+use super::context::BindgenContext;
+use super::item::ItemId;
+use clang;
+use parse::{ClangSubItemParser, ParseError, ParseResult};
+use parse_one;
+
+/// A module, as in, a C++ namespace.
+#[derive(Clone, Debug)]
+pub struct Module {
+ /// The name of the module, or none if it's anonymous.
+ name: Option<String>,
+ /// The children of this module, just here for convenience.
+ children_ids: Vec<ItemId>,
+}
+
+impl Module {
+ pub fn new(name: Option<String>) -> Self {
+ Module {
+ name: name,
+ children_ids: vec![],
+ }
+ }
+
+ pub fn name(&self) -> Option<&str> {
+ self.name.as_ref().map(|n| &**n)
+ }
+
+ pub fn children_mut(&mut self) -> &mut Vec<ItemId> {
+ &mut self.children_ids
+ }
+
+ pub fn children(&self) -> &[ItemId] {
+ &self.children_ids
+ }
+}
+
+impl ClangSubItemParser for Module {
+ fn parse(cursor: clang::Cursor, ctx: &mut BindgenContext) -> Result<ParseResult<Self>, ParseError> {
+ use clangll::*;
+ match cursor.kind() {
+ CXCursor_Namespace => {
+ let module_id = ctx.module(cursor);
+ ctx.with_module(module_id, |ctx, children| {
+ cursor.visit(|cursor, _| parse_one(ctx, *cursor, Some(module_id), children))
+ });
+
+ Ok(ParseResult::AlreadyResolved(module_id))
+ }
+ _ => Err(ParseError::Continue)
+ }
+ }
+}
diff --git a/src/ir/ty.rs b/src/ir/ty.rs
new file mode 100644
index 00000000..b0448437
--- /dev/null
+++ b/src/ir/ty.rs
@@ -0,0 +1,537 @@
+use super::comp::CompInfo;
+use super::enum_ty::Enum;
+use super::function::FunctionSig;
+use super::item::{Item, ItemId};
+use super::int::IntKind;
+use super::layout::Layout;
+use super::context::BindgenContext;
+use super::context::TypeResolver;
+use parse::{ClangItemParser, ParseResult, ParseError};
+use clang::{self, Cursor};
+
+#[derive(Debug)]
+pub struct Type {
+ /// The name of the type, or None if it was an unnamed struct or union.
+ name: Option<String>,
+ /// The layout of the type, if known.
+ layout: Option<Layout>,
+ /// Whether this type is marked as opaque.
+ opaque: bool,
+ /// Whether this type is marked as hidden.
+ hide: bool,
+ /// The inner kind of the type
+ kind: TypeKind,
+ /// Whether this type is const-qualified.
+ is_const: bool,
+}
+
+pub const RUST_DERIVE_IN_ARRAY_LIMIT: usize = 32usize;
+
+impl Type {
+ pub fn as_comp(&self) -> Option<&CompInfo> {
+ match self.kind {
+ TypeKind::Comp(ref ci) => Some(ci),
+ _ => None,
+ }
+ }
+
+ pub fn new(name: Option<String>,
+ layout: Option<Layout>,
+ kind: TypeKind,
+ is_const: bool) -> Self {
+ Type {
+ name: name,
+ layout: layout,
+ opaque: false,
+ hide: false,
+ kind: kind,
+ is_const: is_const,
+ }
+ }
+
+ pub fn kind(&self) -> &TypeKind {
+ &self.kind
+ }
+
+ pub fn kind_mut(&mut self) -> &mut TypeKind {
+ &mut self.kind
+ }
+
+ pub fn name(&self) -> Option<&str> {
+ self.name.as_ref().map(|name| &**name)
+ }
+
+ pub fn is_comp(&self) -> bool {
+ match self.kind {
+ TypeKind::Comp(..) => true,
+ _ => false,
+ }
+ }
+
+ pub fn is_named(&self) -> bool {
+ match self.kind {
+ TypeKind::Named(..) => true,
+ _ => false,
+ }
+ }
+
+ pub fn is_builtin_or_named(&self) -> bool {
+ match self.kind {
+ TypeKind::Void |
+ TypeKind::NullPtr |
+ TypeKind::Function(..) |
+ TypeKind::Array(..) |
+ TypeKind::Reference(..) |
+ TypeKind::Pointer(..) |
+ TypeKind::Int(..) |
+ TypeKind::Float(..) |
+ TypeKind::Named(..) => true,
+ _ => false,
+ }
+ }
+
+ /// Creates a new named type, with name `name`.
+ pub fn named(name: String, default: Option<ItemId>) -> Self {
+ assert!(!name.is_empty());
+ // TODO: stop duplicating the name, it's stupid.
+ let kind = TypeKind::Named(name.clone(), default);
+ Self::new(Some(name), None, kind, false)
+ }
+
+ pub fn is_integer_literal(&self) -> bool {
+ match *self.kind() {
+ TypeKind::Int(..) => true,
+ _ => false,
+ }
+ }
+
+ pub fn is_const(&self) -> bool {
+ self.is_const
+ }
+
+ pub fn layout(&self, type_resolver: &TypeResolver) -> Option<Layout> {
+ use std::mem;
+
+ self.layout.or_else(|| {
+ match self.kind {
+ TypeKind::Comp(ref ci)
+ => ci.layout(type_resolver),
+ // FIXME(emilio): This is a hack for anonymous union templates.
+ // Use the actual pointer size!
+ TypeKind::Pointer(..)
+ => Some(Layout::new(mem::size_of::<*mut ()>(), mem::align_of::<*mut ()>())),
+ TypeKind::ResolvedTypeRef(inner)
+ => type_resolver.resolve_type(inner).layout(type_resolver),
+ _ => None,
+ }
+ })
+ }
+
+ pub fn is_opaque(&self, _type_resolver: &TypeResolver) -> bool {
+ self.opaque
+ }
+
+ pub fn can_derive_debug(&self, type_resolver: &TypeResolver) -> bool {
+ !self.is_opaque(type_resolver) && match self.kind {
+ TypeKind::Array(t, len) => {
+ len <= RUST_DERIVE_IN_ARRAY_LIMIT &&
+ type_resolver.resolve_type(t).can_derive_debug(type_resolver)
+ }
+ TypeKind::ResolvedTypeRef(t) |
+ TypeKind::Alias(_, t) => {
+ type_resolver.resolve_type(t).can_derive_debug(type_resolver)
+ }
+ TypeKind::Comp(ref info) => {
+ info.can_derive_debug(type_resolver, self.layout(type_resolver))
+ }
+ _ => true,
+ }
+ }
+
+ // For some reason, deriving copies of an array of a type that is not known
+ // to be copy is a compile error. e.g.:
+ //
+ // #[derive(Copy)]
+ // struct A<T> {
+ // member: T,
+ // }
+ //
+ // is fine, while:
+ //
+ // #[derive(Copy)]
+ // struct A<T> {
+ // member: [T; 1],
+ // }
+ //
+ // is an error.
+ //
+ // That's the point of the existence of can_derive_copy_in_array().
+ pub fn can_derive_copy_in_array(&self, type_resolver: &TypeResolver) -> bool {
+ match self.kind {
+ TypeKind::ResolvedTypeRef(t) |
+ TypeKind::Alias(_, t) |
+ TypeKind::Array(t, _) => {
+ type_resolver.resolve_type(t)
+ .can_derive_copy_in_array(type_resolver)
+ }
+ TypeKind::Named(..) => false,
+ _ => self.can_derive_copy(type_resolver),
+ }
+ }
+
+ pub fn can_derive_copy(&self, type_resolver: &TypeResolver) -> bool {
+ !self.is_opaque(type_resolver) && match self.kind {
+ TypeKind::Array(t, len) => {
+ len <= RUST_DERIVE_IN_ARRAY_LIMIT &&
+ type_resolver.resolve_type(t).can_derive_copy_in_array(type_resolver)
+ }
+ TypeKind::ResolvedTypeRef(t) |
+ TypeKind::TemplateRef(t, _) |
+ TypeKind::Alias(_, t) => {
+ type_resolver.resolve_type(t).can_derive_copy(type_resolver)
+ }
+ TypeKind::Comp(ref info) => {
+ info.can_derive_copy(type_resolver)
+ }
+ _ => true,
+ }
+ }
+
+ pub fn has_vtable(&self, type_resolver: &TypeResolver) -> bool {
+ // FIXME: Can we do something about template parameters? Huh...
+ match self.kind {
+ TypeKind::TemplateRef(t, _) |
+ TypeKind::Alias(_, t) |
+ TypeKind::ResolvedTypeRef(t) |
+ TypeKind::Array(t, _) => {
+ type_resolver.resolve_type(t).has_vtable(type_resolver)
+ }
+ TypeKind::Comp(ref info) => {
+ info.has_vtable(type_resolver)
+ }
+ _ => false,
+ }
+
+ }
+
+ pub fn has_destructor(&self, type_resolver: &TypeResolver) -> bool {
+ self.is_opaque(type_resolver) || match self.kind {
+ TypeKind::TemplateRef(t, _) |
+ TypeKind::Alias(_, t) |
+ TypeKind::ResolvedTypeRef(t) |
+ TypeKind::Array(t, _) => {
+ type_resolver.resolve_type(t).has_destructor(type_resolver)
+ }
+ TypeKind::Comp(ref info) => {
+ info.has_destructor(type_resolver)
+ }
+ _ => false,
+ }
+ }
+
+ pub fn signature_contains_named_type(&self,
+ type_resolver: &TypeResolver,
+ ty: &Type) -> bool {
+ debug_assert!(ty.is_named());
+ let name = match *ty.kind() {
+ TypeKind::Named(ref name, _) => name,
+ _ => unreachable!(),
+ };
+
+ match self.kind {
+ TypeKind::Named(ref this_name, _)
+ => this_name == name,
+ TypeKind::ResolvedTypeRef(t) |
+ TypeKind::Array(t, _) |
+ TypeKind::Pointer(t)
+ => type_resolver.resolve_type(t)
+ .signature_contains_named_type(type_resolver, ty),
+ TypeKind::TemplateRef(_inner, ref template_args) => {
+ template_args.iter().any(|arg| {
+ type_resolver.resolve_type(*arg)
+ .signature_contains_named_type(type_resolver, ty)
+ })
+ }
+ TypeKind::Comp(ref ci)
+ => ci.signature_contains_named_type(type_resolver, ty),
+ _ => false,
+ }
+ }
+
+ pub fn canonical_type<'tr>(&'tr self, type_resolver: &'tr TypeResolver) -> &'tr Type {
+ match self.kind {
+ TypeKind::Named(..) |
+ TypeKind::Array(..) |
+ TypeKind::Comp(..) |
+ TypeKind::Int(..) |
+ TypeKind::Float(..) |
+ TypeKind::Function(..) |
+ TypeKind::Enum(..) |
+ TypeKind::Reference(..) |
+ TypeKind::Void |
+ TypeKind::NullPtr |
+ TypeKind::Pointer(..) => self,
+
+ TypeKind::ResolvedTypeRef(inner) |
+ TypeKind::Alias(_, inner) |
+ TypeKind::TemplateRef(inner, _)
+ => type_resolver.resolve_type(inner).canonical_type(type_resolver),
+
+ TypeKind::UnresolvedTypeRef(..)
+ => unreachable!("Should have been resolved after parsing!"),
+ }
+ }
+}
+
+#[derive(Debug, Copy, Clone, PartialEq)]
+pub enum FloatKind {
+ Float,
+ Double,
+ LongDouble,
+}
+
+/// The different kinds of types that we can parse.
+///
+/// TODO: The name in the Alias and Named kinds is a bit unsound, should be in
+/// type.name?
+#[derive(Debug)]
+pub enum TypeKind {
+ /// The void type.
+ Void,
+ /// The nullptr_t type.
+ NullPtr,
+ /// A compound type, that is, a class, struct, or union.
+ Comp(CompInfo),
+ /// An integer type, of a given kind. `bool` and `char` are also considered
+ /// integers.
+ Int(IntKind),
+ /// A floating point type.
+ Float(FloatKind),
+ /// A type alias, with a name, that points to another type.
+ Alias(String, ItemId),
+ /// An array of a type and a lenght.
+ Array(ItemId, usize),
+ /// A function type, with a given signature.
+ Function(FunctionSig),
+ /// An enum type.
+ Enum(Enum),
+ /// A pointer to a type. The bool field represents whether it's const or
+ /// not.
+ Pointer(ItemId),
+ /// A reference to a type, as in: int& foo().
+ Reference(ItemId),
+ /// A reference to a template, with different template parameter names. To
+ /// see why this is needed, check out the creation of this variant in
+ /// `Type::from_clang_ty`.
+ TemplateRef(ItemId, Vec<ItemId>),
+
+ /// A reference to a yet-to-resolve type. This stores the clang cursor
+ /// itself, and postpones its resolution.
+ ///
+ /// These are gone in a phase after parsing where these are mapped to
+ /// already known types, and are converted to ResolvedTypeRef.
+ ///
+ /// see tests/headers/typeref.hpp to see somewhere where this is a problem.
+ UnresolvedTypeRef(clang::Type, Option<clang::Cursor>),
+ ResolvedTypeRef(ItemId),
+
+ /// A named type, that is, a template parameter, with an optional default
+ /// type.
+ Named(String, Option<ItemId>),
+}
+
+impl Type {
+ pub fn is_unsized(&self, type_resolver: &TypeResolver) -> bool {
+ match self.kind {
+ TypeKind::Void => true,
+ TypeKind::Comp(ref ci) => ci.is_unsized(type_resolver),
+ TypeKind::Array(inner, size) => {
+ size == 0 ||
+ type_resolver.resolve_type(inner).is_unsized(type_resolver)
+ }
+ TypeKind::ResolvedTypeRef(inner) |
+ TypeKind::Alias(_, inner) |
+ TypeKind::TemplateRef(inner, _)
+ => type_resolver.resolve_type(inner).is_unsized(type_resolver),
+ TypeKind::Named(..) |
+ TypeKind::Int(..) |
+ TypeKind::Float(..) |
+ TypeKind::Function(..) |
+ TypeKind::Enum(..) |
+ TypeKind::Reference(..) |
+ TypeKind::NullPtr |
+ TypeKind::Pointer(..) => false,
+
+ TypeKind::UnresolvedTypeRef(..)
+ => unreachable!("Should have been resolved after parsing!"),
+ }
+ }
+
+ pub fn from_clang_ty(potential_id: ItemId,
+ ty: &clang::Type,
+ location: Option<Cursor>,
+ parent_id: Option<ItemId>,
+ ctx: &mut BindgenContext) -> Result<ParseResult<Self>, ParseError> {
+ use clangll::*;
+ if let Some(ty) = ctx.builtin_or_resolved_ty(parent_id, ty, location) {
+ debug!("{:?} already resolved: {:?}", ty, location);
+ return Ok(ParseResult::AlreadyResolved(ty));
+ }
+
+ let layout = ty.fallible_layout().ok();
+ let cursor = ty.declaration();
+ let mut name = cursor.spelling();
+
+ debug!("from_clang_ty: {:?}, ty: {:?}, loc: {:?}", potential_id, ty, location);
+ debug!("currently_parsed_types: {:?}", ctx.currently_parsed_types);
+
+ let canonical_ty = ty.canonical_type();
+ let kind = match ty.kind() {
+ CXType_Unexposed if *ty != canonical_ty &&
+ canonical_ty.kind() != CXType_Invalid => {
+ debug!("Looking for canonical type: {:?}", canonical_ty);
+ return Self::from_clang_ty(potential_id, &canonical_ty,
+ location, parent_id, ctx);
+ }
+ CXType_Unexposed |
+ CXType_Invalid => {
+ // For some reason Clang doesn't give us any hint
+ // in some situations where we should generate a
+ // function pointer (see
+ // tests/headers/func_ptr_in_struct.h), so we do a
+ // guess here trying to see if it has a valid return
+ // type.
+ if ty.ret_type().kind() != CXType_Invalid {
+ let signature =
+ try!(FunctionSig::from_ty(ty, &location.unwrap_or(cursor), ctx));
+ TypeKind::Function(signature)
+ // Same here, with template specialisations we can safely assume
+ // this is a Comp(..)
+ } else if ty.num_template_args() > 0 {
+ debug!("Template specialization: {:?}", ty);
+ let complex =
+ CompInfo::from_ty(potential_id, ty, location, ctx)
+ .expect("C'mon");
+ TypeKind::Comp(complex)
+ } else if let Some(location) = location {
+ match location.kind() {
+ CXCursor_ClassTemplatePartialSpecialization |
+ CXCursor_ClassTemplate => {
+ name = location.spelling();
+ let complex =
+ CompInfo::from_ty(potential_id, ty, Some(location), ctx)
+ .expect("C'mon");
+ TypeKind::Comp(complex)
+ }
+ CXCursor_TemplateRef => {
+ let referenced = location.referenced();
+ return Self::from_clang_ty(potential_id,
+ &referenced.cur_type(),
+ Some(referenced),
+ parent_id,
+ ctx);
+ }
+ CXCursor_TypeRef => {
+ let referenced = location.referenced();
+ // FIXME: use potential id?
+ return Ok(ParseResult::AlreadyResolved(
+ Item::from_ty_or_ref(referenced.cur_type(),
+ Some(referenced),
+ parent_id,
+ ctx)));
+ }
+ _ => {
+ if ty.kind() == CXType_Unexposed {
+ warn!("Unexposed type {:?}, recursing inside, loc: {:?}", ty, location);
+ return Err(ParseError::Recurse);
+ }
+
+ error!("invalid type {:?}", ty);
+ return Err(ParseError::Continue);
+ }
+ }
+ } else {
+ // TODO: Don't duplicate this!
+ if ty.kind() == CXType_Unexposed {
+ warn!("Unexposed type {:?}, recursing inside", ty);
+ return Err(ParseError::Recurse);
+ }
+
+ error!("invalid type `{}`", ty.spelling());
+ return Err(ParseError::Continue);
+ }
+ }
+ // NOTE: We don't resolve pointers eagerly because the pointee type
+ // might not have been parsed, and if it contains templates or
+ // something else we might get confused, see the comment inside
+ // TypeRef.
+ //
+ // We might need to, though, if the context is already in the
+ // process of resolving them.
+ CXType_MemberPointer |
+ CXType_Pointer => {
+ let inner =
+ Item::from_ty_or_ref(ty.pointee_type(), Some(ty.pointee_type().declaration()), parent_id, ctx);
+ TypeKind::Pointer(inner)
+ }
+ // XXX: RValueReference is most likely wrong, but I don't think we
+ // can even add bindings for that, so huh.
+ CXType_RValueReference |
+ CXType_LValueReference => {
+ let inner =
+ Item::from_ty_or_ref(ty.pointee_type(), Some(ty.pointee_type().declaration()), parent_id, ctx);
+ TypeKind::Reference(inner)
+ }
+ // XXX DependentSizedArray is wrong
+ CXType_VariableArray |
+ CXType_DependentSizedArray |
+ CXType_IncompleteArray => {
+ let inner = Item::from_ty(&ty.elem_type(), location, parent_id, ctx)
+ .expect("Not able to resolve array element?");
+ TypeKind::Pointer(inner)
+ }
+ CXType_FunctionNoProto |
+ CXType_FunctionProto => {
+ let signature = try!(FunctionSig::from_ty(ty, &location.unwrap_or(cursor), ctx));
+ TypeKind::Function(signature)
+ }
+ CXType_Typedef => {
+ let inner = cursor.typedef_type();
+ let inner =
+ Item::from_ty_or_ref(inner, location, parent_id, ctx);
+ TypeKind::Alias(ty.spelling(), inner)
+ }
+ CXType_Enum => {
+ let enum_ = Enum::from_ty(ty, ctx)
+ .expect("Not an enum?");
+ TypeKind::Enum(enum_)
+ }
+ CXType_Record => {
+ let complex = CompInfo::from_ty(potential_id, ty, location, ctx)
+ .expect("Not a complex type?");
+ TypeKind::Comp(complex)
+ }
+ CXType_ConstantArray => {
+ let inner = Item::from_ty(&ty.elem_type(), location, parent_id, ctx)
+ .expect("Not able to resolve array element?");
+ TypeKind::Array(inner, ty.array_size())
+ }
+ #[cfg(not(feature="llvm_stable"))]
+ CXType_Elaborated => {
+ return Self::from_clang_ty(potential_id, &ty.named(),
+ location, parent_id, ctx);
+ }
+ _ => {
+ error!("unsupported type {:?} at {:?}", ty, location);
+ return Err(ParseError::Continue);
+ }
+ };
+
+ let name = if name.is_empty() { None } else { Some(name) };
+ let is_const = ty.is_const();
+
+ let ty = Type::new(name, layout, kind, is_const);
+ // TODO: maybe declaration.canonical()?
+ Ok(ParseResult::New(ty, Some(cursor.canonical())))
+ }
+}
diff --git a/src/ir/var.rs b/src/ir/var.rs
new file mode 100644
index 00000000..ac59973b
--- /dev/null
+++ b/src/ir/var.rs
@@ -0,0 +1,160 @@
+use super::item::{Item, ItemId};
+use super::context::BindgenContext;
+use super::ty::TypeKind;
+use super::int::IntKind;
+use super::function::cursor_mangling;
+use parse::{ClangItemParser, ClangSubItemParser, ParseResult, ParseError};
+use clang;
+
+#[derive(Debug)]
+pub struct Var {
+ /// The name of the variable.
+ name: String,
+ /// The mangled name of the variable.
+ mangled_name: Option<String>,
+ /// The type of the variable.
+ ty: ItemId,
+ /// TODO: support non-integer constants?
+ /// The integer value of the variable.
+ val: Option<i64>,
+ /// Whether this variable is const.
+ is_const: bool,
+}
+
+impl Var {
+ pub fn new(name: String,
+ mangled: Option<String>,
+ ty: ItemId,
+ val: Option<i64>,
+ is_const: bool) -> Var {
+ assert!(!name.is_empty());
+ Var {
+ name: name,
+ mangled_name: mangled,
+ ty: ty,
+ val: val,
+ is_const: is_const,
+ }
+ }
+
+ pub fn is_const(&self) -> bool {
+ self.is_const
+ }
+
+ pub fn val(&self) -> Option<i64> {
+ self.val
+ }
+
+ pub fn ty(&self) -> ItemId {
+ self.ty
+ }
+
+ pub fn name(&self) -> &str {
+ &self.name
+ }
+
+ pub fn mangled_name(&self) -> Option<&str> {
+ self.mangled_name.as_ref().map(|n| &**n)
+ }
+}
+
+impl ClangSubItemParser for Var {
+ fn parse(cursor: clang::Cursor,
+ context: &mut BindgenContext) -> Result<ParseResult<Self>, ParseError> {
+ use clangll::*;
+ match cursor.kind() {
+ CXCursor_MacroDefinition => {
+ let value = match parse_int_literal_tokens(&cursor, context.translation_unit(), 1) {
+ None => return Err(ParseError::Continue),
+ Some(v) => v,
+ };
+
+ let name = cursor.spelling();
+ if name.is_empty() {
+ warn!("Empty macro name?");
+ return Err(ParseError::Continue);
+ }
+
+ if context.parsed_macro(&name) {
+ warn!("Duplicated macro definition: {}", name);
+ return Err(ParseError::Continue);
+ }
+ context.note_parsed_macro(name.clone());
+
+ let ty = if value.abs() > u32::max_value() as i64 {
+ Item::builtin_type(TypeKind::Int(IntKind::ULongLong), true, context)
+ } else {
+ Item::builtin_type(TypeKind::Int(IntKind::UInt), true, context)
+ };
+
+ Ok(ParseResult::New(Var::new(name, None, ty, Some(value), true), Some(cursor)))
+ }
+ CXCursor_VarDecl => {
+ let name = cursor.spelling();
+ if name.is_empty() {
+ warn!("Empty constant name?");
+ return Err(ParseError::Continue);
+ }
+
+ let ty = cursor.cur_type();
+
+ // XXX this is redundant, remove!
+ let is_const = ty.is_const();
+
+ let ty = Item::from_ty(&ty, Some(cursor), None, context)
+ .expect("Unable to resolve constant type?");
+
+ let mut value = None;
+
+ // Note: Ty might not be totally resolved yet, see
+ // tests/headers/inner_const.hpp
+ //
+ // That's fine because in that case we know it's not a literal.
+ if context.safe_resolve_type(ty).map_or(false, |t| t.is_integer_literal()) {
+ // Try to parse a literal token value
+ cursor.visit(|c, _| {
+ if c.kind() == CXCursor_IntegerLiteral {
+ value =
+ parse_int_literal_tokens(&c,
+ context.translation_unit(),
+ 0);
+ }
+ CXChildVisit_Continue
+ });
+ }
+
+ let mangling = cursor_mangling(&cursor);
+
+ let var = Var::new(name, mangling, ty, value, is_const);
+ Ok(ParseResult::New(var, Some(cursor)))
+
+ }
+ _ => {
+ /* TODO */
+ Err(ParseError::Continue)
+ }
+ }
+ }
+}
+
+fn parse_int_literal_tokens(cursor: &clang::Cursor,
+ unit: &clang::TranslationUnit,
+ which: usize) -> Option<i64> {
+ use clangll::CXToken_Literal;
+ let tokens = match unit.tokens(cursor) {
+ None => return None,
+ Some(tokens) => tokens,
+ };
+
+ if tokens.len() <= which || tokens[which].kind != CXToken_Literal {
+ return None;
+ }
+
+ let s = &tokens[which].spelling;
+ // TODO: try to preserve hex literals?
+ if s.starts_with("0x") {
+ i64::from_str_radix(&s[2..], 16).ok()
+ } else {
+ s.parse().ok()
+ }
+}
diff --git a/src/lib.rs b/src/lib.rs
index a6b33c8e..33bd66e7 100755
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -4,19 +4,34 @@
#![cfg_attr(feature = "clippy", feature(plugin))]
#![cfg_attr(feature = "clippy", plugin(clippy))]
+// To avoid rather annoying warnings when matching with CXCursor_xxx as a
+// constant.
+#![allow(non_upper_case_globals)]
+
extern crate syntex_syntax as syntax;
extern crate aster;
extern crate quasi;
extern crate clang_sys;
extern crate libc;
+extern crate regex;
#[macro_use]
extern crate log;
-use std::collections::HashSet;
-use std::default::Default;
-use std::io::{Write, self};
+mod clangll;
+mod clang;
+mod ir;
+mod parse;
+mod regex_set;
+mod codegen {
+ include!(concat!(env!("OUT_DIR"), "/codegen.rs"));
+}
+
+use std::borrow::Borrow;
+use std::io::{self, Write};
use std::fs::OpenOptions;
use std::path::Path;
+use std::marker;
+use std::collections::HashSet;
use syntax::ast;
use syntax::codemap::{DUMMY_SP, Span};
@@ -24,21 +39,16 @@ use syntax::print::pprust;
use syntax::print::pp::eof;
use syntax::ptr::P;
-use types::ModuleMap;
+use ir::context::BindgenContext;
+use ir::item::{Item, ItemId};
+use parse::{ClangItemParser, ParseError};
+use regex_set::RegexSet;
-mod types;
-mod clangll;
-mod clang;
-mod parser;
-mod hacks;
-mod gen {
- include!(concat!(env!("OUT_DIR"), "/gen.rs"));
-}
-
-#[derive(Clone)]
+#[derive(Debug)]
pub struct Builder<'a> {
options: BindgenOptions,
- logger: Option<&'a Logger>
+ // TODO: Before the logger was here, do we still want the lifetime?
+ phantom: marker::PhantomData<&'a ()>,
}
pub fn builder<'a>() -> Builder<'a> {
@@ -51,17 +61,22 @@ impl<'a> Builder<'a> {
}
pub fn match_pat<T: Into<String>>(&mut self, arg: T) -> &mut Self {
- self.options.match_pat.push(arg.into());
+ self.options.match_pat.insert(arg.into());
self
}
- pub fn blacklist_type<T: Into<String>>(&mut self, arg: T) -> &mut Self {
- self.options.blacklist_type.push(arg.into());
+ pub fn hide_type<T: Into<String>>(&mut self, arg: T) -> &mut Self {
+ self.options.hidden_types.insert(arg.into());
self
}
pub fn opaque_type<T: Into<String>>(&mut self, arg: T) -> &mut Self {
- self.options.opaque_types.push(arg.into());
+ self.options.opaque_types.insert(arg.into());
+ self
+ }
+
+ pub fn whitelisted_type<T: Borrow<str>>(&mut self, arg: &T) -> &mut Self {
+ self.options.whitelisted_types.insert(arg);
self
}
@@ -124,36 +139,34 @@ impl<'a> Builder<'a> {
self
}
- pub fn log(&mut self, logger: &'a Logger) -> &mut Self {
- self.logger = Some(logger);
- self
- }
-
pub fn disable_class_constants(&mut self) -> &mut Self {
self.options.class_constants = false;
self
}
- pub fn generate(&self) -> Result<Bindings, ()> {
- Bindings::generate(&self.options, self.logger, None)
+ pub fn generate(self) -> Result<Bindings, ()> {
+ Bindings::generate(self.options, None)
}
}
impl<'a> Default for Builder<'a> {
fn default() -> Builder<'a> {
Builder {
- logger: None,
- options: Default::default()
+ options: Default::default(),
+ phantom: marker::PhantomData,
}
}
}
-#[derive(Clone)]
/// Deprecated - use a `Builder` instead
+#[derive(Debug)]
pub struct BindgenOptions {
- pub match_pat: Vec<String>,
- pub blacklist_type: Vec<String>,
- pub opaque_types: Vec<String>,
+ pub match_pat: HashSet<String>,
+ pub hidden_types: HashSet<String>,
+ pub opaque_types: HashSet<String>,
+ pub whitelisted_types: RegexSet,
+ pub whitelisted_functions: RegexSet,
+ pub whitelisted_vars: RegexSet,
pub builtins: bool,
pub rust_enums: bool,
pub links: Vec<(String, LinkType)>,
@@ -171,7 +184,7 @@ pub struct BindgenOptions {
pub class_constants: bool,
/// Wether to generate names that are **directly** under namespaces.
pub namespaced_constants: bool,
- // whether to use msvc mangling rules
+ /// Whether to use msvc mangling rules
pub msvc_mangling: bool,
pub override_enum_ty: String,
pub raw_lines: Vec<String>,
@@ -183,9 +196,12 @@ pub struct BindgenOptions {
impl Default for BindgenOptions {
fn default() -> BindgenOptions {
BindgenOptions {
- match_pat: vec![],
- blacklist_type: vec![],
- opaque_types: vec![],
+ match_pat: Default::default(),
+ hidden_types: Default::default(),
+ opaque_types: Default::default(),
+ whitelisted_types: Default::default(),
+ whitelisted_functions: Default::default(),
+ whitelisted_vars: Default::default(),
builtins: false,
rust_enums: true,
links: vec![],
@@ -216,11 +232,6 @@ pub enum LinkType {
Framework
}
-pub trait Logger {
- fn error(&self, msg: &str);
- fn warn(&self, msg: &str);
-}
-
#[derive(Debug, Clone)]
pub struct Bindings {
module: ast::Mod,
@@ -229,25 +240,20 @@ pub struct Bindings {
impl Bindings {
/// Deprecated - use a `Builder` instead
- pub fn generate(options: &BindgenOptions, logger: Option<&Logger>, span: Option<Span>) -> Result<Bindings, ()> {
- let l = DummyLogger;
- let logger = logger.unwrap_or(&l as &Logger);
-
+ pub fn generate(options: BindgenOptions, span: Option<Span>) -> Result<Bindings, ()> {
let span = span.unwrap_or(DUMMY_SP);
- let module_map = try!(parse_headers(options, logger));
+ let mut context = BindgenContext::new(options);
+ parse(&mut context);
let module = ast::Mod {
inner: span,
- items: gen::gen_mods(&options.links[..],
- module_map,
- options.clone(),
- span)
+ items: codegen::codegen(&mut context),
};
Ok(Bindings {
module: module,
- raw_lines: options.raw_lines.clone(),
+ raw_lines: context.options().raw_lines.clone(),
})
}
@@ -290,68 +296,6 @@ impl Bindings {
}
}
-
-struct DummyLogger;
-
-impl Logger for DummyLogger {
- fn error(&self, _msg: &str) { }
- fn warn(&self, _msg: &str) { }
-}
-
-fn parse_headers(options: &BindgenOptions, logger: &Logger) -> Result<ModuleMap, ()> {
- fn str_to_ikind(s: &str) -> Option<types::IKind> {
- match s {
- "uchar" => Some(types::IUChar),
- "schar" => Some(types::ISChar),
- "ushort" => Some(types::IUShort),
- "sshort" => Some(types::IShort),
- "uint" => Some(types::IUInt),
- "sint" => Some(types::IInt),
- "ulong" => Some(types::IULong),
- "slong" => Some(types::ILong),
- "ulonglong" => Some(types::IULongLong),
- "slonglong" => Some(types::ILongLong),
- _ => None,
- }
- }
-
- // TODO: Unify most of these with BindgenOptions?
- let clang_opts = parser::ClangParserOptions {
- builtin_names: builtin_names(),
- builtins: options.builtins,
- match_pat: options.match_pat.clone(),
- emit_ast: options.emit_ast,
- class_constants: options.class_constants,
- namespaced_constants: options.namespaced_constants,
- ignore_functions: options.ignore_functions,
- ignore_methods: options.ignore_methods,
- fail_on_unknown_type: options.fail_on_unknown_type,
- enable_cxx_namespaces: options.enable_cxx_namespaces,
- override_enum_ty: str_to_ikind(&options.override_enum_ty),
- clang_args: options.clang_args.clone(),
- opaque_types: options.opaque_types.clone(),
- blacklist_type: options.blacklist_type.clone(),
- msvc_mangling: options.msvc_mangling,
- };
-
- parser::parse(clang_opts, logger)
-}
-
-fn builtin_names() -> HashSet<String> {
- let mut names = HashSet::new();
- let keys = [
- "__va_list_tag",
- "__va_list",
- "__builtin_va_list",
- ];
-
- for s in &keys {
- names.insert((*s).to_owned());
- }
-
- names
-}
-
#[test]
fn builder_state() {
let logger = DummyLogger;
@@ -365,3 +309,57 @@ fn builder_state() {
assert!(build.options.clang_args.binary_search(&"example.h".to_owned()).is_ok());
assert!(build.options.links.binary_search(&("m".to_owned(), LinkType::Static)).is_ok());
}
+
+/// Determines whether the given cursor is in any of the files matched by the
+/// options.
+fn filter_builtins(ctx: &BindgenContext, cursor: &clang::Cursor) -> bool {
+ let (file, _, _, _) = cursor.location().location();
+
+ match file.name() {
+ None => ctx.options().builtins,
+ Some(..) => true,
+ }
+}
+
+pub fn parse_one(ctx: &mut BindgenContext,
+ cursor: clang::Cursor,
+ parent: Option<ItemId>,
+ children: &mut Vec<ItemId>) -> clangll::Enum_CXVisitorResult {
+ if !filter_builtins(ctx, &cursor) {
+ return CXChildVisit_Continue
+ }
+
+ use clangll::CXChildVisit_Continue;
+ match Item::parse(cursor, parent, ctx) {
+ Ok(id) => children.push(id),
+ Err(ParseError::Continue) => {},
+ Err(ParseError::Recurse) => {
+ cursor.visit(|child, _| parse_one(ctx, *child, parent, children));
+ }
+ }
+ CXChildVisit_Continue
+}
+
+fn parse(context: &mut BindgenContext) {
+ use clang::Diagnostic;
+ use clangll::*;
+
+ for d in context.translation_unit().diags().iter() {
+ let msg = d.format(Diagnostic::default_opts());
+ let is_err = d.severity() >= CXDiagnostic_Error;
+ println!("{}, err: {}", msg, is_err);
+ }
+
+ let cursor = context.translation_unit().cursor();
+ if context.options().emit_ast {
+ cursor.visit(|cur, _| clang::ast_dump(cur, 0));
+ }
+
+ let root = context.root_module();
+ context.with_module(root, |context, children| {
+ cursor.visit(|cursor, _| parse_one(context, *cursor, None, children))
+ });
+
+ assert!(context.current_module() == context.root_module(),
+ "How did this happen?");
+}
diff --git a/src/parse.rs b/src/parse.rs
new file mode 100644
index 00000000..39d2644a
--- /dev/null
+++ b/src/parse.rs
@@ -0,0 +1,48 @@
+use clang;
+use ir::ty::TypeKind;
+use ir::item::ItemId;
+use ir::context::BindgenContext;
+
+#[derive(Debug)]
+pub enum ParseError {
+ Recurse,
+ Continue,
+}
+
+#[derive(Debug)]
+pub enum ParseResult<T> {
+ AlreadyResolved(ItemId),
+ New(T, Option<clang::Cursor>),
+}
+
+pub trait ClangSubItemParser : Sized {
+ /// The fact that is a reference guarantees it's holded by the context, and
+ /// allow returning already existing types.
+ fn parse(cursor: clang::Cursor, context: &mut BindgenContext) -> Result<ParseResult<Self>, ParseError>;
+}
+
+pub trait ClangItemParser: Sized {
+ fn parse(cursor: clang::Cursor,
+ parent: Option<ItemId>,
+ context: &mut BindgenContext) -> Result<ItemId, ParseError>;
+ fn from_ty_or_ref(ty: clang::Type,
+ location: Option<clang::Cursor>,
+ parent_id: Option<ItemId>,
+ context: &mut BindgenContext) -> ItemId;
+ fn from_ty_with_id(id: ItemId,
+ ty: &clang::Type,
+ location: Option<clang::Cursor>,
+ parent: Option<ItemId>,
+ ctx: &mut BindgenContext) -> Result<ItemId, ParseError>;
+ fn from_ty(ty: &clang::Type,
+ location: Option<clang::Cursor>,
+ parent: Option<ItemId>,
+ ctx: &mut BindgenContext) -> Result<ItemId, ParseError>;
+ fn named_type<S>(name: S, default: Option<ItemId>, parent: ItemId,
+ context: &mut BindgenContext) -> ItemId
+ where S: Into<String>;
+ fn named_type_with_id<S>(id: ItemId, name: S, default: Option<ItemId>,
+ parent: ItemId, context: &mut BindgenContext) -> ItemId
+ where S: Into<String>;
+ fn builtin_type(kind: TypeKind, is_const: bool, context: &mut BindgenContext) -> ItemId;
+}
diff --git a/src/parser.rs b/src/parser.rs
deleted file mode 100644
index 0e531420..00000000
--- a/src/parser.rs
+++ /dev/null
@@ -1,1516 +0,0 @@
-#![allow(non_upper_case_globals)]
-
-use std::collections::{HashMap, HashSet};
-use hacks::refcell::RefCell;
-use std::rc::Rc;
-use std::path::Path;
-use std::cmp;
-
-use syntax::abi;
-
-use types as il;
-use types::*;
-use clang as cx;
-use clang::{ast_dump, Comment, Cursor, Diagnostic, TranslationUnit, type_to_str, kind_to_str};
-use clangll::*;
-
-use super::Logger;
-
-#[derive(Clone)]
-pub struct ClangParserOptions {
- pub builtin_names: HashSet<String>,
- pub builtins: bool,
- pub match_pat: Vec<String>,
- pub emit_ast: bool,
- pub fail_on_unknown_type: bool,
- pub ignore_functions: bool,
- pub ignore_methods: bool,
- pub enable_cxx_namespaces: bool,
- pub class_constants: bool,
- pub namespaced_constants: bool,
- pub override_enum_ty: Option<il::IKind>,
- pub clang_args: Vec<String>,
- pub opaque_types: Vec<String>,
- pub blacklist_type: Vec<String>,
- pub msvc_mangling: bool,
-}
-
-struct ClangParserCtx<'a> {
- options: ClangParserOptions,
- name: HashMap<Cursor, Global>,
- builtin_defs: Vec<Cursor>,
- module_map: ModuleMap,
- current_module_id: ModuleId,
- /// This member is used to track down if we're in a namespace if the
- /// enable_cxx_namespaces option is disabled.
- namespace_depth: usize,
- current_translation_unit: TranslationUnit,
- logger: &'a (Logger+'a),
- err_count: i32,
- anonymous_modules_found: usize,
-}
-
-impl<'a> ClangParserCtx<'a> {
- fn module(&self, id: &ModuleId) -> &Module {
- self.module_map.get(id).expect("Module not found!")
- }
-
- fn current_module(&self) -> &Module {
- self.module(&self.current_module_id)
- }
-
- fn in_root_namespace(&self) -> bool {
- self.namespace_depth == 0
- }
-
- fn current_module_mut(&mut self) -> &mut Module {
- self.module_map.get_mut(&self.current_module_id).expect("Module not found!")
- }
-}
-
-fn cursor_link_name(_: &mut ClangParserCtx, cursor: &Cursor) -> String {
- // Try to undo backend linkage munging (prepended _, generally)
- let mut mangling = cursor.mangling();
- if cfg!(target_os = "macos") {
- mangling.remove(0);
- }
- mangling
-}
-
-fn match_pattern(ctx: &mut ClangParserCtx, cursor: &Cursor) -> bool {
- let (file, _, _, _) = cursor.location().location();
-
- let name = match file.name() {
- None => return ctx.options.builtins,
- Some(name) => name,
- };
-
- if ctx.options.match_pat.is_empty() {
- return true;
- }
-
- let name = name.replace("\\", "/");
- ctx.options.match_pat.iter().any(|pat| name.contains(pat))
-}
-
-fn conv_template_type_parameter(ctx: &mut ClangParserCtx, cursor: &Cursor) -> Type {
- assert_eq!(cursor.kind(), CXCursor_TemplateTypeParameter);
- let ty = conv_ty(ctx, &cursor.cur_type(), cursor);
- let layout = Layout::new(ty.size(), ty.align());
- TNamed(Rc::new(RefCell::new(TypeInfo::new(cursor.spelling(), ctx.current_module_id, TVoid, layout))))
-}
-
-fn decl_name(ctx: &mut ClangParserCtx, cursor: &Cursor) -> Global {
- let cursor = cursor.canonical();
- let override_enum_ty = ctx.options.override_enum_ty;
- let new_decl = !ctx.name.contains_key(&cursor);
-
- let decl = if new_decl {
- let spelling = cursor.spelling();
- let comment = cursor.raw_comment();
- let (file, _, _, _) = cursor.location().location();
- let ty = cursor.cur_type();
- let layout = Layout::from_ty(&ty);
- let filename = match Path::new(&file.name().unwrap_or("".to_owned())).file_name() {
- Some(name) => name.to_string_lossy().replace(".", "_"),
- _ => "".to_string()
- };
- let glob_decl = match cursor.kind() {
- CXCursor_UnionDecl |
- CXCursor_ClassTemplate |
- CXCursor_ClassDecl |
- CXCursor_StructDecl => {
- let anno = Annotations::new(&cursor);
-
- let kind = match cursor.kind() {
- CXCursor_UnionDecl => CompKind::Union,
- CXCursor_ClassTemplate => {
- match cursor.template_kind() {
- CXCursor_UnionDecl => CompKind::Union,
- _ => CompKind::Struct,
- }
- }
- _ => CompKind::Struct,
- };
-
- let opaque = ctx.options.opaque_types.iter().any(|name| *name == spelling);
- let hide = ctx.options.blacklist_type.iter().any(|name| *name == spelling);
-
- let mut has_non_type_template_params = false;
- let args = match ty.num_template_args() {
- // In forward declarations, etc, they are in the ast... sigh
- -1 => {
- let mut args = vec![];
- cursor.visit(|c, _| {
- if c.kind() == CXCursor_TemplateTypeParameter {
- args.push(conv_template_type_parameter(ctx, c));
- }
- CXChildVisit_Continue
- });
- args
- }
- len => {
- let mut list = Vec::with_capacity(len as usize);
- for i in 0..len {
- let arg_type = ty.template_arg_type(i);
- if arg_type.kind() != CXType_Invalid {
- list.push(conv_ty(ctx, &arg_type, &cursor));
- } else {
- has_non_type_template_params = true;
- ctx.logger.warn("warning: Template parameter is not a type");
- }
- }
- list
- }
- };
-
- let mut ci = CompInfo::new(spelling, ctx.current_module_id,
- filename, comment, kind, vec![],
- layout, anno);
- ci.parser_cursor = Some(cursor);
-
- // If it's an instantiation of another template,
- // find the canonical declaration to find the module
- // it belongs to and if it's opaque.
- let parent = cursor.specialized();
- if let Some(parent) = ctx.name.get(&parent) {
- ci.ref_template = Some(parent.clone().to_type())
- }
-
- ci.opaque = opaque;
- ci.hide = hide;
- ci.args = args;
- ci.has_non_type_template_params = has_non_type_template_params;
-
- let ci = Rc::new(RefCell::new(ci));
- GCompDecl(ci)
- }
- CXCursor_EnumDecl => {
- let kind = match override_enum_ty {
- Some(t) => t,
- None => match cursor.enum_type().kind() {
- CXType_SChar | CXType_Char_S => ISChar,
- CXType_UChar | CXType_Char_U => IUChar,
- CXType_UShort => IUShort,
- CXType_UInt => IUInt,
- CXType_ULong => IULong,
- CXType_ULongLong => IULongLong,
- CXType_Short => IShort,
- CXType_Int => IInt,
- CXType_Long => ILong,
- CXType_LongLong => ILongLong,
- _ => IInt,
- }
- };
-
- let ei = Rc::new(RefCell::new(EnumInfo::new(spelling, ctx.current_module_id, filename, kind, vec!(), layout)));
- GEnumDecl(ei)
- }
- CXCursor_TypeAliasDecl | CXCursor_TypedefDecl => {
- let opaque = ctx.options.opaque_types.iter().any(|name| *name == spelling);
- let hide = ctx.options.blacklist_type.iter().any(|name| *name == spelling);
- let mut ti = TypeInfo::new(spelling, ctx.current_module_id, TVoid, layout);
- ti.opaque = opaque;
- ti.hide = hide;
-
- let ti = Rc::new(RefCell::new(ti));
- GType(ti)
- }
- CXCursor_VarDecl => {
- let mangled = cursor_link_name(ctx, &cursor);
- let is_const = ty.is_const();
- let ty = conv_ty_resolving_typedefs(ctx, &ty, &cursor, true);
- let mut vi = VarInfo::new(spelling, mangled, comment, ty);
- vi.is_const = is_const;
- cursor.visit(|c, _: &Cursor| {
- vi.val = visit_literal(c, &ctx.current_translation_unit);
- CXChildVisit_Continue
- });
- GVar(Rc::new(RefCell::new(vi)))
- }
- CXCursor_MacroDefinition => {
- let vi = Rc::new(RefCell::new(VarInfo::new(spelling, String::new(), comment, TVoid)));
- GVar(vi)
- }
- CXCursor_FunctionDecl => {
- let mangled = cursor_link_name(ctx, &cursor);
- let vi = Rc::new(RefCell::new(VarInfo::new(spelling, mangled, comment, TVoid)));
- GFunc(vi)
- }
- _ => GOther,
- };
-
- ctx.name.insert(cursor, glob_decl.clone());
- glob_decl
- } else {
- ctx.name.get(&cursor).unwrap().clone()
- };
-
- if new_decl && ctx.options.builtin_names.contains(&cursor.spelling()) {
- ctx.builtin_defs.push(cursor);
- }
-
- decl
-}
-
-fn opaque_decl(ctx: &mut ClangParserCtx, decl: &Cursor) {
- let spelling = decl.spelling();
- let hide = ctx.options.blacklist_type.iter().any(|name| *name == spelling);
-
- if hide {
- return;
- }
-
- let name = decl_name(ctx, decl);
- ctx.current_module_mut().globals.push(name);
-}
-
-fn fwd_decl<F: FnOnce(&mut ClangParserCtx)->()>(ctx: &mut ClangParserCtx, cursor: &Cursor, f: F) {
- let def = cursor.definition();
- if cursor == &def {
- f(ctx);
- } else if def.kind() == CXCursor_NoDeclFound ||
- def.kind() == CXCursor_InvalidFile {
- opaque_decl(ctx, cursor);
- }
-}
-
-fn get_abi(cc: Enum_CXCallingConv) -> abi::Abi {
- match cc {
- CXCallingConv_Default => abi::Abi::C,
- CXCallingConv_C => abi::Abi::C,
- CXCallingConv_X86StdCall => abi::Abi::Stdcall,
- CXCallingConv_X86FastCall => abi::Abi::Fastcall,
- CXCallingConv_AAPCS => abi::Abi::Aapcs,
- CXCallingConv_X86_64Win64 => abi::Abi::Win64,
- other => panic!("unsupported calling convention: {}", other),
- }
-}
-
-fn conv_ptr_ty_resolving_typedefs(ctx: &mut ClangParserCtx,
- ty: &cx::Type,
- cursor: &Cursor,
- is_ref: bool,
- layout: Layout,
- resolve_typedefs: bool) -> il::Type {
- let is_const = ty.is_const();
- match ty.kind() {
- CXType_Void => {
- return TPtr(Box::new(TVoid), is_const, is_ref, layout)
- }
- CXType_Unexposed |
- CXType_FunctionProto |
- CXType_FunctionNoProto => {
- let ret_ty = ty.ret_type();
- return if ret_ty.kind() != CXType_Invalid {
- TFuncPtr(mk_fn_sig(ctx, ty, cursor))
- } else if cursor.kind() == CXCursor_VarDecl {
- let can_ty = ty.canonical_type();
- conv_ty_resolving_typedefs(ctx, &can_ty, cursor, resolve_typedefs)
- } else {
- TPtr(Box::new(conv_decl_ty_resolving_typedefs(ctx, ty, cursor, resolve_typedefs)), ty.is_const(), is_ref, layout)
- };
- }
- CXType_Typedef => {
- let decl = ty.declaration();
- let def_ty = decl.typedef_type();
- if def_ty.kind() == CXType_FunctionProto ||
- def_ty.kind() == CXType_FunctionNoProto {
- return TPtr(Box::new(conv_ptr_ty_resolving_typedefs(ctx, &def_ty, cursor, is_ref, layout, resolve_typedefs)), is_const, is_ref, layout);
- } else {
- return TPtr(Box::new(conv_ty_resolving_typedefs(ctx, ty, cursor, resolve_typedefs)), is_const, is_ref, layout);
- }
- }
- _ => return TPtr(Box::new(conv_ty_resolving_typedefs(ctx, ty, cursor, resolve_typedefs)), is_const, is_ref, layout),
- }
-}
-
-fn mk_fn_sig(ctx: &mut ClangParserCtx, ty: &cx::Type, cursor: &Cursor) -> il::FuncSig {
- mk_fn_sig_resolving_typedefs(ctx, ty, cursor, &[])
-}
-
-fn mk_fn_sig_resolving_typedefs(ctx: &mut ClangParserCtx,
- ty: &cx::Type,
- cursor: &Cursor,
- typedefs: &[String]) -> il::FuncSig {
- let args_lst: Vec<(String, il::Type)> = match cursor.kind() {
- CXCursor_FunctionDecl | CXCursor_CXXMethod => {
- // For CXCursor_FunctionDecl, cursor.args() is the reliable way to
- // get parameter names and types.
- cursor.args().iter().map(|arg| {
- let arg_name = arg.spelling();
- let arg_ty = arg.cur_type();
- let is_class_typedef = arg_ty.sanitized_spelling_in(typedefs);
- (arg_name, conv_ty_resolving_typedefs(ctx, &arg_ty, arg, is_class_typedef))
- }).collect()
- }
- _ => {
- // For non-CXCursor_FunctionDecl, visiting the cursor's children is
- // the only reliable way to get parameter names.
- let mut args_lst = vec!();
- cursor.visit(|c: &Cursor, _: &Cursor| {
- if c.kind() == CXCursor_ParmDecl {
- let is_class_typedef = c.cur_type().sanitized_spelling_in(typedefs);
- args_lst.push((c.spelling(), conv_ty_resolving_typedefs(ctx, &c.cur_type(), c, is_class_typedef)));
- }
- CXChildVisit_Continue
- });
- args_lst
- }
- };
-
- let ret_ty = Box::new(conv_ty(ctx, &ty.ret_type(), cursor));
- let abi = get_abi(ty.call_conv());
-
- // Function is presumed unsafe if it takes a pointer argument.
- let is_unsafe = args_lst.iter().any(|arg| match arg.1 {
- TPtr(..) => true,
- _ => false
- });
-
- il::FuncSig {
- ret_ty: ret_ty,
- args: args_lst,
- is_variadic: ty.is_variadic(),
- is_safe: !is_unsafe,
- abi: abi,
- }
-}
-
-fn conv_decl_ty_resolving_typedefs(ctx: &mut ClangParserCtx,
- ty: &cx::Type,
- cursor: &Cursor,
- resolve_typedefs: bool) -> il::Type {
- let ty_decl = ty.declaration();
- // println!("conv_ty_decl: `{}`, ty kind {}: {}, decl `{}` kind {}: {}", cursor.spelling(), ty.kind(), type_to_str(ty.kind()), ty_decl.spelling(), ty_decl.kind(), kind_to_str(ty_decl.kind()));
- return match ty_decl.kind() {
- CXCursor_StructDecl |
- CXCursor_UnionDecl |
- CXCursor_ClassTemplate |
- CXCursor_ClassDecl => {
- let decl = decl_name(ctx, &ty_decl);
- // NB: This will only return a number greater than 0 if this is a **full** class
- // template specialization.
- //
- // If the cursor kind is CXCursor_ClassTemplate, this will still return -1
- // and we'll have to keep traversing the cursor.
- let args = match ty.num_template_args() {
- -1 => vec![],
- len => {
- let mut list = Vec::with_capacity(len as usize);
- for i in 0..len {
- let arg_type = ty.template_arg_type(i);
- if arg_type.kind() != CXType_Invalid {
- list.push(conv_ty(ctx, &arg_type, &cursor));
- } else {
- ctx.logger.warn("warning: Template parameter is not a type");
- }
- }
- list
- }
- };
-
- let ci = decl.compinfo();
- // NB: Args might be filled from decl_name,
- // it's important not to override
- //
- // We might incur in double borrows here. If that's the case, we're
- // already scanning the compinfo, and we'd get the args from the
- // ast.
- use hacks::refcell::BorrowState;
- if !args.is_empty() && ci.borrow_state() == BorrowState::Unused {
- ci.borrow_mut().args = args;
-
- // XXX: This is a super-dumb way to get the spesialisation,
- // but it seems to be the only one that'd work here...
- cursor.visit(|c, _: &Cursor| {
- if c.kind() == CXCursor_TemplateRef {
- let decl = decl_name(ctx, &c.referenced());
- ci.borrow_mut().ref_template = Some(decl.to_type());
- }
- CXChildVisit_Continue
- });
- }
-
- TComp(ci)
- }
- CXCursor_EnumDecl => {
- let decl = decl_name(ctx, &ty_decl);
- let ei = decl.enuminfo();
- TEnum(ei)
- }
- CXCursor_TypeAliasDecl |
- CXCursor_TypedefDecl => {
- if resolve_typedefs {
- return conv_ty_resolving_typedefs(ctx, &ty_decl.typedef_type(), &ty_decl.typedef_type().declaration(), resolve_typedefs);
- }
-
- let decl = decl_name(ctx, &ty_decl);
- let ti = decl.typeinfo();
- TNamed(ti)
- }
- CXCursor_NoDeclFound => {
- let canonical = ty.canonical_type();
- let kind = canonical.kind();
- if kind != CXType_Invalid && kind != CXType_Unexposed {
- conv_ty_resolving_typedefs(ctx, &canonical, &ty_decl, resolve_typedefs)
- } else {
- let layout = Layout::from_ty(ty);
- TNamed(Rc::new(RefCell::new(TypeInfo::new(ty.spelling().replace("const ", ""), ctx.current_module_id, TVoid, layout))))
- }
- }
- _ => {
- let fail = ctx.options.fail_on_unknown_type;
- log_err_warn(ctx,
- &format!("unsupported decl `{}` ({})",
- kind_to_str(ty_decl.kind()), ty_decl.location()
- ),
- fail
- );
- TVoid
- }
- };
-}
-
-fn conv_ty(ctx: &mut ClangParserCtx,
- ty: &cx::Type,
- cursor: &Cursor) -> il::Type {
- conv_ty_resolving_typedefs(ctx, ty, cursor, false)
-}
-
-fn conv_ty_resolving_typedefs(ctx: &mut ClangParserCtx,
- ty: &cx::Type,
- cursor: &Cursor,
- resolve_typedefs: bool) -> il::Type {
- let layout = Layout::from_ty(&ty);
- // println!("conv_ty: `{}` layout: {:?}, kind {}: {}", cursor.spelling(), layout, ty.kind(), type_to_str(ty.kind()));
-
- match ty.kind() {
- CXType_Void => TVoid,
- CXType_Invalid => {
- log_err_warn(ctx,
- &format!("invalid type `{}` ({})",
- cursor.spelling(), cursor.location()
- ),
- false
- );
- TVoid
- }
- CXType_Bool => TInt(IBool, layout),
- CXType_SChar |
- CXType_Char_S => TInt(ISChar, layout),
- CXType_UChar |
- CXType_Char_U => TInt(IUChar, layout),
- CXType_WChar => TInt(IShort, layout),
- CXType_Char16 |
- CXType_UShort => TInt(IUShort, layout),
- CXType_UInt => TInt(IUInt, layout),
- CXType_ULong => TInt(IULong, layout),
- CXType_ULongLong => TInt(IULongLong, layout),
- CXType_Short => TInt(IShort, layout),
- CXType_Int => TInt(IInt, layout),
- CXType_Long => TInt(ILong, layout),
- CXType_LongLong => TInt(ILongLong, layout),
- CXType_Float => TFloat(FFloat, layout),
- CXType_Double => TFloat(FDouble, layout),
- CXType_LongDouble => TFloat(FDouble, layout),
- CXType_Pointer => conv_ptr_ty_resolving_typedefs(ctx, &ty.pointee_type(), cursor, false, layout, resolve_typedefs),
- CXType_LValueReference => conv_ptr_ty_resolving_typedefs(ctx, &ty.pointee_type(), cursor, true, layout, resolve_typedefs),
- // XXX DependentSizedArray is wrong
- CXType_VariableArray |
- CXType_DependentSizedArray |
- CXType_IncompleteArray => {
- conv_ptr_ty_resolving_typedefs(ctx, &ty.elem_type(), cursor, false, layout, resolve_typedefs)
- }
- CXType_FunctionProto => TFuncProto(mk_fn_sig(ctx, ty, cursor)),
- CXType_Record |
- CXType_Typedef |
- CXType_Unexposed |
- CXType_Enum => conv_decl_ty_resolving_typedefs(ctx, ty, cursor, resolve_typedefs),
- CXType_ConstantArray => TArray(Box::new(conv_ty_resolving_typedefs(ctx, &ty.elem_type(), cursor, resolve_typedefs)), ty.array_size(), layout),
- #[cfg(not(feature="llvm_stable"))]
- CXType_Elaborated => conv_ty_resolving_typedefs(ctx, &ty.named(), cursor, resolve_typedefs),
- _ => {
- let fail = ctx.options.fail_on_unknown_type;
- log_err_warn(ctx,
- &format!("unsupported type `{}` ({})",
- type_to_str(ty.kind()), cursor.location()
- ),
- fail
- );
- TVoid
- },
- }
-}
-
-fn opaque_ty(ctx: &mut ClangParserCtx, ty: &cx::Type) {
- if ty.kind() == CXType_Record || ty.kind() == CXType_Enum {
- let decl = ty.declaration();
- let def = decl.definition();
- if def.kind() == CXCursor_NoDeclFound ||
- def.kind() == CXCursor_InvalidFile {
- opaque_decl(ctx, &decl);
- }
- }
-}
-
-#[derive(Copy, PartialEq, Clone, Debug)]
-pub enum Accessor {
- None,
- Regular,
- Unsafe,
- Immutable,
-}
-
-#[derive(Clone, PartialEq, Debug)]
-pub struct Annotations {
- opaque: bool,
- hide: bool,
- use_as: Option<String>,
- /// Disable deriving copy/clone on this struct.
- no_copy: bool,
- // In the None case we fall back to the value specified
- // in the enclosing decl
- private: Option<bool>,
- accessor: Option<Accessor>,
-}
-
-fn parse_accessor(s: &str) -> Accessor {
- match s {
- "false" => Accessor::None,
- "unsafe" => Accessor::Unsafe,
- "immutable" => Accessor::Immutable,
- _ => Accessor::Regular,
- }
-}
-
-impl Annotations {
- fn new(cursor: &Cursor) -> Annotations {
- let mut anno = Annotations {
- opaque: false,
- hide: false,
- use_as: None,
- no_copy: false,
- private: None,
- accessor: None
- };
-
- anno.parse(&cursor.comment());
- anno
- }
-
- fn parse(&mut self, comment: &Comment) {
- if comment.kind() == CXComment_HTMLStartTag &&
- comment.get_tag_name() == "div" &&
- comment.get_num_tag_attrs() > 1 &&
- comment.get_tag_attr_name(0) == "rustbindgen" {
- for i in 0..comment.get_num_tag_attrs() {
- let name = comment.get_tag_attr_name(i);
- match name.as_str() {
- "opaque" => self.opaque = true,
- "hide" => self.hide = true,
- "replaces" => self.use_as = Some(comment.get_tag_attr_value(i)),
- "nocopy" => self.no_copy = true,
- "private" => self.private = Some(comment.get_tag_attr_value(i) != "false"),
- "accessor" => {
- self.accessor = Some(parse_accessor(&comment.get_tag_attr_value(i)))
- },
- _ => (),
- }
- }
- }
-
- for i in 0..comment.num_children() {
- self.parse(&comment.get_child(i));
- }
- }
-}
-
-/// Recursively visits a cursor that represents a composite (struct or union)
-/// type and fills members with CompMember instances representing the fields and
-/// nested composites that make up the visited composite.
-fn visit_composite(cursor: &Cursor, parent: &Cursor,
- ctx: &mut ClangParserCtx,
- ci: &mut CompInfo) -> Enum_CXVisitorResult {
- assert!(ci.parser_cursor.is_some());
- fn is_bitfield_continuation(field: &il::FieldInfo, _ty: &il::Type, width: u32) -> bool {
- match (&field.bitfields, field.ty.layout()) {
- (&Some(ref bitfields), Some(layout)) => {
- let actual_width = bitfields.iter().map(|&(_, w)| w).fold(0u32, |acc, w| acc + w);
- actual_width + width <= (layout.size * 8) as u32
- },
- _ => false
- }
- }
-
- match cursor.kind() {
- CXCursor_TypeAliasDecl | CXCursor_TypedefDecl => {
- ci.typedefs.push(cursor.spelling().to_owned());
- }
- CXCursor_FieldDecl => {
- let anno = Annotations::new(cursor);
- if anno.hide {
- return CXChildVisit_Continue;
- }
-
- let is_class_typedef = cursor.cur_type().sanitized_spelling_in(&ci.typedefs);
- let mutable = cursor.is_mutable_field();
-
- let cursor_ty = cursor.cur_type();
-
- // NB: Overwritten in the case of non-integer bitfield
- let mut ty = conv_ty_resolving_typedefs(ctx,
- &cursor_ty,
- cursor,
- is_class_typedef);
-
-
- use hacks::refcell::BorrowState;
- if let Some(child_ci) = ty.get_outermost_composite() {
- if let BorrowState::Unused = child_ci.borrow_state() {
- let mut child_ci = child_ci.borrow_mut();
- let child_cursor = child_ci.parser_cursor.unwrap();
-
- // TODO: This is lame, ideally we should use cursors.
- // The problem this loop is trying to solve is
- // tests/headers/inner_template_self.hpp, and templates with
- // incomplete types.
- //
- // The problem with this is that, in the first case (see the
- // CXCursor_ClassDecl branch below) clang treats the *prev*
- // field as a Class Declaration instead of a Class Template,
- // so we have to check now for the name and the module id.
- //
- // Ideally, some method like `semantic_parent` or
- // `lexical_parent` should return the reference to the
- // class, but I've tried everything I could think about and
- // failed miserably.
- //
- // Also, there could be more complex cases, like a templated
- // type in an inner type declaration, that this is
- // completely unable to catch.
- //
- // In the second case (the CXCursor_ClassTemplate branch),
- // we're not able to retrieve the template parameters of an
- // incomplete type via the declaration or anything like
- // that. We can inspect the AST and deduct them though,
- // since there's a leading CXCursor_TemplateRef.
- if child_ci.args.is_empty() && child_cursor.kind() == CXCursor_ClassDecl {
- // println!("child: {:?} {:?}, {:?}, {:?}", cursor.spelling(),
- // type_to_str(cursor_ty.kind()),
- // type_to_str(child_cursor.cur_type().kind()),
- // kind_to_str(child_cursor.kind()));
- if child_ci.name == ci.name &&
- child_ci.module_id == ci.module_id {
- child_ci.args = ci.args.clone();
- }
- }
-
- if child_cursor.kind() == CXCursor_ClassTemplate {
- // We need to take into account the possibly different
- // type template names, so we need to clear them and
- // re-scan.
- child_ci.args.clear();
- let mut found_invalid_template_ref = false;
- cursor.visit(|c, _| {
- // println!("ichild: {:?} {:?}, {:?}", c.spelling(),
- // kind_to_str(c.kind()),
- // type_to_str(c.cur_type().kind()));
- if c.kind() == CXCursor_TemplateRef &&
- c.cur_type().kind() == CXType_Invalid {
- found_invalid_template_ref = true;
- }
- if found_invalid_template_ref &&
- c.kind() == CXCursor_TypeRef {
- child_ci.args.push(TNamed(Rc::new(RefCell::new(
- TypeInfo::new(c.spelling(),
- ctx.current_module_id,
- TVoid,
- Layout::zero())))));
- }
- CXChildVisit_Continue
- })
- }
- }
- }
-
- let comment = cursor.raw_comment();
-
- let (name, bitfields) = match (cursor.bit_width(), ci.members.last_mut()) {
- // The field is a continuation of an exising bitfield
- (Some(width), Some(&mut il::CompMember::Field(ref mut field)))
- if is_bitfield_continuation(field, &ty, width) => {
-
- // println!("found bitfield continuation {} (width: {})", cursor.spelling(), width);
-
- field.bitfields.as_mut().unwrap().push((cursor.spelling(), width));
- return CXChildVisit_Continue;
- },
- // The field is the start of a new bitfield
- (Some(width), _) => {
- // Bitfields containing enums are not supported by the c standard
- // https://stackoverflow.com/questions/11983231/is-it-safe-to-use-an-enum-in-a-bit-field
-
- match ty {
- il::TInt(..) => {},
- _ => {
- // NOTE: We rely on the name of the type converted
- // to rust types, and on the alignment.
- let bits = cmp::max(width, ty.size() as u32 * 8);
- let layout_size = cmp::max(1, bits.next_power_of_two() / 8) as usize;
-
- let msg = format!("Enums in bitfields are not supported ({}::{}). Trying to recover with width: {}",
- parent.spelling(), cursor.spelling(), layout_size * 8);
- ctx.logger.warn(&msg);
-
- let name = match layout_size {
- 1 => "uint8_t",
- 2 => "uint16_t",
- 4 => "uint32_t",
- 8 => "uint64_t",
- _ => panic!("bitfield width not supported: {}", layout_size),
- };
-
- // NB: We rely on the ULongLong not being translated
- // (using the common uintxx_t name)
- let ti = TypeInfo::new(name.into(),
- ctx.current_module_id,
- TInt(IKind::IULongLong, Layout::new(layout_size, layout_size)),
- Layout::new(layout_size, layout_size));
- ty = TNamed(Rc::new(RefCell::new(ti)))
- }
- }
- ("".to_owned(), Some(vec![(cursor.spelling(), width)]))
- },
- // The field is not a bitfield
- (None, _) => (cursor.spelling(), None)
- };
-
- // The Clang C api does not fully expose composite fields, but it
- // does expose them in a way that can be detected. When the current
- // field kind is TComp, TPtr or TArray and the previous member is a
- // composite type - the same type as this field - then this is a
- // composite field. e.g.:
- //
- // struct foo {
- // union {
- // int a;
- // char b;
- // } bar;
- // };
- //
- // struct foo {
- // union {
- // int a;
- // char b;
- // } **bar;
- // };
- //
- // struct foo {
- // union {
- // int a;
- // char b;
- // } bar[3][2];
- // };
- //
-
- //let is_composite = match (inner_composite(&ty), ci.members.last()) {
- // (Some(ty_compinfo), Some(&CompMember::Comp(ref c))) => {
- // c.borrow().deref() as *const _ == ty_compinfo.borrow().deref() as *const _
- // },
- // _ => false
- //};
-
- if let Some(&mut CompMember::Field(ref mut info)) = ci.members.last_mut() {
- if bitfields.is_none() && info.bitfields.is_none() {
- let should_replace = if let TComp(ref ci) = info.ty {
- if ci.borrow().was_unnamed && ty.was_unnamed() &&
- Some(&ci.borrow().name) == ty.name().as_ref() {
- true
- } else {
- false
- }
- } else {
- false
- };
-
- if should_replace {
- *info = FieldInfo::new(name, ty, comment, bitfields, mutable);
- info.private = anno.private.unwrap_or(ci.anno.private.unwrap_or(false));
- info.accessor = anno.accessor.unwrap_or(ci.anno.accessor.unwrap_or(Accessor::None));
- return CXChildVisit_Continue;
- }
- }
- }
-
- let mut field = FieldInfo::new(name, ty, comment, bitfields, mutable);
- field.private = anno.private.unwrap_or(ci.anno.private.unwrap_or(false));
- field.accessor = anno.accessor.unwrap_or(ci.anno.accessor.unwrap_or(Accessor::None));
- ci.members.push(CompMember::Field(field));
- }
- CXCursor_StructDecl |
- CXCursor_UnionDecl |
- CXCursor_ClassTemplate |
- CXCursor_ClassDecl => {
- fwd_decl(ctx, cursor, |ctx_| {
- // If the struct is anonymous (i.e. declared here) then it
- // cannot be used elsewhere and so does not need to be added
- // to globals otherwise it will be declared later and a global.
- let decl = decl_name(ctx_, cursor);
- let ci2 = decl.compinfo();
-
- // Mangle the name to prevent multiple definitions
- // of the same inner type to cause conflicts
- let new_name = [&*ci.name, &*ci2.borrow().name].join("_").to_owned();
- ci2.borrow_mut().name = new_name;
-
- // This clear() is needed because of the speculation we do on
- // incomplete types inside visit_composite() members.
- //
- // If this type ends up being complete, we're going to really
- // parse them now, so we should reset them.
- ci2.borrow_mut().args.clear();
-
- // Propagate template arguments and typedefs to inner structs
- ci2.borrow_mut().args.extend(ci.args.clone().into_iter());
- ci2.borrow_mut().typedefs.extend(ci.typedefs.clone().into_iter());
-
- cursor.visit(|c, p| {
- let mut ci_ = ci2.borrow_mut();
- visit_composite(c, p, ctx_, &mut ci_)
- });
-
- ci.members.push(CompMember::Comp(decl.compinfo()));
-
- // Anonymous structs are legal in both C++ and C11
- if ci2.borrow().was_unnamed {
- let ci2b = ci2.borrow();
- let field = FieldInfo::new(ci2b.name.clone(), TComp(ci2.clone()), ci2b.comment.clone(), None, false);
- ci.members.push(CompMember::Field(field));
- }
- });
- }
- CXCursor_PackedAttr => {
- ci.set_packed(true);
- }
- CXCursor_TemplateTypeParameter => {
- ci.args.push(conv_template_type_parameter(ctx, cursor));
- }
- CXCursor_EnumDecl => {
- let anno = Annotations::new(cursor);
-
- fwd_decl(ctx, cursor, |ctx_| {
- let decl = decl_name(ctx_, cursor);
- let ei = decl.enuminfo();
- // Mangle the name to avoid name conflicts with inner types
- let new_name = [&*ci.name, &*ei.borrow().name].join("_").to_owned();
- ei.borrow_mut().name = new_name;
- ei.borrow_mut().comment = cursor.raw_comment();
- cursor.visit(|c, _: &Cursor| {
- let mut ei_ = ei.borrow_mut();
- visit_enum(c, &mut ei_.items)
- });
- if anno.opaque {
- ei.borrow_mut().items = vec!();
- }
- ci.members.push(CompMember::Enum(ei));
- });
- }
- CXCursor_CXXBaseSpecifier => {
- let ty = conv_ty(ctx, &cursor.cur_type(), cursor);
- let fieldname = if ci.members.is_empty() {
- "_base".to_string()
- } else {
- format!("_base{}", ci.members.len())
- };
- let found_virtual_base = if ci.members.is_empty() {
- false
- } else if let CompMember::Field(ref fi) = ci.members[0] {
- if let TComp(ref ci2) = fi.ty {
- ci2.borrow().has_vtable
- } else {
- false
- }
- } else {
- false
- };
-
- if let TComp(ref info) = ty {
- ci.has_nonempty_base |= !info.borrow().members.is_empty();
- ci.has_destructor |= info.borrow().has_destructor;
- ci.typedefs.extend(info.borrow().typedefs.clone().into_iter());
- }
-
- let field = FieldInfo::new(fieldname, ty, "".to_owned(), None, false);
- if !found_virtual_base && cursor.is_virtual_base() {
- ci.members.insert(0, CompMember::Field(field));
- ci.has_vtable = true;
- } else {
- ci.members.push(CompMember::Field(field));
- }
- ci.base_members += 1;
- }
- CXCursor_CXXMethod => {
- // Make sure to mark has_vtable properly, even if we
- // would otherwise skip this method due to linkage/visibility.
- if cursor.method_is_virtual() {
- ci.has_vtable = true;
- }
-
- let linkage = cursor.linkage();
- if linkage != CXLinkage_External {
- return CXChildVisit_Continue;
- }
-
- let visibility = cursor.visibility();
- if visibility != CXVisibility_Default {
- return CXChildVisit_Continue;
- }
-
- if cursor.is_inlined_function() {
- return CXChildVisit_Continue;
- }
-
- // XXX no methods yet for templates
- if !ci.args.is_empty() {
- return CXChildVisit_Continue;
- }
-
- if cursor.access_specifier() == CX_CXXPrivate {
- return CXChildVisit_Continue;
- }
-
- let spelling = cursor.spelling();
- if spelling.len() > 8 &&
- &(spelling)[..8] == "operator" {
- return CXChildVisit_Continue;
- }
-
- fn is_override(ci: &CompInfo, sig: &Type, name: &str) -> bool {
- for vm in ci.vmethods.iter() {
- if vm.name == name && &vm.ty == sig {
- return true;
- }
- }
- for base in ci.members[..ci.base_members].iter() {
- let base = match *base {
- CompMember::Field(ref fi) => {
- match fi.ty {
- TComp(ref ci) => ci.clone(),
- _ => continue,
- }
- },
- _ => unreachable!()
- };
- if is_override(&*base.borrow(), sig, name) {
- return true;
- }
- }
- return false;
- }
-
- let mut sig = mk_fn_sig_resolving_typedefs(ctx, &cursor.cur_type(), cursor, &ci.typedefs);
- if !cursor.method_is_static() {
- // XXX what have i done
- if cursor.method_is_virtual() {
- sig.args.insert(0, ("this".to_string(),TPtr(Box::new(TVoid), cursor.cur_type().is_const(), false, Layout::zero())));
- } else {
- // XXX This is weak and doesn't work if names are mangled further, but...
- // We can't have access to the current Rc from here, so we can't pass the type
- // here.
- //
- // Also, it would form an rc cycle.
- //
- // Possibly marking the "this" attribute with TOther or a similar marked value
- // would be a better choice.
- sig.args.insert(0, ("this".to_string(),
- TPtr(Box::new(TNamed(Rc::new(RefCell::new(TypeInfo::new(ci.name.clone(), ctx.current_module_id, TVoid, Layout::zero()))))), cursor.cur_type().is_const(), false, Layout::zero())));
- }
- }
-
- // XXX with final classes we can optimize a bit
- let sig = TFuncPtr(sig);
- if is_override(ci, &sig, &spelling) {
- return CXChildVisit_Continue;
- }
-
- let mut vi = VarInfo::new(spelling, cursor_link_name(ctx, &cursor), cursor.raw_comment(), sig);
- vi.is_static = cursor.method_is_static();
- vi.is_const = cursor.cur_type().is_const();
-
- if ctx.options.ignore_methods {
- return CXChildVisit_Continue;
- }
-
- if cursor.method_is_virtual() {
- ci.vmethods.push(vi);
- } else {
- ci.methods.push(vi);
- }
- }
- CXCursor_Destructor => {
- ci.has_destructor = true;
- // Propagate the change to the parent
- if let Some(ref t) = ci.ref_template {
- match *t {
- TComp(ref parent_ci) => parent_ci.borrow_mut().has_destructor = true,
- _ => {}
- }
- }
- }
- CXCursor_NonTypeTemplateParameter => {
- log_err_warn(ctx, &format!("warning: Non-type template parameter in composite member could affect layout: `{}` (kind {}) in `{}` ({})",
- cursor.spelling(), cursor.kind(), parent.spelling(),
- cursor.location()), false);
- ci.has_non_type_template_params = true;
- }
- CXCursor_VarDecl => {
- if !ctx.options.class_constants {
- return CXChildVisit_Continue;
- }
-
- let linkage = cursor.linkage();
- if linkage != CXLinkage_External && linkage != CXLinkage_UniqueExternal {
- return CXChildVisit_Continue;
- }
-
- let visibility = cursor.visibility();
- if visibility != CXVisibility_Default {
- return CXChildVisit_Continue;
- }
-
- let var = decl_name(ctx, cursor);
- ci.vars.push(var);
- }
- // Intentionally not handled
- CXCursor_CXXAccessSpecifier |
- CXCursor_CXXFinalAttr |
- CXCursor_Constructor |
- CXCursor_FunctionTemplate |
- CXCursor_ConversionFunction => {}
- _ => {
- // XXX: Some kind of warning would be nice, but this produces far
- // too many.
- log_err_warn(ctx, &format!("unhandled composite member `{}` (kind {}) in `{}` ({})",
- cursor.spelling(), cursor.kind(), parent.spelling(),
- cursor.location()), false);
- }
- }
- CXChildVisit_Continue
-}
-
-fn visit_enum(cursor: &Cursor,
- items: &mut Vec<EnumItem>) -> Enum_CXVisitorResult {
- if cursor.kind() == CXCursor_EnumConstantDecl {
- let name = cursor.spelling();
- let comment = cursor.raw_comment();
- let val = cursor.enum_val();
- let item = EnumItem::new(name, comment, val);
- items.push(item);
- }
- CXChildVisit_Continue
-}
-
-fn parse_int_literal_tokens(cursor: &Cursor, unit: &TranslationUnit, which: usize) -> Option<i64> {
- match unit.tokens(cursor) {
- None => None,
- Some(tokens) => {
- if tokens.len() <= which || tokens[which].kind != CXToken_Literal {
- None
- } else {
- let ref s = tokens[which].spelling;
- let parsed = {
- //TODO: try to preserve hex literals?
- if s.starts_with("0x") {
- i64::from_str_radix(&s[2..], 16)
- } else {
- s.parse()
- }
- };
- match parsed {
- Ok(i) => Some(i),
- Err(_) => None,
- }
- }
- }
- }
-}
-
-fn visit_literal(cursor: &Cursor, unit: &TranslationUnit) -> Option<i64> {
- if cursor.kind() == CXCursor_IntegerLiteral {
- return parse_int_literal_tokens(cursor, unit, 0);
- }
- return None;
-}
-
-fn visit_top(cursor: &Cursor,
- mut ctx: &mut ClangParserCtx) -> Enum_CXVisitorResult {
- if !match_pattern(ctx, cursor) {
- return CXChildVisit_Continue;
- }
-
- match cursor.kind() {
- CXCursor_UnexposedDecl => {
- return CXChildVisit_Recurse;
- }
- CXCursor_StructDecl
- | CXCursor_UnionDecl
- | CXCursor_ClassDecl
- | CXCursor_ClassTemplate => {
- let anno = Annotations::new(cursor);
- fwd_decl(ctx, cursor, move |ctx_| {
- let decl = decl_name(ctx_, cursor);
- let ci = decl.compinfo();
- // This clear() is needed because of the speculation we do
- // on incomplete types inside visit_composite() members.
- ci.borrow_mut().args.clear();
- cursor.visit(|c, p| {
- let mut ci_ = ci.borrow_mut();
- visit_composite(c, p, ctx_, &mut ci_)
- });
-
- if anno.opaque {
- ci.borrow_mut().opaque = true;
- }
-
- if anno.hide {
- ci.borrow_mut().hide = true;
- }
-
- if anno.no_copy {
- ci.borrow_mut().no_copy = true;
- }
-
- // If we find a previous translation, we take it now and carry
- // on.
- //
- // XXX: This clone is spurious and could be avoided with another
- // scope I think.
- let name = ci.borrow().name.clone();
- if let Some(translation) = ctx_.current_module_mut().translations.remove(&name) {
- println!("*** {}: found previous translation", name);
- if let GComp(ref translated) = translation {
- *ci.borrow_mut() = translated.borrow().clone();
- }
- }
-
- if let Some(other_type_name) = anno.use_as {
- ci.borrow_mut().name = other_type_name.clone();
- // if the translated type already existed, and we can
- // replace it, just do it (tm).
- //
- // We'll still need the translations map for not found
- // translations and stuff like that.
- //
- // This is a linear search, which is crap, but fwiw it's not
- // too common (just when a type marked as translation is
- // found).
- //
- // NB: We have to also loop through the `name` map to take
- // declarations in files that haven't been matched into
- // account (since they won't appear in globals).
- let mut found_in_globals = false;
- for v in ctx_.current_module_mut().globals.iter_mut() {
- match *v {
- GComp(ref mut other_ci) => {
- if other_ci.borrow().name == other_type_name {
- *other_ci.borrow_mut() = ci.borrow().clone();
- found_in_globals = true;
- }
- },
- _ => {},
- }
- }
-
- for (cursor, v) in ctx_.name.iter_mut() {
- // We can find ourselves here, and that's no fun at
- // all.
- if *cursor == ci.borrow().parser_cursor.unwrap() {
- continue;
- }
- match *v {
- GComp(ref mut other_ci) |
- GCompDecl(ref mut other_ci) => {
- if other_ci.borrow().name == other_type_name {
- // We have to preserve template parameter
- // names here if we want to survive.
- let args = other_ci.borrow().args.clone();
- *other_ci.borrow_mut() = ci.borrow().clone();
- other_ci.borrow_mut().args = args;
- }
- }
- _ => {}
- }
- }
-
- if !found_in_globals {
- ctx_.current_module_mut().translations
- .insert(other_type_name, GComp(ci));
- }
- } else {
- ctx_.current_module_mut().globals.push(GComp(ci));
- }
- });
- CXChildVisit_Continue
- }
- CXCursor_EnumDecl => {
- fwd_decl(ctx, cursor, |ctx_| {
- let decl = decl_name(ctx_, cursor);
- let ei = decl.enuminfo();
- ei.borrow_mut().comment = cursor.raw_comment();
- cursor.visit(|c, _: &Cursor| {
- let mut ei_ = ei.borrow_mut();
- visit_enum(c, &mut ei_.items)
- });
- ctx_.current_module_mut().globals.push(GEnum(ei));
- });
- CXChildVisit_Continue
- }
- CXCursor_FunctionDecl => {
- if ctx.options.ignore_functions {
- return CXChildVisit_Continue;
- }
-
- let linkage = cursor.linkage();
- if linkage != CXLinkage_External && linkage != CXLinkage_UniqueExternal {
- return CXChildVisit_Continue;
- }
-
- let visibility = cursor.visibility();
- if visibility != CXVisibility_Default {
- return CXChildVisit_Continue;
- }
-
- if cursor.is_inlined_function() {
- return CXChildVisit_Continue;
- }
-
- let spelling = cursor.spelling();
- if spelling.len() > 8 &&
- &(spelling)[..8] == "operator" {
- return CXChildVisit_Continue;
- }
-
- let func = decl_name(ctx, cursor);
- let vi = func.varinfo();
- let mut vi = vi.borrow_mut();
-
- vi.ty = TFuncPtr(mk_fn_sig(ctx, &cursor.cur_type(), cursor));
- ctx.current_module_mut().globals.push(func);
-
- CXChildVisit_Continue
- }
- CXCursor_VarDecl => {
- // TODO: At some point we might want to mangle them instead?
- // We already have a bunch of that logic.
- if !ctx.in_root_namespace() && !ctx.options.namespaced_constants {
- return CXChildVisit_Continue;
- }
-
- let linkage = cursor.linkage();
- if linkage != CXLinkage_External && linkage != CXLinkage_UniqueExternal {
- return CXChildVisit_Continue;
- }
-
- let visibility = cursor.visibility();
- if visibility != CXVisibility_Default {
- return CXChildVisit_Continue;
- }
- let val = decl_name(ctx, cursor);
- ctx.current_module_mut().globals.push(val);
-
- CXChildVisit_Continue
- }
- CXCursor_TypeAliasDecl | CXCursor_TypedefDecl => {
- let anno = Annotations::new(cursor);
- if anno.hide {
- return CXChildVisit_Continue;
- }
-
- let mut under_ty = cursor.typedef_type();
- if under_ty.kind() == CXType_Unexposed {
- under_ty = under_ty.canonical_type();
- }
-
- if cursor.spelling() ==
- cursor.typedef_type().declaration().spelling() {
- // XXX: This is a real hack, but in the common idiom of:
- // typedef struct xxx { ... } xxx;
- //
- // The annotation arrives here, so...
- if anno.opaque {
- ctx.options.opaque_types.push(cursor.spelling());
- }
- return CXChildVisit_Continue;
- }
- let ty = conv_ty(ctx, &under_ty, cursor);
- let typedef = decl_name(ctx, cursor);
- let ti = typedef.typeinfo();
- let mut ti = ti.borrow_mut();
- ti.ty = ty.clone();
-
- if anno.opaque {
- ti.opaque = true;
- }
-
- ti.comment = cursor.raw_comment();
- ctx.current_module_mut().globals.push(typedef);
-
- opaque_ty(ctx, &under_ty);
-
- CXChildVisit_Continue
- }
- CXCursor_FieldDecl => {
- CXChildVisit_Continue
- }
- CXCursor_Namespace => {
- if !ctx.options.enable_cxx_namespaces {
- ctx.namespace_depth += 1;
- cursor.visit(|cur, _: &Cursor| visit_top(cur, &mut ctx));
- ctx.namespace_depth -= 1;
- return CXChildVisit_Continue;
- }
-
- let namespace_name = match ctx.current_translation_unit.tokens(cursor) {
- None => None,
- Some(tokens) => {
- if tokens.len() <= 1 {
- None
- } else {
- match &*tokens[1].spelling {
- "{" => None,
- s => Some(s.to_owned()),
- }
- }
- }
- }.unwrap_or_else(|| {
- ctx.anonymous_modules_found += 1;
- format!("__anonymous{}", ctx.anonymous_modules_found)
- });
-
- // Find an existing namespace children of the current one
- let mod_id = ctx.current_module()
- .children_ids.iter()
- .find(|id| ctx.module_map.get(id).unwrap().name == namespace_name)
- .map(|id| *id);
-
- let mod_id = match mod_id {
- Some(id) => id,
- None => {
- let parent_id = ctx.current_module_id;
- let id = ModuleId::next();
- ctx.module_map.get_mut(&parent_id).unwrap().children_ids.push(id);
- ctx.module_map.insert(id, Module::new(namespace_name, Some(parent_id)));
- id
- }
- };
-
- let previous_id = ctx.current_module_id;
-
- ctx.current_module_id = mod_id;
- ctx.namespace_depth += 1;
- cursor.visit(|cur, _: &Cursor| visit_top(cur, &mut ctx));
- ctx.namespace_depth -= 1;
- ctx.current_module_id = previous_id;
-
- return CXChildVisit_Continue;
- }
- CXCursor_MacroDefinition => {
- let val = parse_int_literal_tokens(cursor, &ctx.current_translation_unit, 1);
- let val = match val {
- None => return CXChildVisit_Continue, // Not an integer literal.
- Some(v) => v,
- };
- let var = decl_name(ctx, cursor);
- let vi = var.varinfo();
- let mut vi = vi.borrow_mut();
- vi.ty = if val.abs() > u32::max_value() as i64 {
- TInt(IULongLong, Layout::new(8, 8))
- } else {
- TInt(IUInt, Layout::new(4, 4))
- };
- vi.is_const = true;
- vi.val = Some(val);
- ctx.current_module_mut().globals.push(var);
-
- return CXChildVisit_Continue;
- }
- _ => {
- // println!("Not handled cursor: {}", cursor.kind());
- return CXChildVisit_Continue;
- }
- }
-}
-
-fn log_err_warn(ctx: &mut ClangParserCtx, msg: &str, is_err: bool) {
- if is_err {
- ctx.err_count += 1;
- ctx.logger.error(msg);
- } else {
- ctx.logger.warn(msg);
- }
-}
-
-pub fn parse(options: ClangParserOptions, logger: &Logger) -> Result<ModuleMap, ()> {
- let ix = cx::Index::create(false, true);
- if ix.is_null() {
- logger.error("Clang failed to create index");
- return Err(())
- }
-
- let unit = TranslationUnit::parse(&ix, "", &options.clang_args, &[], CXTranslationUnit_DetailedPreprocessingRecord);
- if unit.is_null() {
- logger.error("No input files given");
- return Err(())
- }
-
- let mut ctx = ClangParserCtx {
- options: options,
- name: HashMap::new(),
- builtin_defs: vec!(),
- module_map: ModuleMap::new(),
- namespace_depth: 0,
- current_module_id: ROOT_MODULE_ID,
- current_translation_unit: unit,
- logger: logger,
- err_count: 0,
- anonymous_modules_found: 0,
- };
-
- ctx.module_map.insert(ROOT_MODULE_ID, Module::new("root".to_owned(), None));
-
- let diags = ctx.current_translation_unit.diags();
- for d in &diags {
- let msg = d.format(Diagnostic::default_opts());
- let is_err = d.severity() >= CXDiagnostic_Error;
- log_err_warn(&mut ctx, &msg, is_err);
- }
-
- if ctx.err_count > 0 {
- logger.error(&format!("{} errors after diagnostics", ctx.err_count));
- return Err(())
- }
-
- let cursor = ctx.current_translation_unit.cursor();
-
- if ctx.options.emit_ast {
- cursor.visit(|cur, _: &Cursor| ast_dump(cur, 0));
- }
-
- cursor.visit(|cur, _: &Cursor| visit_top(cur, &mut ctx));
-
- while !ctx.builtin_defs.is_empty() {
- let c = ctx.builtin_defs.remove(0);
- visit_top(&c.definition(), &mut ctx);
- }
-
- ctx.current_translation_unit.dispose();
- ix.dispose();
-
- if ctx.err_count > 0 {
- logger.error(&format!("{} errors after translation", ctx.err_count));
- return Err(())
- }
-
- Ok(ctx.module_map)
-}
diff --git a/src/regex_set.rs b/src/regex_set.rs
new file mode 100644
index 00000000..20bc56bf
--- /dev/null
+++ b/src/regex_set.rs
@@ -0,0 +1,58 @@
+use std::borrow::Borrow;
+use regex::Regex;
+
+// Yeah, I'm aware this is sorta crappy, should be cheaper to compile a regex
+// ORing all the patterns, I guess...
+#[derive(Debug)]
+pub struct RegexSet {
+ items: Vec<Regex>
+}
+
+impl RegexSet {
+ pub fn is_empty(&self) -> bool {
+ self.items.is_empty()
+ }
+
+ pub fn extend<I>(&mut self, iter: I)
+ where I: IntoIterator<Item=String>
+ {
+ for s in iter.into_iter() {
+ self.insert(&s)
+ }
+ }
+
+ pub fn insert<S>(&mut self, string: &S)
+ where S: Borrow<str>
+ {
+ let s = string.borrow();
+ match Regex::new(&format!("^{}$", s)) {
+ Ok(r) => {
+ self.items.push(r);
+ }
+ Err(err) => {
+ error!("Invalid pattern provided: {}, {:?}", s, err);
+ }
+ }
+ }
+
+ pub fn matches<S>(&self, string: &S) -> bool
+ where S: Borrow<str>
+ {
+ let s = string.borrow();
+ for r in &self.items {
+ if r.is_match(s) {
+ return true;
+ }
+ }
+
+ false
+ }
+}
+
+impl Default for RegexSet {
+ fn default() -> Self {
+ RegexSet {
+ items: vec![],
+ }
+ }
+}
diff --git a/src/types.rs b/src/types.rs
deleted file mode 100644
index 60af3f59..00000000
--- a/src/types.rs
+++ /dev/null
@@ -1,882 +0,0 @@
-use std::cell::Cell;
-use hacks::refcell::RefCell;
-use std::fmt;
-use std::rc::Rc;
-use std::collections::HashMap;
-use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
-
-use syntax::abi;
-
-pub use self::Global::*;
-pub use self::Type::*;
-pub use self::IKind::*;
-pub use self::FKind::*;
-use clang::{self, Cursor};
-
-use parser::{Annotations, Accessor};
-
-static NEXT_MODULE_ID: AtomicUsize = ATOMIC_USIZE_INIT;
-
-#[derive(Clone, Copy, Eq, PartialEq, Hash, Debug)]
-pub struct ModuleId(usize);
-pub static ROOT_MODULE_ID: ModuleId = ModuleId(0);
-
-impl ModuleId {
- pub fn next() -> ModuleId {
- ModuleId(NEXT_MODULE_ID.fetch_add(1, Ordering::SeqCst) + 1)
- }
-}
-
-pub type ModuleMap = HashMap<ModuleId, Module>;
-
-#[derive(Clone)]
-pub struct Module {
- pub name: String,
- pub globals: Vec<Global>,
- pub parent_id: Option<ModuleId>,
- // Just for convenience
- pub children_ids: Vec<ModuleId>,
- /// Types that must be substituted in this module,
- /// in the form original_name -> substituted_type
- pub translations: HashMap<String, Global>,
-}
-
-impl Module {
- pub fn new(name: String, parent_id: Option<ModuleId>) -> Self {
- Module {
- name: name,
- globals: vec![],
- parent_id: parent_id,
- children_ids: vec![],
- translations: HashMap::new(),
- }
- }
-
- #[allow(dead_code)]
- pub fn add_global(&mut self, g: Global) {
- self.globals.push(g)
- }
-}
-
-#[derive(Clone, PartialEq)]
-pub enum Global {
- GType(Rc<RefCell<TypeInfo>>),
- GComp(Rc<RefCell<CompInfo>>),
- GCompDecl(Rc<RefCell<CompInfo>>),
- GEnum(Rc<RefCell<EnumInfo>>),
- GEnumDecl(Rc<RefCell<EnumInfo>>),
- GVar(Rc<RefCell<VarInfo>>),
- GFunc(Rc<RefCell<VarInfo>>),
- GOther
-}
-
-impl Global {
- // XXX prevent this dumb to_owned()... didn't want to deal with the borrowed lifetime
- pub fn name(&self) -> String {
- match *self {
- GType(ref info) => info.borrow().name.to_owned(),
- GComp(ref info)
- | GCompDecl(ref info) => info.borrow().name.to_owned(),
- GEnum(ref info)
- | GEnumDecl(ref info) => info.borrow().name.to_owned(),
- GVar(ref info)
- | GFunc(ref info) => info.borrow().name.to_owned(),
- GOther => "".to_owned(),
- }
- }
-
- pub fn layout(&self) -> Option<Layout> {
- Some(match *self {
- GType(ref info) => info.borrow().layout,
- GComp(ref info)
- | GCompDecl(ref info) => info.borrow().layout,
- GEnum(ref info)
- | GEnumDecl(ref info) => info.borrow().layout,
- GVar(_)
- | GFunc(_)
- | GOther => return None,
- })
- }
-
- pub fn compinfo(&self) -> Rc<RefCell<CompInfo>> {
- match *self {
- GComp(ref i)
- | GCompDecl(ref i) => i.clone(),
- _ => panic!("global_compinfo")
- }
- }
-
- pub fn enuminfo(&self) -> Rc<RefCell<EnumInfo>> {
- match *self {
- GEnum(ref i)
- | GEnumDecl(ref i) => i.clone(),
- _ => panic!("global_enuminfo")
- }
- }
-
- pub fn typeinfo(&self) -> Rc<RefCell<TypeInfo>> {
- match *self {
- GType(ref i) => i.clone(),
- _ => panic!("global_typeinfo")
- }
- }
-
- pub fn varinfo(&self) -> Rc<RefCell<VarInfo>> {
- match *self {
- GVar(ref i)
- | GFunc(ref i) => i.clone(),
- _ => panic!("global_varinfo")
- }
- }
-
- pub fn to_type(self) -> Type {
- match self {
- GType(ti) => TNamed(ti),
- GComp(ci)
- | GCompDecl(ci) => TComp(ci),
- GEnum(ei)
- | GEnumDecl(ei) => TEnum(ei),
- GVar(_)
- | GFunc(_)
- | GOther => TVoid,
- }
- }
-}
-
-impl fmt::Debug for Global {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- match *self {
- GType(ref ti) => ti.borrow().fmt(f),
- GComp(ref ci)
- | GCompDecl(ref ci) => ci.borrow().fmt(f),
- GEnum(ref ei)
- | GEnumDecl(ref ei) => ei.borrow().fmt(f),
- GVar(ref vi)
- | GFunc(ref vi) => vi.borrow().fmt(f),
- GOther => "*".fmt(f),
- }
- }
-}
-
-#[derive(Debug, Clone, PartialEq)]
-pub struct FuncSig {
- pub ret_ty: Box<Type>,
- pub args: Vec<(String, Type)>,
- pub is_variadic: bool,
- pub is_safe: bool,
- pub abi: abi::Abi,
-}
-
-// NOTE: Remember to add your new variant to the PartialEq implementation below!
-#[derive(Clone, Debug)]
-pub enum Type {
- TVoid,
- TInt(IKind, Layout),
- TFloat(FKind, Layout),
- TPtr(Box<Type>, bool, bool, Layout),
- TArray(Box<Type>, usize, Layout),
- TFuncProto(FuncSig),
- TFuncPtr(FuncSig),
- TNamed(Rc<RefCell<TypeInfo>>),
- TComp(Rc<RefCell<CompInfo>>),
- TEnum(Rc<RefCell<EnumInfo>>)
-}
-
-/// Compares to Rc<T> types looking first at the value they point to.
-///
-/// This is needed to avoid infinite recursion in things like virtual function
-/// signatures.
-fn ref_ptr_aware_eq<T: PartialEq>(one: &Rc<T>, other: &Rc<T>) -> bool {
- &**one as *const T == &**other as *const T ||
- **one == **other
-}
-
-impl PartialEq for Type {
- fn eq(&self, other: &Self) -> bool {
- match (self, other) {
- (&TVoid, &TVoid)
- => true,
- (&TInt(ref kind, ref l), &TInt(ref o_kind, ref o_l))
- => kind == o_kind && l == o_l,
- (&TFloat(ref kind, ref l), &TFloat(ref o_kind, ref o_l))
- => kind == o_kind && l == o_l,
- (&TPtr(ref ty, is_const, is_ref, ref l), &TPtr(ref o_ty, o_is_const, o_is_ref, ref o_l))
- => is_const == o_is_const && is_ref == o_is_ref && l == o_l && ty == o_ty,
- (&TArray(ref ty, count, ref l), &TArray(ref o_ty, o_count, ref o_l))
- => count == o_count && l == o_l && ty == o_ty,
- (&TFuncProto(ref sig), &TFuncProto(ref o_sig))
- => sig == o_sig,
- (&TNamed(ref ti), &TNamed(ref o_ti))
- => ref_ptr_aware_eq(ti, o_ti),
- (&TComp(ref ci), &TComp(ref o_ci))
- => ref_ptr_aware_eq(ci, o_ci),
- (&TEnum(ref ei), &TEnum(ref o_ei))
- => ref_ptr_aware_eq(ei, o_ei),
- _ => false,
- }
- }
-}
-
-impl Type {
- #[allow(dead_code)]
- pub fn name(&self) -> Option<String> {
- match *self {
- TNamed(ref info) => Some(info.borrow().name.clone()),
- TComp(ref info) => Some(info.borrow().name.clone()),
- TEnum(ref info) => Some(info.borrow().name.clone()),
- TArray(ref t, _, _) => t.name(),
- TPtr(ref t, _, _, _) => t.name(),
- _ => None
- }
- }
-
- pub fn signature_contains_type(&self, other: &Type) -> bool {
- self == other || match *self {
- TPtr(ref t, _, _, _) => t.signature_contains_type(other),
- TArray(ref t, _, _) => t.signature_contains_type(other),
- TComp(ref info) => info.borrow().signature_contains_type(other),
- _ => false,
- }
- }
-
- // XXX Add this info to enums?
- pub fn was_unnamed(&self) -> bool {
- match *self {
- TComp(ref ci) => ci.borrow().was_unnamed,
- TArray(ref t, _, _) => t.was_unnamed(),
- TPtr(ref t, _, _, _) => t.was_unnamed(),
- _ => false,
- }
- }
-
- pub fn get_outermost_composite(&self) -> Option<Rc<RefCell<CompInfo>>> {
- match *self {
- TComp(ref ci) => Some(ci.clone()),
- TArray(ref t, _, _) => t.get_outermost_composite(),
- TPtr(ref t, _, _, _) => t.get_outermost_composite(),
- _ => None,
- }
- }
-
- pub fn size(&self) -> usize {
- self.layout().map(|l| l.size).unwrap_or(0)
- }
-
- pub fn align(&self) -> usize {
- self.layout().map(|l| l.align).unwrap_or(0)
- }
-
- pub fn layout(&self) -> Option<Layout> {
- Some(match *self {
- TInt(_, l) => l.clone(),
- TFloat(_, l) => l.clone(),
- TPtr(_, _, _, l) => l.clone(),
- TArray(_, _, l) => l.clone(),
- TComp(ref ci) => ci.borrow().layout.clone(),
- TEnum(ref ei) => ei.borrow().layout.clone(),
- // Test first with the underlying type layout, else with the reported one
- // This fixes a weird bug in SM when it can't find layout for uint32_t
- TNamed(ref ti) => ti.borrow().ty.layout().unwrap_or(ti.borrow().layout.clone()),
- TVoid |
- TFuncProto(..) |
- TFuncPtr(..) => return None,
- })
- }
-
- pub fn can_derive_debug(&self) -> bool {
- !self.is_opaque() && match *self {
- TArray(ref t, size, _) => size <= 32 && t.can_derive_debug(),
- TNamed(ref ti) => ti.borrow().ty.can_derive_debug(),
- TComp(ref comp) => comp.borrow().can_derive_debug(),
- _ => true,
- }
- }
-
- // For some reason, deriving copies of an array of a type that is not known to be copy
- // is a compile error. e.g.:
- //
- // #[derive(Copy)]
- // struct A<T> {
- // member: T,
- // }
- //
- // is fine, while:
- //
- // #[derive(Copy)]
- // struct A<T> {
- // member: [T; 1],
- // }
- //
- // is an error.
- //
- // That's the point of the existance of can_derive_copy_in_array().
- pub fn can_derive_copy_in_array(&self) -> bool {
- match *self {
- TVoid => false,
- TNamed(ref ti) => ti.borrow().ty.can_derive_copy_in_array(),
- TArray(ref t, _, _) => t.can_derive_copy_in_array(),
- ref t => t.can_derive_copy(),
- }
- }
-
- pub fn can_derive_copy(&self) -> bool {
- !self.is_opaque() && match *self {
- TArray(ref t, _, _) => t.can_derive_copy_in_array(),
- TNamed(ref ti) => ti.borrow().ty.can_derive_copy(),
- TComp(ref comp) => comp.borrow().can_derive_copy(),
- _ => true,
- }
- }
-
- pub fn is_opaque(&self) -> bool {
- match *self {
- TArray(ref t, _, _) => t.is_opaque(),
- TPtr(ref t, _, _, _) => t.is_opaque(),
- TNamed(ref ti) => ti.borrow().opaque || ti.borrow().ty.is_opaque(),
- TComp(ref ci) => ci.borrow().is_opaque(),
- _ => false,
- }
- }
-
- #[allow(dead_code)]
- pub fn is_union_like(&self) -> bool {
- match *self {
- TArray(ref t, _, _) => t.is_union_like(),
- TPtr(ref t, _, _, _) => t.is_union_like(),
- TNamed(ref ti) => ti.borrow().ty.is_union_like(),
- TComp(ref ci) => ci.borrow().kind == CompKind::Union,
- _ => false,
- }
- }
-
- // If a type is opaque we conservatively
- // assume it has destructor
- pub fn has_destructor(&self) -> bool {
- self.is_opaque() || match *self {
- TArray(ref t, _, _) => t.has_destructor(),
- TNamed(ref ti) => ti.borrow().ty.has_destructor(),
- TComp(ref ci) => ci.borrow().has_destructor(),
- _ => false,
- }
- }
-
- pub fn is_translatable(&self) -> bool {
- match *self {
- TVoid => false,
- TArray(ref t, _, _) => t.is_translatable(),
- TComp(ref ci) => ci.borrow().is_translatable(),
- // NB: TNamed explicitely ommited here
- _ => true,
- }
- }
-}
-
-#[derive(Copy, Clone, Debug, PartialEq)]
-pub struct Layout {
- pub size: usize,
- pub align: usize,
- pub packed: bool,
-}
-
-impl Layout {
- pub fn new(size: usize, align: usize) -> Self {
- Layout { size: size, align: align, packed: false }
- }
-
- // TODO: make this fallible using fallible_size().
- pub fn from_ty(ty: &clang::Type) -> Self {
- Self::new(ty.size(), ty.align())
- }
-
- pub fn zero() -> Layout {
- Layout { size: 0, align: 0, packed: false }
- }
-
- pub fn is_zero(&self) -> bool {
- *self == Self::zero()
- }
-}
-
-#[derive(Debug, Copy, Clone, PartialEq)]
-pub enum IKind {
- IBool,
- ISChar,
- IUChar,
- IShort,
- IUShort,
- IInt,
- IUInt,
- ILong,
- IULong,
- ILongLong,
- IULongLong
-}
-
-impl IKind {
- #[allow(dead_code)]
- pub fn is_signed(self) -> bool {
- match self {
- IBool => false,
- ISChar => true,
- IUChar => false,
- IShort => true,
- IUShort => false,
- IInt => true,
- IUInt => false,
- ILong => true,
- IULong => false,
- ILongLong => true,
- IULongLong => false,
- }
- }
-}
-
-#[derive(Debug, Copy, Clone, PartialEq)]
-pub enum FKind {
- FFloat,
- FDouble
-}
-
-#[derive(Clone, PartialEq, Debug)]
-pub enum CompMember {
- Field(FieldInfo),
- Comp(Rc<RefCell<CompInfo>>),
- Enum(Rc<RefCell<EnumInfo>>),
-}
-
-#[derive(Copy, Clone, PartialEq)]
-pub enum CompKind {
- Struct,
- Union,
-}
-
-#[derive(Clone, PartialEq)]
-pub struct CompInfo {
- pub kind: CompKind,
- pub name: String,
- pub module_id: ModuleId,
- pub filename: String,
- pub comment: String,
- pub members: Vec<CompMember>,
- pub args: Vec<Type>,
- pub methods: Vec<VarInfo>,
- pub vmethods: Vec<VarInfo>,
- pub ref_template: Option<Type>,
- pub has_vtable: bool,
- pub has_destructor: bool,
- pub has_nonempty_base: bool,
- pub hide: bool,
- pub parser_cursor: Option<Cursor>,
- /// If this struct should be replaced by an opaque blob.
- ///
- /// This is useful if for some reason we can't generate
- /// the correct layout.
- pub opaque: bool,
- pub base_members: usize,
- layout: Layout,
- /// If this struct is explicitely marked as non-copiable.
- pub no_copy: bool,
- /// Typedef'd types names, that we'll resolve early to avoid name conflicts
- pub typedefs: Vec<String>,
- /// If this type has a template parameter which is not a type (e.g.: a size_t)
- pub has_non_type_template_params: bool,
- /// If this type was unnamed when parsed
- pub was_unnamed: bool,
- /// Set of static vars declared inside this class.
- pub vars: Vec<Global>,
- /// Used to detect if we've run in a can_derive_debug cycle while cycling
- /// around the template arguments.
- detect_derive_debug_cycle: Cell<bool>,
- /// Used to detect if we've run in a has_destructor cycle while cycling
- /// around the template arguments.
- detect_has_destructor_cycle: Cell<bool>,
-
- /// Annotations on the decl
- pub anno: Annotations,
-}
-
-static mut UNNAMED_COUNTER: u32 = 0;
-
-fn unnamed_name(name: String, filename: &String) -> String {
- if name.is_empty() {
- let n = unsafe { UNNAMED_COUNTER += 1; UNNAMED_COUNTER };
- format!("{}_unnamed_{}", filename, n)
- } else {
- name
- }
-}
-
-impl CompInfo {
- pub fn new(name: String,
- module_id: ModuleId,
- filename: String,
- comment: String,
- kind: CompKind,
- members: Vec<CompMember>,
- layout: Layout,
- anno: Annotations) -> CompInfo {
- let was_unnamed = name.is_empty();
- CompInfo {
- kind: kind,
- module_id: module_id,
- name: unnamed_name(name, &filename),
- filename: filename,
- comment: comment,
- members: members,
- args: vec![],
- methods: vec![],
- vmethods: vec![],
- ref_template: None,
- has_vtable: false,
- has_destructor: false,
- has_nonempty_base: false,
- hide: false,
- parser_cursor: None,
- opaque: false,
- no_copy: false,
- base_members: 0,
- layout: layout,
- typedefs: vec![],
- vars: vec![],
- has_non_type_template_params: false,
- was_unnamed: was_unnamed,
- detect_derive_debug_cycle: Cell::new(false),
- detect_has_destructor_cycle: Cell::new(false),
- anno: anno,
- }
- }
-
- // Gets or computes the layout as appropriately.
- pub fn layout(&self) -> Layout {
- use std::cmp;
- // The returned layout from clang is zero as of right now, but we should
- // change it to be fallible to distinguish correctly between zero-sized
- // types and unknown layout.
- if !self.layout.is_zero() {
- return self.layout.clone();
- }
-
- if self.args.is_empty() {
- return self.layout.clone();
- }
-
- if self.kind == CompKind::Struct {
- return self.layout.clone();
- }
-
- // If we're a union without known layout, we try to compute it from our
- // members. This is not ideal, but clang fails to report the size for
- // these kind of unions, see test/headers/template_union.hpp
- let mut max_size = 0;
- let mut max_align = 0;
- for member in &self.members {
- let layout = match *member {
- CompMember::Field(ref f) => f.ty.layout().unwrap_or(Layout::zero()),
- CompMember::Comp(ref ci) => ci.borrow().layout(),
- CompMember::Enum(ref ei) => ei.borrow().layout.clone(),
- };
-
- max_size = cmp::max(max_size, layout.size);
- max_align = cmp::max(max_align, layout.align);
- }
-
- Layout::new(max_size, max_align)
- }
-
- pub fn set_packed(&mut self, packed: bool) {
- self.layout.packed = packed
- }
-
- // Return the module id or the class declaration module id.
- pub fn module_id(&self) -> ModuleId {
- self.ref_template.as_ref().and_then(|t| if let TComp(ref ci) = *t {
- Some(ci.borrow().module_id)
- } else {
- None
- }).unwrap_or(self.module_id)
- }
-
- pub fn can_derive_debug(&self) -> bool {
- if self.hide || self.is_opaque() {
- return false;
- }
-
- if self.detect_derive_debug_cycle.get() {
- println!("Derive debug cycle detected: {}!", self.name);
- return true;
- }
-
- match self.kind {
- CompKind::Union => {
- let size_divisor = if self.layout.align == 0 { 1 } else { self.layout.align };
- if self.layout.size / size_divisor > 32 {
- return false;
- }
-
- true
- }
- CompKind::Struct => {
- self.detect_derive_debug_cycle.set(true);
-
- let can_derive_debug = self.args.iter().all(|ty| ty.can_derive_debug()) &&
- self.members.iter()
- .all(|member| match *member {
- CompMember::Field(ref f) => f.ty.can_derive_debug(),
- _ => true,
- });
- self.detect_derive_debug_cycle.set(false);
-
- can_derive_debug
- }
- }
- }
-
- pub fn is_opaque(&self) -> bool {
- if let Some(ref template) = self.ref_template {
- if template.is_opaque() {
- return true;
- }
- }
- self.opaque
- }
-
- pub fn has_destructor(&self) -> bool {
- if self.detect_has_destructor_cycle.get() {
- warn!("Cycle detected looking for destructors: {}!", self.name);
- // Assume no destructor, since we don't have an explicit one.
- return false;
- }
-
- self.detect_has_destructor_cycle.set(true);
-
- let has_destructor = self.has_destructor || match self.kind {
- CompKind::Union => false,
- CompKind::Struct => {
- // NB: We can't rely on a type with type parameters
- // not having destructor.
- //
- // This is unfortunate, but...
- self.ref_template.as_ref().map_or(false, |t| t.has_destructor()) ||
- self.args.iter().any(|t| t.has_destructor()) ||
- self.members.iter().enumerate().any(|(index, m)| match *m {
- CompMember::Field(ref f) => {
- // Base members may not be resolved yet
- if index < self.base_members {
- f.ty.has_destructor()
- } else {
- f.ty.has_destructor() || !f.ty.is_translatable()
- }
- },
- _ => false,
- })
- }
- };
-
- self.detect_has_destructor_cycle.set(false);
-
- has_destructor
- }
-
- pub fn can_derive_copy(&self) -> bool {
- if self.no_copy {
- return false;
- }
-
- // NOTE: Take into account that while unions in C and C++ are copied by
- // default, the may have an explicit destructor in C++, so we can't
- // defer this check just for the union case.
- if self.has_destructor() {
- return false;
- }
-
- match self.kind {
- CompKind::Union => true,
- CompKind::Struct => {
- // With template args, use a safe subset of the types,
- // since copyability depends on the types itself.
- self.ref_template.as_ref().map_or(true, |t| t.can_derive_copy()) &&
- self.members.iter().all(|m| match *m {
- CompMember::Field(ref f) => f.ty.can_derive_copy(),
- _ => true,
- })
- }
- }
- }
-
- pub fn is_translatable(&self) -> bool {
- match self.kind {
- CompKind::Union => true,
- CompKind::Struct => {
- self.args.iter().all(|t| t != &TVoid) && !self.has_non_type_template_params
- }
- }
- }
-
- pub fn signature_contains_type(&self, other: &Type) -> bool {
- self.args.iter().any(|t| t.signature_contains_type(other))
- }
-}
-
-impl fmt::Debug for CompInfo {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "CompInfo({}, ref: {:?}, args: {:?}, members: {:?}", self.name, self.ref_template, self.args, self.members)
- }
-}
-
-#[derive(Clone, PartialEq)]
-pub struct FieldInfo {
- pub name: String,
- pub ty: Type,
- pub comment: String,
- pub bitfields: Option<Vec<(String, u32)>>,
- /// If the C++ field is marked as `mutable`
- pub mutable: bool,
- /// True when field or enclosing struct
- /// has a `<div rust-bindgen private>` annotation
- pub private: bool,
- /// Set by the `<div rust-bindgen accessor="..">`
- /// annotation on a field or enclosing struct
- pub accessor: Accessor,
-}
-
-impl FieldInfo {
- pub fn new(name: String,
- ty: Type,
- comment: String,
- bitfields: Option<Vec<(String, u32)>>,
- mutable: bool) -> FieldInfo {
- FieldInfo {
- name: name,
- ty: ty,
- comment: comment,
- bitfields: bitfields,
- mutable: mutable,
- private: false,
- accessor: Accessor::None,
- }
- }
-}
-
-impl fmt::Debug for FieldInfo {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- self.name.fmt(f)
- }
-}
-
-#[derive(Clone, PartialEq)]
-pub struct EnumInfo {
- pub name: String,
- pub module_id: ModuleId,
- pub comment: String,
- pub filename: String,
- pub items: Vec<EnumItem>,
- pub kind: IKind,
- pub layout: Layout,
-}
-
-impl EnumInfo {
- pub fn new(name: String, module_id: ModuleId, filename: String, kind: IKind, items: Vec<EnumItem>, layout: Layout) -> EnumInfo {
- EnumInfo {
- name: unnamed_name(name, &filename),
- module_id: module_id,
- comment: String::new(),
- filename: filename,
- items: items,
- kind: kind,
- layout: layout,
- }
- }
-}
-
-impl fmt::Debug for EnumInfo {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- self.name.fmt(f)
- }
-}
-
-#[derive(Clone, PartialEq)]
-pub struct EnumItem {
- pub name: String,
- pub comment: String,
- pub val: i64
-}
-
-impl EnumItem {
- pub fn new(name: String, comment: String, val: i64) -> EnumItem {
- EnumItem {
- name: name,
- comment: comment,
- val: val
- }
- }
-}
-
-#[derive(Clone, PartialEq)]
-pub struct TypeInfo {
- pub name: String,
- pub module_id: ModuleId,
- pub comment: String,
- pub ty: Type,
- pub layout: Layout,
- // TODO: Is this really useful?
- // You can just make opaque the underlying type
- pub opaque: bool,
- pub hide: bool,
-}
-
-impl TypeInfo {
- pub fn new(name: String, module_id: ModuleId, ty: Type, layout: Layout) -> TypeInfo {
- TypeInfo {
- name: name,
- module_id: module_id,
- comment: String::new(),
- ty: ty,
- layout: layout,
- opaque: false,
- hide: false,
- }
- }
-}
-
-impl fmt::Debug for TypeInfo {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- self.name.fmt(f)
- }
-}
-
-#[derive(Clone, PartialEq)]
-pub struct VarInfo {
- pub name: String,
- pub mangled: String,
- pub comment: String,
- pub ty: Type,
- //TODO: support non-integer constants
- pub val: Option<i64>,
- pub is_const: bool,
- pub is_static: bool,
-}
-
-impl VarInfo {
- pub fn new(name: String, mangled: String, comment: String, ty: Type) -> VarInfo {
- let mangled = if name == mangled {
- String::new()
- } else {
- mangled
- };
- VarInfo {
- name: name,
- mangled: mangled,
- comment: comment,
- ty: ty,
- val: None,
- is_const: false,
- is_static: false,
- }
- }
-}
-
-impl fmt::Debug for VarInfo {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- self.name.fmt(f)
- }
-}