Skip to content

Commit bf75b0b

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 7d995d7 commit bf75b0b

File tree

11 files changed

+330
-4
lines changed

11 files changed

+330
-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: 137 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;
@@ -84,6 +85,8 @@ struct CodegenResult<'a> {
8485
/// Whether an union has been generated at least once.
8586
saw_union: bool,
8687

88+
saw_objc: bool,
89+
8790
items_seen: HashSet<ItemId>,
8891
/// The set of generated function/var names, needed because in C/C++ is
8992
/// legal to do something like:
@@ -115,6 +118,7 @@ impl<'a> CodegenResult<'a> {
115118
CodegenResult {
116119
items: vec![],
117120
saw_union: false,
121+
saw_objc: false,
118122
codegen_id: codegen_id,
119123
items_seen: Default::default(),
120124
functions_seen: Default::default(),
@@ -132,6 +136,10 @@ impl<'a> CodegenResult<'a> {
132136
self.saw_union = true;
133137
}
134138

139+
fn saw_objc(&mut self) {
140+
self.saw_objc = true;
141+
}
142+
135143
fn seen(&self, item: ItemId) -> bool {
136144
self.items_seen.contains(&item)
137145
}
@@ -175,6 +183,7 @@ impl<'a> CodegenResult<'a> {
175183
cb(&mut new);
176184

177185
self.saw_union |= new.saw_union;
186+
self.saw_objc |= new.saw_objc;
178187

179188
new.items
180189
}
@@ -347,6 +356,9 @@ impl CodeGenerator for Module {
347356
if ctx.need_bindegen_complex_type() {
348357
utils::prepend_complex_type(ctx, &mut *result);
349358
}
359+
if result.saw_objc {
360+
utils::prepend_objc_header(ctx, &mut *result);
361+
}
350362
}
351363
};
352364

@@ -591,6 +603,9 @@ impl CodeGenerator for Type {
591603
TypeKind::Enum(ref ei) => {
592604
ei.codegen(ctx, result, whitelisted_items, item)
593605
}
606+
TypeKind::ObjCInterface(ref interface) => {
607+
interface.codegen(ctx, result, whitelisted_items, item)
608+
}
594609
ref u @ TypeKind::UnresolvedTypeRef(..) => {
595610
unreachable!("Should have been resolved after parsing {:?}!", u)
596611
}
@@ -2068,6 +2083,10 @@ impl ToRustTy for Type {
20682083
let ident = ctx.rust_ident(&name);
20692084
quote_ty!(ctx.ext_cx(), $ident)
20702085
}
2086+
TypeKind::ObjCInterface(..) => {
2087+
let ident = ctx.rust_ident("id");
2088+
quote_ty!(ctx.ext_cx(), $ident)
2089+
}
20712090
ref u @ TypeKind::UnresolvedTypeRef(..) => {
20722091
unreachable!("Should have been resolved after parsing {:?}!", u)
20732092
}
@@ -2101,10 +2120,24 @@ impl ToRustTy for FunctionSig {
21012120
// the array type derivation.
21022121
//
21032122
// [1]: http://c0x.coding-guidelines.com/6.7.5.3.html
2104-
let arg_ty = if let TypeKind::Array(t, _) = *arg_ty.canonical_type(ctx).kind() {
2123+
2124+
2125+
let arg_ty = match *arg_ty.canonical_type(ctx).kind() {
2126+
TypeKind::Array(t, _) => {
21052127
t.to_rust_ty(ctx).to_ptr(arg_ty.is_const(), ctx.span())
2128+
},
2129+
TypeKind::Pointer(inner) => {
2130+
let inner = ctx.resolve_item(inner);
2131+
let inner_ty = inner.expect_type();
2132+
if let TypeKind::ObjCInterface(_) = *inner_ty.canonical_type(ctx).kind() {
2133+
aster::ty::TyBuilder::new().id("id")
21062134
} else {
21072135
arg_item.to_rust_ty(ctx)
2136+
}
2137+
},
2138+
_ => {
2139+
arg_item.to_rust_ty(ctx)
2140+
}
21082141
};
21092142

21102143
let arg_name = match *name {
@@ -2220,6 +2253,90 @@ impl CodeGenerator for Function {
22202253
}
22212254
}
22222255

2256+
impl CodeGenerator for ObjCInterface {
2257+
type Extra = Item;
2258+
fn codegen<'a>(&self,
2259+
ctx: &BindgenContext,
2260+
result: &mut CodegenResult<'a>,
2261+
_whitelisted_items: &ItemSet,
2262+
_: &Item) {
2263+
2264+
let mut impl_items = vec![];
2265+
let mut trait_items = vec![];
2266+
2267+
for method in &self.methods {
2268+
let method_name = ctx.rust_ident(&method.name);
2269+
2270+
let body = quote_stmt!(ctx.ext_cx(), msg_send![self, $method_name])
2271+
.unwrap();
2272+
let block = ast::Block {
2273+
stmts: vec![body],
2274+
id: ast::DUMMY_NODE_ID,
2275+
rules: ast::BlockCheckMode::Default,
2276+
span: ctx.span(),
2277+
};
2278+
2279+
let sig = aster::AstBuilder::new()
2280+
.method_sig()
2281+
.unsafe_()
2282+
.fn_decl()
2283+
.self_()
2284+
.build(ast::SelfKind::Value(ast::Mutability::Immutable))//ast::SelfKind::Region(None, ast::Mutability::Mutable))
2285+
.build(ast::FunctionRetTy::Default(ctx.span()));
2286+
let attrs = vec![];
2287+
2288+
let impl_item = ast::ImplItem {
2289+
id: ast::DUMMY_NODE_ID,
2290+
ident: ctx.rust_ident(&method.rust_name),
2291+
vis: ast::Visibility::Inherited, // Public,
2292+
attrs: attrs.clone(),
2293+
node: ast::ImplItemKind::Method(sig.clone(), P(block)),
2294+
defaultness: ast::Defaultness::Final,
2295+
span: ctx.span(),
2296+
};
2297+
2298+
let trait_item = ast::TraitItem {
2299+
id: ast::DUMMY_NODE_ID,
2300+
ident: ctx.rust_ident(&method.rust_name),
2301+
attrs: attrs,
2302+
node: ast::TraitItemKind::Method(sig, None),
2303+
span: ctx.span(),
2304+
};
2305+
2306+
impl_items.push(impl_item);
2307+
trait_items.push(trait_item)
2308+
}
2309+
2310+
2311+
let trait_block = aster::AstBuilder::new()
2312+
.item()
2313+
.pub_()
2314+
.trait_(&self.name)
2315+
.with_items(trait_items)
2316+
.build();
2317+
2318+
let ty_for_impl = aster::AstBuilder::new()
2319+
.ty()
2320+
.path()
2321+
.id(ctx.rust_ident("id"))
2322+
.build();
2323+
let impl_block = aster::AstBuilder::new()
2324+
.item()
2325+
.impl_()
2326+
.trait_()
2327+
.id(&self.name)
2328+
.build()
2329+
.with_items(impl_items)
2330+
.build_ty(ty_for_impl);
2331+
2332+
result.push(trait_block);
2333+
result.push(impl_block);
2334+
result.saw_objc();
2335+
}
2336+
}
2337+
2338+
2339+
22232340
pub fn codegen(context: &mut BindgenContext) -> Vec<P<ast::Item>> {
22242341
context.gen(|context| {
22252342
let counter = Cell::new(0);
@@ -2253,6 +2370,25 @@ mod utils {
22532370
use syntax::ast;
22542371
use syntax::ptr::P;
22552372

2373+
2374+
pub fn prepend_objc_header(ctx: &BindgenContext,
2375+
result: &mut Vec<P<ast::Item>>) {
2376+
2377+
let use_objc = quote_item!(ctx.ext_cx(),
2378+
use objc;
2379+
)
2380+
.unwrap();
2381+
let id_type = quote_item!(ctx.ext_cx(),
2382+
#[allow(non_camel_case_types)]
2383+
pub type id = *mut objc::runtime::Object;
2384+
)
2385+
.unwrap();
2386+
2387+
let items = vec![use_objc, id_type];
2388+
let old_items = mem::replace(result, items);
2389+
result.extend(old_items.into_iter());
2390+
}
2391+
22562392
pub fn prepend_union_types(ctx: &BindgenContext,
22572393
result: &mut Vec<P<ast::Item>>) {
22582394
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+
}

src/ir/ty.rs

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use super::function::FunctionSig;
1010
use super::int::IntKind;
1111
use super::item::Item;
1212
use super::layout::Layout;
13+
use super::objc::ObjCInterface;
1314
use super::type_collector::{ItemSet, TypeCollector};
1415

1516
/// The base representation of a type in bindgen.
@@ -312,7 +313,8 @@ impl Type {
312313
TypeKind::Void |
313314
TypeKind::NullPtr |
314315
TypeKind::BlockPointer |
315-
TypeKind::Pointer(..) => Some(self),
316+
TypeKind::Pointer(..) |
317+
TypeKind::ObjCInterface(..) => Some(self),
316318

317319
TypeKind::ResolvedTypeRef(inner) |
318320
TypeKind::Alias(_, inner) |
@@ -480,6 +482,9 @@ pub enum TypeKind {
480482

481483
/// A named type, that is, a template parameter.
482484
Named(String),
485+
486+
/// Objective C interface. Always referenced through a pointer
487+
ObjCInterface(ObjCInterface),
483488
}
484489

485490
impl Type {
@@ -513,6 +518,8 @@ impl Type {
513518
TypeKind::BlockPointer |
514519
TypeKind::Pointer(..) => false,
515520

521+
TypeKind::ObjCInterface(..) => true, // dunno?
522+
516523
TypeKind::UnresolvedTypeRef(..) => {
517524
unreachable!("Should have been resolved after parsing!");
518525
}
@@ -554,7 +561,16 @@ impl Type {
554561
debug!("currently_parsed_types: {:?}", ctx.currently_parsed_types);
555562

556563
let canonical_ty = ty.canonical_type();
557-
let kind = match ty.kind() {
564+
565+
// Parse objc protocols as if they were interfaces
566+
let mut ty_kind = ty.kind();
567+
if let Some(loc) = location {
568+
if loc.kind() == CXCursor_ObjCProtocolDecl {
569+
ty_kind = CXType_ObjCInterface;
570+
}
571+
}
572+
573+
let kind = match ty_kind {
558574
CXType_Unexposed if *ty != canonical_ty &&
559575
canonical_ty.kind() != CXType_Invalid => {
560576
debug!("Looking for canonical type: {:?}", canonical_ty);
@@ -795,6 +811,7 @@ impl Type {
795811
//
796812
// We might need to, though, if the context is already in the
797813
// process of resolving them.
814+
CXType_ObjCObjectPointer |
798815
CXType_MemberPointer |
799816
CXType_Pointer => {
800817
let inner = Item::from_ty_or_ref(ty.pointee_type().unwrap(),
@@ -869,6 +886,11 @@ impl Type {
869886
parent_id,
870887
ctx);
871888
}
889+
CXType_ObjCInterface => {
890+
let interface = ObjCInterface::from_ty(&location.unwrap(), ctx)
891+
.expect("Not a valid objc interface?");
892+
TypeKind::ObjCInterface(interface)
893+
}
872894
_ => {
873895
error!("unsupported type: kind = {:?}; ty = {:?}; at {:?}",
874896
ty.kind(),
@@ -923,6 +945,10 @@ impl TypeCollector for Type {
923945
types.insert(id);
924946
}
925947

948+
TypeKind::ObjCInterface(_) => {
949+
// TODO:
950+
}
951+
926952
// None of these variants have edges to other items and types.
927953
TypeKind::UnresolvedTypeRef(_, _, None) |
928954
TypeKind::Named(_) |

0 commit comments

Comments
 (0)