Skip to content

Commit 3ffa01d

Browse files
committed
Add initial Objective C support
It parses interfaces and protocol but ignores base classes, methods that don’t have arguments, the arguments are 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 e4420b6 commit 3ffa01d

File tree

12 files changed

+334
-25
lines changed

12 files changed

+334
-25
lines changed

src/clang.rs

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -683,7 +683,8 @@ impl Type {
683683
CXType_Pointer |
684684
CXType_RValueReference |
685685
CXType_LValueReference |
686-
CXType_MemberPointer => {
686+
CXType_MemberPointer |
687+
CXType_ObjCObjectPointer => {
687688
let ret = Type {
688689
x: unsafe { clang_getPointeeType(self.x) },
689690
};
@@ -780,6 +781,10 @@ impl Type {
780781
!args.any(|t| t.spelling().contains("type-parameter"))
781782
})
782783
}
784+
785+
pub fn objc_encoding(&self) -> String {
786+
unsafe { cxstring_into_string(clang_Type_getObjCEncoding(self.x)) }
787+
}
783788
}
784789

785790
/// An iterator for a type's template arguments.
@@ -1039,27 +1044,31 @@ impl TranslationUnit {
10391044
cmd_args: &[String],
10401045
unsaved: &[UnsavedFile],
10411046
opts: CXTranslationUnit_Flags)
1042-
-> Option<TranslationUnit> {
1047+
-> Result<TranslationUnit, CXErrorCode> {
10431048
let fname = CString::new(file).unwrap();
10441049
let _c_args: Vec<CString> =
10451050
cmd_args.iter().map(|s| CString::new(s.clone()).unwrap()).collect();
10461051
let c_args: Vec<*const c_char> =
10471052
_c_args.iter().map(|s| s.as_ptr()).collect();
10481053
let mut c_unsaved: Vec<CXUnsavedFile> =
10491054
unsaved.iter().map(|f| f.x).collect();
1055+
let error_code;
10501056
let tu = unsafe {
1051-
clang_parseTranslationUnit(ix.x,
1057+
let mut tu_out: CXTranslationUnit = mem::uninitialized();
1058+
error_code = clang_parseTranslationUnit2(ix.x,
10521059
fname.as_ptr(),
10531060
c_args.as_ptr(),
10541061
c_args.len() as c_int,
10551062
c_unsaved.as_mut_ptr(),
10561063
c_unsaved.len() as c_uint,
1057-
opts)
1064+
opts,
1065+
&mut tu_out);
1066+
tu_out
10581067
};
10591068
if tu.is_null() {
1060-
None
1069+
Err(error_code)
10611070
} else {
1062-
Some(TranslationUnit {
1071+
Ok(TranslationUnit {
10631072
x: tu,
10641073
})
10651074
}

src/codegen/mod.rs

Lines changed: 114 additions & 0 deletions
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;
@@ -309,6 +310,10 @@ impl CodeGenerator for Item {
309310
ty.codegen(ctx, result, whitelisted_items, self);
310311
}
311312
}
313+
ItemKind::ObjCInterface(ref interface) => {
314+
// TODO:
315+
interface.codegen(ctx, result, whitelisted_items, self);
316+
}
312317
}
313318
}
314319
}
@@ -583,6 +588,11 @@ impl CodeGenerator for Type {
583588
TypeKind::Enum(ref ei) => {
584589
ei.codegen(ctx, result, whitelisted_items, item)
585590
}
591+
TypeKind::ObjCInterface(..) => {
592+
593+
// TODO: ?
594+
595+
}
586596
ref u @ TypeKind::UnresolvedTypeRef(..) => {
587597
unreachable!("Should have been resolved after parsing {:?}!", u)
588598
}
@@ -2039,6 +2049,13 @@ impl ToRustTy for Type {
20392049
let ident = ctx.rust_ident(&name);
20402050
quote_ty!(ctx.ext_cx(), $ident)
20412051
}
2052+
2053+
TypeKind::ObjCInterface(..) => {
2054+
let name = item.canonical_name(ctx);
2055+
let ident = ctx.rust_ident(&name);
2056+
quote_ty!(ctx.ext_cx(), $ident)
2057+
}
2058+
20422059
ref u @ TypeKind::UnresolvedTypeRef(..) => {
20432060
unreachable!("Should have been resolved after parsing {:?}!", u)
20442061
}
@@ -2074,6 +2091,18 @@ impl ToRustTy for FunctionSig {
20742091
// [1]: http://c0x.coding-guidelines.com/6.7.5.3.html
20752092
let arg_ty = if let TypeKind::Array(t, _) = *arg_ty.canonical_type(ctx).kind() {
20762093
t.to_rust_ty(ctx).to_ptr(arg_ty.is_const(), ctx.span())
2094+
} else if let TypeKind::Pointer(inner) = *arg_ty.canonical_type(ctx).kind(){
2095+
2096+
let inner = ctx.resolve_item(inner);
2097+
let inner_ty = inner.expect_type();
2098+
if let TypeKind::ObjCInterface(_) = *inner_ty.canonical_type(ctx).kind() {
2099+
aster::ty::TyBuilder::new().id("id")
2100+
// inner.to_rust_ty(ctx)
2101+
} else {
2102+
arg_item.to_rust_ty(ctx)
2103+
}
2104+
2105+
20772106
} else {
20782107
arg_item.to_rust_ty(ctx)
20792108
};
@@ -2189,6 +2218,91 @@ impl CodeGenerator for Function {
21892218
}
21902219
}
21912220

2221+
impl CodeGenerator for ObjCInterface {
2222+
type Extra = Item;
2223+
fn codegen<'a>(&self,
2224+
ctx: &BindgenContext,
2225+
result: &mut CodegenResult<'a>,
2226+
_whitelisted_items: &ItemSet,
2227+
_: &Item) {
2228+
2229+
2230+
2231+
let mut impl_items = vec![];
2232+
let mut trait_items = vec![];
2233+
2234+
for method in &self.methods {
2235+
let method_name = ctx.rust_ident(&method.name);
2236+
2237+
let body = quote_stmt!(ctx.ext_cx(),msg_send![self, $method_name])
2238+
.unwrap();
2239+
let block = ast::Block {
2240+
stmts: vec![body],
2241+
id: ast::DUMMY_NODE_ID,
2242+
rules: ast::BlockCheckMode::Default,
2243+
span: ctx.span(),
2244+
};
2245+
2246+
let sig = aster::AstBuilder::new()
2247+
.method_sig()
2248+
.unsafe_()
2249+
.fn_decl()
2250+
.self_()
2251+
.build(ast::SelfKind::Value(ast::Mutability::Immutable))//ast::SelfKind::Region(None, ast::Mutability::Mutable))
2252+
.build(ast::FunctionRetTy::Default(ctx.span()));
2253+
let attrs = vec![];
2254+
2255+
let impl_item = ast::ImplItem {
2256+
id: ast::DUMMY_NODE_ID,
2257+
ident: ctx.rust_ident(&method.rust_name),
2258+
vis: ast::Visibility::Inherited, // Public,
2259+
attrs: attrs.clone(),
2260+
node: ast::ImplItemKind::Method(sig.clone(), P(block)),
2261+
defaultness: ast::Defaultness::Final,
2262+
span: ctx.span(),
2263+
};
2264+
2265+
let trait_item = ast::TraitItem {
2266+
id: ast::DUMMY_NODE_ID,
2267+
ident: ctx.rust_ident(&method.rust_name),
2268+
attrs: attrs,
2269+
node: ast::TraitItemKind::Method(sig, None),
2270+
span: ctx.span(),
2271+
};
2272+
2273+
impl_items.push(impl_item);
2274+
trait_items.push(trait_item)
2275+
}
2276+
2277+
2278+
let trait_block = aster::AstBuilder::new()
2279+
.item()
2280+
.trait_(&self.name)
2281+
.with_items(trait_items)
2282+
.build();
2283+
2284+
let ty_for_impl = aster::AstBuilder::new()
2285+
.ty()
2286+
.path()
2287+
.id(ctx.rust_ident("id"))
2288+
.build();
2289+
let impl_block = aster::AstBuilder::new()
2290+
.item()
2291+
.impl_()
2292+
.trait_()
2293+
.id(&self.name)
2294+
.build()
2295+
.with_items(impl_items)
2296+
.build_ty(ty_for_impl);
2297+
2298+
result.push(trait_block);
2299+
result.push(impl_block);
2300+
2301+
}
2302+
}
2303+
2304+
2305+
21922306
pub fn codegen(context: &mut BindgenContext) -> Vec<P<ast::Item>> {
21932307
context.gen(|context| {
21942308
let counter = Cell::new(0);

src/ir/comp.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -668,8 +668,11 @@ impl CompInfo {
668668

669669
// NB: This gets us an owned `Function`, not a
670670
// `FunctionSig`.
671-
let signature = match Item::parse(cur, Some(potential_id), ctx) {
672-
Ok(item) if ctx.resolve_item(item).kind().is_function() => item,
671+
let signature =
672+
match Item::parse(cur, Some(potential_id), ctx) {
673+
Ok(item) if ctx.resolve_item(item)
674+
.kind()
675+
.is_function() => item,
673676
_ => return CXChildVisit_Continue,
674677
};
675678

src/ir/context.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -961,7 +961,8 @@ impl<'ctx> BindgenContext<'ctx> {
961961
fn tokenize_namespace(&self,
962962
cursor: &clang::Cursor)
963963
-> (Option<String>, ModuleKind) {
964-
assert_eq!(cursor.kind(), ::clang_sys::CXCursor_Namespace,
964+
assert_eq!(cursor.kind(),
965+
::clang_sys::CXCursor_Namespace,
965966
"Be a nice person");
966967
let tokens = match self.translation_unit.tokens(&cursor) {
967968
Some(tokens) => tokens,
@@ -995,7 +996,7 @@ impl<'ctx> BindgenContext<'ctx> {
995996
token);
996997
}
997998
}
998-
};
999+
}
9991000

10001001
(module_name, kind)
10011002
}
@@ -1070,6 +1071,7 @@ impl<'ctx> BindgenContext<'ctx> {
10701071
let name = item.canonical_path(self)[1..].join("::");
10711072
debug!("whitelisted_items: testing {:?}", name);
10721073
match *item.kind() {
1074+
ItemKind::ObjCInterface(_) => true, // TODO:
10731075
ItemKind::Module(..) => true,
10741076
ItemKind::Function(_) => {
10751077
self.options().whitelisted_functions.matches(&name)

src/ir/enum_ty.rs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,11 @@ impl Enum {
7777
});
7878

7979
let type_name = ty.spelling();
80-
let type_name = if type_name.is_empty() { None } else { Some(type_name) };
80+
let type_name = if type_name.is_empty() {
81+
None
82+
} else {
83+
Some(type_name)
84+
};
8185
let type_name = type_name.as_ref().map(String::as_str);
8286

8387
declaration.visit(|cursor| {
@@ -106,8 +110,10 @@ impl Enum {
106110
});
107111

108112
let comment = cursor.raw_comment();
109-
variants.push(
110-
EnumVariant::new(name, comment, val, custom_behavior));
113+
variants.push(EnumVariant::new(name,
114+
comment,
115+
val,
116+
custom_behavior));
111117
}
112118
}
113119
CXChildVisit_Continue

src/ir/function.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,8 @@ impl ClangSubItemParser for Function {
275275
}
276276

277277
let linkage = cursor.linkage();
278-
if linkage != CXLinkage_External && linkage != CXLinkage_UniqueExternal {
278+
if linkage != CXLinkage_External &&
279+
linkage != CXLinkage_UniqueExternal {
279280
return Err(ParseError::Continue);
280281
}
281282

src/ir/item.rs

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use super::derive::{CanDeriveCopy, CanDeriveDebug};
1212
use super::function::Function;
1313
use super::item_kind::ItemKind;
1414
use super::module::Module;
15+
use super::objc::ObjCInterface;
1516
use super::ty::{Type, TypeKind};
1617
use super::type_collector::{ItemSet, TypeCollector};
1718

@@ -193,7 +194,8 @@ impl TypeCollector for Item {
193194
// There are some types, like resolved type references, where we
194195
// don't want to stop collecting types even though they may be
195196
// opaque.
196-
if ty.should_be_traced_unconditionally() || !self.is_opaque(ctx) {
197+
if ty.should_be_traced_unconditionally() ||
198+
!self.is_opaque(ctx) {
197199
ty.collect_types(ctx, types, self);
198200
}
199201
}
@@ -211,6 +213,9 @@ impl TypeCollector for Item {
211213
// expected: everything in every module would end up
212214
// whitelisted.
213215
}
216+
ItemKind::ObjCInterface(_) => {
217+
// TODO:
218+
}
214219
}
215220
}
216221
}
@@ -219,7 +224,8 @@ impl CanDeriveDebug for Item {
219224
type Extra = ();
220225

221226
fn can_derive_debug(&self, ctx: &BindgenContext, _: ()) -> bool {
222-
ctx.options().derive_debug && match self.kind {
227+
ctx.options().derive_debug &&
228+
match self.kind {
223229
ItemKind::Type(ref ty) => {
224230
if self.is_opaque(ctx) {
225231
ty.layout(ctx)
@@ -749,6 +755,7 @@ impl Item {
749755
}
750756

751757
match *self.kind() {
758+
ItemKind::ObjCInterface(ref interface) => interface.name.to_owned(),
752759
ItemKind::Var(ref var) => var.name().to_owned(),
753760
ItemKind::Module(ref module) => {
754761
module.name()
@@ -759,9 +766,7 @@ impl Item {
759766
}
760767
ItemKind::Type(ref ty) => {
761768
let name = match *ty.kind() {
762-
TypeKind::ResolvedTypeRef(..) => {
763-
panic!("should have resolved this in name_target()")
764-
}
769+
TypeKind::ResolvedTypeRef(..) => panic!("should have resolved this in name_target()"),
765770
_ => ty.name(),
766771
};
767772
name.map(ToOwned::to_owned)
@@ -982,6 +987,8 @@ impl ClangItemParser for Item {
982987
try_parse!(Function);
983988
try_parse!(Var);
984989

990+
try_parse!(ObjCInterface);
991+
985992
// Types are sort of special, so to avoid parsing template classes
986993
// twice, handle them separately.
987994
{
@@ -1136,7 +1143,7 @@ impl ClangItemParser for Item {
11361143
}
11371144

11381145
if let Some(ty) =
1139-
ctx.builtin_or_resolved_ty(id, parent_id, ty, location) {
1146+
ctx.builtin_or_resolved_ty(id, parent_id, ty, location) {
11401147
return Ok(ty);
11411148
}
11421149

@@ -1154,9 +1161,10 @@ impl ClangItemParser for Item {
11541161
};
11551162

11561163
if valid_decl {
1157-
if let Some(&(_, item_id)) = ctx.currently_parsed_types
1158-
.iter()
1159-
.find(|&&(d, _)| d == declaration_to_look_for) {
1164+
if let Some(&(_, item_id)) =
1165+
ctx.currently_parsed_types
1166+
.iter()
1167+
.find(|&&(d, _)| d == declaration_to_look_for) {
11601168
debug!("Avoiding recursion parsing type: {:?}", ty);
11611169
return Ok(item_id);
11621170
}
@@ -1325,7 +1333,7 @@ impl ItemCanonicalPath for Item {
13251333
item.id() == target.id() ||
13261334
item.as_module().map_or(false, |module| {
13271335
!module.is_inline() ||
1328-
ctx.options().conservative_inline_namespaces
1336+
ctx.options().conservative_inline_namespaces
13291337
})
13301338
})
13311339
.map(|item| {

0 commit comments

Comments
 (0)