Skip to content

Commit 773352f

Browse files
committed
objc: Implement class methods
1 parent b821252 commit 773352f

14 files changed

+270
-73
lines changed

src/codegen/mod.rs

Lines changed: 107 additions & 58 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

@@ -2408,8 +2408,91 @@ impl CodeGenerator for Function {
24082408
}
24092409
}
24102410

2411+
2412+
fn objc_method_codegen(ctx: &BindgenContext,
2413+
method: &ObjCMethod,
2414+
class_name: Option<&str>)
2415+
-> (ast::ImplItem, ast::TraitItem) {
2416+
let signature = method.signature();
2417+
let fn_args = utils::fnsig_arguments(ctx, signature);
2418+
let fn_ret = utils::fnsig_return_ty(ctx, signature);
2419+
2420+
let sig = if method.is_class_method() {
2421+
aster::AstBuilder::new()
2422+
.method_sig()
2423+
.unsafe_()
2424+
.fn_decl()
2425+
.with_args(fn_args.clone())
2426+
.build(fn_ret)
2427+
} else {
2428+
aster::AstBuilder::new()
2429+
.method_sig()
2430+
.unsafe_()
2431+
.fn_decl()
2432+
.self_()
2433+
.build(ast::SelfKind::Value(ast::Mutability::Immutable))
2434+
.with_args(fn_args.clone())
2435+
.build(fn_ret)
2436+
};
2437+
2438+
// Collect the actual used argument names
2439+
let arg_names: Vec<_> = fn_args.iter()
2440+
.map(|ref arg| match arg.pat.node {
2441+
ast::PatKind::Ident(_, ref spanning, _) => {
2442+
spanning.node.name.as_str().to_string()
2443+
}
2444+
_ => {
2445+
panic!("odd argument!");
2446+
}
2447+
})
2448+
.collect();
2449+
2450+
let methods_and_args =
2451+
ctx.rust_ident(&method.format_method_call(&arg_names));
2452+
2453+
let body = if method.is_class_method() {
2454+
let class_name =
2455+
class_name.expect("Generating a class method without class name?")
2456+
.to_owned();
2457+
quote_stmt!(ctx.ext_cx(),
2458+
msg_send![class($class_name), $methods_and_args])
2459+
.unwrap()
2460+
} else {
2461+
quote_stmt!(ctx.ext_cx(), msg_send![self, $methods_and_args]).unwrap()
2462+
};
2463+
let block = ast::Block {
2464+
stmts: vec![body],
2465+
id: ast::DUMMY_NODE_ID,
2466+
rules: ast::BlockCheckMode::Default,
2467+
span: ctx.span(),
2468+
};
2469+
2470+
let attrs = vec![];
2471+
2472+
let impl_item = ast::ImplItem {
2473+
id: ast::DUMMY_NODE_ID,
2474+
ident: ctx.rust_ident(method.rust_name()),
2475+
vis: ast::Visibility::Inherited, // Public,
2476+
attrs: attrs.clone(),
2477+
node: ast::ImplItemKind::Method(sig.clone(), P(block)),
2478+
defaultness: ast::Defaultness::Final,
2479+
span: ctx.span(),
2480+
};
2481+
2482+
let trait_item = ast::TraitItem {
2483+
id: ast::DUMMY_NODE_ID,
2484+
ident: ctx.rust_ident(method.rust_name()),
2485+
attrs: attrs,
2486+
node: ast::TraitItemKind::Method(sig, None),
2487+
span: ctx.span(),
2488+
};
2489+
2490+
(impl_item, trait_item)
2491+
}
2492+
24112493
impl CodeGenerator for ObjCInterface {
24122494
type Extra = Item;
2495+
24132496
fn codegen<'a>(&self,
24142497
ctx: &BindgenContext,
24152498
result: &mut CodegenResult<'a>,
@@ -2419,66 +2502,18 @@ impl CodeGenerator for ObjCInterface {
24192502
let mut trait_items = vec![];
24202503

24212504
for method in self.methods() {
2422-
let signature = method.signature();
2423-
let fn_args = utils::fnsig_arguments(ctx, signature);
2424-
let fn_ret = utils::fnsig_return_ty(ctx, signature);
2425-
let sig = aster::AstBuilder::new()
2426-
.method_sig()
2427-
.unsafe_()
2428-
.fn_decl()
2429-
.self_()
2430-
.build(ast::SelfKind::Value(ast::Mutability::Immutable))
2431-
.with_args(fn_args.clone())
2432-
.build(fn_ret);
2433-
2434-
// Collect the actual used argument names
2435-
let arg_names: Vec<_> = fn_args.iter()
2436-
.map(|ref arg| match arg.pat.node {
2437-
ast::PatKind::Ident(_, ref spanning, _) => {
2438-
spanning.node.name.as_str().to_string()
2439-
}
2440-
_ => {
2441-
panic!("odd argument!");
2442-
}
2443-
})
2444-
.collect();
2445-
2446-
let methods_and_args =
2447-
ctx.rust_ident(&method.format_method_call(&arg_names));
2448-
let body = quote_stmt!(ctx.ext_cx(),
2449-
msg_send![self, $methods_and_args])
2450-
.unwrap();
2451-
let block = ast::Block {
2452-
stmts: vec![body],
2453-
id: ast::DUMMY_NODE_ID,
2454-
rules: ast::BlockCheckMode::Default,
2455-
span: ctx.span(),
2456-
};
2457-
2458-
let attrs = vec![];
2459-
2460-
let impl_item = ast::ImplItem {
2461-
id: ast::DUMMY_NODE_ID,
2462-
ident: ctx.rust_ident(method.rust_name()),
2463-
vis: ast::Visibility::Inherited, // Public,
2464-
attrs: attrs.clone(),
2465-
node: ast::ImplItemKind::Method(sig.clone(), P(block)),
2466-
defaultness: ast::Defaultness::Final,
2467-
span: ctx.span(),
2468-
};
2469-
2470-
let trait_item = ast::TraitItem {
2471-
id: ast::DUMMY_NODE_ID,
2472-
ident: ctx.rust_ident(method.rust_name()),
2473-
attrs: attrs,
2474-
node: ast::TraitItemKind::Method(sig, None),
2475-
span: ctx.span(),
2476-
};
2477-
2505+
let (impl_item, trait_item) =
2506+
objc_method_codegen(ctx, method, None);
24782507
impl_items.push(impl_item);
24792508
trait_items.push(trait_item)
24802509
}
24812510

2511+
for class_method in self.class_methods() {
2512+
let (impl_item, trait_item) =
2513+
objc_method_codegen(ctx, class_method, Some(self.name()));
2514+
impl_items.push(impl_item);
2515+
trait_items.push(trait_item)
2516+
}
24822517

24832518
let trait_name = self.rust_name();
24842519

@@ -2570,7 +2605,21 @@ mod utils {
25702605
)
25712606
.unwrap();
25722607

2573-
let items = vec![use_objc, id_type];
2608+
let class_ty = quote_item!(ctx.ext_cx(),
2609+
type Class = *mut objc::runtime::Class;
2610+
)
2611+
.unwrap();
2612+
let class_fn = quote_item!(ctx.ext_cx(),
2613+
#[inline]
2614+
fn class(name: &str) -> Class {
2615+
unsafe {
2616+
std::mem::transmute(objc::runtime::Class::get(name))
2617+
}
2618+
}
2619+
)
2620+
.unwrap();
2621+
2622+
let items = vec![use_objc, id_type, class_ty, class_fn];
25742623
let old_items = mem::replace(result, items);
25752624
result.extend(old_items.into_iter());
25762625
}

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: 45 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_method: 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,33 +143,46 @@ 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+
let is_class_method = c.kind() == CXCursor_ObjCClassMethodDecl;
153+
let method = ObjCMethod::new(&name, signature, is_class_method);
154+
interface.add_method(method);
142155
}
143156
_ => {}
144157
}
145158
CXChildVisit_Continue
146159
});
147160
Some(interface)
148161
}
162+
163+
fn add_method(&mut self, method: ObjCMethod) {
164+
if method.is_class_method {
165+
self.class_methods.push(method);
166+
} else {
167+
self.methods.push(method);
168+
}
169+
}
149170
}
150171

