summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMikko Lehtonen <scoopr@iki.fi>2017-02-04 02:10:34 +0200
committerMikko Lehtonen <scoopr@iki.fi>2017-02-05 22:10:15 +0200
commit8128b2a6c909fac6131f41c140dfd32f00fe71f7 (patch)
tree30cb2306edc6cf9f9e1acce09251914f8acd9d9f
parent2fdb02fddd26a4445085faa2e5f09ff4c814b68d (diff)
objc: Support method arguments
-rw-r--r--src/clang.rs11
-rw-r--r--src/codegen/mod.rs160
-rw-r--r--src/ir/function.rs10
-rw-r--r--src/ir/objc.rs46
-rw-r--r--tests/expectations/tests/objc_method.rs31
-rw-r--r--tests/headers/objc_method.h6
6 files changed, 191 insertions, 73 deletions
diff --git a/src/clang.rs b/src/clang.rs
index 8741663d..4a46b694 100644
--- a/src/clang.rs
+++ b/src/clang.rs
@@ -523,6 +523,14 @@ impl Cursor {
pub fn evaluate(&self) -> Option<EvalResult> {
EvalResult::new(*self)
}
+
+ /// Return the result type for this cursor
+ pub fn ret_type(&self) -> Option<Type> {
+ let rt = Type {
+ x: unsafe { clang_getCursorResultType(self.x) },
+ };
+ if rt.is_valid() { Some(rt) } else { None }
+ }
}
extern "C" fn visit_children<Visitor>(cur: CXCursor,
@@ -1363,6 +1371,9 @@ pub fn ast_dump(c: &Cursor, depth: isize) -> CXChildVisitResult {
prefix,
type_to_str(ty.kind())));
}
+ if let Some(ty) = c.ret_type() {
+ print_indent(depth, format!(" {}ret-type = {}", prefix, type_to_str(ty.kind())));
+ }
if let Some(refd) = c.referenced() {
if refd != *c {
diff --git a/src/codegen/mod.rs b/src/codegen/mod.rs
index 9c71e993..97009185 100644
--- a/src/codegen/mod.rs
+++ b/src/codegen/mod.rs
@@ -2153,61 +2153,8 @@ impl ToRustTy for FunctionSig {
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[1]:
- //
- // 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.
- //
- // [1]: http://c0x.coding-guidelines.com/6.7.5.3.html
- let arg_ty = match *arg_ty.canonical_type(ctx).kind() {
- TypeKind::Array(t, _) => {
- t.to_rust_ty(ctx).to_ptr(arg_ty.is_const(), ctx.span())
- },
- TypeKind::Pointer(inner) => {
- let inner = ctx.resolve_item(inner);
- let inner_ty = inner.expect_type();
- if let TypeKind::ObjCInterface(_) = *inner_ty.canonical_type(ctx).kind() {
- quote_ty!(ctx.ext_cx(), id)
- } else {
- arg_item.to_rust_ty(ctx)
- }
- },
- _ => {
- 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 ret = utils::fnsig_return_ty(ctx, &self);
+ let arguments = utils::fnsig_arguments(ctx, &self);
let decl = P(ast::FnDecl {
inputs: arguments,
@@ -2316,9 +2263,36 @@ impl CodeGenerator for ObjCInterface {
let mut trait_items = vec![];
for method in self.methods() {
- let method_name = ctx.rust_ident(method.name());
+ let signature = method.signature();
+ let fn_args = utils::fnsig_arguments(ctx, signature);
+ let fn_ret = utils::fnsig_return_ty(ctx, signature);
+ let sig = aster::AstBuilder::new()
+ .method_sig()
+ .unsafe_()
+ .fn_decl()
+ .self_()
+ .build(ast::SelfKind::Value(ast::Mutability::Immutable))
+ .with_args(fn_args.clone())
+ .build(fn_ret);
+
+ // Collect the actual used argument names
+ let arg_names: Vec<_> = fn_args.iter()
+ .map(|ref arg| {
+ match arg.pat.node {
+ ast::PatKind::Ident(_, ref spanning, _) => {
+ spanning.node.name.as_str().to_string()
+ }
+ _ => {
+ panic!("odd argument!");
+ }
+ }
+ })
+ .collect();
- let body = quote_stmt!(ctx.ext_cx(), msg_send![self, $method_name])
+ let methods_and_args =
+ ctx.rust_ident(&method.format_method_call(&arg_names));
+ let body =
+ quote_stmt!(ctx.ext_cx(), msg_send![self, $methods_and_args])
.unwrap();
let block = ast::Block {
stmts: vec![body],
@@ -2327,13 +2301,6 @@ impl CodeGenerator for ObjCInterface {
span: ctx.span(),
};
- let sig = aster::AstBuilder::new()
- .method_sig()
- .unsafe_()
- .fn_decl()
- .self_()
- .build(ast::SelfKind::Value(ast::Mutability::Immutable))
- .build(ast::FunctionRetTy::Default(ctx.span()));
let attrs = vec![];
let impl_item = ast::ImplItem {
@@ -2697,4 +2664,69 @@ mod utils {
_ => panic!("How did this happen exactly?"),
}
}
+
+ pub fn fnsig_return_ty(ctx: &BindgenContext,
+ sig: &super::FunctionSig)
+ -> ast::FunctionRetTy {
+ let return_item = ctx.resolve_item(sig.return_type());
+ 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))
+ }
+ }
+
+ pub fn fnsig_arguments(ctx: &BindgenContext,
+ sig: &super::FunctionSig)
+ -> Vec<ast::Arg> {
+ use super::ToPtr;
+ let mut unnamed_arguments = 0;
+ sig.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[1]:
+ //
+ // 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.
+ //
+ // [1]: http://c0x.coding-guidelines.com/6.7.5.3.html
+ let arg_ty = match *arg_ty.canonical_type(ctx).kind() {
+ TypeKind::Array(t, _) => {
+ t.to_rust_ty(ctx).to_ptr(arg_ty.is_const(), ctx.span())
+ },
+ TypeKind::Pointer(inner) => {
+ let inner = ctx.resolve_item(inner);
+ let inner_ty = inner.expect_type();
+ if let TypeKind::ObjCInterface(_) = *inner_ty.canonical_type(ctx).kind() {
+ quote_ty!(ctx.ext_cx(), id)
+ } else {
+ arg_item.to_rust_ty(ctx)
+ }
+ },
+ _ => {
+ 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<_>>()
+ }
+
}
diff --git a/src/ir/function.rs b/src/ir/function.rs
index cc318679..147557f3 100644
--- a/src/ir/function.rs
+++ b/src/ir/function.rs
@@ -85,6 +85,7 @@ fn get_abi(cc: CXCallingConv) -> abi::Abi {
CXCallingConv_X86FastCall => abi::Abi::Fastcall,
CXCallingConv_AAPCS => abi::Abi::Aapcs,
CXCallingConv_X86_64Win64 => abi::Abi::Win64,
+ CXCallingConv_Invalid => abi::Abi::C, // TODO:
other => panic!("unsupported calling convention: {:?}", other),
}
}
@@ -154,7 +155,8 @@ impl FunctionSig {
let mut args: Vec<_> = match cursor.kind() {
CXCursor_FunctionDecl |
CXCursor_Constructor |
- CXCursor_CXXMethod => {
+ CXCursor_CXXMethod |
+ CXCursor_ObjCInstanceMethodDecl => {
// For CXCursor_FunctionDecl, cursor.args() is the reliable way
// to get parameter names and types.
cursor.args()
@@ -218,7 +220,11 @@ impl FunctionSig {
}
}
- let ty_ret_type = try!(ty.ret_type().ok_or(ParseError::Continue));
+ let ty_ret_type = if cursor.kind() == CXCursor_ObjCInstanceMethodDecl {
+ try!(cursor.ret_type().ok_or(ParseError::Continue))
+ } else {
+ try!(ty.ret_type().ok_or(ParseError::Continue))
+ };
let ret = Item::from_ty_or_ref(ty_ret_type, None, None, ctx);
let abi = get_abi(ty.call_conv());
diff --git a/src/ir/objc.rs b/src/ir/objc.rs
index 08cab1cc..ea2cc0c8 100644
--- a/src/ir/objc.rs
+++ b/src/ir/objc.rs
@@ -1,11 +1,10 @@
//! Objective C types
-// use clang_sys::CXCursor_ObjCSuperClassRef;
-
-use super::context::BindgenContext;
use clang;
use clang_sys::CXChildVisit_Continue;
use clang_sys::CXCursor_ObjCInstanceMethodDecl;
+use super::context::BindgenContext;
+use super::function::FunctionSig;
/// Objective C interface as used in TypeKind
///
@@ -30,6 +29,8 @@ pub struct ObjCInstanceMethod {
/// Method name as converted to rust
/// like, dataWithBytes_length_
rust_name: String,
+
+ signature: FunctionSig,
}
impl ObjCInterface {
@@ -53,7 +54,7 @@ impl ObjCInterface {
/// Parses the Objective C interface from the cursor
pub fn from_ty(cursor: &clang::Cursor,
- _ctx: &mut BindgenContext)
+ ctx: &mut BindgenContext)
-> Option<Self> {
let name = cursor.spelling();
let mut interface = Self::new(&name);
@@ -62,7 +63,10 @@ impl ObjCInterface {
match cursor.kind() {
CXCursor_ObjCInstanceMethodDecl => {
let name = cursor.spelling();
- let method = ObjCInstanceMethod::new(&name);
+ let signature =
+ FunctionSig::from_ty(&cursor.cur_type(), &cursor, ctx)
+ .expect("Invalid function sig");
+ let method = ObjCInstanceMethod::new(&name, signature);
interface.methods.push(method);
}
@@ -75,7 +79,7 @@ impl ObjCInterface {
}
impl ObjCInstanceMethod {
- fn new(name: &str) -> ObjCInstanceMethod {
+ fn new(name: &str, signature: FunctionSig) -> ObjCInstanceMethod {
let split_name: Vec<&str> = name.split(':').collect();
let rust_name = split_name.join("_");
@@ -83,6 +87,7 @@ impl ObjCInstanceMethod {
ObjCInstanceMethod {
name: name.to_owned(),
rust_name: rust_name.to_owned(),
+ signature: signature,
}
}
@@ -97,4 +102,33 @@ impl ObjCInstanceMethod {
pub fn rust_name(&self) -> &str {
self.rust_name.as_ref()
}
+
+ /// Returns the methods signature as FunctionSig
+ pub fn signature(&self) -> &FunctionSig {
+ &self.signature
+ }
+
+ /// Formats the method call
+ pub fn format_method_call(&self, args: &[String]) -> String {
+ let split_name: Vec<&str> =
+ self.name.split(':').filter(|p| !p.is_empty()).collect();
+
+ // No arguments
+ if args.len() == 0 && split_name.len() == 1 {
+ return split_name[0].to_string();
+ }
+
+ // Check right amount of arguments
+ if args.len() != split_name.len() {
+ panic!("Incorrect method name or arguments for objc method, {:?} vs {:?}",
+ args,
+ split_name);
+ }
+
+ split_name.iter()
+ .zip(args.iter())
+ .map(|parts| format!("{}:{} ", parts.0, parts.1))
+ .collect::<Vec<_>>()
+ .join("")
+ }
}
diff --git a/tests/expectations/tests/objc_method.rs b/tests/expectations/tests/objc_method.rs
index e2db24f6..d0342a21 100644
--- a/tests/expectations/tests/objc_method.rs
+++ b/tests/expectations/tests/objc_method.rs
@@ -11,7 +11,38 @@ extern crate objc;
pub type id = *mut objc::runtime::Object;
pub trait Foo {
unsafe fn method(self);
+ unsafe fn methodWithInt_(self, foo: ::std::os::raw::c_int);
+ unsafe fn methodWithFoo_(self, foo: id);
+ unsafe fn methodReturningInt(self)
+ -> ::std::os::raw::c_int;
+ unsafe fn methodReturningFoo(self)
+ -> *mut id;
+ unsafe fn methodWithArg1_andArg2_andArg3_(self,
+ intvalue: ::std::os::raw::c_int,
+ ptr:
+ *mut ::std::os::raw::c_char,
+ floatvalue: f32);
}
impl Foo for id {
unsafe fn method(self) { msg_send!(self , method) }
+ unsafe fn methodWithInt_(self, foo: ::std::os::raw::c_int) {
+ msg_send!(self , methodWithInt:foo )
+ }
+ unsafe fn methodWithFoo_(self, foo: id) {
+ msg_send!(self , methodWithFoo:foo )
+ }
+ unsafe fn methodReturningInt(self) -> ::std::os::raw::c_int {
+ msg_send!(self , methodReturningInt)
+ }
+ unsafe fn methodReturningFoo(self) -> *mut id {
+ msg_send!(self , methodReturningFoo)
+ }
+ unsafe fn methodWithArg1_andArg2_andArg3_(self,
+ intvalue: ::std::os::raw::c_int,
+ ptr:
+ *mut ::std::os::raw::c_char,
+ floatvalue: f32) {
+ msg_send!(self ,
+ methodWithArg1:intvalue andArg2:ptr andArg3:floatvalue )
+ }
}
diff --git a/tests/headers/objc_method.h b/tests/headers/objc_method.h
index 91645f16..7a22e8e4 100644
--- a/tests/headers/objc_method.h
+++ b/tests/headers/objc_method.h
@@ -3,5 +3,9 @@
@interface Foo
- (void)method;
-// TODO: argument methods
+- (void)methodWithInt:(int)foo;
+- (void)methodWithFoo:(Foo*)foo;
+- (int)methodReturningInt;
+- (Foo*)methodReturningFoo;
+- (void)methodWithArg1:(int)intvalue andArg2:(char*)ptr andArg3:(float)floatvalue;
@end