Skip to content

Commit 6ca3259

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 6ca3259

14 files changed

+363
-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: 151 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(),
@@ -140,6 +145,10 @@ impl<'a> CodegenResult<'a> {
140145
self.saw_incomplete_array = true;
141146
}
142147

148+
fn saw_objc(&mut self) {
149+
self.saw_objc = true;
150+
}
151+
143152
fn seen(&self, item: ItemId) -> bool {
144153
self.items_seen.contains(&item)
145154
}
@@ -184,6 +193,7 @@ impl<'a> CodegenResult<'a> {
184193

185194
self.saw_union |= new.saw_union;
186195
self.saw_incomplete_array |= new.saw_incomplete_array;
196+
self.saw_objc |= new.saw_objc;
187197

188198
new.items
189199
}
@@ -359,6 +369,9 @@ impl CodeGenerator for Module {
359369
if ctx.need_bindegen_complex_type() {
360370
utils::prepend_complex_type(ctx, &mut *result);
361371
}
372+
if result.saw_objc {
373+
utils::prepend_objc_header(ctx, &mut *result);
374+
}
362375
}
363376
};
364377

@@ -603,6 +616,9 @@ impl CodeGenerator for Type {
603616
TypeKind::Enum(ref ei) => {
604617
ei.codegen(ctx, result, whitelisted_items, item)
605618
}
619+
TypeKind::ObjCInterface(ref interface) => {
620+
interface.codegen(ctx, result, whitelisted_items, item)
621+
}
606622
ref u @ TypeKind::UnresolvedTypeRef(..) => {
607623
unreachable!("Should have been resolved after parsing {:?}!", u)
608624
}
@@ -2090,6 +2106,10 @@ impl ToRustTy for Type {
20902106
let ident = ctx.rust_ident(&name);
20912107
quote_ty!(ctx.ext_cx(), $ident)
20922108
}
2109+
TypeKind::ObjCInterface(..) => {
2110+
let ident = ctx.rust_ident("id");
2111+
quote_ty!(ctx.ext_cx(), $ident)
2112+
}
20932113
ref u @ TypeKind::UnresolvedTypeRef(..) => {
20942114
unreachable!("Should have been resolved after parsing {:?}!", u)
20952115
}
@@ -2123,10 +2143,24 @@ impl ToRustTy for FunctionSig {
21232143
// the array type derivation.
21242144
//
21252145
// [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() {
2146+
2147+
2148+
let arg_ty = match *arg_ty.canonical_type(ctx).kind() {
2149+
TypeKind::Array(t, _) => {
21272150
t.to_rust_ty(ctx).to_ptr(arg_ty.is_const(), ctx.span())
2151+
},
2152+
TypeKind::Pointer(inner) => {
2153+
let inner = ctx.resolve_item(inner);
2154+
let inner_ty = inner.expect_type();
2155+
if let TypeKind::ObjCInterface(_) = *inner_ty.canonical_type(ctx).kind() {
2156+
aster::ty::TyBuilder::new().id("id")
21282157
} else {
21292158
arg_item.to_rust_ty(ctx)
2159+
}
2160+
},
2161+
_ => {
2162+
arg_item.to_rust_ty(ctx)
2163+
}
21302164
};
21312165

21322166
let arg_name = match *name {
@@ -2242,6 +2276,90 @@ impl CodeGenerator for Function {
22422276
}
22432277
}
22442278

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

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