Skip to content

Commit

Permalink
Strip Ref suffix from CF types
Browse files Browse the repository at this point in the history
  • Loading branch information
madsmtm committed Jan 8, 2025
1 parent 171a694 commit f2f7b94
Show file tree
Hide file tree
Showing 7 changed files with 83 additions and 48 deletions.
27 changes: 25 additions & 2 deletions crates/header-translator/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,14 +66,37 @@ impl Config {
})
}

pub fn replace_typedef_name(&self, id: ItemIdentifier) -> ItemIdentifier {
pub fn replace_typedef_name(&self, id: ItemIdentifier, is_cf: bool) -> ItemIdentifier {
let library_config = self.library(id.library_name());
id.map_name(|name| {
library_config
.typedef_data
.get(&name)
.and_then(|data| data.renamed.clone())
.unwrap_or(name)
.unwrap_or_else(|| {
// If a typedef's underlying type is itself a "CF pointer"
// typedef, the "alias" typedef will be imported as a
// regular typealias, with the suffix "Ref" still dropped
// from its name (if present).
//
// <https://github.com/swiftlang/swift/blob/swift-6.0.3-RELEASE/docs/CToSwiftNameTranslation.md#cf-types>
//
// NOTE: There's an extra clause that we don't support:
// > unless doing so would conflict with another
// > declaration in the same module as the typedef.
//
// We'll have to manually keep the name of those in
// translation-config.toml.
if is_cf {
if let Some(name) = name.strip_suffix("Ref") {
name.to_string()
} else {
name
}
} else {
name
}
})
})
}

Expand Down
84 changes: 44 additions & 40 deletions crates/header-translator/src/rust_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -446,8 +446,8 @@ pub enum Ty {
nullability: Nullability,
lifetime: Lifetime,
to: Box<Self>,
/// Whether the typedef's declaration has a bridge attribute.
is_bridged: bool,
/// Whether the typedef's declaration is a CF-like type.
is_cf: bool,
},
IncompleteArray {
nullability: Nullability,
Expand Down Expand Up @@ -1011,7 +1011,7 @@ impl Ty {
nullability,
lifetime,
to: Box::new(Self::Primitive(Primitive::Int)),
is_bridged: is_bridged(&declaration, context),
is_cf: false,
}
}

Expand All @@ -1038,15 +1038,18 @@ impl Ty {
};
}

let to = Self::parse(to, Lifetime::Unspecified, context);

let id = ItemIdentifier::new(&declaration, context);
let id = context.replace_typedef_name(id);
let is_cf = to.is_inner_cf_type(&id.name, is_bridged(&declaration, context));
let id = context.replace_typedef_name(id, is_cf);

Self::TypeDef {
id,
nullability,
lifetime,
to: Box::new(Self::parse(to, Lifetime::Unspecified, context)),
is_bridged: is_bridged(&declaration, context),
to: Box::new(to),
is_cf,
}
}
// Assume that functions without a prototype simply have 0 arguments.
Expand Down Expand Up @@ -1376,6 +1379,10 @@ impl Ty {
}
}

