diff --git a/compiler/util-klib/src/org/jetbrains/kotlin/library/KotlinLibrary.kt b/compiler/util-klib/src/org/jetbrains/kotlin/library/KotlinLibrary.kt index 8bfb03af202..f49dbfc3ba6 100644 --- a/compiler/util-klib/src/org/jetbrains/kotlin/library/KotlinLibrary.kt +++ b/compiler/util-klib/src/org/jetbrains/kotlin/library/KotlinLibrary.kt @@ -20,6 +20,7 @@ const val KLIB_PROPERTY_CONTAINS_ERROR_CODE = "contains_error_code" // Native-specific: const val KLIB_PROPERTY_INTEROP = "interop" const val KLIB_PROPERTY_EXPORT_FORWARD_DECLARATIONS = "exportForwardDeclarations" +const val KLIB_PROPERTY_INCLUDED_FORWARD_DECLARATIONS = "includedForwardDeclarations" /** * Copy-pasted to `kotlin-native/build-tools/src/main/kotlin/org/jetbrains/kotlin/Utils.kt` @@ -104,6 +105,9 @@ val KotlinLibrary.packageFqName: String? val KotlinLibrary.exportForwardDeclarations: List get() = manifestProperties.propertyList(KLIB_PROPERTY_EXPORT_FORWARD_DECLARATIONS, escapeInQuotes = true) +val KotlinLibrary.includedForwardDeclarations: List + get() = manifestProperties.propertyList(KLIB_PROPERTY_INCLUDED_FORWARD_DECLARATIONS, escapeInQuotes = true) + val BaseKotlinLibrary.nativeTargets: List get() = manifestProperties.propertyList(KLIB_PROPERTY_NATIVE_TARGETS) diff --git a/kotlin-native/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/KotlinCodeModel.kt b/kotlin-native/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/KotlinCodeModel.kt index 91b2cda44a1..502092a779c 100644 --- a/kotlin-native/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/KotlinCodeModel.kt +++ b/kotlin-native/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/KotlinCodeModel.kt @@ -162,6 +162,8 @@ data class KotlinFunctionType( } internal val cnamesStructsPackageName = "cnames.structs" +internal val objcnamesClassesPackageName = "objcnames.classes" +internal val objcnamesProtocolsPackageName = "objcnames.protocols" object KotlinTypes { val independent = Classifier.topLevel("kotlin.native.internal", "Independent") diff --git a/kotlin-native/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/Mappings.kt b/kotlin-native/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/Mappings.kt index f4f406d7baf..74916e01e7b 100644 --- a/kotlin-native/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/Mappings.kt +++ b/kotlin-native/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/Mappings.kt @@ -37,8 +37,8 @@ fun DeclarationMapper.getKotlinClassFor( ): Classifier { val pkg = if (objCClassOrProtocol.isForwardDeclaration) { when (objCClassOrProtocol) { - is ObjCClass -> "objcnames.classes" - is ObjCProtocol -> "objcnames.protocols" + is ObjCClass -> objcnamesClassesPackageName + is ObjCProtocol -> objcnamesProtocolsPackageName } } else { this.getPackageFor(objCClassOrProtocol) @@ -539,6 +539,8 @@ internal tailrec fun ObjCClass.isNSStringOrSubclass(): Boolean = when (this.name internal fun ObjCClass.isNSStringSubclass(): Boolean = this.baseClass?.isNSStringOrSubclass() == true +internal fun ObjCClass.shouldBeIncludedIntoKotlinAPI(): Boolean = !this.isNSStringSubclass() + private fun objCPointerMirror(declarationMapper: DeclarationMapper, type: ObjCPointer): TypeMirror.ByValue { if (type is ObjCObjectPointer && type.def.isNSStringOrSubclass()) { val valueType = KotlinTypes.string diff --git a/kotlin-native/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/StubIrBuilder.kt b/kotlin-native/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/StubIrBuilder.kt index 166bd375a47..65cd797a16a 100644 --- a/kotlin-native/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/StubIrBuilder.kt +++ b/kotlin-native/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/StubIrBuilder.kt @@ -329,8 +329,9 @@ class StubIrBuilder(private val context: StubIrContext) { fun build(): StubIrBuilderResult { nativeIndex.objCProtocols.filter { !it.isForwardDeclaration }.forEach { generateStubsForObjCProtocol(it) } - nativeIndex.objCClasses.filter { !it.isForwardDeclaration && !it.isNSStringSubclass()} .forEach { generateStubsForObjCClass(it) } - nativeIndex.objCCategories.filter { !it.clazz.isNSStringSubclass() }.forEach { generateStubsForObjCCategory(it) } + nativeIndex.objCClasses.filter { !it.isForwardDeclaration && it.shouldBeIncludedIntoKotlinAPI() } + .forEach { generateStubsForObjCClass(it) } + nativeIndex.objCCategories.filter { it.clazz.shouldBeIncludedIntoKotlinAPI() }.forEach { generateStubsForObjCCategory(it) } nativeIndex.structs.forEach { generateStubsForStruct(it) } nativeIndex.enums.forEach { generateStubsForEnum(it) } nativeIndex.functions.filter { it.name !in excludedFunctions }.forEach { generateStubsForFunction(it) } diff --git a/kotlin-native/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/StubIrDriver.kt b/kotlin-native/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/StubIrDriver.kt index 7e83f3e7d1f..417f1940182 100644 --- a/kotlin-native/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/StubIrDriver.kt +++ b/kotlin-native/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/StubIrDriver.kt @@ -5,6 +5,8 @@ package org.jetbrains.kotlin.native.interop.gen import kotlinx.metadata.klib.KlibModuleMetadata +import org.jetbrains.kotlin.library.KLIB_PROPERTY_EXPORT_FORWARD_DECLARATIONS +import org.jetbrains.kotlin.library.KLIB_PROPERTY_INCLUDED_FORWARD_DECLARATIONS import org.jetbrains.kotlin.native.interop.gen.jvm.GenerationMode import org.jetbrains.kotlin.native.interop.gen.jvm.InteropConfiguration import org.jetbrains.kotlin.native.interop.gen.jvm.KotlinPlatform @@ -93,7 +95,31 @@ class StubIrContext( "$cnamesStructsPackageName.${getKotlinName(it)}" } - properties["exportForwardDeclarations"] = exportForwardDeclarations.joinToString(" ") + // Note: includedForwardDeclarations is somewhat similar to exportForwardDeclarations. But reusing the latter + // instead is undesirable: exportForwardDeclarations makes the compiler enable importing the listed declarations + // through interop library package. E.g., if `cnames.structs.Foo` is in exportForwardDeclarations of a cinterop + // klib bar with package bar, then `import bar.Foo` is valid. This is an arguable feature and a candidate for + // deprecation, so enabling it for new declarations instead is undesirable. + // That's why, to make the included Obj-C forward declarations known to the compiler, we have to create a new + // manifest property for that. + val includedForwardDeclarations = mutableListOf() + includedForwardDeclarations.addAll(exportForwardDeclarations) + + // TODO: should we add meta classes? + nativeIndex.objCClasses + .filter { it.isForwardDeclaration && it.shouldBeIncludedIntoKotlinAPI() } + .mapTo(includedForwardDeclarations) { + "$objcnamesClassesPackageName.${it.kotlinClassName(isMeta = false)}" + } + + nativeIndex.objCProtocols + .filter { it.isForwardDeclaration } + .mapTo(includedForwardDeclarations) { + "$objcnamesProtocolsPackageName.${it.kotlinClassName(isMeta = false)}" + } + + properties[KLIB_PROPERTY_EXPORT_FORWARD_DECLARATIONS] = exportForwardDeclarations.joinToString(" ") + properties[KLIB_PROPERTY_INCLUDED_FORWARD_DECLARATIONS] = includedForwardDeclarations.joinToString(" ") // TODO: consider exporting Objective-C class and protocol forward refs. }