summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEmilio Cobos Álvarez <emilio@crisal.io>2020-05-12 17:54:17 +0200
committerGitHub <noreply@github.com>2020-05-12 17:54:17 +0200
commitfcc10961dbfe128d2e592cb302316122938d7b58 (patch)
tree169787cd659bcd8c41f801e5342850c62fa00b79
parentee2f289a2d57e4d67fe38d060f0c93e9ab866183 (diff)
parent1f324cabfc24042903002e1f2cf1530ee8818942 (diff)
Merge pull request #1750 from simlay/objc-inheritance
Objective-c inheritance support
-rw-r--r--src/codegen/mod.rs35
-rw-r--r--src/ir/objc.rs13
-rw-r--r--tests/expectations/tests/libclang-3.8/objc_inheritance.rs68
-rw-r--r--tests/expectations/tests/libclang-3.9/objc_inheritance.rs68
-rw-r--r--tests/expectations/tests/libclang-4/objc_inheritance.rs68
-rw-r--r--tests/expectations/tests/libclang-5/objc_inheritance.rs68
-rw-r--r--tests/expectations/tests/libclang-9/objc_inheritance.rs68
-rw-r--r--tests/headers/objc_inheritance.h11
8 files changed, 398 insertions, 1 deletions
diff --git a/src/codegen/mod.rs b/src/codegen/mod.rs
index 8344c4d1..af1622da 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<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() {
diff --git a/src/ir/objc.rs b/src/ir/objc.rs
index 5fb645d5..91855c67 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<ItemId>,
+ /// The direct parent for this interface.
+ pub parent_class: Option<ItemId>,
+
/// List of the methods defined in this interfae
methods: Vec<ObjCMethod>,
@@ -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 00000000..5443dd43
--- /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 00000000..5443dd43
--- /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 00000000..5443dd43
--- /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 00000000..5443dd43
--- /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 00000000..5443dd43
--- /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 00000000..8f96e45b
--- /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