Skip to content

Commit

Permalink
Merge pull request #1750 from simlay/objc-inheritance
Browse files Browse the repository at this point in the history
Objective-c inheritance support
  • Loading branch information
emilio authored May 12, 2020
2 parents ee2f289 + 1f324ca commit fcc1096
Show file tree
Hide file tree
Showing 8 changed files with 398 additions and 1 deletion.
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

0 comments on commit fcc1096

Please sign in to comment.