Skip to content

Commit 761f075

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 7bfb5a5 commit 761f075

File tree

5 files changed

+244
-4
lines changed

5 files changed

+244
-4
lines changed

src/clang.rs

Lines changed: 6 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
};
@@ -785,6 +786,10 @@ impl Type {
785786
!args.any(|t| t.spelling().contains("type-parameter"))
786787
})
787788
}
789+
790+
pub fn objc_encoding(&self) -> String {
791+
unsafe { cxstring_into_string(clang_Type_getObjCEncoding(self.x)) }
792+
}
788793
}
789794

790795
/// An iterator for a type's template arguments.

src/codegen/mod.rs

Lines changed: 143 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
}
@@ -342,6 +351,9 @@ impl CodeGenerator for Module {
342351
if ctx.need_bindegen_complex_type() {
343352
utils::prepend_complex_type(ctx, &mut *result);
344353
}
354+
if result.saw_objc {
355+
utils::prepend_objc_header(ctx, &mut *result);
356+
}
345357
}
346358
};
347359

@@ -586,6 +598,9 @@ impl CodeGenerator for Type {
586598
TypeKind::Enum(ref ei) => {
587599
ei.codegen(ctx, result, whitelisted_items, item)
588600
}
601+
TypeKind::ObjCInterface(ref interface) => {
602+
interface.codegen(ctx, result, whitelisted_items, item)
603+
}
589604
ref u @ TypeKind::UnresolvedTypeRef(..) => {
590605
unreachable!("Should have been resolved after parsing {:?}!", u)
591606
}
@@ -2062,6 +2077,13 @@ impl ToRustTy for Type {
20622077
let ident = ctx.rust_ident(&name);
20632078
quote_ty!(ctx.ext_cx(), $ident)
20642079
}
2080+
2081+
TypeKind::ObjCInterface(..) => {
2082+
let name = item.canonical_name(ctx);
2083+
let ident = ctx.rust_ident(&name);
2084+
quote_ty!(ctx.ext_cx(), $ident)
2085+
}
2086+
20652087
ref u @ TypeKind::UnresolvedTypeRef(..) => {
20662088
unreachable!("Should have been resolved after parsing {:?}!", u)
20672089
}
@@ -2095,10 +2117,27 @@ impl ToRustTy for FunctionSig {
20952117
// the array type derivation.
20962118
//
20972119
// [1]: http://c0x.coding-guidelines.com/6.7.5.3.html
2098-
let arg_ty = if let TypeKind::Array(t, _) = *arg_ty.canonical_type(ctx).kind() {
2120+
2121+
2122+
let arg_ty = match *arg_ty.canonical_type(ctx).kind()
2123+
{
2124+
TypeKind::Array(t, _) =>
2125+
{
20992126
t.to_rust_ty(ctx).to_ptr(arg_ty.is_const(), ctx.span())
2127+
},
2128+
TypeKind::Pointer(inner) => {
2129+
let inner = ctx.resolve_item(inner);
2130+
let inner_ty = inner.expect_type();
2131+
if let TypeKind::ObjCInterface(_) = *inner_ty.canonical_type(ctx).kind() {
2132+
aster::ty::TyBuilder::new().id("id")
2133+
//inner.to_rust_ty(ctx)
21002134
} else {
21012135
arg_item.to_rust_ty(ctx)
2136+
}
2137+
},
2138+
_ => {
2139+
arg_item.to_rust_ty(ctx)
2140+
}
21022141
};
21032142

21042143
let arg_name = match *name {
@@ -2214,6 +2253,90 @@ impl CodeGenerator for Function {
22142253
}
22152254
}
22162255

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+
22172340
pub fn codegen(context: &mut BindgenContext) -> Vec<P<ast::Item>> {
22182341
context.gen(|context| {
22192342
let counter = Cell::new(0);
@@ -2247,6 +2370,25 @@ mod utils {
22472370
use syntax::ast;
22482371
use syntax::ptr::P;
22492372

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+
22502392
pub fn prepend_union_types(ctx: &BindgenContext,
22512393
result: &mut Vec<P<ast::Item>>) {
22522394
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: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
use clang;
2+
use clang_sys::CXChildVisit_Continue;
3+
use clang_sys::CXCursor_ObjCInstanceMethodDecl;
4+
// use clang_sys::CXCursor_ObjCSuperClassRef;
5+
use super::context::BindgenContext;
6+
7+
#[derive(Debug)]
8+
pub struct ObjCInterface {
9+
pub name: String,
10+
pub methods: Vec<ObjCInstanceMethod>,
11+
}
12+
13+
#[derive(Debug)]
14+
pub struct ObjCInstanceMethod {
15+
pub name: String, // signature
16+
pub rust_name: String,
17+
}
18+
19+
impl ObjCInterface {
20+
fn new(name: &str) -> ObjCInterface {
21+
ObjCInterface {
22+
name: name.to_owned(),
23+
methods: Vec::new(),
24+
}
25+
}
26+
27+
pub fn from_ty(cursor: &clang::Cursor,
28+
_ctx: &mut BindgenContext)
29+
-> Option<Self> {
30+
let name = cursor.spelling();
31+
let mut interface = Self::new(&name);
32+
33+
if true {
34+
println!("cursor type {:?}", cursor.cur_type());
35+
}
36+
37+
cursor.visit(|cursor| {
38+
match cursor.kind() {
39+
CXCursor_ObjCInstanceMethodDecl => {
40+
let name = cursor.spelling();
41+
let method = ObjCInstanceMethod::new(&name);
42+
43+
interface.methods.push(method);
44+
}
45+
_ => {}
46+
}
47+
CXChildVisit_Continue
48+
});
49+
Some(interface)
50+
}
51+
}
52+
53+
54+
impl ObjCInstanceMethod {
55+
fn new(name: &str) -> ObjCInstanceMethod {
56+
57+
let split_name: Vec<&str> = name.split(':').collect();
58+
59+
let rust_name = split_name.join("_");
60+
61+
ObjCInstanceMethod {
62+
name: name.to_owned(),
63+
rust_name: rust_name.to_owned(),
64+
}
65+
}
66+
}

0 commit comments

Comments
 (0)