From eeffa49cd9c381fe8977fca9f85e3c68048ee6d1 Mon Sep 17 00:00:00 2001 From: Svyatoslav Scherbina Date: Fri, 25 Jun 2021 21:59:08 +0300 Subject: [PATCH] Native: don't generate .companion in ObjCExport if the companion is not exported ^KT-47462 Fixed --- .../konan/objcexport/ObjCExportCodeSpec.kt | 2 +- .../objcexport/ObjCExportHeaderGenerator.kt | 13 ++++++--- .../tests/objcexport/expectedLazy.h | 16 +++++++++++ .../tests/objcexport/expectedLazyNoGenerics.h | 16 +++++++++++ .../tests/objcexport/kt43780.kt | 27 ++++++++++++++++++- .../tests/objcexport/kt43780.swift | 9 +++++++ 6 files changed, 78 insertions(+), 5 deletions(-) diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/objcexport/ObjCExportCodeSpec.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/objcexport/ObjCExportCodeSpec.kt index f6e2bfe6e35..acb334b5098 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/objcexport/ObjCExportCodeSpec.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/objcexport/ObjCExportCodeSpec.kt @@ -78,7 +78,7 @@ internal fun ObjCExportedInterface.createCodeSpec(symbolTable: SymbolTable): Obj methods += ObjCGetterForObjectInstance(namer.getObjectPropertySelector(descriptor), irClassSymbol) } - if (descriptor.needCompanionObjectProperty(namer)) { + if (descriptor.needCompanionObjectProperty(namer, mapper)) { methods += ObjCGetterForObjectInstance(namer.getCompanionObjectPropertySelector(descriptor), symbolTable.referenceClass(descriptor.companionObjectDescriptor!!)) } diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/objcexport/ObjCExportHeaderGenerator.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/objcexport/ObjCExportHeaderGenerator.kt index 30e224c5994..b6662882813 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/objcexport/ObjCExportHeaderGenerator.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/objcexport/ObjCExportHeaderGenerator.kt @@ -352,7 +352,7 @@ internal class ObjCExportTranslatorImpl( } } - if (descriptor.needCompanionObjectProperty(namer)) { + if (descriptor.needCompanionObjectProperty(namer, mapper)) { add { ObjCProperty( ObjCExportNamer.companionObjectPropertyName, null, @@ -1326,8 +1326,15 @@ private fun computeSuperClassType(descriptor: ClassDescriptor): KotlinType? = de internal const val OBJC_SUBCLASSING_RESTRICTED = "objc_subclassing_restricted" -internal fun ClassDescriptor.needCompanionObjectProperty(namer: ObjCExportNamer) = hasCompanionObject && - (kind != ClassKind.ENUM_CLASS || enumEntries.all { namer.getEnumEntrySelector(it) != ObjCExportNamer.companionObjectPropertyName }) +internal fun ClassDescriptor.needCompanionObjectProperty(namer: ObjCExportNamer, mapper: ObjCExportMapper): Boolean { + val companionObject = companionObjectDescriptor + if (companionObject == null || !mapper.shouldBeExposed(companionObject)) return false + + if (kind == ClassKind.ENUM_CLASS && enumEntries.any { namer.getEnumEntrySelector(it) == ObjCExportNamer.companionObjectPropertyName }) + return false // 'companion' property would clash with enum entry, don't generate it. + + return true +} private fun Deprecation.toDeprecationAttribute(): String { diff --git a/kotlin-native/backend.native/tests/objcexport/expectedLazy.h b/kotlin-native/backend.native/tests/objcexport/expectedLazy.h index adbd1bc7a9d..644e3ea91b1 100644 --- a/kotlin-native/backend.native/tests/objcexport/expectedLazy.h +++ b/kotlin-native/backend.native/tests/objcexport/expectedLazy.h @@ -857,6 +857,22 @@ __attribute__((swift_name("KT43780Enum.Companion"))) @property (readonly) int32_t x __attribute__((swift_name("x"))); @end; +__attribute__((objc_subclassing_restricted)) +__attribute__((swift_name("ClassWithInternalCompanion"))) +@interface KtClassWithInternalCompanion : KtBase +- (instancetype)init __attribute__((swift_name("init()"))) __attribute__((objc_designated_initializer)); ++ (instancetype)new __attribute__((availability(swift, unavailable, message="use object initializers instead"))); +@property (readonly) int32_t y __attribute__((swift_name("y"))); +@end; + +__attribute__((objc_subclassing_restricted)) +__attribute__((swift_name("ClassWithPrivateCompanion"))) +@interface KtClassWithPrivateCompanion : KtBase +- (instancetype)init __attribute__((swift_name("init()"))) __attribute__((objc_designated_initializer)); ++ (instancetype)new __attribute__((availability(swift, unavailable, message="use object initializers instead"))); +@property (readonly) int32_t y __attribute__((swift_name("y"))); +@end; + __attribute__((swift_name("Host"))) @protocol KtHost @required diff --git a/kotlin-native/backend.native/tests/objcexport/expectedLazyNoGenerics.h b/kotlin-native/backend.native/tests/objcexport/expectedLazyNoGenerics.h index 98c3e4b5459..61baa649b08 100644 --- a/kotlin-native/backend.native/tests/objcexport/expectedLazyNoGenerics.h +++ b/kotlin-native/backend.native/tests/objcexport/expectedLazyNoGenerics.h @@ -799,6 +799,22 @@ __attribute__((swift_name("KT43780Enum.Companion"))) @property (readonly) int32_t x __attribute__((swift_name("x"))); @end; +__attribute__((objc_subclassing_restricted)) +__attribute__((swift_name("ClassWithInternalCompanion"))) +@interface KtClassWithInternalCompanion : KtBase +- (instancetype)init __attribute__((swift_name("init()"))) __attribute__((objc_designated_initializer)); ++ (instancetype)new __attribute__((availability(swift, unavailable, message="use object initializers instead"))); +@property (readonly) int32_t y __attribute__((swift_name("y"))); +@end; + +__attribute__((objc_subclassing_restricted)) +__attribute__((swift_name("ClassWithPrivateCompanion"))) +@interface KtClassWithPrivateCompanion : KtBase +- (instancetype)init __attribute__((swift_name("init()"))) __attribute__((objc_designated_initializer)); ++ (instancetype)new __attribute__((availability(swift, unavailable, message="use object initializers instead"))); +@property (readonly) int32_t y __attribute__((swift_name("y"))); +@end; + __attribute__((swift_name("Host"))) @protocol KtHost @required diff --git a/kotlin-native/backend.native/tests/objcexport/kt43780.kt b/kotlin-native/backend.native/tests/objcexport/kt43780.kt index c255ba25d33..7163e4b3e2a 100644 --- a/kotlin-native/backend.native/tests/objcexport/kt43780.kt +++ b/kotlin-native/backend.native/tests/objcexport/kt43780.kt @@ -34,4 +34,29 @@ enum class KT43780Enum { companion object { val x = 11 } -} \ No newline at end of file +} + +class ClassWithInternalCompanion { + internal companion object { + val x = 12 + } + + val y = 13 +} + +class ClassWithPrivateCompanion { + private companion object { + val x = 14 + } + + val y = 15 +} + +// Shouldn't be exported at all: +internal class InternalClassWithCompanion { + companion object +} + +private class PrivateClassWithCompanion { + companion object +} diff --git a/kotlin-native/backend.native/tests/objcexport/kt43780.swift b/kotlin-native/backend.native/tests/objcexport/kt43780.swift index d509d42e95e..94366106631 100644 --- a/kotlin-native/backend.native/tests/objcexport/kt43780.swift +++ b/kotlin-native/backend.native/tests/objcexport/kt43780.swift @@ -37,6 +37,14 @@ private func testNameClash() throws { try assertEquals(actual: KT43780Enum.otherEntry.name, expected: "OTHER_ENTRY") } +// Reported as https://youtrack.jetbrains.com/issue/KT-47462 +private func testUnexposedCompanion() throws { + // Just trying to ensure that the classes are accessible: + try assertEquals(actual: 13, expected: ClassWithInternalCompanion().y) + try assertEquals(actual: 15, expected: ClassWithPrivateCompanion().y) + // and this doesn't make the companions accessible as well. +} + class Kt43780Tests : SimpleTestProvider { override init() { @@ -45,5 +53,6 @@ class Kt43780Tests : SimpleTestProvider { test("testObject", testObject) test("testCompanionObject", testCompanionObject) test("testNameClash", testNameClash) + test("testUnexposedCompanion", testUnexposedCompanion) } }