summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMikko Lehtonen <scoopr@iki.fi>2017-02-22 00:51:35 +0200
committerMikko Lehtonen <scoopr@iki.fi>2017-02-22 00:54:21 +0200
commit5f7636ea752da80dc222d05239dac74a434013ef (patch)
tree23a2b7464c0965c35b627ad3853996668408c0e7
parent31c9132cac96de3cada18722d3e2d2bed6ab54a6 (diff)
objc: Implement categories, id, selector
-rw-r--r--src/codegen/mod.rs11
-rw-r--r--src/ir/objc.rs33
-rw-r--r--src/ir/ty.rs27
-rw-r--r--tests/expectations/tests/objc_category.rs23
-rw-r--r--tests/expectations/tests/objc_class.rs21
-rw-r--r--tests/expectations/tests/objc_sel_and_id.rs22
-rw-r--r--tests/headers/objc_category.h10
-rw-r--r--tests/headers/objc_class.h10
-rw-r--r--tests/headers/objc_sel_and_id.h7
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);