Skip to content

Commit 1273da9

Browse files
committed
Add initial Objective C support
It parses interfaces and protocol but ignores base classes, and their methods which don’t have arguments, the method signature is currently ignored. Also you can pass objc class instances to C functions. Next steps are inheritance/base classes, method signatures, properties, categories. Then check with system headers what is missing.
1 parent 3660d4d commit 1273da9

14 files changed

+362
-4
lines changed

src/clang.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -688,7 +688,8 @@ impl Type {
688688
CXType_Pointer |
689689
CXType_RValueReference |
690690
CXType_LValueReference |
691-
CXType_MemberPointer => {
691+
CXType_MemberPointer |
692+
CXType_ObjCObjectPointer => {
692693
let ret = Type {
693694
x: unsafe { clang_getPointeeType(self.x) },
694695
};

src/codegen/mod.rs

Lines changed: 150 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use ir::item::{Item, ItemAncestors, ItemCanonicalName, ItemCanonicalPath};
1313
use ir::item_kind::ItemKind;
1414
use ir::layout::Layout;
1515
use ir::module::Module;
16+
use ir::objc::ObjCInterface;
1617
use ir::ty::{Type, TypeKind};
1718
use ir::type_collector::ItemSet;
1819
use ir::var::Var;
@@ -87,6 +88,9 @@ struct CodegenResult<'a> {
8788
/// Whether an incomplete array has been generated at least once.
8889
saw_incomplete_array: bool,
8990

91+
/// Whether Objective C types have been seen at least once.
92+
saw_objc: bool,
93+
9094
items_seen: HashSet<ItemId>,
9195
/// The set of generated function/var names, needed because in C/C++ is
9296
/// legal to do something like:
@@ -119,6 +123,7 @@ impl<'a> CodegenResult<'a> {
119123
items: vec![],
120124
saw_union: false,
121125
saw_incomplete_array: false,
126+
saw_objc: false,
122127
codegen_id: codegen_id,
123128
items_seen: Default::default(),
124129
functions_seen: Default::default(),
@@ -138,6 +143,9 @@ impl<'a> CodegenResult<'a> {
138143

139144
fn saw_incomplete_array(&mut self) {
140145
self.saw_incomplete_array = true;
146+
147+
fn saw_objc(&mut self) {
148+
self.saw_objc = true;
141149
}
142150

143151
fn seen(&self, item: ItemId) -> bool {
@@ -184,6 +192,7 @@ impl<'a> CodegenResult<'a> {
184192

185193
self.saw_union |= new.saw_union;
186194
self.saw_incomplete_array |= new.saw_incomplete_array;
195+
self.saw_objc |= new.saw_objc;
187196

188197
new.items
189198
}
@@ -359,6 +368,9 @@ impl CodeGenerator for Module {
359368
if ctx.need_bindegen_complex_type() {
360369
utils::prepend_complex_type(ctx, &mut *result);
361370
}
371+
if result.saw_objc {
372+
utils::prepend_objc_header(ctx, &mut *result);
373+
}
362374
}
363375
};
364376

@@ -603,6 +615,9 @@ impl CodeGenerator for Type {
603615
TypeKind::Enum(ref ei) => {
604616
ei.codegen(ctx, result, whitelisted_items, item)
605617
}
618+
TypeKind::ObjCInterface(ref interface) => {
619+
interface.codegen(ctx, result, whitelisted_items, item)
620+
}
606621
ref u @ TypeKind::UnresolvedTypeRef(..) => {
607622
unreachable!("Should have been resolved after parsing {:?}!", u)
608623
}
@@ -2090,6 +2105,10 @@ impl ToRustTy for Type {
20902105
let ident = ctx.rust_ident(&name);
20912106
quote_ty!(ctx.ext_cx(), $ident)
20922107
}
2108+
TypeKind::ObjCInterface(..) => {
2109+
let ident = ctx.rust_ident("id");
2110+
quote_ty!(ctx.ext_cx(), $ident)
2111+
}
20932112
ref u @ TypeKind::UnresolvedTypeRef(..) => {
20942113
unreachable!("Should have been resolved after parsing {:?}!", u)
20952114
}
@@ -2123,10 +2142,24 @@ impl ToRustTy for FunctionSig {
21232142
// the array type derivation.
21242143
//
21252144
// [1]: http://c0x.coding-guidelines.com/6.7.5.3.html
2126-
let arg_ty = if let TypeKind::Array(t, _) = *arg_ty.canonical_type(ctx).kind() {
2145+
2146+
2147+
let arg_ty = match *arg_ty.canonical_type(ctx).kind() {
2148+
TypeKind::Array(t, _) => {
21272149
t.to_rust_ty(ctx).to_ptr(arg_ty.is_const(), ctx.span())
2150+
},
2151+
TypeKind::Pointer(inner) => {
2152+
let inner = ctx.resolve_item(inner);
2153+
let inner_ty = inner.expect_type();
2154+
if let TypeKind::ObjCInterface(_) = *inner_ty.canonical_type(ctx).kind() {
2155+
aster::ty::TyBuilder::new().id("id")
21282156
} else {
21292157
arg_item.to_rust_ty(ctx)
2158+
}
2159+
},
2160+
_ => {
2161+
arg_item.to_rust_ty(ctx)
2162+
}
21302163
};
21312164

21322165
let arg_name = match *name {
@@ -2242,6 +2275,90 @@ impl CodeGenerator for Function {
22422275
}
22432276
}
22442277

2278+
impl CodeGenerator for ObjCInterface {
2279+
type Extra = Item;
2280+
fn codegen<'a>(&self,
2281+
ctx: &BindgenContext,
2282+
result: &mut CodegenResult<'a>,
2283+
_whitelisted_items: &ItemSet,
2284+
_: &Item) {
2285+
2286+
let mut impl_items = vec![];
2287+
let mut trait_items = vec![];
2288+
2289+
for method in &self.methods {
2290+
let method_name = ctx.rust_ident(&method.name);
2291+
2292+
let body = quote_stmt!(ctx.ext_cx(), msg_send![self, $method_name])
2293+
.unwrap();
2294+
let block = ast::Block {
2295+
stmts: vec![body],
2296+
id: ast::DUMMY_NODE_ID,
2297+
rules: ast::BlockCheckMode::Default,
2298+
span: ctx.span(),
2299+
};
2300+
2301+
let sig = aster::AstBuilder::new()
2302+
.method_sig()
2303+
.unsafe_()
2304+
.fn_decl()
2305+
.self_()
2306+
.build(ast::SelfKind::Value(ast::Mutability::Immutable))//ast::SelfKind::Region(None, ast::Mutability::Mutable))
2307+
.build(ast::FunctionRetTy::Default(ctx.span()));
2308+
let attrs = vec![];
2309+
2310+
let impl_item = ast::ImplItem {
2311+
id: ast::DUMMY_NODE_ID,
2312+
ident: ctx.rust_ident(&method.rust_name),
2313+
vis: ast::Visibility::Inherited, // Public,
2314+
attrs: attrs.clone(),
2315+
node: ast::ImplItemKind::Method(sig.clone(), P(block)),
2316+
defaultness: ast::Defaultness::Final,
2317+
span: ctx.span(),
2318+
};
2319+
2320+
let trait_item = ast::TraitItem {
2321+
id: ast::DUMMY_NODE_ID,
2322+
ident: ctx.rust_ident(&method.rust_name),
2323+
attrs: attrs,
2324+
node: ast::TraitItemKind::Method(sig, None),
2325+
span: ctx.span(),
2326+
};
2327+
2328+
impl_items.push(impl_item);
2329+
trait_items.push(trait_item)
2330+
}
2331+
2332+
2333+
let trait_block = aster::AstBuilder::new()
2334+
.item()
2335+
.pub_()
2336+
.trait_(&self.name)
2337+
.with_items(trait_items)
2338+
.build();
2339+
2340+
let ty_for_impl = aster::AstBuilder::new()
2341+
.ty()
2342+
.path()
2343+
.id(ctx.rust_ident("id"))
2344+
.build();
2345+
let impl_block = aster::AstBuilder::new()
2346+
.item()
2347+
.impl_()
2348+
.trait_()
2349+
.id(&self.name)
2350+
.build()
2351+
.with_items(impl_items)
2352+
.build_ty(ty_for_impl);
2353+
2354+
result.push(trait_block);
2355+
result.push(impl_block);
2356+
result.saw_objc();
2357+
}
2358+
}
2359+
2360+
2361+
22452362
pub fn codegen(context: &mut BindgenContext) -> Vec<P<ast::Item>> {
22462363
context.gen(|context| {
22472364
let counter = Cell::new(0);
@@ -2275,6 +2392,38 @@ mod utils {
22752392
use syntax::ast;
22762393
use syntax::ptr::P;
22772394

2395+
2396+
pub fn prepend_objc_header(ctx: &BindgenContext,
2397+
result: &mut Vec<P<ast::Item>>) {
2398+
2399+
2400+
let use_objc;
2401+
2402+
if ctx.options().objc_extern_crate {
2403+
use_objc = quote_item!(ctx.ext_cx(),
2404+
use objc;
2405+
)
2406+
.unwrap();
2407+
} else {
2408+
use_objc = quote_item!(ctx.ext_cx(),
2409+
#[macro_use]
2410+
extern crate objc;
2411+
)
2412+
.unwrap();
2413+
}
2414+
2415+
2416+
let id_type = quote_item!(ctx.ext_cx(),
2417+
#[allow(non_camel_case_types)]
2418+
pub type id = *mut objc::runtime::Object;
2419+
)
2420+
.unwrap();
2421+
2422+
let items = vec![use_objc, id_type];
2423+
let old_items = mem::replace(result, items);
2424+
result.extend(old_items.into_iter());
2425+
}
2426+
22782427
pub fn prepend_union_types(ctx: &BindgenContext,
22792428
result: &mut Vec<P<ast::Item>>) {
22802429
let prefix = ctx.trait_prefix();

src/ir/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,4 @@ pub mod module;
1717
pub mod ty;
1818
pub mod type_collector;
1919
pub mod var;
20+
pub mod objc;

src/ir/objc.rs

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
//! Objective C types
2+
3+
use clang;
4+
use clang_sys::CXChildVisit_Continue;
5+
use clang_sys::CXCursor_ObjCInstanceMethodDecl;
6+
// use clang_sys::CXCursor_ObjCSuperClassRef;
7+
use super::context::BindgenContext;
8+
9+
/// Objective C interface as used in TypeKind
10+
///
11+
/// Also protocols are parsed as this type
12+
#[derive(Debug)]
13+
pub struct ObjCInterface {
14+
/// The name
15+
/// like, NSObject
16+
pub name: String,
17+
18+
/// List of the methods defined in this interfae
19+
pub methods: Vec<ObjCInstanceMethod>,
20+
}
21+
22+
/// The objective c methods
23+
#[derive(Debug)]
24+
pub struct ObjCInstanceMethod {
25+
/// The original method selector name
26+
/// like, dataWithBytes:length:
27+
pub name: String,
28+
29+
/// Method name as converted to rust
30+
/// like, dataWithBytes_length_
31+
pub rust_name: String,
32+
}
33+
34+
impl ObjCInterface {
35+
fn new(name: &str) -> ObjCInterface {
36+
ObjCInterface {
37+
name: name.to_owned(),
38+
methods: Vec::new(),
39+
}
40+
}
41+
42+
/// Parses the Objective C interface from the cursor
43+
pub fn from_ty(cursor: &clang::Cursor,
44+
_ctx: &mut BindgenContext)
45+
-> Option<Self> {
46+
let name = cursor.spelling();
47+
let mut interface = Self::new(&name);
48+
49+
cursor.visit(|cursor| {
50+
match cursor.kind() {
51+
CXCursor_ObjCInstanceMethodDecl => {
52+
let name = cursor.spelling();
53+
let method = ObjCInstanceMethod::new(&name);
54+
55+
interface.methods.push(method);
56+
}
57+
_ => {}
58+
}
59+
CXChildVisit_Continue
60+
});
61+
Some(interface)
62+
}
63+
}
64+
65+
66+
impl ObjCInstanceMethod {
67+
fn new(name: &str) -> ObjCInstanceMethod {
68+
69+
let split_name: Vec<&str> = name.split(':').collect();
70+
71+
let rust_name = split_name.join("_");
72+
73+
ObjCInstanceMethod {
74+
name: name.to_owned(),
75+
rust_name: rust_name.to_owned(),
76+
}
77+
}
78+
}

0 commit comments

Comments
 (0)