151-
impl ObjCInstanceMethod {
152-
fn new(name: &str, signature: FunctionSig) -> ObjCInstanceMethod {
172+
impl ObjCMethod {
173+
fn new(name: &str,
174+
signature: FunctionSig,
175+
is_class_method: bool)
176+
-> ObjCMethod {
153177
let split_name: Vec<&str> = name.split(':').collect();
154178

155179
let rust_name = split_name.join("_");
156180

157-
ObjCInstanceMethod {
181+
ObjCMethod {
158182
name: name.to_owned(),
159183
rust_name: rust_name.to_owned(),
160184
signature: signature,
185+
is_class_method: is_class_method,
161186
}
162187
}
163188

@@ -178,6 +203,11 @@ impl ObjCInstanceMethod {
178203
&self.signature
179204
}
180205

206+
/// Is this a class method?
207+
pub fn is_class_method(&self) -> bool {
208+
self.is_class_method
209+
}
210+
181211
/// Formats the method call
182212
pub fn format_method_call(&self, args: &[String]) -> String {
183213
let split_name: Vec<&str> =
@@ -213,6 +243,10 @@ impl Trace for ObjCInterface {
213243
method.signature.trace(context, tracer, &());
214244
}
215245

246+
for class_method in &self.class_methods {
247+
class_method.signature.trace(context, tracer, &());
248+
}
249+
216250
for protocol in &self.conforms_to {
217251
tracer.visit(*protocol);
218252
}

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
}

0 commit comments

Comments
 (0)