-
Notifications
You must be signed in to change notification settings - Fork 706
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Added Objc category inheritance #1784
Changes from 21 commits
0bedb67
bcd3d7f
1367006
079571d
3ad80d9
70f38c6
7a642c3
a04e151
5118d3e
ade5901
c162325
670331c
996af2e
924182b
5c93c5c
a2287a3
b9615e6
d19f52e
999133e
84a3de9
6a2c809
a70adff
0ce8926
78bf091
6663c80
bd5f919
4c00a97
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,10 @@ | ||
//! Objective C types | ||
|
||
use super::context::{BindgenContext, ItemId}; | ||
use super::context::{BindgenContext, ItemId, TypeId}; | ||
use super::function::FunctionSig; | ||
use super::item::Item; | ||
use super::traversal::{Trace, Tracer}; | ||
use super::ty::TypeKind; | ||
use super::ty::{Type, TypeKind}; | ||
use crate::clang; | ||
use crate::parse::ClangItemParser; | ||
use clang_sys::CXChildVisit_Continue; | ||
|
@@ -37,6 +37,9 @@ pub struct ObjCInterface { | |
/// The list of protocols that this interface conforms to. | ||
pub conforms_to: Vec<ItemId>, | ||
|
||
/// The list of categories (and the template tags) that this interface is extended by. | ||
pub categories: Vec<(String, Vec<String>)>, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why shouldn't these be There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These should probably be |
||
|
||
/// The direct parent for this interface. | ||
pub parent_class: Option<ItemId>, | ||
|
||
|
@@ -68,6 +71,7 @@ impl ObjCInterface { | |
ObjCInterface { | ||
name: name.to_owned(), | ||
category: None, | ||
categories: Vec::new(), | ||
is_protocol: false, | ||
template_names: Vec::new(), | ||
parent_class: None, | ||
|
@@ -135,14 +139,23 @@ impl ObjCInterface { | |
interface.is_protocol = true; | ||
} | ||
|
||
// This is the ItemId for the real interface to which a category extends. We must make it | ||
// an optional, set it when we visit the ObjCCategoryDecl and then use it after we've | ||
// visited the entire tree. We must do it in this order to ensure that this interface has | ||
// all the template tags assigned to it. | ||
let mut real_interface_id_for_category: Option<ItemId> = None; | ||
|
||
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 | ||
// to the original interface, so name this interface approriately. | ||
|
||
interface.name = c.spelling(); | ||
interface.category = Some(cursor.spelling()); | ||
real_interface_id_for_category = Some(Item::from_ty_or_ref(c.cur_type(), c, None, ctx).into()); | ||
simlay marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
} | ||
} | ||
CXCursor_ObjCProtocolRef => { | ||
|
@@ -194,9 +207,61 @@ impl ObjCInterface { | |
} | ||
CXChildVisit_Continue | ||
}); | ||
|
||
if interface.is_category() { | ||
// If this interface is a category, we need to find the interface that this category | ||
// extends. | ||
if let Some(ref mut ty) = | ||
Self::get_parent_ty(ctx, real_interface_id_for_category) | ||
{ | ||
if let TypeKind::ObjCInterface(ref mut real_interface) = | ||
ty.kind_mut() | ||
{ | ||
if !real_interface.is_category() { | ||
real_interface.categories.push(( | ||
interface.rust_name(), | ||
interface.template_names.clone(), | ||
)); | ||
} | ||
} | ||
} | ||
} | ||
Some(interface) | ||
} | ||
|
||
fn get_parent_ty( | ||
ctx: &mut BindgenContext, | ||
parent_id: Option<ItemId>, | ||
) -> Option<&mut Type> { | ||
// This is pretty gross but using the ItemResolver doesn't yield a mutable reference. | ||
let mut ty = ctx.resolve_item_fallible(parent_id?)?.kind().as_type()?; | ||
let mut item_id: Option<&TypeId> = None; | ||
loop { | ||
match ty.kind() { | ||
TypeKind::ResolvedTypeRef(ref_id) => { | ||
let ref_item: ItemId = ref_id.into(); | ||
ty = ctx | ||
.resolve_item_fallible(ref_item)? | ||
.kind() | ||
.as_type()?; | ||
//ty = ref_item.kind().as_type()()?;; | ||
item_id = Some(ref_id); | ||
} | ||
TypeKind::ObjCInterface(..) => { | ||
simlay marked this conversation as resolved.
Show resolved
Hide resolved
|
||
break; | ||
} | ||
_ => return None, | ||
}; | ||
} | ||
|
||
let real_interface_id: ItemId = item_id?.into(); | ||
let ty = ctx | ||
.get_item_mut(real_interface_id)? | ||
.kind_mut() | ||
.as_type_mut()?; | ||
return Some(ty); | ||
} | ||
|
||
fn add_method(&mut self, method: ObjCMethod) { | ||
if method.is_class_method { | ||
self.class_methods.push(method); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
#![allow( | ||
dead_code, | ||
non_snake_case, | ||
non_camel_case_types, | ||
non_upper_case_globals | ||
)] | ||
#![cfg(target_os = "macos")] | ||
|
||
#[macro_use] | ||
extern crate objc; | ||
#[allow(non_camel_case_types)] | ||
pub type id = *mut objc::runtime::Object; | ||
#[repr(transparent)] | ||
#[derive(Clone, Copy)] | ||
pub struct Foo(pub id); | ||
impl std::ops::Deref for Foo { | ||
type Target = objc::runtime::Object; | ||
fn deref(&self) -> &Self::Target { | ||
unsafe { &*self.0 } | ||
} | ||
} | ||
unsafe impl objc::Message for Foo {} | ||
impl Foo { | ||
pub fn alloc() -> Self { | ||
Self(unsafe { msg_send!(objc::class!(Foo), alloc) }) | ||
} | ||
} | ||
impl IFoo for Foo {} | ||
pub trait IFoo: Sized + std::ops::Deref {} | ||
impl Foo_BarCategory for Foo {} | ||
pub trait Foo_BarCategory: Sized + std::ops::Deref {} | ||
#[repr(transparent)] | ||
#[derive(Clone, Copy)] | ||
pub struct Bar(pub id); | ||
impl std::ops::Deref for Bar { | ||
type Target = objc::runtime::Object; | ||
fn deref(&self) -> &Self::Target { | ||
unsafe { &*self.0 } | ||
} | ||
} | ||
unsafe impl objc::Message for Bar {} | ||
impl Bar { | ||
pub fn alloc() -> Self { | ||
Self(unsafe { msg_send!(objc::class!(Bar), alloc) }) | ||
} | ||
} | ||
impl IFoo for Bar {} | ||
impl Foo_BarCategory for Bar {} | ||
impl IBar for Bar {} | ||
pub trait IBar: Sized + std::ops::Deref {} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
#![allow( | ||
dead_code, | ||
non_snake_case, | ||
non_camel_case_types, | ||
non_upper_case_globals | ||
)] | ||
#![cfg(target_os = "macos")] | ||
|
||
#[macro_use] | ||
extern crate objc; | ||
#[allow(non_camel_case_types)] | ||
pub type id = *mut objc::runtime::Object; | ||
#[repr(transparent)] | ||
#[derive(Clone, Copy)] | ||
pub struct Foo(pub id); | ||
impl std::ops::Deref for Foo { | ||
type Target = objc::runtime::Object; | ||
fn deref(&self) -> &Self::Target { | ||
unsafe { &*self.0 } | ||
} | ||
} | ||
unsafe impl objc::Message for Foo {} | ||
impl Foo { | ||
pub fn alloc() -> Self { | ||
Self(unsafe { msg_send!(objc::class!(Foo), alloc) }) | ||
} | ||
} | ||
impl<ObjectType: 'static> IFoo<ObjectType> for Foo {} | ||
pub trait IFoo<ObjectType>: Sized + std::ops::Deref {} | ||
impl<ObjectType: 'static> Foo_Baz<ObjectType> for Foo {} | ||
pub trait Foo_Baz<ObjectType>: Sized + std::ops::Deref {} | ||
#[repr(transparent)] | ||
#[derive(Clone, Copy)] | ||
pub struct Bar(pub id); | ||
impl std::ops::Deref for Bar { | ||
type Target = objc::runtime::Object; | ||
fn deref(&self) -> &Self::Target { | ||
unsafe { &*self.0 } | ||
} | ||
} | ||
unsafe impl objc::Message for Bar {} | ||
impl Bar { | ||
pub fn alloc() -> Self { | ||
Self(unsafe { msg_send!(objc::class!(Bar), alloc) }) | ||
} | ||
} | ||
impl<ObjectType: 'static> IFoo<ObjectType> for Bar {} | ||
impl<ObjectType: 'static> Foo_Baz<ObjectType> for Bar {} | ||
impl<ObjectType: 'static> IBar<ObjectType> for Bar {} | ||
pub trait IBar<ObjectType>: Sized + std::ops::Deref {} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
#![allow( | ||
dead_code, | ||
non_snake_case, | ||
non_camel_case_types, | ||
non_upper_case_globals | ||
)] | ||
#![cfg(target_os = "macos")] | ||
|
||
#[macro_use] | ||
extern crate objc; | ||
#[allow(non_camel_case_types)] | ||
pub type id = *mut objc::runtime::Object; | ||
#[repr(transparent)] | ||
#[derive(Clone, Copy)] | ||
pub struct Foo(pub id); | ||
impl std::ops::Deref for Foo { | ||
type Target = objc::runtime::Object; | ||
fn deref(&self) -> &Self::Target { | ||
unsafe { &*self.0 } | ||
} | ||
} | ||
unsafe impl objc::Message for Foo {} | ||
impl Foo { | ||
pub fn alloc() -> Self { | ||
Self(unsafe { msg_send!(objc::class!(Foo), alloc) }) | ||
} | ||
} | ||
impl<ObjectType: 'static> IFoo<ObjectType> for Foo {} | ||
pub trait IFoo<ObjectType>: Sized + std::ops::Deref {} | ||
#[repr(transparent)] | ||
#[derive(Clone, Copy)] | ||
pub struct Bar(pub id); | ||
impl std::ops::Deref for Bar { | ||
type Target = objc::runtime::Object; | ||
fn deref(&self) -> &Self::Target { | ||
unsafe { &*self.0 } | ||
} | ||
} | ||
unsafe impl objc::Message for Bar {} | ||
impl Bar { | ||
pub fn alloc() -> Self { | ||
Self(unsafe { msg_send!(objc::class!(Bar), alloc) }) | ||
} | ||
} | ||
impl<ObjectType: 'static> IFoo<ObjectType> for Bar {} | ||
impl<ObjectType: 'static> IBar<ObjectType> for Bar {} | ||
pub trait IBar<ObjectType>: Sized + std::ops::Deref {} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
// bindgen-flags: --objc-extern-crate -- -x objective-c | ||
// bindgen-osx-only | ||
|
||
@interface Foo | ||
@end | ||
|
||
@interface Foo (BarCategory) | ||
@end | ||
|
||
@interface Bar: Foo | ||
@end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
// bindgen-flags: --objc-extern-crate -- -x objective-c | ||
// bindgen-osx-only | ||
|
||
@interface Foo<__covariant ObjectType> | ||
@end | ||
|
||
@interface Foo<__covariant ObjectType> (Baz) | ||
@end | ||
|
||
@interface Bar<__covariant ObjectType>: Foo | ||
@end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
// bindgen-flags: --objc-extern-crate -- -x objective-c | ||
// bindgen-osx-only | ||
|
||
@interface Foo<__covariant ObjectType> | ||
@end | ||
|
||
@interface Bar<__covariant ObjectType>: Foo | ||
@end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So here's a thought, is there any reason we can't just implement this when generating code for the
ObjCInterface
?It feels weird that stuff that would be blacklisted would implement these traits and so on. It should also avoid the weird lookup, right?
As in, instead of keeping the
category
as aString
in the interface, you would keep theItemId
. Then when doing code generation you can do the lookup just fine.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is an interesting idea. I'm not a big fan of
String
for the type ofcategory
. I'll try this out.