Skip to content

Commit 0ec92d7

Browse files
author
bors-servo
authored
Auto merge of #558 - scoopr:objc, r=emilio
objc: Implement class methods Ah yes, I was still missing class methods. They are handled pretty much identically with instance methods, except for in the codegen it needs to know the class name.
2 parents dd1dc9e + cc6ab47 commit 0ec92d7

File tree

7 files changed

+221
-72
lines changed

7 files changed

+221
-72
lines changed

src/codegen/mod.rs

+93-57
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::template::{AsNamed, TemplateInstantiation};
2424
use ir::ty::{TemplateDeclaration, Type, TypeKind};
2525
use ir::var::Var;
@@ -2434,8 +2434,92 @@ impl CodeGenerator for Function {
24342434
}
24352435
}
24362436

2437+
2438+
fn objc_method_codegen(ctx: &BindgenContext,
2439+
method: &ObjCMethod,
2440+
class_name: Option<&str>)
2441+
-> (ast::ImplItem, ast::TraitItem) {
2442+
let signature = method.signature();
2443+
let fn_args = utils::fnsig_arguments(ctx, signature);
2444+
let fn_ret = utils::fnsig_return_ty(ctx, signature);
2445+
2446+
let sig = if method.is_class_method() {
2447+
aster::AstBuilder::new()
2448+
.method_sig()
2449+
.unsafe_()
2450+
.fn_decl()
2451+
.with_args(fn_args.clone())
2452+
.build(fn_ret)
2453+
} else {
2454+
aster::AstBuilder::new()
2455+
.method_sig()
2456+
.unsafe_()
2457+
.fn_decl()
2458+
.self_()
2459+
.build(ast::SelfKind::Value(ast::Mutability::Immutable))
2460+
.with_args(fn_args.clone())
2461+
.build(fn_ret)
2462+
};
2463+
2464+
// Collect the actual used argument names
2465+
let arg_names: Vec<_> = fn_args.iter()
2466+
.map(|ref arg| match arg.pat.node {
2467+
ast::PatKind::Ident(_, ref spanning, _) => {
2468+
spanning.node.name.as_str().to_string()
2469+
}
2470+
_ => {
2471+
panic!("odd argument!");
2472+
}
2473+
})
2474+
.collect();
2475+
2476+
let methods_and_args =
2477+
ctx.rust_ident(&method.format_method_call(&arg_names));
2478+
2479+
let body = if method.is_class_method() {
2480+
let class_name =
2481+
class_name.expect("Generating a class method without class name?")
2482+
.to_owned();
2483+
let expect_msg = format!("Couldn't find {}", class_name);
2484+
quote_stmt!(ctx.ext_cx(),
2485+
msg_send![objc::runtime::Class::get($class_name).expect($expect_msg), $methods_and_args])
2486+
.unwrap()
2487+
} else {
2488+
quote_stmt!(ctx.ext_cx(), msg_send![self, $methods_and_args]).unwrap()
2489+
};
2490+
let block = ast::Block {
2491+
stmts: vec![body],
2492+
id: ast::DUMMY_NODE_ID,
2493+
rules: ast::BlockCheckMode::Default,
2494+
span: ctx.span(),
2495+
};
2496+
2497+
let attrs = vec![];
2498+
2499+
let impl_item = ast::ImplItem {
2500+
id: ast::DUMMY_NODE_ID,
2501+
ident: ctx.rust_ident(method.rust_name()),
2502+
vis: ast::Visibility::Inherited, // Public,
2503+
attrs: attrs.clone(),
2504+
node: ast::ImplItemKind::Method(sig.clone(), P(block)),
2505+
defaultness: ast::Defaultness::Final,
2506+
span: ctx.span(),
2507+
};
2508+
2509+
let trait_item = ast::TraitItem {
2510+
id: ast::DUMMY_NODE_ID,
2511+
ident: ctx.rust_ident(method.rust_name()),
2512+
attrs: attrs,
2513+
node: ast::TraitItemKind::Method(sig, None),
2514+
span: ctx.span(),
2515+
};
2516+
2517+
(impl_item, trait_item)
2518+
}
2519+
24372520
impl CodeGenerator for ObjCInterface {
24382521
type Extra = Item;
2522+
24392523
fn codegen<'a>(&self,
24402524
ctx: &BindgenContext,
24412525
result: &mut CodegenResult<'a>,
@@ -2445,66 +2529,18 @@ impl CodeGenerator for ObjCInterface {
24452529
let mut trait_items = vec![];
24462530

24472531
for method in self.methods() {
2448-
let signature = method.signature();
2449-
let fn_args = utils::fnsig_arguments(ctx, signature);
2450-
let fn_ret = utils::fnsig_return_ty(ctx, signature);
2451-
let sig = aster::AstBuilder::new()
2452-
.method_sig()
2453-
.unsafe_()
2454-
.fn_decl()
2455-
.self_()
2456-
.build(ast::SelfKind::Value(ast::Mutability::Immutable))
2457-
.with_args(fn_args.clone())
2458-
.build(fn_ret);
2459-
2460-
// Collect the actual used argument names
2461-
let arg_names: Vec<_> = fn_args.iter()
2462-
.map(|ref arg| match arg.pat.node {
2463-
ast::PatKind::Ident(_, ref spanning, _) => {
2464-
spanning.node.name.as_str().to_string()
2465-
}
2466-
_ => {
2467-
panic!("odd argument!");
2468-
}
2469-
})
2470-
.collect();
2471-
2472-
let methods_and_args =
2473-
ctx.rust_ident(&method.format_method_call(&arg_names));
2474-
let body = quote_stmt!(ctx.ext_cx(),
2475-
msg_send![self, $methods_and_args])
2476-
.unwrap();
2477-
let block = ast::Block {
2478-
stmts: vec![body],
2479-
id: ast::DUMMY_NODE_ID,
2480-
rules: ast::BlockCheckMode::Default,
2481-
span: ctx.span(),
2482-
};
2483-
2484-
let attrs = vec![];
2485-
2486-
let impl_item = ast::ImplItem {
2487-
id: ast::DUMMY_NODE_ID,
2488-
ident: ctx.rust_ident(method.rust_name()),
2489-
vis: ast::Visibility::Inherited, // Public,
2490-
attrs: attrs.clone(),
2491-
node: ast::ImplItemKind::Method(sig.clone(), P(block)),
2492-
defaultness: ast::Defaultness::Final,
2493-
span: ctx.span(),
2494-
};
2495-
2496-
let trait_item = ast::TraitItem {
2497-
id: ast::DUMMY_NODE_ID,
2498-
ident: ctx.rust_ident(method.rust_name()),
2499-
attrs: attrs,
2500-
node: ast::TraitItemKind::Method(sig, None),
2501-
span: ctx.span(),
2502-
};
2503-
2532+
let (impl_item, trait_item) =
2533+
objc_method_codegen(ctx, method, None);
25042534
impl_items.push(impl_item);
25052535
trait_items.push(trait_item)
25062536
}
25072537

2538+
for class_method in self.class_methods() {
2539+
let (impl_item, trait_item) =
2540+
objc_method_codegen(ctx, class_method, Some(self.name()));
2541+
impl_items.push(impl_item);
2542+
trait_items.push(trait_item)
2543+
}
25082544

25092545
let trait_name = self.rust_name();
25102546

src/ir/function.rs

+6-4
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,8 @@ impl FunctionSig {
182182
CXCursor_FunctionDecl |
183183
CXCursor_Constructor |
184184
CXCursor_CXXMethod |
185-
CXCursor_ObjCInstanceMethodDecl => {
185+
CXCursor_ObjCInstanceMethodDecl |
186+
CXCursor_ObjCClassMethodDecl => {
186187
// For CXCursor_FunctionDecl, cursor.args() is the reliable way
187188
// to get parameter names and types.
188189
cursor.args()
@@ -243,7 +244,8 @@ impl FunctionSig {
243244
}
244245
}
245246

246-
let ty_ret_type = if cursor.kind() == CXCursor_ObjCInstanceMethodDecl {
247+
let ty_ret_type = if cursor.kind() == CXCursor_ObjCInstanceMethodDecl ||
248+
cursor.kind() == CXCursor_ObjCClassMethodDecl {
247249
try!(cursor.ret_type().ok_or(ParseError::Continue))
248250
} else {
249251
try!(ty.ret_type().ok_or(ParseError::Continue))
@@ -252,8 +254,8 @@ impl FunctionSig {
252254
let abi = get_abi(ty.call_conv());
253255

254256
if abi.is_none() {
255-
assert_eq!(cursor.kind(),
256-
CXCursor_ObjCInstanceMethodDecl,
257+
assert!(cursor.kind() == CXCursor_ObjCInstanceMethodDecl ||
258+
cursor.kind() == CXCursor_ObjCClassMethodDecl,
257259
"Invalid ABI for function signature")
258260
}
259261

src/ir/objc.rs

+45-11
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
}

0 commit comments

Comments
 (0)