Skip to content

Commit e14f1bd

Browse files
committed
objc: Implement class methods
1 parent 6320ed2 commit e14f1bd

14 files changed

+223
-30
lines changed

src/codegen/mod.rs

Lines changed: 67 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use ir::item::{Item, ItemAncestors, ItemCanonicalName, ItemCanonicalPath,
1919
use ir::item_kind::ItemKind;
2020
use ir::layout::Layout;
2121
use ir::module::Module;
22-
use ir::objc::ObjCInterface;
22+
use ir::objc::{ObjCInterface, ObjCMethod};
2323
use ir::ty::{Type, TypeKind};
2424
use ir::var::Var;
2525

@@ -2400,28 +2400,33 @@ impl CodeGenerator for Function {
24002400
}
24012401
}
24022402

2403-
impl CodeGenerator for ObjCInterface {
2404-
type Extra = Item;
2405-
fn codegen<'a>(&self,
2406-
ctx: &BindgenContext,
2407-
result: &mut CodegenResult<'a>,
2408-
_whitelisted_items: &ItemSet,
2409-
_: &Item) {
2410-
let mut impl_items = vec![];
2411-
let mut trait_items = vec![];
24122403

2413-
for method in self.methods() {
2404+
fn objc_method_codegen(ctx: &BindgenContext,
2405+
method: &ObjCMethod,
2406+
class_name: Option<&str>)
2407+
-> (ast::ImplItem, ast::TraitItem) {
24142408
let signature = method.signature();
24152409
let fn_args = utils::fnsig_arguments(ctx, signature);
24162410
let fn_ret = utils::fnsig_return_ty(ctx, signature);
2417-
let sig = aster::AstBuilder::new()
2411+
let sig;
2412+
2413+
if method.is_class() {
2414+
sig = aster::AstBuilder::new()
2415+
.method_sig()
2416+
.unsafe_()
2417+
.fn_decl()
2418+
.with_args(fn_args.clone())
2419+
.build(fn_ret);
2420+
} else {
2421+
sig = aster::AstBuilder::new()
24182422
.method_sig()
24192423
.unsafe_()
24202424
.fn_decl()
24212425
.self_()
24222426
.build(ast::SelfKind::Value(ast::Mutability::Immutable))
24232427
.with_args(fn_args.clone())
24242428
.build(fn_ret);
2429+
}
24252430

24262431
// Collect the actual used argument names
24272432
let arg_names: Vec<_> = fn_args.iter()
@@ -2437,9 +2442,19 @@ impl CodeGenerator for ObjCInterface {
24372442

24382443
let methods_and_args =
24392444
ctx.rust_ident(&method.format_method_call(&arg_names));
2440-
let body = quote_stmt!(ctx.ext_cx(),
2441-
msg_send![self, $methods_and_args])
2445+
let body;
2446+
2447+
if method.is_class() {
2448+
let class_name =
2449+
class_name.expect("Generating a class method without class name?")
2450+
.to_owned();
2451+
body = quote_stmt!(ctx.ext_cx(),
2452+
msg_send![class($class_name), $methods_and_args])
24422453
.unwrap();
2454+
} else {
2455+
body = quote_stmt!(ctx.ext_cx(), msg_send![self, $methods_and_args])
2456+
.unwrap();
2457+
}
24432458
let block = ast::Block {
24442459
stmts: vec![body],
24452460
id: ast::DUMMY_NODE_ID,
@@ -2467,10 +2482,33 @@ impl CodeGenerator for ObjCInterface {
24672482
span: ctx.span(),
24682483
};
24692484

2485+
(impl_item, trait_item)
2486+
}
2487+
2488+
impl CodeGenerator for ObjCInterface {
2489+
type Extra = Item;
2490+
2491+
fn codegen<'a>(&self,
2492+
ctx: &BindgenContext,
2493+
result: &mut CodegenResult<'a>,
2494+
_whitelisted_items: &ItemSet,
2495+
_: &Item) {
2496+
let mut impl_items = vec![];
2497+
let mut trait_items = vec![];
2498+
2499+
for method in self.methods() {
2500+
let (impl_item, trait_item) =
2501+
objc_method_codegen(ctx, method, None);
24702502
impl_items.push(impl_item);
24712503
trait_items.push(trait_item)
24722504
}
24732505

2506+
for class_method in self.class_methods() {
2507+
let (impl_item, trait_item) =
2508+
objc_method_codegen(ctx, class_method, Some(self.name()));
2509+
impl_items.push(impl_item);
2510+
trait_items.push(trait_item)
2511+
}
24742512

24752513
let trait_name = self.rust_name();
24762514

@@ -2562,7 +2600,21 @@ mod utils {
25622600
)
25632601
.unwrap();
25642602

2565-
let items = vec![use_objc, id_type];
2603+
let class_ty = quote_item!(ctx.ext_cx(),
2604+
type Class = *mut objc::runtime::Class;
2605+
)
2606+
.unwrap();
2607+
let class_fn = quote_item!(ctx.ext_cx(),
2608+
#[inline]
2609+
fn class(name: &str) -> Class {
2610+
unsafe {
2611+
std::mem::transmute(objc::runtime::Class::get(name))
2612+
}
2613+
}
2614+
)
2615+
.unwrap();
2616+
2617+
let items = vec![use_objc, id_type, class_ty, class_fn];
25662618
let old_items = mem::replace(result, items);
25672619
result.extend(old_items.into_iter());
25682620
}

src/ir/function.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,8 @@ impl FunctionSig {
177177
CXCursor_FunctionDecl |
178178
CXCursor_Constructor |
179179
CXCursor_CXXMethod |
180-
CXCursor_ObjCInstanceMethodDecl => {
180+
CXCursor_ObjCInstanceMethodDecl |
181+
CXCursor_ObjCClassMethodDecl => {
181182
// For CXCursor_FunctionDecl, cursor.args() is the reliable way
182183
// to get parameter names and types.
183184
cursor.args()
@@ -241,7 +242,8 @@ impl FunctionSig {
241242
}
242243
}
243244

244-
let ty_ret_type = if cursor.kind() == CXCursor_ObjCInstanceMethodDecl {
245+
let ty_ret_type = if cursor.kind() == CXCursor_ObjCInstanceMethodDecl ||
246+
cursor.kind() == CXCursor_ObjCClassMethodDecl {
245247
try!(cursor.ret_type().ok_or(ParseError::Continue))
246248
} else {
247249
try!(ty.ret_type().ok_or(ParseError::Continue))
@@ -250,8 +252,8 @@ impl FunctionSig {
250252
let abi = get_abi(ty.call_conv());
251253

252254
if abi.is_none() {
253-
assert_eq!(cursor.kind(),
254-
CXCursor_ObjCInstanceMethodDecl,
255+
assert!(cursor.kind() == CXCursor_ObjCInstanceMethodDecl ||
256+
cursor.kind() == CXCursor_ObjCClassMethodDecl,
255257
"Invalid ABI for function signature")
256258
}
257259

src/ir/objc.rs

Lines changed: 38 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use super::ty::TypeKind;
77
use clang;
88
use clang_sys::CXChildVisit_Continue;
99
use clang_sys::CXCursor_ObjCCategoryDecl;
10+
use clang_sys::CXCursor_ObjCClassMethodDecl;
1011
use clang_sys::CXCursor_ObjCClassRef;
1112
use clang_sys::CXCursor_ObjCInstanceMethodDecl;
1213
use clang_sys::CXCursor_ObjCProtocolDecl;
@@ -28,12 +29,14 @@ pub struct ObjCInterface {
2829
conforms_to: Vec<ItemId>,
2930

3031
/// List of the methods defined in this interfae
31-
methods: Vec<ObjCInstanceMethod>,
32+
methods: Vec<ObjCMethod>,
33+
34+
class_methods: Vec<ObjCMethod>,
3235
}
3336

3437
/// The objective c methods
3538
#[derive(Debug)]
36-
pub struct ObjCInstanceMethod {
39+
pub struct ObjCMethod {
3740
/// The original method selector name
3841
/// like, dataWithBytes:length:
3942
name: String,
@@ -43,6 +46,9 @@ pub struct ObjCInstanceMethod {
4346
rust_name: String,
4447

4548
signature: FunctionSig,
49+
50+
/// Is class method?
51+
is_class: bool,
4652
}
4753

4854
impl ObjCInterface {
@@ -53,6 +59,7 @@ impl ObjCInterface {
5359
is_protocol: false,
5460
conforms_to: Vec::new(),
5561
methods: Vec::new(),
62+
class_methods: Vec::new(),
5663
}
5764
}
5865

@@ -77,11 +84,16 @@ impl ObjCInterface {
7784
}
7885
}
7986

80-
/// List of the methods defined in this interfae
81-
pub fn methods(&self) -> &Vec<ObjCInstanceMethod> {
87+
/// List of the methods defined in this interface
88+
pub fn methods(&self) -> &Vec<ObjCMethod> {
8289
&self.methods
8390
}
8491

92+
/// List of the class methods defined in this interface
93+
pub fn class_methods(&self) -> &Vec<ObjCMethod> {
94+
&self.class_methods
95+
}
96+
8597
/// Parses the Objective C interface from the cursor
8698
pub fn from_ty(cursor: &clang::Cursor,
8799
ctx: &mut BindgenContext)
@@ -131,14 +143,19 @@ impl ObjCInterface {
131143
}
132144

133145
}
134-
CXCursor_ObjCInstanceMethodDecl => {
146+
CXCursor_ObjCInstanceMethodDecl |
147+
CXCursor_ObjCClassMethodDecl => {
135148
let name = c.spelling();
136149
let signature =
137150
FunctionSig::from_ty(&c.cur_type(), &c, ctx)
138151
.expect("Invalid function sig");
139-
let method = ObjCInstanceMethod::new(&name, signature);
140-
141-
interface.methods.push(method);
152+
if c.kind() == CXCursor_ObjCInstanceMethodDecl {
153+
let method = ObjCMethod::new(&name, signature, false);
154+
interface.methods.push(method);
155+
} else {
156+
let method = ObjCMethod::new(&name, signature, true);
157+
interface.class_methods.push(method);
158+
}
142159
}
143160
_ => {}
144161
}
@@ -148,16 +165,17 @@ impl ObjCInterface {
148165
}
149166
}
150167

151-
impl ObjCInstanceMethod {
152-
fn new(name: &str, signature: FunctionSig) -> ObjCInstanceMethod {
168+
impl ObjCMethod {
169+
fn new(name: &str, signature: FunctionSig, is_class: bool) -> ObjCMethod {
153170
let split_name: Vec<&str> = name.split(':').collect();
154171

155172
let rust_name = split_name.join("_");
156173

157-
ObjCInstanceMethod {
174+
ObjCMethod {
158175
name: name.to_owned(),
159176
rust_name: rust_name.to_owned(),
160177
signature: signature,
178+
is_class: is_class,
161179
}
162180
}
163181

@@ -178,6 +196,11 @@ impl ObjCInstanceMethod {
178196
&self.signature
179197
}
180198

199+
/// Is this a class method?
200+
pub fn is_class(&self) -> bool {
201+
self.is_class
202+
}
203+
181204
/// Formats the method call
182205
pub fn format_method_call(&self, args: &[String]) -> String {
183206
let split_name: Vec<&str> =
@@ -213,6 +236,10 @@ impl Trace for ObjCInterface {
213236
method.signature.trace(context, tracer, &());
214237
}
215238

239+
for class_method in &self.class_methods {
240+
class_method.signature.trace(context, tracer, &());
241+
}
242+
216243
for protocol in &self.conforms_to {
217244
tracer.visit(*protocol);
218245
}

tests/expectations/tests/objc_category.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,11 @@
99
extern crate objc;
1010
#[allow(non_camel_case_types)]
1111
pub type id = *mut objc::runtime::Object;
12+
type Class = *mut objc::runtime::Class;
13+
#[inline]
14+
fn class(name: &str) -> Class {
15+
unsafe { std::mem::transmute(objc::runtime::Class::get(name)) }
16+
}
1217
pub trait Foo {
1318
unsafe fn method(self);
1419
}

tests/expectations/tests/objc_class.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,11 @@
99
extern crate objc;
1010
#[allow(non_camel_case_types)]
1111
pub type id = *mut objc::runtime::Object;
12+
type Class = *mut objc::runtime::Class;
13+
#[inline]
14+
fn class(name: &str) -> Class {
15+
unsafe { std::mem::transmute(objc::runtime::Class::get(name)) }
16+
}
1217
pub trait Foo {
1318
unsafe fn method(self);
1419
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/* automatically generated by rust-bindgen */
2+
3+
4+
#![allow(non_snake_case)]
5+
6+
#![cfg(target_os="macos")]
7+
8+
#[macro_use]
9+
extern crate objc;
10+
#[allow(non_camel_case_types)]
11+
pub type id = *mut objc::runtime::Object;
12+
type Class = *mut objc::runtime::Class;
13+
#[inline]
14+
fn class(name: &str) -> Class {
15+
unsafe { std::mem::transmute(objc::runtime::Class::get(name)) }
16+
}
17+
pub trait Foo {
18+
unsafe fn method();
19+
unsafe fn methodWithInt_(foo: ::std::os::raw::c_int);
20+
unsafe fn methodWithFoo_(foo: id);
21+
unsafe fn methodReturningInt()
22+
-> ::std::os::raw::c_int;
23+
unsafe fn methodReturningFoo()
24+
-> *mut id;
25+
unsafe fn methodWithArg1_andArg2_andArg3_(intvalue: ::std::os::raw::c_int,
26+
ptr:
27+
*mut ::std::os::raw::c_char,
28+
floatvalue: f32);
29+
}
30+
impl Foo for id {
31+
unsafe fn method() { msg_send!(class ( "Foo" ) , method) }
32+
unsafe fn methodWithInt_(foo: ::std::os::raw::c_int) {
33+
msg_send!(class ( "Foo" ) , methodWithInt:foo )
34+
}
35+
unsafe fn methodWithFoo_(foo: id) {
36+
msg_send!(class ( "Foo" ) , methodWithFoo:foo )
37+
}
38+
unsafe fn methodReturningInt() -> ::std::os::raw::c_int {
39+
msg_send!(class ( "Foo" ) , methodReturningInt)
40+
}
41+
unsafe fn methodReturningFoo() -> *mut id {
42+
msg_send!(class ( "Foo" ) , methodReturningFoo)
43+
}
44+
unsafe fn methodWithArg1_andArg2_andArg3_(intvalue: ::std::os::raw::c_int,
45+
ptr:
46+
*mut ::std::os::raw::c_char,
47+
floatvalue: f32) {
48+
msg_send!(class ( "Foo" ) ,
49+
methodWithArg1:intvalue andArg2:ptr andArg3:floatvalue )
50+
}
51+
}

tests/expectations/tests/objc_interface.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,11 @@
99
extern crate objc;
1010
#[allow(non_camel_case_types)]
1111
pub type id = *mut objc::runtime::Object;
12+
type Class = *mut objc::runtime::Class;
13+
#[inline]
14+
fn class(name: &str) -> Class {
15+
unsafe { std::mem::transmute(objc::runtime::Class::get(name)) }
16+
}
1217
pub trait Foo { }
1318
impl Foo for id { }
1419
pub trait protocol_bar { }

tests/expectations/tests/objc_interface_type.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,11 @@
99
extern crate objc;
1010
#[allow(non_camel_case_types)]
1111
pub type id = *mut objc::runtime::Object;
12+
type Class = *mut objc::runtime::Class;
13+
#[inline]
14+
fn class(name: &str) -> Class {
15+
unsafe { std::mem::transmute(objc::runtime::Class::get(name)) }
16+
}
1217
pub trait Foo { }
1318
impl Foo for id { }
1419
#[repr(C)]

0 commit comments

Comments
 (0)