diff --git a/src/codegen/mod.rs b/src/codegen/mod.rs index 8344c4d1b5..af1622daff 100644 --- a/src/codegen/mod.rs +++ b/src/codegen/mod.rs @@ -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 = 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() { diff --git a/src/ir/objc.rs b/src/ir/objc.rs index 5fb645d57f..91855c6776 100644 --- a/src/ir/objc.rs +++ b/src/ir/objc.rs @@ -2,9 +2,11 @@ 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; @@ -12,6 +14,7 @@ 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}; @@ -34,6 +37,9 @@ pub struct ObjCInterface { /// The list of protocols that this interface conforms to. pub conforms_to: Vec, + /// The direct parent for this interface. + pub parent_class: Option, + /// List of the methods defined in this interfae methods: Vec, @@ -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(), @@ -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 @@ -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 diff --git a/tests/expectations/tests/libclang-3.8/objc_inheritance.rs b/tests/expectations/tests/libclang-3.8/objc_inheritance.rs new file mode 100644 index 0000000000..5443dd430f --- /dev/null +++ b/tests/expectations/tests/libclang-3.8/objc_inheritance.rs @@ -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 {} diff --git a/tests/expectations/tests/libclang-3.9/objc_inheritance.rs b/tests/expectations/tests/libclang-3.9/objc_inheritance.rs new file mode 100644 index 0000000000..5443dd430f --- /dev/null +++ b/tests/expectations/tests/libclang-3.9/objc_inheritance.rs @@ -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 {} diff --git a/tests/expectations/tests/libclang-4/objc_inheritance.rs b/tests/expectations/tests/libclang-4/objc_inheritance.rs new file mode 100644 index 0000000000..5443dd430f --- /dev/null +++ b/tests/expectations/tests/libclang-4/objc_inheritance.rs @@ -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 {} diff --git a/tests/expectations/tests/libclang-5/objc_inheritance.rs b/tests/expectations/tests/libclang-5/objc_inheritance.rs new file mode 100644 index 0000000000..5443dd430f --- /dev/null +++ b/tests/expectations/tests/libclang-5/objc_inheritance.rs @@ -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 {} diff --git a/tests/expectations/tests/libclang-9/objc_inheritance.rs b/tests/expectations/tests/libclang-9/objc_inheritance.rs new file mode 100644 index 0000000000..5443dd430f --- /dev/null +++ b/tests/expectations/tests/libclang-9/objc_inheritance.rs @@ -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 {} diff --git a/tests/headers/objc_inheritance.h b/tests/headers/objc_inheritance.h new file mode 100644 index 0000000000..8f96e45ba8 --- /dev/null +++ b/tests/headers/objc_inheritance.h @@ -0,0 +1,11 @@ +// bindgen-flags: --objc-extern-crate -- -x objective-c +// bindgen-osx-only + +@interface Foo +@end + +@interface Bar: Foo +@end + +@interface Baz: Bar +@end