Skip to content

Commit 10878c4

Browse files
committed
Change syntax of method family attribute
Also put it after `#[method_id(...)]` in generated output, and add a few tests.
1 parent a62b9dc commit 10878c4

12 files changed

+189
-27
lines changed

crates/header-translator/src/method.rs

+13-13
Original file line numberDiff line numberDiff line change
@@ -767,6 +767,18 @@ impl fmt::Display for Method {
767767
writeln!(f, " #[optional]")?;
768768
}
769769

770+
let method_kind = if self.memory_management == MemoryManagement::Normal {
771+
"method"
772+
} else {
773+
"method_id"
774+
};
775+
let error_trailing = if self.is_error { "_" } else { "" };
776+
writeln!(
777+
f,
778+
" #[{}({}{})]",
779+
method_kind, self.selector, error_trailing
780+
)?;
781+
770782
let id_mm_name = match &self.memory_management {
771783
// MemoryManagement::IdAlloc => Some("alloc"), // Unsupported
772784
MemoryManagement::IdCopy => Some("copy"),
@@ -779,21 +791,9 @@ impl fmt::Display for Method {
779791
if let Some(id_mm_name) = id_mm_name {
780792
// TODO: Be explicit about when we emit this for better
781793
// compile-times, and when we do it for soundness.
782-
writeln!(f, " #[unsafe(method_family({id_mm_name}))]")?;
794+
writeln!(f, " #[unsafe(method_family = {id_mm_name})]")?;
783795
};
784796

785-
let method_kind = if self.memory_management == MemoryManagement::Normal {
786-
"method"
787-
} else {
788-
"method_id"
789-
};
790-
let error_trailing = if self.is_error { "_" } else { "" };
791-
writeln!(
792-
f,
793-
" #[{}({}{})]",
794-
method_kind, self.selector, error_trailing
795-
)?;
796-
797797
//
798798
// Signature
799799
//

crates/objc2/CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
3434
* Added 16-fold `Encode` and `RefEncode` impls for function pointers
3535
(previously only implemented for up to 12 arguments, which turned out to be
3636
insufficient).
37+
* Added `#[unsafe(method_family = ...)]` attribute in `extern_methods!` and
38+
`extern_protocol!`, to allow overriding the inferred method family.
3739

3840
### Changed
3941
* **BREAKING**: Renamed `declare_class!` to `define_class!`, and changed the

crates/objc2/src/__macro_helpers/method_family.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,8 @@ pub type MutableCopy = MethodFamily<5>;
3434
/// No family.
3535
pub type Other = MethodFamily<6>;
3636

37-
/// Helper module where `#[method_family($family:ident)]` will import its
38-
/// value from.
37+
/// Helper module where `#[unsafe(method_family = $family:ident)]` will import
38+
/// its value from.
3939
#[allow(non_camel_case_types)]
4040
pub mod method_family_import {
4141
// Rename to match Clang's `__attribute__((objc_method_family(family)))`.

crates/objc2/src/__macro_helpers/msg_send_retained.rs

+95-1
Original file line numberDiff line numberDiff line change
@@ -595,7 +595,7 @@ mod tests {
595595

596596
use crate::rc::{autoreleasepool, RcTestObject, ThreadTestData};
597597
use crate::runtime::{NSObject, NSZone};
598-
use crate::{class, msg_send_id, AllocAnyThread};
598+
use crate::{class, extern_methods, msg_send_id, AllocAnyThread};
599599

600600
mod test_trait_disambugated {
601601
use super::*;
@@ -1136,4 +1136,98 @@ mod tests {
11361136
let retained = retained.unwrap();
11371137
assert_eq!(&*retained, cls);
11381138
}
1139+
1140+
extern_methods!(
1141+
unsafe impl RcTestObject {
1142+
#[method_id(copy)]
1143+
#[unsafe(method_family = new)]
1144+
fn copy_new(&self) -> Retained<Self>;
1145+
1146+
#[method_id(copy)]
1147+
#[unsafe(method_family = init)]
1148+
fn copy_init(this: Allocated<Self>) -> Retained<Self>;
1149+
1150+
#[method_id(copy)]
1151+
#[unsafe(method_family = copy)]
1152+
fn copy_copy(&self) -> Retained<Self>;
1153+
1154+
#[method_id(copy)]
1155+
#[unsafe(method_family = mutableCopy)]
1156+
fn copy_mutable_copy(&self) -> Retained<Self>;
1157+
1158+
#[method_id(copy)]
1159+
#[unsafe(method_family = none)]
1160+
fn copy_none(&self) -> Retained<Self>;
1161+
}
1162+
);
1163+
1164+
#[test]
1165+
fn test_method_family() {
1166+
// Test a few combinations of (incorrect) method families.
1167+
let obj = RcTestObject::new();
1168+
let mut expected = ThreadTestData::current();
1169+
1170+
let copy = obj.copy_new();
1171+
expected.copy += 1;
1172+
expected.alloc += 1;
1173+
expected.init += 1;
1174+
expected.assert_current();
1175+
drop(copy);
1176+
expected.release += 1;
1177+
expected.drop += 1;
1178+
expected.assert_current();
1179+
1180+
let alloc = RcTestObject::alloc();
1181+
let ptr = Allocated::as_ptr(&alloc);
1182+
expected.alloc += 1;
1183+
expected.assert_current();
1184+
let copy = RcTestObject::copy_init(alloc);
1185+
expected.copy += 1;
1186+
expected.alloc += 1;
1187+
expected.init += 1;
1188+
expected.assert_current();
1189+
drop(copy);
1190+
expected.release += 1;
1191+
expected.drop += 1;
1192+
expected.assert_current();
1193+
drop(unsafe { Allocated::new(ptr.cast_mut()) });
1194+
expected.release += 1;
1195+
expected.assert_current();
1196+
1197+
let copy = obj.copy_copy();
1198+
expected.copy += 1;
1199+
expected.alloc += 1;
1200+
expected.init += 1;
1201+
expected.assert_current();
1202+
drop(copy);
1203+
expected.release += 1;
1204+
expected.drop += 1;
1205+
expected.assert_current();
1206+
1207+
let copy = obj.copy_mutable_copy();
1208+
expected.copy += 1;
1209+
expected.alloc += 1;
1210+
expected.init += 1;
1211+
expected.assert_current();
1212+
drop(copy);
1213+
expected.release += 1;
1214+
expected.drop += 1;
1215+
expected.assert_current();
1216+
1217+
let copy = obj.copy_none();
1218+
expected.copy += 1;
1219+
expected.alloc += 1;
1220+
expected.init += 1;
1221+
expected.retain += 1;
1222+
expected.assert_current();
1223+
// SAFETY: Wrong method family specified, so we have +1 retain count
1224+
// in excess.
1225+
drop(unsafe { Retained::from_raw(Retained::as_ptr(&copy).cast_mut()) });
1226+
expected.release += 1;
1227+
expected.assert_current();
1228+
drop(copy);
1229+
expected.release += 1;
1230+
expected.drop += 1;
1231+
expected.assert_current();
1232+
}
11391233
}

crates/objc2/src/macros/__attribute_helpers.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,7 @@ macro_rules! __extract_method_attributes_inner {
234234
// `method_family` attribute
235235
{
236236
(
237-
#[unsafe(method_family($($parsed:tt)+))]
237+
#[unsafe(method_family = $($parsed:tt)+)]
238238
$($rest:tt)*
239239
)
240240
($($method:tt)*)

crates/objc2/src/macros/define_class.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -144,8 +144,8 @@
144144
///
145145
/// The desired selector can be specified using the `#[method(my:selector:)]`
146146
/// or `#[method_id(my:selector:)]` attribute, similar to the
147-
/// [`extern_methods!`] macro. The `#[method_family(family)]` attribute is not
148-
/// yet supported.
147+
/// [`extern_methods!`] macro. The `#[unsafe(method_family = family)]`
148+
/// attribute is not yet supported.
149149
///
150150
/// If the `#[method_id(...)]` attribute is used, the return type must be
151151
/// `Option<Retained<T>>` or `Retained<T>`. Additionally, if the selector is
@@ -1448,7 +1448,7 @@ macro_rules! __define_class_no_method_family {
14481448
() => {};
14491449
($($t:tt)+) => {
14501450
$crate::__macro_helpers::compile_error!(
1451-
"`#[method_family(...)]` is not yet supported in `define_class!`"
1451+
"`#[method_family = ...]` is not yet supported in `define_class!`"
14521452
)
14531453
};
14541454
}

crates/objc2/src/macros/extern_methods.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@
5454
/// for details.
5555
///
5656
///
57-
/// ### `#[unsafe(method_family(...))]`
57+
/// ### `#[unsafe(method_family = ...)]` (optional)
5858
///
5959
/// The Cocoa memory management convention is figured out automatically based
6060
/// on the name of the selector, but it can be overwritten with this `unsafe`
@@ -413,7 +413,7 @@ macro_rules! __extern_methods_no_method_family {
413413
() => {};
414414
($($t:tt)+) => {
415415
$crate::__macro_helpers::compile_error!(
416-
"`#[method_family(...)]` is only supported together with `#[method_id(...)]`"
416+
"`#[method_family = ...]` is only supported together with `#[method_id(...)]`"
417417
)
418418
};
419419
}

crates/objc2/src/macros/extern_protocol.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,9 @@
3333
/// This macro creates an `unsafe` trait with the specified methods. A default
3434
/// implementation of the method is generated based on the selector specified
3535
/// with `#[method(a:selector:)]` or `#[method_id(a:selector:)]`.
36-
/// Similar to [`extern_methods!`], you can use the `#[method_family(...)]`
37-
/// attribute to override the inferred method family.
36+
/// Similar to [`extern_methods!`], you can use the
37+
/// `#[unsafe(method_family = ...)]` attribute to override the inferred method
38+
/// family.
3839
///
3940
/// Other protocols that this protocol conforms to / inherits can be specified
4041
/// as supertraits.
@@ -489,7 +490,7 @@ macro_rules! __extern_protocol_no_method_family {
489490
() => {};
490491
($($t:tt)+) => {
491492
$crate::__macro_helpers::compile_error!(
492-
"`#[method_family(...)]` is only supported together with `#[method_id(...)]`"
493+
"`#[method_family = ...]` is only supported together with `#[method_id(...)]`"
493494
)
494495
};
495496
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
//! Test various usage of the method_family attribute.
2+
use objc2::rc::Retained;
3+
use objc2::runtime::NSObject;
4+
use objc2::{extern_class, extern_methods};
5+
6+
extern_class!(
7+
#[unsafe(super(NSObject))]
8+
pub struct MyObject;
9+
);
10+
11+
extern_methods!(
12+
unsafe impl MyObject {
13+
#[method_id(noUnsafe)]
14+
#[method_family = none]
15+
fn no_unsafe(&self) -> Retained<Self>;
16+
}
17+
);
18+
19+
extern_methods!(
20+
unsafe impl MyObject {
21+
#[method_id(unknownFamily)]
22+
#[unsafe(method_family = unknown)]
23+
fn unknown_family(&self) -> Retained<Self>;
24+
}
25+
);
26+
27+
extern_methods!(
28+
unsafe impl MyObject {
29+
#[method(notOnMethodId)]
30+
#[unsafe(method_family = none)]
31+
fn not_on_method_id(&self);
32+
}
33+
);
34+
35+
fn main() {}

crates/test-ui/ui/extern_methods_invalid_method_family.stderr

+30
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/test-ui/ui/nsarray_not_message.stderr

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

generated

Submodule generated updated 2716 files

0 commit comments

Comments
 (0)