Skip to content

Commit da6484e

Browse files
committed
Parse sendability/mainthread attributes
1 parent bffd0db commit da6484e

File tree

8 files changed

+214
-37
lines changed

8 files changed

+214
-37
lines changed

crates/header-translator/src/cache.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ impl<'a> Cache<'a> {
8484
ty: enum_ty,
8585
kind: _,
8686
variants: _,
87+
sendable: _,
8788
}) = iter.peek_mut()
8889
{
8990
if enum_ty.is_typedef_to(&id.name) {

crates/header-translator/src/method.rs

Lines changed: 43 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,9 @@ struct MethodModifiers {
5252
returns_retained: bool,
5353
returns_not_retained: bool,
5454
designated_initializer: bool,
55+
non_isolated: bool,
56+
sendable: Option<bool>,
57+
mainthreadonly: bool,
5558
}
5659

5760
impl MethodModifiers {
@@ -68,6 +71,18 @@ impl MethodModifiers {
6871
UnexposedAttr::ReturnsNotRetained => {
6972
this.returns_not_retained = true;
7073
}
74+
UnexposedAttr::NonIsolated => {
75+
this.non_isolated = true;
76+
}
77+
UnexposedAttr::Sendable => {
78+
this.sendable = Some(true);
79+
}
80+
UnexposedAttr::NonSendable => {
81+
this.sendable = Some(false);
82+
}
83+
UnexposedAttr::UIActor => {
84+
this.mainthreadonly = true;
85+
}
7186
attr => error!(?attr, "unknown attribute"),
7287
}
7388
}
@@ -214,6 +229,7 @@ impl MemoryManagement {
214229
consumes_self: false,
215230
returns_retained: false,
216231
returns_not_retained: false,
232+
..
217233
} = modifiers
218234
{
219235
Self::Normal
@@ -238,6 +254,9 @@ pub struct Method {
238254
safe: bool,
239255
mutating: bool,
240256
is_protocol: bool,
257+
// Thread-safe, even on main-thread only (@MainActor/@UIActor) classes
258+
non_isolated: bool,
259+
mainthreadonly: bool,
241260
}
242261

243262
impl Method {
@@ -367,6 +386,10 @@ impl<'tu> PartialMethod<'tu> {
367386

368387
let modifiers = MethodModifiers::parse(&entity, context);
369388

389+
if modifiers.sendable.is_some() {
390+
error!("sendable on method");
391+
}
392+
370393
let mut arguments: Vec<_> = entity
371394
.get_arguments()
372395
.expect("method arguments")
@@ -377,6 +400,7 @@ impl<'tu> PartialMethod<'tu> {
377400
let qualifier = entity
378401
.get_objc_qualifiers()
379402
.map(MethodArgumentQualifier::parse);
403+
let mut sendable = None;
380404

381405
immediate_children(&entity, |entity, _span| match entity.get_kind() {
382406
EntityKind::ObjCClassRef
@@ -390,7 +414,11 @@ impl<'tu> PartialMethod<'tu> {
390414
}
391415
EntityKind::UnexposedAttr => {
392416
if let Some(attr) = UnexposedAttr::parse(&entity, context) {
393-
error!(?attr, "unknown attribute");
417+
match attr {
418+
UnexposedAttr::Sendable => sendable = Some(true),
419+
UnexposedAttr::NonSendable => sendable = Some(false),
420+
attr => error!(?attr, "unknown attribute"),
421+
}
394422
}
395423
}
396424
// For some reason we recurse into array types
@@ -399,7 +427,7 @@ impl<'tu> PartialMethod<'tu> {
399427
});
400428

401429
let ty = entity.get_type().expect("argument type");
402-
let ty = Ty::parse_method_argument(ty, qualifier, context);
430+
let ty = Ty::parse_method_argument(ty, qualifier, sendable, context);
403431

404432
(name, ty)
405433
})
@@ -463,6 +491,8 @@ impl<'tu> PartialMethod<'tu> {
463491
// immutable subclass, or as a property.
464492
mutating: data.mutating.unwrap_or(parent_is_mutable),
465493
is_protocol,
494+
non_isolated: modifiers.non_isolated,
495+
mainthreadonly: modifiers.mainthreadonly,
466496
},
467497
))
468498
}
@@ -519,6 +549,7 @@ impl PartialProperty<'_> {
519549
let ty = Ty::parse_property_return(
520550
entity.get_type().expect("property type"),
521551
is_copy,
552+
modifiers.sendable,
522553
context,
523554
);
524555

@@ -538,6 +569,8 @@ impl PartialProperty<'_> {
538569
// is, so let's default to immutable.
539570
mutating: getter_data.mutating.unwrap_or(false),
540571
is_protocol,
572+
non_isolated: modifiers.non_isolated,
573+
mainthreadonly: modifiers.mainthreadonly,
541574
})
542575
} else {
543576
None
@@ -546,8 +579,12 @@ impl PartialProperty<'_> {
546579
let setter = if let Some(setter_name) = setter_name {
547580
let setter_data = setter_data.expect("setter_data must be present if setter_name was");
548581
if !setter_data.skipped {
549-
let ty =
550-
Ty::parse_property(entity.get_type().expect("property type"), is_copy, context);
582+
let ty = Ty::parse_property(
583+
entity.get_type().expect("property type"),
584+
is_copy,
585+
modifiers.sendable,
586+
context,
587+
);
551588

552589
let selector = setter_name.clone() + ":";
553590
let memory_management =
@@ -566,6 +603,8 @@ impl PartialProperty<'_> {
566603
// Setters are usually mutable if the class itself is.
567604
mutating: setter_data.mutating.unwrap_or(parent_is_mutable),
568605
is_protocol,
606+
non_isolated: modifiers.non_isolated,
607+
mainthreadonly: modifiers.mainthreadonly,
569608
})
570609
} else {
571610
None

crates/header-translator/src/rust_type.rs

Lines changed: 51 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -532,10 +532,30 @@ impl Inner {
532532

533533
let unexposed_nullability = if let TypeKind::Unexposed = ty.get_kind() {
534534
let nullability = ty.get_nullability();
535-
attributed_name = parse_unexposed_tokens(&attributed_name);
535+
let (new_attributed_name, attributed_attr) = parse_unexposed_tokens(&attributed_name);
536536
// Also parse the expected name to ensure that the formatting that
537537
// TokenStream does is the same on both.
538-
name = parse_unexposed_tokens(&name);
538+
let (new_name, attr) = parse_unexposed_tokens(&name);
539+
if attributed_attr != attr {
540+
error!(
541+
?attributed_attr,
542+
?attr,
543+
"attributed attr was not equal to attr",
544+
);
545+
}
546+
547+
match attr {
548+
Some(UnexposedAttr::NonIsolated | UnexposedAttr::UIActor) => {
549+
// Ignored for now; these are almost always also emitted on the method/property,
550+
// which is where they will be useful in any case.
551+
}
552+
Some(attr) => error!(?attr, "unknown attribute"),
553+
None => {}
554+
}
555+
556+
attributed_name = new_attributed_name;
557+
name = new_name;
558+
539559
ty = ty
540560
.get_modified_type()
541561
.expect("attributed type to have modified type");
@@ -1193,6 +1213,7 @@ impl Ty {
11931213
pub fn parse_method_argument(
11941214
ty: Type<'_>,
11951215
_qualifier: Option<MethodArgumentQualifier>,
1216+
_sendable: Option<bool>,
11961217
context: &Context<'_>,
11971218
) -> Self {
11981219
let ty = Inner::parse(ty, Lifetime::Unspecified, context);
@@ -1253,7 +1274,7 @@ impl Ty {
12531274
}
12541275

12551276
pub fn parse_function_argument(ty: Type<'_>, context: &Context<'_>) -> Self {
1256-
let mut this = Self::parse_method_argument(ty, None, context);
1277+
let mut this = Self::parse_method_argument(ty, None, None, context);
12571278
this.kind = TyKind::FnArgument;
12581279
this
12591280
}
@@ -1304,6 +1325,7 @@ impl Ty {
13041325
ty: Type<'_>,
13051326
// Ignored; see `parse_property_return`
13061327
_is_copy: bool,
1328+
_sendable: Option<bool>,
13071329
context: &Context<'_>,
13081330
) -> Self {
13091331
let ty = Inner::parse(ty, Lifetime::Unspecified, context);
@@ -1320,7 +1342,12 @@ impl Ty {
13201342
}
13211343
}
13221344

1323-
pub fn parse_property_return(ty: Type<'_>, is_copy: bool, context: &Context<'_>) -> Self {
1345+
pub fn parse_property_return(
1346+
ty: Type<'_>,
1347+
is_copy: bool,
1348+
_sendable: Option<bool>,
1349+
context: &Context<'_>,
1350+
) -> Self {
13241351
let mut ty = Inner::parse(ty, Lifetime::Unspecified, context);
13251352

13261353
// `@property(copy)` is expected to always return a nonnull instance
@@ -1736,10 +1763,10 @@ impl fmt::Display for Ty {
17361763
/// - NS_SWIFT_UNAVAILABLE
17371764
/// - NS_REFINED_FOR_SWIFT
17381765
/// - ...
1739-
fn parse_unexposed_tokens(s: &str) -> String {
1766+
fn parse_unexposed_tokens(s: &str) -> (String, Option<UnexposedAttr>) {
17401767
let tokens = TokenStream::from_str(s).expect("parse attributed name");
17411768
let mut iter = tokens.into_iter().peekable();
1742-
if let Some(TokenTree::Ident(ident)) = iter.peek() {
1769+
let attr = if let Some(TokenTree::Ident(ident)) = iter.peek() {
17431770
let ident = ident.to_string();
17441771
if let Ok(attr) = UnexposedAttr::from_name(&ident, || {
17451772
iter.next();
@@ -1750,13 +1777,15 @@ fn parse_unexposed_tokens(s: &str) -> String {
17501777
None
17511778
}
17521779
}) {
1753-
if let Some(attr) = attr {
1754-
error!(?attr, "unknown attribute");
1755-
}
17561780
iter.next();
1781+
attr
1782+
} else {
1783+
None
17571784
}
1758-
}
1759-
TokenStream::from_iter(iter).to_string()
1785+
} else {
1786+
None
1787+
};
1788+
(TokenStream::from_iter(iter).to_string(), attr)
17601789
}
17611790

17621791
#[cfg(test)]
@@ -1766,7 +1795,9 @@ mod tests {
17661795
#[test]
17671796
fn test_parse_unexposed_tokens() {
17681797
fn check(inp: &str, expected: &str) {
1769-
assert_eq!(parse_unexposed_tokens(inp), expected);
1798+
let (actual, attr) = parse_unexposed_tokens(inp);
1799+
assert_eq!(actual, expected);
1800+
assert_eq!(attr, None);
17701801
}
17711802

17721803
check("NS_RETURNS_INNER_POINTER const char *", "const char *");
@@ -1791,5 +1822,13 @@ mod tests {
17911822
"API_DEPRECATED_WITH_REPLACEMENT(\"@\\\"com.adobe.encapsulated-postscript\\\"\", macos(10.0,10.14)) NSPasteboardType __strong",
17921823
"NSPasteboardType __strong",
17931824
);
1825+
1826+
let (actual, attr) = parse_unexposed_tokens("NS_SWIFT_NONISOLATED NSTextAttachment *");
1827+
assert_eq!(actual, "NSTextAttachment *");
1828+
assert_eq!(attr, Some(UnexposedAttr::NonIsolated));
1829+
1830+
let (actual, attr) = parse_unexposed_tokens("NS_SWIFT_UI_ACTOR SEL");
1831+
assert_eq!(actual, "SEL");
1832+
assert_eq!(attr, Some(UnexposedAttr::UIActor));
17941833
}
17951834
}

0 commit comments

Comments
 (0)