Skip to content

Commit

Permalink
Require counterparts to be set when implementing NSMutableCopying
Browse files Browse the repository at this point in the history
This allows us to easily see and fix the missing counterparts.
  • Loading branch information
madsmtm committed Sep 6, 2024
1 parent c31ee02 commit 25a6dd6
Show file tree
Hide file tree
Showing 11 changed files with 84 additions and 26 deletions.
62 changes: 41 additions & 21 deletions crates/header-translator/src/stmt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -289,15 +289,9 @@ pub(crate) fn items_required_by_decl(

match entity.get_kind() {
EntityKind::ObjCInterfaceDecl => {
let data = context.library(id.library_name()).class_data.get(&id.name);

for (superclass, _, _) in parse_superclasses(entity, context) {
items.push(superclass);
}
if let Some(Counterpart::MutableSubclass(subclass)) = data.map(|data| &data.counterpart)
{
items.push(subclass.clone());
}
}
EntityKind::ObjCProtocolDecl => {
for entity in parse_direct_protocols(entity, context) {
Expand Down Expand Up @@ -1965,8 +1959,35 @@ impl Stmt {
.map_name(|_| "MutableCopyingHelper".to_string())
};

let mut required_items = self.required_items();

// Assume counterparts have the same generics.
let ty = match (cls_counterpart, &*protocol.name) {
(Counterpart::ImmutableSuperclass(superclass), "NSCopying") => {
required_items.push(superclass.clone());
format!(
"{}{}",
superclass.path_in_relation_to(id),
GenericTyHelper(generics)
)
}
(Counterpart::MutableSubclass(subclass), "NSMutableCopying") => {
required_items.push(subclass.clone());
format!(
"{}{}",
subclass.path_in_relation_to(id),
GenericTyHelper(generics)
)
}
_ => "Self".into(),
};

writeln!(f)?;
write!(f, "{}", self.cfg_gate_ln(config))?;
write!(
f,
"{}",
cfg_gate_ln(required_items, [self.location()], config, self.location())
)?;
writeln!(
f,
"unsafe impl{} {} for {}{} {{",
Expand All @@ -1976,23 +1997,22 @@ impl Stmt {
GenericTyHelper(generics),
)?;

write!(f, " type Result = ")?;
// Assume counterparts have the same generics.
match (cls_counterpart, &*protocol.name) {
(Counterpart::ImmutableSuperclass(superclass), "NSCopying") => {
write!(f, "{}", superclass.path_in_relation_to(id))?;
write!(f, "{}", GenericTyHelper(generics))?;
}
(Counterpart::MutableSubclass(subclass), "NSMutableCopying") => {
write!(f, "{}", subclass.path_in_relation_to(id))?;
write!(f, "{}", GenericTyHelper(generics))?;
}
_ => write!(f, "Self")?,
}
writeln!(f, ";")?;
writeln!(f, " type Result = {ty};")?;

writeln!(f, "}}")?;
}

if protocol.name == "NSMutableCopying"
&& *cls_counterpart == Counterpart::NoCounterpart
{
error!(
?cls,
"Class implements NSMutableCopying, \
but does not have a counterpart. You should \
define the counterpart for this class, or \
ignore the NSMutableCopying implementation"
);
}
}
Self::ProtocolDecl {
id,
Expand Down
6 changes: 3 additions & 3 deletions crates/test-ui/ui/ns_copying_without_copy_helper.stderr

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion crates/test-ui/ui/protocol_object_only_protocols.stderr

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions framework-crates/objc2-app-kit/translation-config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@ static.NSApp.skipped = true
# These protocol impls would return the wrong types
class.NSTextStorage.skipped-protocols = ["NSCopying", "NSMutableCopying"]

# Set counterparts
class.NSFontCollection.counterpart = "MutableSubclass(AppKit::NSFontCollection::NSMutableFontCollection)"
class.NSMutableFontCollection.counterpart = "ImmutableSuperclass(AppKit::NSFontCollection::NSFontCollection)"
class.NSParagraphStyle.counterpart = "MutableSubclass(AppKit::NSParagraphStyle::NSMutableParagraphStyle)"
class.NSMutableParagraphStyle.counterpart = "ImmutableSuperclass(AppKit::NSParagraphStyle::NSParagraphStyle)"

# Typedef that uses a generic from a class
typedef.NSCollectionViewDiffableDataSourceItemProvider.skipped = true
class.NSCollectionViewDiffableDataSource.methods."initWithCollectionView:itemProvider:".skipped = true
Expand Down
8 changes: 8 additions & 0 deletions framework-crates/objc2-contacts/translation-config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,11 @@ maccatalyst = "13.0"
ios = "9.0"
watchos = "2.0"
visionos = "1.0"

# Set counterparts
class.CNContact.counterpart = "MutableSubclass(Contacts::CNMutableContact::CNMutableContact)"
class.CNMutableContact.counterpart = "ImmutableSuperclass(Contacts::CNContact::CNContact)"
class.CNGroup.counterpart = "MutableSubclass(Contacts::CNMutableGroup::CNMutableGroup)"
class.CNMutableGroup.counterpart = "ImmutableSuperclass(Contacts::CNGroup::CNGroup)"
class.CNPostalAddress.counterpart = "MutableSubclass(Contacts::CNMutablePostalAddress::CNMutablePostalAddress)"
class.CNMutablePostalAddress.counterpart = "ImmutableSuperclass(Contacts::CNPostalAddress::CNPostalAddress)"
6 changes: 6 additions & 0 deletions framework-crates/objc2-core-wlan/translation-config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@ required-dependencies = ["objc2-foundation"]
macos = "10.6"
maccatalyst = "13.0"

# Set counterparts
class.CWConfiguration.counterpart = "MutableSubclass(CoreWLAN::CWConfiguration::CWMutableConfiguration)"
class.CWMutableConfiguration.counterpart = "ImmutableSuperclass(CoreWLAN::CWConfiguration::CWConfiguration)"
class.CWNetworkProfile.counterpart = "MutableSubclass(CoreWLAN::CWNetworkProfile::CWMutableNetworkProfile)"
class.CWMutableNetworkProfile.counterpart = "ImmutableSuperclass(CoreWLAN::CWNetworkProfile::CWNetworkProfile)"

# Uses types from CoreFoundation
fn.CWKeychainCopyEAPUsernameAndPassword.skipped = true
fn.CWKeychainCopyEAPIdentityList.skipped = true
Expand Down
1 change: 1 addition & 0 deletions framework-crates/objc2-foundation/translation-config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ class.NSNumber.methods.new.skipped = true
class.NSSimpleCString.skipped-protocols = ["NSCopying", "NSMutableCopying"]
class.NSConstantString.skipped-protocols = ["NSCopying", "NSMutableCopying"]
class.NSPurgeableData.skipped-protocols = ["NSCopying", "NSMutableCopying"]
class.NSCountedSet.skipped-protocols = ["NSCopying", "NSMutableCopying"]

# Custom implementation for now
struct._NSRange.skipped = true
Expand Down
4 changes: 4 additions & 0 deletions framework-crates/objc2-store-kit/translation-config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,7 @@ ios = "3.0"
tvos = "9.0"
watchos = "6.2"
visionos = "1.0"

# Set counterparts
class.SKPayment.counterpart = "MutableSubclass(StoreKit::SKPayment::SKMutablePayment)"
class.SKMutablePayment.counterpart = "ImmutableSuperclass(StoreKit::SKPayment::SKPayment)"
10 changes: 10 additions & 0 deletions framework-crates/objc2-ui-kit/translation-config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,16 @@ static.UIKeyInputF1.skipped = true
# These protocol impls would return the wrong types
class.NSTextStorage.skipped-protocols = ["NSCopying", "NSMutableCopying"]

# Set counterparts
class.NSParagraphStyle.counterpart = "MutableSubclass(UIKit::NSParagraphStyle::NSMutableParagraphStyle)"
class.NSMutableParagraphStyle.counterpart = "ImmutableSuperclass(UIKit::NSParagraphStyle::NSParagraphStyle)"
class.UIApplicationShortcutItem.counterpart = "MutableSubclass(UIKit::UIApplicationShortcutItem::UIMutableApplicationShortcutItem)"
class.UIMutableApplicationShortcutItem.counterpart = "ImmutableSuperclass(UIKit::UIApplicationShortcutItem::UIApplicationShortcutItem)"
class.UIUserNotificationCategory.counterpart = "MutableSubclass(UIKit::UIUserNotificationSettings::UIMutableUserNotificationCategory)"
class.UIMutableUserNotificationCategory.counterpart = "ImmutableSuperclass(UIKit::UIUserNotificationSettings::UIUserNotificationCategory)"
class.UIUserNotificationAction.counterpart = "MutableSubclass(UIKit::UIUserNotificationSettings::UIMutableUserNotificationAction)"
class.UIMutableUserNotificationAction.counterpart = "ImmutableSuperclass(UIKit::UIUserNotificationSettings::UIUserNotificationAction)"

# These subclass a generic struct, and hence the type parameter defaults to
# `AnyObject`, which is not PartialEq, Eq nor Hash.
class.NSLayoutXAxisAnchor.derives = "Debug"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,6 @@ ios = "10.0"
tvos = "10.0"
watchos = "3.0"
visionos = "1.0"

class.UNNotificationContent.counterpart = "MutableSubclass(UserNotifications::UNNotificationContent::UNMutableNotificationContent)"
class.UNMutableNotificationContent.counterpart = "ImmutableSuperclass(UserNotifications::UNNotificationContent::UNNotificationContent)"

0 comments on commit 25a6dd6

Please sign in to comment.