Skip to content

Commit 8128b2a

Browse files
committed
objc: Support method arguments
1 parent 2fdb02f commit 8128b2a

File tree

6 files changed

+191
-73
lines changed

6 files changed

+191
-73
lines changed

src/clang.rs

+11
Original file line numberDiff line numberDiff line change
@@ -523,6 +523,14 @@ impl Cursor {
523523
pub fn evaluate(&self) -> Option<EvalResult> {
524524
EvalResult::new(*self)
525525
}
526+
527+
/// Return the result type for this cursor
528+
pub fn ret_type(&self) -> Option<Type> {
529+
let rt = Type {
530+
x: unsafe { clang_getCursorResultType(self.x) },
531+
};
532+
if rt.is_valid() { Some(rt) } else { None }
533+
}
526534
}
527535

528536
extern "C" fn visit_children<Visitor>(cur: CXCursor,
@@ -1363,6 +1371,9 @@ pub fn ast_dump(c: &Cursor, depth: isize) -> CXChildVisitResult {
13631371
prefix,
13641372
type_to_str(ty.kind())));
13651373
}
1374+
if let Some(ty) = c.ret_type() {
1375+
print_indent(depth, format!(" {}ret-type = {}", prefix, type_to_str(ty.kind())));
1376+
}
13661377

