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 842db0ed5b2..88dae17e0b9 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 @@ -22,7 +22,10 @@ internal fun ObjCExportedInterface.createCodeSpec(symbolTable: SymbolTable): Obj fun List.toObjCMethods() = createObjCMethods(this.flatMap { when (it) { - is PropertyDescriptor -> listOfNotNull(it.getter, it.setter) + is PropertyDescriptor -> listOfNotNull( + it.getter, + it.setter?.takeIf(mapper::shouldBeExposed) // Similar to [ObjCExportTranslatorImpl.buildProperty]. + ) is FunctionDescriptor -> listOf(it) else -> error(it) } 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 5b309e2bd00..c23d37ebec0 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 @@ -552,6 +552,7 @@ internal class ObjCExportTranslatorImpl( val setterName: String? val propertySetter = property.setter + // Note: the condition below is similar to "toObjCMethods" logic in [ObjCExportedInterface.createCodeSpec]. if (propertySetter != null && mapper.shouldBeExposed(propertySetter)) { val setterSelector = mapper.getBaseMethods(propertySetter).map { namer.getSelector(it) }.distinct().single() setterName = if (setterSelector != "set" + name.capitalize() + ":") setterSelector else null diff --git a/kotlin-native/backend.native/tests/objcexport/expectedLazy.h b/kotlin-native/backend.native/tests/objcexport/expectedLazy.h index 85973717d55..0bbb1375263 100644 --- a/kotlin-native/backend.native/tests/objcexport/expectedLazy.h +++ b/kotlin-native/backend.native/tests/objcexport/expectedLazy.h @@ -611,6 +611,26 @@ __attribute__((swift_name("Kt41907Kt"))) + (void)testKt41907O:(id)o __attribute__((swift_name("testKt41907(o:)"))); @end; +__attribute__((objc_subclassing_restricted)) +__attribute__((swift_name("KT43599"))) +@interface KtKT43599 : KtBase +- (instancetype)init __attribute__((swift_name("init()"))) __attribute__((objc_designated_initializer)); ++ (instancetype)new __attribute__((availability(swift, unavailable, message="use object initializers instead"))); +@property (readonly) NSString *memberProperty __attribute__((swift_name("memberProperty"))); +@end; + +@interface KtKT43599 (Kt43599Kt) +@property (readonly) NSString *extensionProperty __attribute__((swift_name("extensionProperty"))); +@end; + +__attribute__((objc_subclassing_restricted)) +__attribute__((swift_name("Kt43599Kt"))) +@interface KtKt43599Kt : KtBase ++ (void)setTopLevelLateinitPropertyValue:(NSString *)value __attribute__((swift_name("setTopLevelLateinitProperty(value:)"))); +@property (class, readonly) NSString *topLevelProperty __attribute__((swift_name("topLevelProperty"))); +@property (class, readonly) NSString *topLevelLateinitProperty __attribute__((swift_name("topLevelLateinitProperty"))); +@end; + __attribute__((objc_subclassing_restricted)) __attribute__((swift_name("LibraryKt"))) @interface KtLibraryKt : KtBase diff --git a/kotlin-native/backend.native/tests/objcexport/kt43599.kt b/kotlin-native/backend.native/tests/objcexport/kt43599.kt new file mode 100644 index 00000000000..ecd84c93da5 --- /dev/null +++ b/kotlin-native/backend.native/tests/objcexport/kt43599.kt @@ -0,0 +1,28 @@ +/* + * Copyright 2010-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the LICENSE file. + */ + +package kt43599 + +// Note: this test relies on two-stage compilation. + +class KT43599 { + var memberProperty = "memberProperty" + private set +} + +var KT43599.extensionProperty + get() = "extensionProperty" + private set(value) { TODO() } + +var topLevelProperty + get() = "topLevelProperty" + private set(value) { TODO() } + +lateinit var topLevelLateinitProperty: String + private set + +fun setTopLevelLateinitProperty(value: String) { + topLevelLateinitProperty = value +} diff --git a/kotlin-native/backend.native/tests/objcexport/kt43599.swift b/kotlin-native/backend.native/tests/objcexport/kt43599.swift new file mode 100644 index 00000000000..d7ecea36e70 --- /dev/null +++ b/kotlin-native/backend.native/tests/objcexport/kt43599.swift @@ -0,0 +1,24 @@ +/* + * Copyright 2010-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the LICENSE file. + */ + +import Kt + +private func testPropertyWithPrivateSetter() throws { + try assertEquals(actual: KT43599().memberProperty, expected: "memberProperty") + try assertEquals(actual: KT43599().extensionProperty, expected: "extensionProperty") + try assertEquals(actual: Kt43599Kt.topLevelProperty, expected: "topLevelProperty") + + // Checking the reported case too: + Kt43599Kt.setTopLevelLateinitProperty(value: "topLevelLateinitProperty") + try assertEquals(actual: Kt43599Kt.topLevelLateinitProperty, expected: "topLevelLateinitProperty") +} + +class Kt43599Tests : SimpleTestProvider { + override init() { + super.init() + + test("TestPropertyWithPrivateSetter", testPropertyWithPrivateSetter) + } +}