diff options
author | bors-servo <lbergstrom+bors@mozilla.com> | 2017-02-23 03:50:45 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-02-23 03:50:45 -0800 |
commit | dd7c46941adb3f04b3ea55b13a1826abdd2e48d6 (patch) | |
tree | 7305700637595c92e98972b1ca6c324e001acef5 | |
parent | 1eae33ad6a99be3ec8558369888171a62b754405 (diff) | |
parent | fe06265567b9ee1207bc95077932da85c0ed0788 (diff) |
Auto merge of #535 - scoopr:objc, r=emilio
More objective c features
These changes implement the `id` and `SEL` type, `@class` forward declaration handling (though very superficially), and also renames the traits generated from protocols to have a `protocol_` prefix.
With these, I'm able to parse and compile NSObject.h, but I haven't really tested using it yet.
-rw-r--r-- | src/codegen/mod.rs | 11 | ||||
-rw-r--r-- | src/ir/objc.rs | 46 | ||||
-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_interface.rs | 4 | ||||
-rw-r--r-- | tests/expectations/tests/objc_protocol.rs | 15 | ||||
-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_protocol.h | 8 | ||||
-rw-r--r-- | tests/headers/objc_sel_and_id.h | 7 |
12 files changed, 193 insertions, 11 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..963c8e20 100644 --- a/src/ir/objc.rs +++ b/src/ir/objc.rs @@ -4,17 +4,24 @@ 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; +use clang_sys::CXCursor_ObjCProtocolDecl; /// 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>, + + is_protocol: bool, + /// List of the methods defined in this interfae methods: Vec<ObjCInstanceMethod>, } @@ -37,6 +44,8 @@ impl ObjCInterface { fn new(name: &str) -> ObjCInterface { ObjCInterface { name: name.to_owned(), + category: None, + is_protocol: false, methods: Vec::new(), } } @@ -47,6 +56,21 @@ impl ObjCInterface { self.name.as_ref() } + /// Formats the name for rust + /// Can be like NSObject, but with categories might be like NSObject_NSCoderMethods + /// and protocols are like protocol_NSObject + pub fn rust_name(&self) -> String { + if let Some(ref cat) = self.category { + format!("{}_{}", self.name(), cat) + } else { + if self.is_protocol { + format!("protocol_{}", self.name()) + } else { + self.name().to_owned() + } + } + } + /// List of the methods defined in this interfae pub fn methods(&self) -> &Vec<ObjCInstanceMethod> { &self.methods @@ -59,12 +83,24 @@ impl ObjCInterface { let name = cursor.spelling(); let mut interface = Self::new(&name); - cursor.visit(|cursor| { - match cursor.kind() { + if cursor.kind() == CXCursor_ObjCProtocolDecl { + interface.is_protocol = true; + } + + 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_interface.rs b/tests/expectations/tests/objc_interface.rs index 027cf57e..3ca67b89 100644 --- a/tests/expectations/tests/objc_interface.rs +++ b/tests/expectations/tests/objc_interface.rs @@ -11,5 +11,5 @@ extern crate objc; pub type id = *mut objc::runtime::Object; pub trait Foo { } impl Foo for id { } -pub trait bar { } -impl bar for id { } +pub trait protocol_bar { } +impl protocol_bar for id { } diff --git a/tests/expectations/tests/objc_protocol.rs b/tests/expectations/tests/objc_protocol.rs new file mode 100644 index 00000000..a21d4baa --- /dev/null +++ b/tests/expectations/tests/objc_protocol.rs @@ -0,0 +1,15 @@ +/* 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 protocol_Foo { } +impl protocol_Foo for id { } +pub trait Foo { } +impl Foo for 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_protocol.h b/tests/headers/objc_protocol.h new file mode 100644 index 00000000..0c760fa5 --- /dev/null +++ b/tests/headers/objc_protocol.h @@ -0,0 +1,8 @@ +// bindgen-flags: --objc-extern-crate -- -x objective-c +// bindgen-osx-only + +@protocol Foo +@end + +@interface Foo <Foo> +@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); |