From 2af7c9d892d27ce5dd5ab1238c7ec4052a7e660f Mon Sep 17 00:00:00 2001 From: Mads Marquart Date: Fri, 1 Sep 2023 21:58:33 +0200 Subject: [PATCH] Parse NS_NOESCAPE --- crates/header-translator/src/id.rs | 4 ++ crates/header-translator/src/method.rs | 4 +- crates/header-translator/src/rust_type.rs | 57 +++++++++++++++++-- .../header-translator/src/unexposed_attr.rs | 5 +- 4 files changed, 62 insertions(+), 8 deletions(-) diff --git a/crates/header-translator/src/id.rs b/crates/header-translator/src/id.rs index 5ec83cdb9..3a36d92d8 100644 --- a/crates/header-translator/src/id.rs +++ b/crates/header-translator/src/id.rs @@ -119,6 +119,10 @@ impl ItemIdentifier { self.library == "Foundation" && self.name == "NSString" } + pub fn is_nscomparator(&self) -> bool { + self.library == "Foundation" && self.name == "NSComparator" + } + pub fn feature(&self) -> Option { struct ItemIdentifierFeature<'a>(&'a ItemIdentifier); diff --git a/crates/header-translator/src/method.rs b/crates/header-translator/src/method.rs index 78b91ac7b..7cda71d9f 100644 --- a/crates/header-translator/src/method.rs +++ b/crates/header-translator/src/method.rs @@ -401,6 +401,7 @@ impl<'tu> PartialMethod<'tu> { .get_objc_qualifiers() .map(MethodArgumentQualifier::parse); let mut sendable = None; + let mut no_escape = false; immediate_children(&entity, |entity, _span| match entity.get_kind() { EntityKind::ObjCClassRef @@ -417,6 +418,7 @@ impl<'tu> PartialMethod<'tu> { match attr { UnexposedAttr::Sendable => sendable = Some(true), UnexposedAttr::NonSendable => sendable = Some(false), + UnexposedAttr::NoEscape => no_escape = true, attr => error!(?attr, "unknown attribute"), } } @@ -427,7 +429,7 @@ impl<'tu> PartialMethod<'tu> { }); let ty = entity.get_type().expect("argument type"); - let ty = Ty::parse_method_argument(ty, qualifier, sendable, context); + let ty = Ty::parse_method_argument(ty, qualifier, sendable, no_escape, context); (name, ty) }) diff --git a/crates/header-translator/src/rust_type.rs b/crates/header-translator/src/rust_type.rs index 9fcf11170..3534246ab 100644 --- a/crates/header-translator/src/rust_type.rs +++ b/crates/header-translator/src/rust_type.rs @@ -501,10 +501,13 @@ enum Inner { }, Fn { is_variadic: bool, + no_escape: bool, arguments: Vec, result_type: Box, }, Block { + sendable: Option, + no_escape: bool, arguments: Vec, result_type: Box, }, @@ -546,7 +549,7 @@ impl Inner { match attr { Some(UnexposedAttr::NonIsolated | UnexposedAttr::UIActor) => { - // Ignored for now; these are almost always also emitted on the method/property, + // Ignored for now; these are usually also emitted on the method/property, // which is where they will be useful in any case. } Some(attr) => error!(?attr, "unknown attribute"), @@ -681,12 +684,15 @@ impl Inner { match Self::parse(ty, Lifetime::Unspecified, context) { Self::Fn { is_variadic: false, + no_escape, arguments, result_type, } => Self::Pointer { nullability, is_const, pointee: Box::new(Self::Block { + sendable: None, + no_escape, arguments, result_type, }), @@ -924,6 +930,7 @@ impl Inner { Self::Fn { is_variadic: ty.is_variadic(), + no_escape: false, arguments, result_type: Box::new(result_type), } @@ -1008,11 +1015,14 @@ impl Inner { // // } Self::Fn { + is_variadic: _, + no_escape: _, arguments, result_type, - .. } | Self::Block { + sendable: _, + no_escape: _, arguments, result_type, } => { @@ -1106,6 +1116,7 @@ impl fmt::Display for Inner { } => match &**pointee { Self::Fn { is_variadic, + no_escape: _, arguments, result_type, } => { @@ -1161,6 +1172,8 @@ impl fmt::Display for Inner { Enum { id } | Struct { id } | TypeDef { id } => write!(f, "{}", id.path()), Self::Fn { .. } => write!(f, "TodoFunction"), Self::Block { + sendable: _, + no_escape: _, arguments, result_type, } => { @@ -1213,10 +1226,44 @@ impl Ty { pub fn parse_method_argument( ty: Type<'_>, _qualifier: Option, - _sendable: Option, + mut arg_sendable: Option, + mut arg_no_escape: bool, context: &Context<'_>, ) -> Self { - let ty = Inner::parse(ty, Lifetime::Unspecified, context); + let mut ty = Inner::parse(ty, Lifetime::Unspecified, context); + + match &mut ty { + Inner::Pointer { pointee, .. } => match &mut **pointee { + Inner::Block { + sendable, + no_escape, + .. + } => { + *sendable = arg_sendable; + *no_escape = arg_no_escape; + arg_sendable = None; + arg_no_escape = false; + } + Inner::Fn { no_escape, .. } => { + *no_escape = arg_no_escape; + arg_no_escape = false; + } + _ => {} + }, + // Ignore NSComparator for now + Inner::TypeDef { id } if id.is_nscomparator() => { + arg_no_escape = false; + } + _ => {} + } + + if arg_sendable.is_some() { + warn!(?ty, "did not consume sendable in argument"); + } + + if arg_no_escape { + warn!(?ty, "did not consume no_escape in argument"); + } match &ty { Inner::Pointer { pointee, .. } => pointee.visit_lifetime(|lifetime| { @@ -1274,7 +1321,7 @@ impl Ty { } pub fn parse_function_argument(ty: Type<'_>, context: &Context<'_>) -> Self { - let mut this = Self::parse_method_argument(ty, None, None, context); + let mut this = Self::parse_method_argument(ty, None, None, false, context); this.kind = TyKind::FnArgument; this } diff --git a/crates/header-translator/src/unexposed_attr.rs b/crates/header-translator/src/unexposed_attr.rs index 879779eaf..d48db1933 100644 --- a/crates/header-translator/src/unexposed_attr.rs +++ b/crates/header-translator/src/unexposed_attr.rs @@ -25,6 +25,8 @@ pub enum UnexposedAttr { NonSendable, UIActor, NonIsolated, + + NoEscape, } impl UnexposedAttr { @@ -77,8 +79,7 @@ impl UnexposedAttr { let _ = get_arguments(); None } - // TODO - "NS_NOESCAPE" => None, + "NS_NOESCAPE" => Some(Self::NoEscape), // TODO: We could potentially automatically elide this argument // from the method call, though it's rare enough that it's // probably not really worth the effort.