/// Determine whether the inner type of a TypeDef is a CF-like type.
///
/// Similar to what's done in Swift's implementation:
/// <https://github.com/swiftlang/swift/blob/swift-6.0.3-RELEASE/lib/ClangImporter/CFTypeInfo.cpp#L53>
pub(crate) fn is_inner_cf_type(&self, typedef_name: &str, typedef_is_bridged: bool) -> bool {
// Pre-defined list of known CF types.
// Taken from the Swift project (i.e. this is also what they do).
Expand All @@ -1393,7 +1400,7 @@ impl Ty {
// <https://github.com/llvm/llvm-project/blob/llvmorg-19.1.6/clang/lib/Analysis/CocoaConventions.cpp#L57>
match self {
// Recurse
Self::TypeDef { .. } => self.is_cf_type(),
Self::TypeDef { is_cf, .. } => *is_cf,
Self::Pointer { pointee, .. } => match &**pointee {
// Typedefs to structs are CF types if bridged, or in
// pre-defined list.
Expand All @@ -1413,21 +1420,6 @@ impl Ty {
}
}

/// Determine whether the typedef is a CF-like type.
///
/// Similar to what's done in Swift's implementation:
/// <https://github.com/swiftlang/swift/blob/swift-6.0.3-RELEASE/lib/ClangImporter/CFTypeInfo.cpp#L53>
fn is_cf_type(&self) -> bool {
if let Self::TypeDef {
id, to, is_bridged, ..
} = self
{
to.is_inner_cf_type(&id.name, *is_bridged)
} else {
false
}
}

pub(crate) fn is_objc_bool(&self) -> bool {
match self {
Self::Primitive(Primitive::ObjcBool) => true,
Expand Down Expand Up @@ -1492,8 +1484,11 @@ impl Ty {
}
},
Self::TypeDef {
id, nullability, ..
} if self.is_object_like() || self.is_cf_type() => {
id,
nullability,
is_cf,
..
} if self.is_object_like() || *is_cf => {
if *nullability == Nullability::NonNull {
write!(f, "NonNull<{}>", id.path())
} else {
Expand Down Expand Up @@ -1553,8 +1548,8 @@ impl Ty {
Self::Pointer { pointee, .. } if pointee.is_object_like() => {
write!(f, "{},", pointee.behind_pointer())?
}
Self::TypeDef { id, .. }
if generic.is_object_like() || generic.is_cf_type() =>
Self::TypeDef { id, is_cf, .. }
if generic.is_object_like() || *is_cf =>
{
write!(f, "{},", id.path())?
}
Expand Down Expand Up @@ -1635,8 +1630,11 @@ impl Ty {
}
}
Self::TypeDef {
id, nullability, ..
} if (self.is_object_like() || self.is_cf_type()) && !self.is_static_object() => {
id,
nullability,
is_cf,
..
} if (self.is_object_like() || *is_cf) && !self.is_static_object() => {
// NOTE: We return CF types as `Retained` for now, since we
// don't have support for the CF wrapper in msg_send! yet.
if *nullability == Nullability::NonNull {
Expand Down Expand Up @@ -1690,8 +1688,8 @@ impl Ty {
nullability: Nullability::Nullable,
lifetime: Lifetime::Unspecified,
to: _,
..
} if self.is_object_like() || self.is_cf_type() => {
is_cf,
} if self.is_object_like() || *is_cf => {
// NULL -> error
write!(
f,
Expand Down Expand Up @@ -1799,7 +1797,7 @@ impl Ty {
Some((res, start, end(*nullability)))
}
// TODO: Use custom CF type to do retain/release management here.
Self::TypeDef { .. } if self.is_cf_type() && !self.is_static_object() => None,
Self::TypeDef { is_cf, .. } if *is_cf && !self.is_static_object() => None,
_ => None,
}
}
Expand All @@ -1821,8 +1819,11 @@ impl Ty {
}
}
Self::TypeDef {
id, nullability, ..
} if self.is_object_like() || self.is_cf_type() => {
id,
nullability,
is_cf,
..
} if self.is_object_like() || *is_cf => {
if *nullability == Nullability::NonNull {
write!(f, "&'static {}", id.path())
} else {
Expand All @@ -1843,7 +1844,7 @@ impl Ty {
} if pointee.is_object_like() => {
write!(f, "{}", pointee.behind_pointer())
}
Self::TypeDef { id, .. } if self.is_object_like() || self.is_cf_type() => {
Self::TypeDef { id, is_cf, .. } if self.is_object_like() || *is_cf => {
write!(f, "{}", id.path())
}
Self::IncompleteArray { .. } => unimplemented!("incomplete array in typedef"),
Expand All @@ -1867,8 +1868,11 @@ impl Ty {
}
}
Self::TypeDef {
id, nullability, ..
} if self.is_object_like() || self.is_cf_type() => {
id,
nullability,
is_cf,
..
} if self.is_object_like() || *is_cf => {
if *nullability == Nullability::NonNull {
write!(f, "&{}", id.path())
} else {
Expand Down Expand Up @@ -2267,8 +2271,8 @@ impl Ty {
{
true
}
Self::TypeDef { .. }
if self.is_object_like() || self.is_cf_type() && !self.is_static_object() =>
Self::TypeDef { is_cf, .. }
if (self.is_object_like() || *is_cf) && !self.is_static_object() =>
{
true
}
Expand Down Expand Up @@ -2425,9 +2429,9 @@ mod tests {
protocols: vec![],
}),
}),
is_bridged: false,
is_cf: false,
}),
is_bridged: false,
is_cf: false,
};

assert!(ty.is_object_like());
Expand Down
8 changes: 3 additions & 5 deletions crates/header-translator/src/stmt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1067,7 +1067,6 @@ impl Stmt {
}
EntityKind::TypedefDecl => {
let id = ItemIdentifier::new(entity, context);
let id = context.replace_typedef_name(id);
let availability = Availability::parse(entity, context);
let documentation = Documentation::from_entity(entity);

Expand Down Expand Up @@ -1136,6 +1135,9 @@ impl Stmt {
return vec![];
}

let is_cf = ty.is_inner_cf_type(&id.name, is_bridged(entity, context));
let id = context.replace_typedef_name(id, is_cf);

if let Some(encoding_name) = ty.pointer_to_opaque_struct() {
if kind.is_some() {
error!(?kind, "unknown kind on opaque struct");
Expand All @@ -1144,10 +1146,6 @@ impl Stmt {
let entity = inner_struct.unwrap();
assert_eq!(entity.get_name().unwrap(), encoding_name);

// TODO: Remove `Ref` on these:
// <https://github.com/swiftlang/swift/blob/swift-6.0.3-RELEASE/docs/CToSwiftNameTranslation.md#cf-types>
let is_cf = ty.is_inner_cf_type(&id.name, is_bridged(&entity, context));

return if is_cf {
// If the class name contains the word "Mutable"
// exactly once per the usual word-boundary rules, a
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ fn.CGDisplayStreamCreateWithDispatchQueue.skipped = true
fn.CGColorSpaceRelease.skipped = true

# CoreGraphics defines this for some reason?
typedef.IOSurfaceRef.renamed = "IOSurfaceRef"
typedef.IOSurfaceRef.skipped = true
struct.__IOSurface.skipped = true

Expand Down
1 change: 1 addition & 0 deletions framework-crates/objc2-io-surface/translation-config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,6 @@ fn.IOSurfaceLookupFromXPCObject.skipped = true
fn.IOSurfaceSetOwnershipIdentity.skipped = true

# Defined in other crates too, so needs manual definition
typedef.IOSurfaceRef.renamed = "IOSurfaceRef" # TODO: Merge IOSurface and IOSurfaceRef somehow
typedef.IOSurfaceRef.skipped = true
struct.__IOSurface.skipped = true
8 changes: 8 additions & 0 deletions framework-crates/objc2-open-directory/translation-config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,11 @@ fn.ODQuerySetDispatchQueue.skipped = true
typedef._ODRecordType.skipped = true
typedef._ODAttributeType.skipped = true
typedef._ODAuthenticationType.skipped = true

# These exist both in Objective-C and CF.
# TODO: Make these somehow be the same type.
typedef.ODContextRef.renamed = "ODContextRef"
typedef.ODNodeRef.renamed = "ODNodeRef"
typedef.ODQueryRef.renamed = "ODQueryRef"
typedef.ODRecordRef.renamed = "ODRecordRef"
typedef.ODSessionRef.renamed = "ODSessionRef"
2 changes: 1 addition & 1 deletion generated
Submodule generated updated 252 files

0 comments on commit f2f7b94

Please sign in to comment.