diff options
author | Mikko Lehtonen <scoopr@iki.fi> | 2017-02-22 00:51:35 +0200 |
---|---|---|
committer | Mikko Lehtonen <scoopr@iki.fi> | 2017-02-22 00:54:21 +0200 |
commit | 5f7636ea752da80dc222d05239dac74a434013ef (patch) | |
tree | 23a2b7464c0965c35b627ad3853996668408c0e7 | |
parent | 31c9132cac96de3cada18722d3e2d2bed6ab54a6 (diff) |
objc: Implement categories, id, selector
-rw-r--r-- | src/codegen/mod.rs | 11 | ||||
-rw-r--r-- | src/ir/objc.rs | 33 | ||||
-rw-r--r-- | src/ir/ty.rs | 27 | ||||
-rw-r--r-- | tests/expectations/tests/objc_category.rs | 23 | ||||
-rw-r--r-- | tests/expectations/tests/objc_class.rs | 21 | ||||
-rw-r--r-- | tests/expectations/tests/objc_sel_and_id.rs | 22 | ||||
-rw-r--r-- | tests/headers/objc_category.h | 10 | ||||
-rw-r--r-- | tests/headers/objc_class.h | 10 | ||||
-rw-r--r-- | tests/headers/objc_sel_and_id.h | 7 |
9 files changed, 155 insertions, 9 deletions
diff --git a/src/codegen/mod.rs b/src/codegen/mod.rs index aab59946..46b0a3e7 100644 --- a/src/codegen/mod.rs +++ b/src/codegen/mod.rs @@ -647,6 +647,9 @@ impl CodeGenerator for Type { TypeKind::Enum(ref ei) => { ei.codegen(ctx, result, whitelisted_items, item) } + TypeKind::ObjCId | TypeKind::ObjCSel => { + result.saw_objc(); + } TypeKind::ObjCInterface(ref interface) => { interface.codegen(ctx, result, whitelisted_items, item) } @@ -2276,6 +2279,8 @@ impl ToRustTy for Type { let ident = ctx.rust_ident(&name); quote_ty!(ctx.ext_cx(), $ident) } + TypeKind::ObjCSel => quote_ty!(ctx.ext_cx(), objc::runtime::Sel), + TypeKind::ObjCId | TypeKind::ObjCInterface(..) => quote_ty!(ctx.ext_cx(), id), ref u @ TypeKind::UnresolvedTypeRef(..) => { unreachable!("Should have been resolved after parsing {:?}!", u) @@ -2461,10 +2466,12 @@ impl CodeGenerator for ObjCInterface { } + let trait_name = self.rust_name(); + let trait_block = aster::AstBuilder::new() .item() .pub_() - .trait_(self.name()) + .trait_(&trait_name) .with_items(trait_items) .build(); @@ -2473,7 +2480,7 @@ impl CodeGenerator for ObjCInterface { .item() .impl_() .trait_() - .id(self.name()) + .id(&trait_name) .build() .with_items(impl_items) .build_ty(ty_for_impl); diff --git a/src/ir/objc.rs b/src/ir/objc.rs index b3c3688b..ff36c7b6 100644 --- a/src/ir/objc.rs +++ b/src/ir/objc.rs @@ -4,17 +4,21 @@ use super::context::BindgenContext; use super::function::FunctionSig; use clang; use clang_sys::CXChildVisit_Continue; +use clang_sys::CXCursor_ObjCCategoryDecl; +use clang_sys::CXCursor_ObjCClassRef; use clang_sys::CXCursor_ObjCInstanceMethodDecl; /// Objective C interface as used in TypeKind /// -/// Also protocols are parsed as this type +/// Also protocols and categories are parsed as this type #[derive(Debug)] pub struct ObjCInterface { /// The name /// like, NSObject name: String, + category: Option<String>, + /// List of the methods defined in this interfae methods: Vec<ObjCInstanceMethod>, } @@ -37,6 +41,7 @@ impl ObjCInterface { fn new(name: &str) -> ObjCInterface { ObjCInterface { name: name.to_owned(), + category: None, methods: Vec::new(), } } @@ -47,6 +52,16 @@ impl ObjCInterface { self.name.as_ref() } + /// Formats the name for rust + /// Can be like NSObject, but with categories might be like NSObject_NSCoderMethods + pub fn rust_name(&self) -> String { + if let Some(ref cat) = self.category { + format!("{}_{}", self.name(), cat) + } else { + self.name().to_owned() + } + } + /// List of the methods defined in this interfae pub fn methods(&self) -> &Vec<ObjCInstanceMethod> { &self.methods @@ -59,12 +74,20 @@ impl ObjCInterface { let name = cursor.spelling(); let mut interface = Self::new(&name); - cursor.visit(|cursor| { - match cursor.kind() { + cursor.visit(|c| { + match c.kind() { + CXCursor_ObjCClassRef => { + if cursor.kind() == CXCursor_ObjCCategoryDecl { + // We are actually a category extension, and we found the reference + // to the original interface, so name this interface approriately + interface.name = c.spelling(); + interface.category = Some(cursor.spelling()); + } + } CXCursor_ObjCInstanceMethodDecl => { - let name = cursor.spelling(); + let name = c.spelling(); let signature = - FunctionSig::from_ty(&cursor.cur_type(), &cursor, ctx) + FunctionSig::from_ty(&c.cur_type(), &c, ctx) .expect("Invalid function sig"); let method = ObjCInstanceMethod::new(&name, signature); diff --git a/src/ir/ty.rs b/src/ir/ty.rs index 44a88744..5491ceaf 100644 --- a/src/ir/ty.rs +++ b/src/ir/ty.rs @@ -358,6 +358,8 @@ impl Type { TypeKind::NullPtr | TypeKind::BlockPointer | TypeKind::Pointer(..) | + TypeKind::ObjCId | + TypeKind::ObjCSel | TypeKind::ObjCInterface(..) => Some(self), TypeKind::ResolvedTypeRef(inner) | @@ -433,6 +435,8 @@ impl DotAttributes for TypeKind { TypeKind::TemplateInstantiation(..) => "TemplateInstantiation", TypeKind::ResolvedTypeRef(..) => "ResolvedTypeRef", TypeKind::Named => "Named", + TypeKind::ObjCId => "ObjCId", + TypeKind::ObjCSel => "ObjCSel", TypeKind::ObjCInterface(..) => "ObjCInterface", TypeKind::UnresolvedTypeRef(..) => { unreachable!("there shouldn't be any more of these anymore") @@ -516,6 +520,8 @@ impl TemplateDeclaration for TypeKind { TypeKind::UnresolvedTypeRef(..) | TypeKind::Named | TypeKind::Alias(_) | + TypeKind::ObjCId | + TypeKind::ObjCSel | TypeKind::ObjCInterface(_) => None, } } @@ -562,6 +568,8 @@ impl CanDeriveDefault for Type { TypeKind::NullPtr | TypeKind::Pointer(..) | TypeKind::BlockPointer | + TypeKind::ObjCId | + TypeKind::ObjCSel | TypeKind::ObjCInterface(..) | TypeKind::Enum(..) => false, TypeKind::Function(..) | @@ -707,6 +715,12 @@ pub enum TypeKind { /// Objective C interface. Always referenced through a pointer ObjCInterface(ObjCInterface), + + /// Objective C 'id' type, points to any object + ObjCId, + + /// Objective C selector type + ObjCSel, } impl Type { @@ -738,6 +752,8 @@ impl Type { TypeKind::Reference(..) | TypeKind::NullPtr | TypeKind::BlockPointer | + TypeKind::ObjCId | + TypeKind::ObjCSel | TypeKind::Pointer(..) => false, TypeKind::ObjCInterface(..) => true, // dunno? @@ -787,8 +803,10 @@ impl Type { // Parse objc protocols as if they were interfaces let mut ty_kind = ty.kind(); if let Some(loc) = location { - if loc.kind() == CXCursor_ObjCProtocolDecl { - ty_kind = CXType_ObjCInterface; + match loc.kind() { + CXCursor_ObjCProtocolDecl | + CXCursor_ObjCCategoryDecl => ty_kind = CXType_ObjCInterface, + _ => {} } } @@ -1146,6 +1164,9 @@ impl Type { parent_id, ctx); } + CXType_ObjCId => TypeKind::ObjCId, + CXType_ObjCSel => TypeKind::ObjCSel, + CXType_ObjCClass | CXType_ObjCInterface => { let interface = ObjCInterface::from_ty(&location.unwrap(), ctx) .expect("Not a valid objc interface?"); @@ -1214,6 +1235,8 @@ impl Trace for Type { TypeKind::Int(_) | TypeKind::Float(_) | TypeKind::Complex(_) | + TypeKind::ObjCId | + TypeKind::ObjCSel | TypeKind::BlockPointer => {} } } diff --git a/tests/expectations/tests/objc_category.rs b/tests/expectations/tests/objc_category.rs new file mode 100644 index 00000000..d358e132 --- /dev/null +++ b/tests/expectations/tests/objc_category.rs @@ -0,0 +1,23 @@ +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + +#![cfg(target_os="macos")] + +#[macro_use] +extern crate objc; +#[allow(non_camel_case_types)] +pub type id = *mut objc::runtime::Object; +pub trait Foo { + unsafe fn method(self); +} +impl Foo for id { + unsafe fn method(self) { msg_send!(self , method) } +} +pub trait Foo_BarCategory { + unsafe fn categoryMethod(self); +} +impl Foo_BarCategory for id { + unsafe fn categoryMethod(self) { msg_send!(self , categoryMethod) } +} diff --git a/tests/expectations/tests/objc_class.rs b/tests/expectations/tests/objc_class.rs new file mode 100644 index 00000000..9aa30c1a --- /dev/null +++ b/tests/expectations/tests/objc_class.rs @@ -0,0 +1,21 @@ +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + +#![cfg(target_os="macos")] + +#[macro_use] +extern crate objc; +#[allow(non_camel_case_types)] +pub type id = *mut objc::runtime::Object; +pub trait Foo { + unsafe fn method(self); +} +impl Foo for id { + unsafe fn method(self) { msg_send!(self , method) } +} +extern "C" { + #[link_name = "fooVar"] + pub static mut fooVar: *mut id; +} diff --git a/tests/expectations/tests/objc_sel_and_id.rs b/tests/expectations/tests/objc_sel_and_id.rs new file mode 100644 index 00000000..d72b0bc7 --- /dev/null +++ b/tests/expectations/tests/objc_sel_and_id.rs @@ -0,0 +1,22 @@ +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + +#![cfg(target_os="macos")] + +#[macro_use] +extern crate objc; +#[allow(non_camel_case_types)] +pub type id = *mut objc::runtime::Object; +extern "C" { + #[link_name = "object"] + pub static mut object: id; +} +extern "C" { + #[link_name = "selector"] + pub static mut selector: objc::runtime::Sel; +} +extern "C" { + pub fn f(object: id, selector: objc::runtime::Sel); +} diff --git a/tests/headers/objc_category.h b/tests/headers/objc_category.h new file mode 100644 index 00000000..c464b72e --- /dev/null +++ b/tests/headers/objc_category.h @@ -0,0 +1,10 @@ +// bindgen-flags: --objc-extern-crate -- -x objective-c +// bindgen-osx-only + +@interface Foo +-(void)method; +@end + +@interface Foo (BarCategory) +-(void)categoryMethod; +@end diff --git a/tests/headers/objc_class.h b/tests/headers/objc_class.h new file mode 100644 index 00000000..cea72e78 --- /dev/null +++ b/tests/headers/objc_class.h @@ -0,0 +1,10 @@ +// bindgen-flags: --objc-extern-crate -- -x objective-c +// bindgen-osx-only + +@class Foo; + +Foo* fooVar; + +@interface Foo +-(void)method; +@end diff --git a/tests/headers/objc_sel_and_id.h b/tests/headers/objc_sel_and_id.h new file mode 100644 index 00000000..3c8c6561 --- /dev/null +++ b/tests/headers/objc_sel_and_id.h @@ -0,0 +1,7 @@ +// bindgen-flags: --objc-extern-crate -- -x objective-c +// bindgen-osx-only + +id object; +SEL selector; + +void f(id object, SEL selector); |