Enables blocklisting of Objective-C methods

This commit is contained in:
Cameron Mulhern 2021-12-27 10:49:50 -05:00 committed by Darren Kulp
parent e68b8c0e2b
commit 8b69ba05aa
4 changed files with 78 additions and 7 deletions

View File

@ -32,6 +32,8 @@ methods found in `NSObject`.
In order to initialize a class `Foo`, you will have to do something like `let
foo = Foo(Foo::alloc().initWithStuff())`.
To blocklist an Objective-C method, you should add the bindgen generated method
path (e.g. `IFoo::method` or `IFoo::class_method`) as a blocklist item.
## Supported Features

View File

@ -4191,9 +4191,19 @@ impl CodeGenerator for Function {
fn objc_method_codegen(
ctx: &BindgenContext,
method: &ObjCMethod,
methods: &mut Vec<proc_macro2::TokenStream>,
class_name: Option<&str>,
rust_class_name: &str,
prefix: &str,
) -> proc_macro2::TokenStream {
) {
// This would ideally resolve the method into an Item, and use
// Item::process_before_codegen; however, ObjC methods are not currently
// made into function items.
let name = format!("{}::{}{}", rust_class_name, prefix, method.rust_name());
if ctx.options().blocklisted_items.matches(name) {
return;
}
let signature = method.signature();
let fn_args = utils::fnsig_arguments(ctx, signature);
let fn_ret = utils::fnsig_return_ty(ctx, signature);
@ -4229,11 +4239,11 @@ fn objc_method_codegen(
let method_name =
ctx.rust_ident(format!("{}{}", prefix, method.rust_name()));
quote! {
methods.push(quote! {
unsafe fn #method_name #sig where <Self as std::ops::Deref>::Target: objc::Message + Sized {
#body
}
}
});
}
impl CodeGenerator for ObjCInterface {
@ -4249,10 +4259,17 @@ impl CodeGenerator for ObjCInterface {
debug_assert!(item.is_enabled_for_codegen(ctx));
let mut impl_items = vec![];
let rust_class_name = item.path_for_allowlisting(ctx)[1..].join("::");
for method in self.methods() {
let impl_item = objc_method_codegen(ctx, method, None, "");
impl_items.push(impl_item);
objc_method_codegen(
ctx,
method,
&mut impl_items,
None,
&rust_class_name,
"",
);
}
for class_method in self.class_methods() {
@ -4262,13 +4279,14 @@ impl CodeGenerator for ObjCInterface {
.map(|m| m.rust_name())
.any(|x| x == class_method.rust_name());
let prefix = if ambiquity { "class_" } else { "" };
let impl_item = objc_method_codegen(
objc_method_codegen(
ctx,
class_method,
&mut impl_items,
Some(self.name()),
&rust_class_name,
prefix,
);
impl_items.push(impl_item);
}
let trait_name = ctx.rust_ident(self.rust_name());

View File

@ -0,0 +1,42 @@
#![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(Debug, Copy, Clone)]
pub struct SomeClass(pub id);
impl std::ops::Deref for SomeClass {
type Target = objc::runtime::Object;
fn deref(&self) -> &Self::Target {
unsafe { &*self.0 }
}
}
unsafe impl objc::Message for SomeClass {}
impl SomeClass {
pub fn alloc() -> Self {
Self(unsafe { msg_send!(class!(SomeClass), alloc) })
}
}
impl ISomeClass for SomeClass {}
pub trait ISomeClass: Sized + std::ops::Deref {
unsafe fn ambiguouslyBlockedMethod(&self)
where
<Self as std::ops::Deref>::Target: objc::Message + Sized,
{
msg_send!(*self, ambiguouslyBlockedMethod)
}
unsafe fn instanceMethod(&self)
where
<Self as std::ops::Deref>::Target: objc::Message + Sized,
{
msg_send!(*self, instanceMethod)
}
}

View File

@ -0,0 +1,9 @@
// bindgen-flags: --objc-extern-crate --blocklist-item ISomeClass::class_ambiguouslyBlockedMethod --blocklist-item ISomeClass::blockedInstanceMethod -- -x objective-c
// bindgen-osx-only
@interface SomeClass
+ (void)ambiguouslyBlockedMethod;
- (void)ambiguouslyBlockedMethod;
- (void)instanceMethod;
- (void)blockedInstanceMethod;
@end