Skip to content

Objective-c inheritance support #1750

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

Merged
merged 1 commit into from
May 12, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions src/codegen/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3791,6 +3791,41 @@ impl CodeGenerator for ObjCInterface {
};
result.push(impl_trait);
}
let mut parent_class = self.parent_class;
while let Some(parent_id) = parent_class {
let parent = parent_id
.expect_type_id(ctx)
.into_resolver()
.through_type_refs()
.resolve(ctx)
.expect_type()
.kind();

parent_class = if let TypeKind::ObjCInterface(ref parent) =
parent
{
let parent_name = ctx.rust_ident(parent.rust_name());
let impl_trait = if parent.is_template() {
let template_names: Vec<Ident> = parent
.template_names
.iter()
.map(|g| ctx.rust_ident(g))
.collect();
quote! {
impl <#(#template_names :'static),*> #parent_name <#(#template_names),*> for #class_name {
}
}
} else {
quote! {
impl #parent_name for #class_name { }
}
};
result.push(impl_trait);
parent.parent_class
} else {
None
};
}
}

if !self.is_protocol() {
Expand Down
13 changes: 12 additions & 1 deletion src/ir/objc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,19 @@

use super::context::{BindgenContext, ItemId};
use super::function::FunctionSig;
use super::item::Item;
use super::traversal::{Trace, Tracer};
use super::ty::TypeKind;
use crate::clang;
use crate::parse::ClangItemParser;
use clang_sys::CXChildVisit_Continue;
use clang_sys::CXCursor_ObjCCategoryDecl;
use clang_sys::CXCursor_ObjCClassMethodDecl;
use clang_sys::CXCursor_ObjCClassRef;
use clang_sys::CXCursor_ObjCInstanceMethodDecl;
use clang_sys::CXCursor_ObjCProtocolDecl;
use clang_sys::CXCursor_ObjCProtocolRef;
use clang_sys::CXCursor_ObjCSuperClassRef;
use clang_sys::CXCursor_TemplateTypeParameter;
use proc_macro2::{Ident, Span, TokenStream};

Expand All @@ -34,6 +37,9 @@ pub struct ObjCInterface {
/// The list of protocols that this interface conforms to.
pub conforms_to: Vec<ItemId>,

/// The direct parent for this interface.
pub parent_class: Option<ItemId>,

/// List of the methods defined in this interfae
methods: Vec<ObjCMethod>,

Expand Down Expand Up @@ -64,6 +70,7 @@ impl ObjCInterface {
category: None,
is_protocol: false,
template_names: Vec::new(),
parent_class: None,
conforms_to: Vec::new(),
methods: Vec::new(),
class_methods: Vec::new(),
Expand Down Expand Up @@ -146,7 +153,7 @@ impl ObjCInterface {

for (id, item) in items_map
{
if let Some(ty) = item.as_type() {
if let Some(ty) = item.as_type() {
match *ty.kind() {
TypeKind::ObjCInterface(ref protocol) => {
if protocol.is_protocol
Expand Down Expand Up @@ -179,6 +186,10 @@ impl ObjCInterface {
let name = c.spelling();
interface.template_names.push(name);
}
CXCursor_ObjCSuperClassRef => {
let item = Item::from_ty_or_ref(c.cur_type(), c, None, ctx);
interface.parent_class = Some(item.into());
},
_ => {}
}
CXChildVisit_Continue
Expand Down
68 changes: 68 additions & 0 deletions tests/expectations/tests/libclang-3.8/objc_inheritance.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/* automatically generated by rust-bindgen */

#![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 {}
#[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 IBar for Bar {}
pub trait IBar: Sized + std::ops::Deref {}
#[repr(transparent)]
#[derive(Clone, Copy)]
pub struct Baz(pub id);
impl std::ops::Deref for Baz {
type Target = objc::runtime::Object;
fn deref(&self) -> &Self::Target {
unsafe { &*self.0 }
}
}
unsafe impl objc::Message for Baz {}
impl Baz {
pub fn alloc() -> Self {
Self(unsafe { msg_send!(objc::class!(Baz), alloc) })
}
}
impl IBar for Baz {}
impl IFoo for Baz {}
impl IBaz for Baz {}
pub trait IBaz: Sized + std::ops::Deref {}
68 changes: 68 additions & 0 deletions tests/expectations/tests/libclang-3.9/objc_inheritance.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/* automatically generated by rust-bindgen */

#![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 {}
#[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 IBar for Bar {}
pub trait IBar: Sized + std::ops::Deref {}
#[repr(transparent)]
#[derive(Clone, Copy)]
pub struct Baz(pub id);
impl std::ops::Deref for Baz {
type Target = objc::runtime::Object;
fn deref(&self) -> &Self::Target {
unsafe { &*self.0 }
}
}
unsafe impl objc::Message for Baz {}
impl Baz {
pub fn alloc() -> Self {
Self(unsafe { msg_send!(objc::class!(Baz), alloc) })
}
}
impl IBar for Baz {}
impl IFoo for Baz {}
impl IBaz for Baz {}
pub trait IBaz: Sized + std::ops::Deref {}
68 changes: 68 additions & 0 deletions tests/expectations/tests/libclang-4/objc_inheritance.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/* automatically generated by rust-bindgen */

#![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 {}
#[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 IBar for Bar {}
pub trait IBar: Sized + std::ops::Deref {}
#[repr(transparent)]
#[derive(Clone, Copy)]
pub struct Baz(pub id);
impl std::ops::Deref for Baz {
type Target = objc::runtime::Object;
fn deref(&self) -> &Self::Target {
unsafe { &*self.0 }
}
}
unsafe impl objc::Message for Baz {}
impl Baz {
pub fn alloc() -> Self {
Self(unsafe { msg_send!(objc::class!(Baz), alloc) })
}
}
impl IBar for Baz {}
impl IFoo for Baz {}
impl IBaz for Baz {}
pub trait IBaz: Sized + std::ops::Deref {}
68 changes: 68 additions & 0 deletions tests/expectations/tests/libclang-5/objc_inheritance.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/* automatically generated by rust-bindgen */

#![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 {}
#[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 IBar for Bar {}
pub trait IBar: Sized + std::ops::Deref {}
#[repr(transparent)]
#[derive(Clone, Copy)]
pub struct Baz(pub id);
impl std::ops::Deref for Baz {
type Target = objc::runtime::Object;
fn deref(&self) -> &Self::Target {
unsafe { &*self.0 }
}
}
unsafe impl objc::Message for Baz {}
impl Baz {
pub fn alloc() -> Self {
Self(unsafe { msg_send!(objc::class!(Baz), alloc) })
}
}
impl IBar for Baz {}
impl IFoo for Baz {}
impl IBaz for Baz {}
pub trait IBaz: Sized + std::ops::Deref {}
Loading