summaryrefslogtreecommitdiff
path: root/libbindgen/src
diff options
context:
space:
mode:
authorEmilio Cobos Álvarez <emilio@crisal.io>2016-12-12 16:11:43 +0100
committerEmilio Cobos Álvarez <emilio@crisal.io>2016-12-13 14:33:01 +0100
commit883ff74e5f20b68b41f322daa582d9208eece65a (patch)
tree10f0c8aa40dad4a9b48d8a705761074fff9036d3 /libbindgen/src
parent5d9c48e59b49135db1ecfd4ff8c3dbab8ed05086 (diff)
Add support for constructors, and integration tests.
Diffstat (limited to 'libbindgen/src')
-rw-r--r--libbindgen/src/codegen/helpers.rs22
-rw-r--r--libbindgen/src/codegen/mod.rs96
-rw-r--r--libbindgen/src/ir/comp.rs70
-rw-r--r--libbindgen/src/ir/function.rs13
-rw-r--r--libbindgen/src/ir/item.rs23
-rw-r--r--libbindgen/src/lib.rs4
6 files changed, 156 insertions, 72 deletions
diff --git a/libbindgen/src/codegen/helpers.rs b/libbindgen/src/codegen/helpers.rs
index f1a0f314..c09f0071 100644
--- a/libbindgen/src/codegen/helpers.rs
+++ b/libbindgen/src/codegen/helpers.rs
@@ -75,6 +75,7 @@ impl BlobTyBuilder {
pub mod ast_ty {
use aster;
use ir::context::BindgenContext;
+ use ir::function::FunctionSig;
use ir::ty::FloatKind;
use syntax::ast;
use syntax::ptr::P;
@@ -164,4 +165,25 @@ pub mod ast_ty {
let kind = ast::LitKind::FloatUnsuffixed(interned_str);
aster::AstBuilder::new().expr().lit().build_lit(kind)
}
+
+ pub fn arguments_from_signature(signature: &FunctionSig,
+ ctx: &BindgenContext)
+ -> Vec<P<ast::Expr>> {
+ // 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;
+ 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<_>>()
+ }
}
diff --git a/libbindgen/src/codegen/mod.rs b/libbindgen/src/codegen/mod.rs
index 31946964..f3181de7 100644
--- a/libbindgen/src/codegen/mod.rs
+++ b/libbindgen/src/codegen/mod.rs
@@ -4,7 +4,7 @@ mod helpers;
use aster;
use ir::annotations::FieldAccessorKind;
-use ir::comp::{CompInfo, CompKind, Field, Method};
+use ir::comp::{CompInfo, CompKind, Field, Method, MethodKind};
use ir::context::{BindgenContext, ItemId};
use ir::enum_ty::{Enum, EnumVariant, EnumVariantValue};
use ir::function::{Function, FunctionSig};
@@ -1181,15 +1181,28 @@ impl CodeGenerator for CompInfo {
result.push(item);
}
+ let mut method_names = Default::default();
if ctx.options().codegen_config.methods {
- let mut method_names = Default::default();
for method in self.methods() {
+ assert!(method.kind() != MethodKind::Constructor);
method.codegen_method(ctx,
&mut methods,
&mut method_names,
result,
whitelisted_items,
- item);
+ self);
+ }
+ }
+
+ if ctx.options().codegen_config.constructors {
+ for sig in self.constructors() {
+ Method::new(MethodKind::Constructor, *sig, /* const */ false)
+ .codegen_method(ctx,
+ &mut methods,
+ &mut method_names,
+ result,
+ whitelisted_items,
+ self);
}
}
}
@@ -1242,7 +1255,7 @@ trait MethodCodegen {
method_names: &mut HashMap<String, usize>,
result: &mut CodegenResult<'a>,
whitelisted_items: &ItemSet,
- parent: &Item);
+ parent: &CompInfo);
}
impl MethodCodegen for Method {
@@ -1252,18 +1265,21 @@ impl MethodCodegen for Method {
method_names: &mut HashMap<String, usize>,
result: &mut CodegenResult<'a>,
whitelisted_items: &ItemSet,
- _parent: &Item) {
+ _parent: &CompInfo) {
if self.is_virtual() {
return; // FIXME
}
// First of all, output the actual function.
- ctx.resolve_item(self.signature())
- .codegen(ctx, result, whitelisted_items, &());
-
let function_item = ctx.resolve_item(self.signature());
+ function_item.codegen(ctx, result, whitelisted_items, &());
+
let function = function_item.expect_function();
- let mut name = function.name().to_owned();
let signature_item = ctx.resolve_item(function.signature());
+ let mut name = match self.kind() {
+ MethodKind::Constructor => "new".into(),
+ _ => function.name().to_owned(),
+ };
+
let signature = match *signature_item.expect_type().kind() {
TypeKind::Function(ref sig) => sig,
_ => panic!("How in the world?"),
@@ -1283,7 +1299,7 @@ impl MethodCodegen for Method {
let function_name = function_item.canonical_name(ctx);
let mut fndecl = utils::rust_fndecl_from_signature(ctx, signature_item)
.unwrap();
- if !self.is_static() {
+ if !self.is_static() && !self.is_constructor() {
let mutability = if self.is_const() {
ast::Mutability::Immutable
} else {
@@ -1319,32 +1335,38 @@ impl MethodCodegen for Method {
};
}
+ // If it's a constructor, we always return `Self`, and we inject the
+ // "this" parameter, so there's no need to ask the user for it.
+ //
+ // Note that constructors in Clang are represented as functions with
+ // return-type = void.
+ if self.is_constructor() {
+ fndecl.inputs.remove(0);
+ fndecl.output = ast::FunctionRetTy::Ty(quote_ty!(ctx.ext_cx(), Self));
+ }
+
let sig = ast::MethodSig {
unsafety: ast::Unsafety::Unsafe,
abi: Abi::Rust,
- decl: P(fndecl.clone()),
+ decl: P(fndecl),
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<_>>();
+ let mut exprs =
+ helpers::ast_ty::arguments_from_signature(&signature, ctx);
+
+ let mut stmts = vec![];
- if !self.is_static() {
+ // If it's a constructor, we need to insert an extra parameter with a
+ // variable called `tmp` we're going to create.
+ if self.is_constructor() {
+ let tmp_variable_decl =
+ quote_stmt!(ctx.ext_cx(), let mut tmp = ::std::mem::uninitialized())
+ .unwrap();
+ stmts.push(tmp_variable_decl);
+ exprs[0] = quote_expr!(ctx.ext_cx(), &mut tmp);
+ } else if !self.is_static() {
assert!(!exprs.is_empty());
exprs[0] = if self.is_const() {
quote_expr!(ctx.ext_cx(), &*self)
@@ -1359,14 +1381,18 @@ impl MethodCodegen for Method {
.with_args(exprs)
.build();
+ stmts.push(ast::Stmt {
+ id: ast::DUMMY_NODE_ID,
+ node: ast::StmtKind::Expr(call),
+ span: ctx.span(),
+ });
+
+ if self.is_constructor() {
+ stmts.push(quote_stmt!(ctx.ext_cx(), tmp).unwrap());
+ }
+
let block = ast::Block {
- stmts: vec![
- ast::Stmt {
- id: ast::DUMMY_NODE_ID,
- node: ast::StmtKind::Expr(call),
- span: ctx.span(),
- }
- ],
+ stmts: stmts,
id: ast::DUMMY_NODE_ID,
rules: ast::BlockCheckMode::Default,
span: ctx.span(),
diff --git a/libbindgen/src/ir/comp.rs b/libbindgen/src/ir/comp.rs
index d2ace023..c351a152 100644
--- a/libbindgen/src/ir/comp.rs
+++ b/libbindgen/src/ir/comp.rs
@@ -23,6 +23,9 @@ pub enum CompKind {
/// The kind of C++ method.
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum MethodKind {
+ /// A constructor. We represent it as method for convenience, to avoid code
+ /// duplication.
+ Constructor,
/// A static method.
Static,
/// A normal method.
@@ -45,7 +48,7 @@ pub struct Method {
impl Method {
/// Construct a new `Method`.
- fn new(kind: MethodKind, signature: ItemId, is_const: bool) -> Self {
+ pub fn new(kind: MethodKind, signature: ItemId, is_const: bool) -> Self {
Method {
kind: kind,
signature: signature,
@@ -58,6 +61,11 @@ impl Method {
self.kind
}
+ /// Is this a constructor?
+ pub fn is_constructor(&self) -> bool {
+ self.kind == MethodKind::Constructor
+ }
+
/// Is this a virtual method?
pub fn is_virtual(&self) -> bool {
self.kind == MethodKind::Virtual
@@ -167,6 +175,9 @@ pub struct CompInfo {
/// The method declarations inside this class, if in C++ mode.
methods: Vec<Method>,
+ /// The different constructors this struct or class contains.
+ constructors: Vec<ItemId>,
+
/// Vector of classes this one inherits from.
base_members: Vec<ItemId>,
@@ -235,6 +246,7 @@ impl CompInfo {
fields: vec![],
template_args: vec![],
methods: vec![],
+ constructors: vec![],
base_members: vec![],
ref_template: None,
inner_types: vec![],
@@ -454,6 +466,10 @@ impl CompInfo {
&self.methods
}
+ pub fn constructors(&self) -> &[ItemId] {
+ &self.constructors
+ }
+
/// What kind of compound type is this?
pub fn kind(&self) -> CompKind {
self.kind
@@ -651,14 +667,15 @@ impl CompInfo {
.expect("BaseSpecifier");
ci.base_members.push(type_id);
}
+ CXCursor_Constructor |
+ CXCursor_Destructor |
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;
- }
+ ci.has_destructor |= cur.kind() == CXCursor_Destructor;
+ ci.has_vtable |= is_virtual;
let linkage = cur.linkage();
if linkage != CXLinkage_External {
@@ -699,30 +716,34 @@ impl CompInfo {
// NB: This gets us an owned `Function`, not a
// `FunctionSig`.
- let method_signature =
+ let 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
- };
-
- let method =
- Method::new(method_kind, method_signature, is_const);
-
- ci.methods.push(method);
- }
- CXCursor_Destructor => {
- if cur.method_is_virtual() {
- // FIXME: Push to the method list?
- ci.has_vtable = true;
+ match cur.kind() {
+ CXCursor_Constructor => {
+ ci.constructors.push(signature);
+ }
+ // TODO(emilio): Bind the destructor?
+ CXCursor_Destructor => {},
+ CXCursor_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
+ };
+
+ let method = Method::new(method_kind,
+ signature,
+ is_const);
+
+ ci.methods.push(method);
+ }
+ _ => unreachable!("How can we see this here?"),
}
- ci.has_destructor = true;
}
CXCursor_NonTypeTemplateParameter => {
ci.has_non_type_template_params = true;
@@ -746,7 +767,6 @@ impl CompInfo {
// Intentionally not handled
CXCursor_CXXAccessSpecifier |
CXCursor_CXXFinalAttr |
- CXCursor_Constructor |
CXCursor_FunctionTemplate |
CXCursor_ConversionFunction => {}
_ => {
diff --git a/libbindgen/src/ir/function.rs b/libbindgen/src/ir/function.rs
index 5a864cfc..c4c26c62 100644
--- a/libbindgen/src/ir/function.rs
+++ b/libbindgen/src/ir/function.rs
@@ -147,6 +147,7 @@ impl FunctionSig {
};
let mut args: Vec<_> = match cursor.kind() {
CXCursor_FunctionDecl |
+ CXCursor_Constructor |
CXCursor_CXXMethod => {
// For CXCursor_FunctionDecl, cursor.args() is the reliable way
// to get parameter names and types.
@@ -184,10 +185,12 @@ impl FunctionSig {
}
};
- 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();
+ let is_method = cursor.kind() == CXCursor_CXXMethod;
+
+ if is_method || cursor.kind() == CXCursor_Constructor {
+ let is_const = is_method && cursor.method_is_const();
+ let is_virtual = is_method && cursor.method_is_virtual();
+ let is_static = is_method && cursor.method_is_static();
if !is_static && !is_virtual {
let class = Item::parse(cursor.semantic_parent(), None, ctx)
.expect("Expected to parse the class");
@@ -240,6 +243,8 @@ impl ClangSubItemParser for Function {
use clangll::*;
match cursor.kind() {
CXCursor_FunctionDecl |
+ CXCursor_Constructor |
+ CXCursor_Destructor |
CXCursor_CXXMethod => {}
_ => return Err(ParseError::Continue),
};
diff --git a/libbindgen/src/ir/item.rs b/libbindgen/src/ir/item.rs
index 6601216e..11ec7d99 100644
--- a/libbindgen/src/ir/item.rs
+++ b/libbindgen/src/ir/item.rs
@@ -654,19 +654,26 @@ impl Item {
/// Get the overload index for this method. If this is not a method, return
/// `None`.
- fn method_overload_index(&self, ctx: &BindgenContext) -> Option<usize> {
+ fn overload_index(&self, ctx: &BindgenContext) -> Option<usize> {
self.func_name().and_then(|func_name| {
let parent = ctx.resolve_item(self.parent_id());
if let ItemKind::Type(ref ty) = *parent.kind() {
if let TypeKind::Comp(ref ci) = *ty.kind() {
- return ci.methods()
+ // All the constructors have the same name, so no need to
+ // resolve and check.
+ return ci.constructors()
.iter()
- .filter(|method| {
- let item = ctx.resolve_item(method.signature());
- let func = item.expect_function();
- func.name() == func_name
+ .position(|c| *c == self.id())
+ .or_else(|| {
+ ci.methods()
+ .iter()
+ .filter(|m| {
+ let item = ctx.resolve_item(m.signature());
+ let func = item.expect_function();
+ func.name() == func_name
+ })
+ .position(|m| m.signature() == self.id())
})
- .position(|method| method.signature() == self.id());
}
}
@@ -704,7 +711,7 @@ impl Item {
ItemKind::Function(ref fun) => {
let mut name = fun.name().to_owned();
- if let Some(idx) = self.method_overload_index(ctx) {
+ if let Some(idx) = self.overload_index(ctx) {
if idx > 0 {
write!(&mut name, "{}", idx).unwrap();
}
diff --git a/libbindgen/src/lib.rs b/libbindgen/src/lib.rs
index 29580f36..2ff61f90 100644
--- a/libbindgen/src/lib.rs
+++ b/libbindgen/src/lib.rs
@@ -108,6 +108,8 @@ pub struct CodegenConfig {
pub vars: bool,
/// Whether to generate methods.
pub methods: bool,
+ /// Whether to generate constructors.
+ pub constructors: bool,
}
impl CodegenConfig {
@@ -118,6 +120,7 @@ impl CodegenConfig {
types: true,
vars: true,
methods: true,
+ constructors: true,
}
}
@@ -128,6 +131,7 @@ impl CodegenConfig {
types: false,
vars: false,
methods: false,
+ constructors: false,
}
}
}