13671378
if let Some(refd) = c.referenced() {
13681379
if refd != *c {

src/codegen/mod.rs

+96-64
Original file line numberDiff line numberDiff line change
@@ -2153,61 +2153,8 @@ impl ToRustTy for FunctionSig {
21532153

21542154
fn to_rust_ty(&self, ctx: &BindgenContext, _item: &Item) -> P<ast::Ty> {
21552155
// TODO: we might want to consider ignoring the reference return value.
2156-
let return_item = ctx.resolve_item(self.return_type());
2157-
let ret =
2158-
if let TypeKind::Void = *return_item.kind().expect_type().kind() {
2159-
ast::FunctionRetTy::Default(ctx.span())
2160-
} else {
2161-
ast::FunctionRetTy::Ty(return_item.to_rust_ty(ctx))
2162-
};
2163-
2164-
let mut unnamed_arguments = 0;
2165-
let arguments = self.argument_types().iter().map(|&(ref name, ty)| {
2166-
let arg_item = ctx.resolve_item(ty);
2167-
let arg_ty = arg_item.kind().expect_type();
2168-
2169-
// From the C90 standard[1]:
2170-
//
2171-
// A declaration of a parameter as "array of type" shall be
2172-
// adjusted to "qualified pointer to type", where the type
2173-
// qualifiers (if any) are those specified within the [ and ] of
2174-
// the array type derivation.
2175-
//
2176-
// [1]: http://c0x.coding-guidelines.com/6.7.5.3.html
2177-
let arg_ty = match *arg_ty.canonical_type(ctx).kind() {
2178-
TypeKind::Array(t, _) => {
2179-
t.to_rust_ty(ctx).to_ptr(arg_ty.is_const(), ctx.span())
2180-
},
2181-
TypeKind::Pointer(inner) => {
2182-
let inner = ctx.resolve_item(inner);
2183-
let inner_ty = inner.expect_type();
2184-
if let TypeKind::ObjCInterface(_) = *inner_ty.canonical_type(ctx).kind() {
2185-
quote_ty!(ctx.ext_cx(), id)
2186-
} else {
2187-
arg_item.to_rust_ty(ctx)
2188-
}
2189-
},
2190-
_ => {
2191-
arg_item.to_rust_ty(ctx)
2192-
}
2193-
};
2194-
2195-
let arg_name = match *name {
2196-
Some(ref name) => ctx.rust_mangle(name).into_owned(),
2197-
None => {
2198-
unnamed_arguments += 1;
2199-
format!("arg{}", unnamed_arguments)
2200-
}
2201-
};
2202-
2203-
assert!(!arg_name.is_empty());
2204-
2205-
ast::Arg {
2206-
ty: arg_ty,
2207-
pat: aster::AstBuilder::new().pat().id(arg_name),
2208-
id: ast::DUMMY_NODE_ID,
2209-
}
2210-
}).collect::<Vec<_>>();
2156+
let ret = utils::fnsig_return_ty(ctx, &self);
2157+
let arguments = utils::fnsig_arguments(ctx, &self);
22112158

22122159
let decl = P(ast::FnDecl {
22132160
inputs: arguments,
@@ -2316,9 +2263,36 @@ impl CodeGenerator for ObjCInterface {
23162263
let mut trait_items = vec![];
23172264

23182265
for method in self.methods() {
2319-
let method_name = ctx.rust_ident(method.name());
2266+
let signature = method.signature();
2267+
let fn_args = utils::fnsig_arguments(ctx, signature);
2268+
let fn_ret = utils::fnsig_return_ty(ctx, signature);
2269+
let sig = aster::AstBuilder::new()
2270+
.method_sig()
2271+
.unsafe_()
2272+
.fn_decl()
2273+
.self_()
2274+
.build(ast::SelfKind::Value(ast::Mutability::Immutable))
2275+
.with_args(fn_args.clone())
2276+
.build(fn_ret);
2277+
2278+
// Collect the actual used argument names
2279+
let arg_names: Vec<_> = fn_args.iter()
2280+
.map(|ref arg| {
2281+
match arg.pat.node {
2282+
ast::PatKind::Ident(_, ref spanning, _) => {
2283+
spanning.node.name.as_str().to_string()
2284+
}
2285+
_ => {
2286+
panic!("odd argument!");
2287+
}
2288+
}
2289+
})
2290+
.collect();
23202291

2321-
let body = quote_stmt!(ctx.ext_cx(), msg_send![self, $method_name])
2292+
let methods_and_args =
2293+
ctx.rust_ident(&method.format_method_call(&arg_names));
2294+
let body =
2295+
quote_stmt!(ctx.ext_cx(), msg_send![self, $methods_and_args])
23222296
.unwrap();
23232297
let block = ast::Block {
23242298
stmts: vec![body],
@@ -2327,13 +2301,6 @@ impl CodeGenerator for ObjCInterface {
23272301
span: ctx.span(),
23282302
};
23292303

2330-
let sig = aster::AstBuilder::new()
2331-
.method_sig()
2332-
.unsafe_()
2333-
.fn_decl()
2334-
.self_()
2335-
.build(ast::SelfKind::Value(ast::Mutability::Immutable))
2336-
.build(ast::FunctionRetTy::Default(ctx.span()));
23372304
let attrs = vec![];
23382305

23392306
let impl_item = ast::ImplItem {
@@ -2697,4 +2664,69 @@ mod utils {
26972664
_ => panic!("How did this happen exactly?"),
26982665
}
26992666
}
2667+
2668+
pub fn fnsig_return_ty(ctx: &BindgenContext,
2669+
sig: &super::FunctionSig)
2670+
-> ast::FunctionRetTy {
2671+
let return_item = ctx.resolve_item(sig.return_type());
2672+
if let TypeKind::Void = *return_item.kind().expect_type().kind() {
2673+
ast::FunctionRetTy::Default(ctx.span())
2674+
} else {
2675+
ast::FunctionRetTy::Ty(return_item.to_rust_ty(ctx))
2676+
}
2677+
}
2678+
2679+
pub fn fnsig_arguments(ctx: &BindgenContext,
2680+
sig: &super::FunctionSig)
2681+
-> Vec<ast::Arg> {
2682+
use super::ToPtr;
2683+
let mut unnamed_arguments = 0;
2684+
sig.argument_types().iter().map(|&(ref name, ty)| {
2685+
let arg_item = ctx.resolve_item(ty);
2686+
let arg_ty = arg_item.kind().expect_type();
2687+
2688+
// From the C90 standard[1]:
2689+
//
2690+
// A declaration of a parameter as "array of type" shall be
2691+
// adjusted to "qualified pointer to type", where the type
2692+
// qualifiers (if any) are those specified within the [ and ] of
2693+
// the array type derivation.
2694+
//
2695+
// [1]: http://c0x.coding-guidelines.com/6.7.5.3.html
2696+
let arg_ty = match *arg_ty.canonical_type(ctx).kind() {
2697+
TypeKind::Array(t, _) => {
2698+
t.to_rust_ty(ctx).to_ptr(arg_ty.is_const(), ctx.span())
2699+
},
2700+
TypeKind::Pointer(inner) => {
2701+
let inner = ctx.resolve_item(inner);
2702+
let inner_ty = inner.expect_type();
2703+
if let TypeKind::ObjCInterface(_) = *inner_ty.canonical_type(ctx).kind() {
2704+
quote_ty!(ctx.ext_cx(), id)
2705+
} else {
2706+
arg_item.to_rust_ty(ctx)
2707+
}
2708+
},
2709+
_ => {
2710+
arg_item.to_rust_ty(ctx)
2711+
}
2712+
};
2713+
2714+
let arg_name = match *name {
2715+
Some(ref name) => ctx.rust_mangle(name).into_owned(),
2716+
None => {
2717+
unnamed_arguments += 1;
2718+
format!("arg{}", unnamed_arguments)
2719+
}
2720+
};
2721+
2722+
assert!(!arg_name.is_empty());
2723+
2724+
ast::Arg {
2725+
ty: arg_ty,
2726+
pat: aster::AstBuilder::new().pat().id(arg_name),
2727+
id: ast::DUMMY_NODE_ID,
2728+
}
2729+
}).collect::<Vec<_>>()
2730+
}
2731+
27002732
}

src/ir/function.rs

+8-2
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ fn get_abi(cc: CXCallingConv) -> abi::Abi {
8585
CXCallingConv_X86FastCall => abi::Abi::Fastcall,
8686
CXCallingConv_AAPCS => abi::Abi::Aapcs,
8787
CXCallingConv_X86_64Win64 => abi::Abi::Win64,
88+
CXCallingConv_Invalid => abi::Abi::C, // TODO:
8889
other => panic!("unsupported calling convention: {:?}", other),
8990
}
9091
}
@@ -154,7 +155,8 @@ impl FunctionSig {
154155
let mut args: Vec<_> = match cursor.kind() {
155156
CXCursor_FunctionDecl |
156157
CXCursor_Constructor |
157-
CXCursor_CXXMethod => {
158+
CXCursor_CXXMethod |
159+
CXCursor_ObjCInstanceMethodDecl => {
158160
// For CXCursor_FunctionDecl, cursor.args() is the reliable way
159161
// to get parameter names and types.
160162
cursor.args()
@@ -218,7 +220,11 @@ impl FunctionSig {
218220
}
219221
}
220222

221-
let ty_ret_type = try!(ty.ret_type().ok_or(ParseError::Continue));
223+
let ty_ret_type = if cursor.kind() == CXCursor_ObjCInstanceMethodDecl {
224+
try!(cursor.ret_type().ok_or(ParseError::Continue))
225+
} else {
226+
try!(ty.ret_type().ok_or(ParseError::Continue))
227+
};
222228
let ret = Item::from_ty_or_ref(ty_ret_type, None, None, ctx);
223229
let abi = get_abi(ty.call_conv());
224230

src/ir/objc.rs

+40-6
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
//! Objective C types
22
3-
// use clang_sys::CXCursor_ObjCSuperClassRef;
4-
5-
use super::context::BindgenContext;
63
use clang;
74
use clang_sys::CXChildVisit_Continue;
85
use clang_sys::CXCursor_ObjCInstanceMethodDecl;
6+
use super::context::BindgenContext;
7+
use super::function::FunctionSig;
98

109
/// Objective C interface as used in TypeKind
1110
///
@@ -30,6 +29,8 @@ pub struct ObjCInstanceMethod {
3029
/// Method name as converted to rust
3130
/// like, dataWithBytes_length_
3231
rust_name: String,
32+
33+
signature: FunctionSig,
3334
}
3435

3536
impl ObjCInterface {
@@ -53,7 +54,7 @@ impl ObjCInterface {
5354

5455
/// Parses the Objective C interface from the cursor
5556
pub fn from_ty(cursor: &clang::Cursor,
56-
_ctx: &mut BindgenContext)
57+
ctx: &mut BindgenContext)
5758
-> Option<Self> {
5859
let name = cursor.spelling();
5960
let mut interface = Self::new(&name);
@@ -62,7 +63,10 @@ impl ObjCInterface {
6263
match cursor.kind() {
6364
CXCursor_ObjCInstanceMethodDecl => {
6465
let name = cursor.spelling();
65-
let method = ObjCInstanceMethod::new(&name);
66+
let signature =
67+
FunctionSig::from_ty(&cursor.cur_type(), &cursor, ctx)
68+
.expect("Invalid function sig");
69+
let method = ObjCInstanceMethod::new(&name, signature);
6670

6771
interface.methods.push(method);
6872
}
@@ -75,14 +79,15 @@ impl ObjCInterface {
7579
}
7680

7781
impl ObjCInstanceMethod {
78-
fn new(name: &str) -> ObjCInstanceMethod {
82+
fn new(name: &str, signature: FunctionSig) -> ObjCInstanceMethod {
7983
let split_name: Vec<&str> = name.split(':').collect();
8084

8185
let rust_name = split_name.join("_");
8286

8387
ObjCInstanceMethod {
8488
name: name.to_owned(),
8589
rust_name: rust_name.to_owned(),
90+
signature: signature,
8691
}
8792
}
8893

@@ -97,4 +102,33 @@ impl ObjCInstanceMethod {
97102
pub fn rust_name(&self) -> &str {
98103
self.rust_name.as_ref()
99104
}
105+
106+
/// Returns the methods signature as FunctionSig
107+
pub fn signature(&self) -> &FunctionSig {
108+
&self.signature
109+
}
110+
111+
/// Formats the method call
112+
pub fn format_method_call(&self, args: &[String]) -> String {
113+
let split_name: Vec<&str> =
114+
self.name.split(':').filter(|p| !p.is_empty()).collect();
115+
116+
// No arguments
117+
if args.len() == 0 && split_name.len() == 1 {
118+
return split_name[0].to_string();
119+
}
120+
121+
// Check right amount of arguments
122+
if args.len() != split_name.len() {
123+
panic!("Incorrect method name or arguments for objc method, {:?} vs {:?}",
124+
args,
125+
split_name);
126+
}
127+
128+
split_name.iter()
129+
.zip(args.iter())
130+
.map(|parts| format!("{}:{} ", parts.0, parts.1))
131+
.collect::<Vec<_>>()
132+
.join("")
133+
}
100134
}

tests/expectations/tests/objc_method.rs

+31
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,38 @@ extern crate objc;
1111
pub type id = *mut objc::runtime::Object;
1212
pub trait Foo {
1313
unsafe fn method(self);
14+
unsafe fn methodWithInt_(self, foo: ::std::os::raw::c_int);
15+
unsafe fn methodWithFoo_(self, foo: id);
16+
unsafe fn methodReturningInt(self)
17+
-> ::std::os::raw::c_int;
18+
unsafe fn methodReturningFoo(self)
19+
-> *mut id;
20+
unsafe fn methodWithArg1_andArg2_andArg3_(self,
21+
intvalue: ::std::os::raw::c_int,
22+
ptr:
23+
*mut ::std::os::raw::c_char,
24+
floatvalue: f32);
1425
}
1526
impl Foo for id {
1627
unsafe fn method(self) { msg_send!(self , method) }
28+
unsafe fn methodWithInt_(self, foo: ::std::os::raw::c_int) {
29+
msg_send!(self , methodWithInt:foo )
30+
}
31+
unsafe fn methodWithFoo_(self, foo: id) {
32+
msg_send!(self , methodWithFoo:foo )
33+
}
34+
unsafe fn methodReturningInt(self) -> ::std::os::raw::c_int {
35+
msg_send!(self , methodReturningInt)
36+
}
37+
unsafe fn methodReturningFoo(self) -> *mut id {
38+
msg_send!(self , methodReturningFoo)
39+
}
40+
unsafe fn methodWithArg1_andArg2_andArg3_(self,
41+
intvalue: ::std::os::raw::c_int,
42+
ptr:
43+
*mut ::std::os::raw::c_char,
44+
floatvalue: f32) {
45+
msg_send!(self ,
46+
methodWithArg1:intvalue andArg2:ptr andArg3:floatvalue )
47+
}
1748
}

tests/headers/objc_method.h

+5-1
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,9 @@
33

44
@interface Foo
55
- (void)method;
6-
// TODO: argument methods
6+
- (void)methodWithInt:(int)foo;
7+
- (void)methodWithFoo:(Foo*)foo;
8+
- (int)methodReturningInt;
9+
- (Foo*)methodReturningFoo;
10+
- (void)methodWithArg1:(int)intvalue andArg2:(char*)ptr andArg3:(float)floatvalue;
711
@end

0 commit comments

Comments
 (0)