[ObjCExport] ObjCType: Implement HasExtras instead of HasMutableExtras

... to enforce the immutability concept of this entities.

KT-65891 Fixed
This commit is contained in:
Sebastian Sellmair
2024-02-21 13:37:33 +01:00
committed by Space Team
parent 704379934e
commit 6b6808d87c
9 changed files with 118 additions and 41 deletions
@@ -4,7 +4,8 @@ import org.jetbrains.kotlin.analysis.api.types.KtClassErrorType
import org.jetbrains.kotlin.analysis.api.types.KtType import org.jetbrains.kotlin.analysis.api.types.KtType
import org.jetbrains.kotlin.backend.konan.objcexport.* import org.jetbrains.kotlin.backend.konan.objcexport.*
import org.jetbrains.kotlin.objcexport.KtObjCExportSession import org.jetbrains.kotlin.objcexport.KtObjCExportSession
import org.jetbrains.kotlin.objcexport.extras.withRequiresForwardDeclaration import org.jetbrains.kotlin.objcexport.extras.objCTypeExtras
import org.jetbrains.kotlin.objcexport.extras.requiresForwardDeclaration
/** /**
* Traverses stubs and returns true if [objCErrorType] is used as a return, parameter or property type * Traverses stubs and returns true if [objCErrorType] is used as a return, parameter or property type
@@ -45,4 +46,6 @@ internal val errorInterface
superClassGenerics = emptyList() superClassGenerics = emptyList()
) )
internal val objCErrorType = ObjCClassType(errorClassName).withRequiresForwardDeclaration() internal val objCErrorType = ObjCClassType(errorClassName, extras = objCTypeExtras {
requiresForwardDeclaration = true
})
@@ -6,8 +6,9 @@ import org.jetbrains.kotlin.backend.konan.objcexport.ObjCClassType
import org.jetbrains.kotlin.backend.konan.objcexport.ObjCProperty import org.jetbrains.kotlin.backend.konan.objcexport.ObjCProperty
import org.jetbrains.kotlin.backend.konan.objcexport.swiftNameAttribute import org.jetbrains.kotlin.backend.konan.objcexport.swiftNameAttribute
import org.jetbrains.kotlin.objcexport.analysisApiUtils.isCompanion import org.jetbrains.kotlin.objcexport.analysisApiUtils.isCompanion
import org.jetbrains.kotlin.objcexport.extras.withOriginClassId import org.jetbrains.kotlin.objcexport.extras.objCTypeExtras
import org.jetbrains.kotlin.objcexport.extras.withRequiresForwardDeclaration import org.jetbrains.kotlin.objcexport.extras.originClassId
import org.jetbrains.kotlin.objcexport.extras.requiresForwardDeclaration
/** /**
* If object class has companion object it needs to have property which returns this companion. * If object class has companion object it needs to have property which returns this companion.
@@ -25,9 +26,10 @@ internal fun KtClassOrObjectSymbol.buildCompanionProperty(): ObjCProperty {
name = propertyName, name = propertyName,
comment = null, comment = null,
origin = null, origin = null,
type = ObjCClassType(typeName.objCName) type = ObjCClassType(typeName.objCName, extras = objCTypeExtras {
.withRequiresForwardDeclaration() requiresForwardDeclaration = true
.withOriginClassId(companion.classIdIfNonLocal), originClassId = companion.classIdIfNonLocal
}),
propertyAttributes = listOf("class", "readonly"), propertyAttributes = listOf("class", "readonly"),
getterName = propertyName, getterName = propertyName,
declarationAttributes = listOf(swiftNameAttribute(propertyName)) declarationAttributes = listOf(swiftNameAttribute(propertyName))
@@ -0,0 +1,26 @@
/*
* Copyright 2010-2024 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.objcexport.extras
import org.jetbrains.kotlin.backend.konan.objcexport.ObjCType
import org.jetbrains.kotlin.tooling.core.Extras
import org.jetbrains.kotlin.tooling.core.MutableExtras
import org.jetbrains.kotlin.tooling.core.mutableExtrasOf
/**
* Acts as scope for discoverable 'builder functions'
* - See [objCTypeExtras] factory function
* - See [MutableExtras.originClassId] as example for declaring a discoverable API for types
* - See [MutableExtras.requiresForwardDeclaration] "="
*/
internal object ObjCTypeExtrasBuilderContext
/**
* Convenience function for building extras for [ObjCType]
*/
internal fun objCTypeExtras(builder: context(ObjCTypeExtrasBuilderContext) MutableExtras.() -> Unit): Extras {
return mutableExtrasOf().also { extras -> builder(ObjCTypeExtrasBuilderContext, extras) }
}
@@ -6,12 +6,13 @@
package org.jetbrains.kotlin.objcexport.extras package org.jetbrains.kotlin.objcexport.extras
import org.jetbrains.kotlin.backend.konan.objcexport.ObjCNullableReferenceType import org.jetbrains.kotlin.backend.konan.objcexport.ObjCNullableReferenceType
import org.jetbrains.kotlin.backend.konan.objcexport.ObjCReferenceType
import org.jetbrains.kotlin.backend.konan.objcexport.ObjCType import org.jetbrains.kotlin.backend.konan.objcexport.ObjCType
import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.tooling.core.MutableExtras
import org.jetbrains.kotlin.tooling.core.extrasKeyOf import org.jetbrains.kotlin.tooling.core.extrasKeyOf
private val originClassIdKey = extrasKeyOf<ClassId>()
private val originClassIdKey = extrasKeyOf<ClassId?>()
/** /**
* Tracks the Kotlin origin associated with [this] [ObjCType]. * Tracks the Kotlin origin associated with [this] [ObjCType].
@@ -30,9 +31,11 @@ internal val ObjCType.originClassId: ClassId?
} }
/** /**
* See [originClassId] * See [ObjCType.originClassId]
*/ */
internal fun <T : ObjCReferenceType> T.withOriginClassId(classId: ClassId?): T = also { type -> context(ObjCTypeExtrasBuilderContext)
if (classId != null) type.extras[originClassIdKey] = classId internal var MutableExtras.originClassId: ClassId?
else type.extras.remove(originClassIdKey) get() = this[originClassIdKey]
} set(value) {
this[originClassIdKey] = value
}
@@ -6,8 +6,8 @@
package org.jetbrains.kotlin.objcexport.extras package org.jetbrains.kotlin.objcexport.extras
import org.jetbrains.kotlin.backend.konan.objcexport.ObjCReferenceType import org.jetbrains.kotlin.backend.konan.objcexport.ObjCReferenceType
import org.jetbrains.kotlin.tooling.core.MutableExtras
import org.jetbrains.kotlin.tooling.core.extrasKeyOf import org.jetbrains.kotlin.tooling.core.extrasKeyOf
import org.jetbrains.kotlin.tooling.core.readWriteProperty
private val requiresForwardDeclarationKey = extrasKeyOf<Boolean>("isForwardDeclaration") private val requiresForwardDeclarationKey = extrasKeyOf<Boolean>("isForwardDeclaration")
@@ -16,13 +16,16 @@ private val requiresForwardDeclarationKey = extrasKeyOf<Boolean>("isForwardDecla
* - Default value: `false`. * - Default value: `false`.
* - Example: All types used in function and method signature are expected to render forward declarations * - Example: All types used in function and method signature are expected to render forward declarations
*/ */
internal val ObjCReferenceType.requiresForwardDeclaration by requiresForwardDeclarationKey.readWriteProperty.notNull(false) internal val ObjCReferenceType.requiresForwardDeclaration: Boolean get() = extras[requiresForwardDeclarationKey] ?: false
/** /**
* ⚠️ Marks [this] [ObjCReferenceType] as 'requires forward declaration' and returns the same instance. * ⚠️ Marks [this] [ObjCReferenceType] as 'requires forward declaration' and returns the same instance.
* This method shall be used during the construction of a new type. * This method shall be used during the construction of a new type.
* @see ObjCReferenceType.requiresForwardDeclaration * @see ObjCReferenceType.requiresForwardDeclaration
*/ */
internal fun <T : ObjCReferenceType> T.withRequiresForwardDeclaration(): T = also { type -> context(ObjCTypeExtrasBuilderContext)
type.extras[requiresForwardDeclarationKey] = true internal var MutableExtras.requiresForwardDeclaration: Boolean
} get() = this[requiresForwardDeclarationKey] ?: false
set(value) {
this[requiresForwardDeclarationKey] = value
}
@@ -8,8 +8,9 @@ import org.jetbrains.kotlin.backend.konan.objcexport.*
import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.objcexport.analysisApiUtils.isCompanion import org.jetbrains.kotlin.objcexport.analysisApiUtils.isCompanion
import org.jetbrains.kotlin.objcexport.analysisApiUtils.isVisibleInObjC import org.jetbrains.kotlin.objcexport.analysisApiUtils.isVisibleInObjC
import org.jetbrains.kotlin.objcexport.extras.withOriginClassId import org.jetbrains.kotlin.objcexport.extras.objCTypeExtras
import org.jetbrains.kotlin.objcexport.extras.withRequiresForwardDeclaration import org.jetbrains.kotlin.objcexport.extras.originClassId
import org.jetbrains.kotlin.objcexport.extras.requiresForwardDeclaration
context(KtAnalysisSession, KtObjCExportSession) context(KtAnalysisSession, KtObjCExportSession)
fun KtClassOrObjectSymbol.translateToObjCObject(): ObjCClass? { fun KtClassOrObjectSymbol.translateToObjCObject(): ObjCClass? {
@@ -85,8 +86,14 @@ private fun KtClassOrObjectSymbol.getDefaultMembers(): List<ObjCExportStub> {
* See also: [org.jetbrains.kotlin.backend.konan.objcexport.ObjCExportTranslatorImpl.mapReferenceType] * See also: [org.jetbrains.kotlin.backend.konan.objcexport.ObjCExportTranslatorImpl.mapReferenceType]
*/ */
context(KtAnalysisSession, KtObjCExportSession) context(KtAnalysisSession, KtObjCExportSession)
private fun KtClassOrObjectSymbol.toPropertyType() = ObjCClassType(getObjCClassOrProtocolName().objCName, emptyList(),) private fun KtClassOrObjectSymbol.toPropertyType() = ObjCClassType(
.withRequiresForwardDeclaration().withOriginClassId(classIdIfNonLocal) className = getObjCClassOrProtocolName().objCName,
typeArguments = emptyList(),
extras = objCTypeExtras {
requiresForwardDeclaration = true
originClassId = classIdIfNonLocal
}
)
/** /**
* [org.jetbrains.kotlin.backend.konan.objcexport.ObjCExportNamerImpl.getObjectInstanceSelector] * [org.jetbrains.kotlin.backend.konan.objcexport.ObjCExportNamerImpl.getObjectInstanceSelector]
@@ -21,7 +21,8 @@ import org.jetbrains.kotlin.name.NativeStandardInteropNames.cInteropPackage
import org.jetbrains.kotlin.objcexport.analysisApiUtils.getDeclaredSuperInterfaceSymbols import org.jetbrains.kotlin.objcexport.analysisApiUtils.getDeclaredSuperInterfaceSymbols
import org.jetbrains.kotlin.objcexport.analysisApiUtils.getSuperClassSymbolNotAny import org.jetbrains.kotlin.objcexport.analysisApiUtils.getSuperClassSymbolNotAny
import org.jetbrains.kotlin.objcexport.analysisApiUtils.objCErrorType import org.jetbrains.kotlin.objcexport.analysisApiUtils.objCErrorType
import org.jetbrains.kotlin.objcexport.extras.withRequiresForwardDeclaration import org.jetbrains.kotlin.objcexport.extras.objCTypeExtras
import org.jetbrains.kotlin.objcexport.extras.requiresForwardDeclaration
/** /**
* ClassId for 'kotlinx.cinterop.ObjCClass' * ClassId for 'kotlinx.cinterop.ObjCClass'
@@ -49,13 +50,19 @@ internal fun KtType.translateToObjCObjectType(): ObjCNonNullReferenceType {
context(KtAnalysisSession, KtObjCExportSession) context(KtAnalysisSession, KtObjCExportSession)
private fun KtClassOrObjectSymbol.translateToObjCObjectType(): ObjCNonNullReferenceType { private fun KtClassOrObjectSymbol.translateToObjCObjectType(): ObjCNonNullReferenceType {
if (isObjCMetaClass()) return ObjCMetaClassType if (isObjCMetaClass()) return ObjCMetaClassType
if (isObjCProtocolClass()) return ObjCClassType("Protocol").withRequiresForwardDeclaration() if (isObjCProtocolClass()) return ObjCClassType("Protocol", extras = objCTypeExtras {
requiresForwardDeclaration = true
})
if (isExternalObjCClass() || isObjCForwardDeclaration()) { if (isExternalObjCClass() || isObjCForwardDeclaration()) {
return if (classKind == KtClassKind.INTERFACE) { return if (classKind == KtClassKind.INTERFACE) {
ObjCProtocolType(nameOrAnonymous.asString().removeSuffix("Protocol")).withRequiresForwardDeclaration() ObjCProtocolType(nameOrAnonymous.asString().removeSuffix("Protocol"), extras = objCTypeExtras {
requiresForwardDeclaration = true
})
} else { } else {
ObjCClassType(nameOrAnonymous.asString()).withRequiresForwardDeclaration() ObjCClassType(nameOrAnonymous.asString(), extras = objCTypeExtras {
requiresForwardDeclaration = true
})
} }
} }
@@ -19,8 +19,9 @@ import org.jetbrains.kotlin.objcexport.analysisApiUtils.getInlineTargetTypeOrNul
import org.jetbrains.kotlin.objcexport.analysisApiUtils.isError import org.jetbrains.kotlin.objcexport.analysisApiUtils.isError
import org.jetbrains.kotlin.objcexport.analysisApiUtils.isObjCObjectType import org.jetbrains.kotlin.objcexport.analysisApiUtils.isObjCObjectType
import org.jetbrains.kotlin.objcexport.analysisApiUtils.objCErrorType import org.jetbrains.kotlin.objcexport.analysisApiUtils.objCErrorType
import org.jetbrains.kotlin.objcexport.extras.withOriginClassId import org.jetbrains.kotlin.objcexport.extras.objCTypeExtras
import org.jetbrains.kotlin.objcexport.extras.withRequiresForwardDeclaration import org.jetbrains.kotlin.objcexport.extras.originClassId
import org.jetbrains.kotlin.objcexport.extras.requiresForwardDeclaration
/** /**
@@ -106,13 +107,24 @@ internal fun KtType.mapToReferenceTypeIgnoringNullability(): ObjCNonNullReferenc
} }
if (fullyExpandedType is KtNonErrorClassType) { if (fullyExpandedType is KtNonErrorClassType) {
// TODO NOW: create type translation test
return if (classSymbol?.classKind == KtClassKind.INTERFACE) { return if (classSymbol?.classKind == KtClassKind.INTERFACE) {
ObjCProtocolType(fullyExpandedType.objCTypeName) ObjCProtocolType(
protocolName = fullyExpandedType.objCTypeName,
extras = objCTypeExtras {
requiresForwardDeclaration = true
originClassId = classId
}
)
} else { } else {
ObjCClassType(fullyExpandedType.objCTypeName, translateTypeArgumentsToObjC()) ObjCClassType(
}.withRequiresForwardDeclaration().withOriginClassId(classId) className = fullyExpandedType.objCTypeName,
typeArguments = translateTypeArgumentsToObjC(),
extras = objCTypeExtras {
requiresForwardDeclaration = true
originClassId = classId
}
)
}
} }
if (fullyExpandedType is KtTypeParameterType) { if (fullyExpandedType is KtTypeParameterType) {
@@ -6,14 +6,12 @@
package org.jetbrains.kotlin.backend.konan.objcexport package org.jetbrains.kotlin.backend.konan.objcexport
import org.jetbrains.kotlin.backend.konan.InternalKotlinNativeApi import org.jetbrains.kotlin.backend.konan.InternalKotlinNativeApi
import org.jetbrains.kotlin.tooling.core.HasMutableExtras import org.jetbrains.kotlin.tooling.core.Extras
import org.jetbrains.kotlin.tooling.core.MutableExtras import org.jetbrains.kotlin.tooling.core.HasExtras
import org.jetbrains.kotlin.tooling.core.mutableExtrasOf import org.jetbrains.kotlin.tooling.core.emptyExtras
import org.jetbrains.kotlin.types.Variance import org.jetbrains.kotlin.types.Variance
sealed class ObjCType : HasMutableExtras { sealed class ObjCType : HasExtras {
override val extras: MutableExtras = mutableExtrasOf()
final override fun toString(): String = this.render() final override fun toString(): String = this.render()
abstract fun render(attrsAndName: String): String abstract fun render(attrsAndName: String): String
@@ -26,6 +24,7 @@ sealed class ObjCType : HasMutableExtras {
data class ObjCRawType( data class ObjCRawType(
val rawText: String, val rawText: String,
override val extras: Extras = emptyExtras()
) : ObjCType() { ) : ObjCType() {
override fun render(attrsAndName: String): String = rawText.withAttrsAndName(attrsAndName) override fun render(attrsAndName: String): String = rawText.withAttrsAndName(attrsAndName)
} }
@@ -36,6 +35,7 @@ sealed class ObjCNonNullReferenceType : ObjCReferenceType()
data class ObjCNullableReferenceType( data class ObjCNullableReferenceType(
val nonNullType: ObjCNonNullReferenceType, val nonNullType: ObjCNonNullReferenceType,
val isNullableResult: Boolean = false, val isNullableResult: Boolean = false,
override val extras: Extras = emptyExtras(),
) : ObjCReferenceType() { ) : ObjCReferenceType() {
override fun render(attrsAndName: String): String { override fun render(attrsAndName: String): String {
val attribute = if (isNullableResult) objcNullableResultAttribute else objcNullableAttribute val attribute = if (isNullableResult) objcNullableResultAttribute else objcNullableAttribute
@@ -46,6 +46,7 @@ data class ObjCNullableReferenceType(
data class ObjCClassType( data class ObjCClassType(
val className: String, val className: String,
val typeArguments: List<ObjCNonNullReferenceType> = emptyList(), val typeArguments: List<ObjCNonNullReferenceType> = emptyList(),
override val extras: Extras = emptyExtras()
) : ObjCNonNullReferenceType() { ) : ObjCNonNullReferenceType() {
@@ -68,29 +69,37 @@ sealed class ObjCGenericTypeUsage : ObjCNonNullReferenceType() {
} }
} }
data class ObjCGenericTypeRawUsage(override val typeName: String) : ObjCGenericTypeUsage() data class ObjCGenericTypeRawUsage(
override val typeName: String,
override val extras: Extras = emptyExtras()
) : ObjCGenericTypeUsage()
data class ObjCGenericTypeParameterUsage( data class ObjCGenericTypeParameterUsage(
override val typeName: String, override val typeName: String,
override val extras: Extras = emptyExtras()
) : ObjCGenericTypeUsage() ) : ObjCGenericTypeUsage()
data class ObjCProtocolType( data class ObjCProtocolType(
val protocolName: String, val protocolName: String,
override val extras: Extras = emptyExtras()
) : ObjCNonNullReferenceType() { ) : ObjCNonNullReferenceType() {
override fun render(attrsAndName: String) = "id<$protocolName>".withAttrsAndName(attrsAndName) override fun render(attrsAndName: String) = "id<$protocolName>".withAttrsAndName(attrsAndName)
} }
object ObjCIdType : ObjCNonNullReferenceType() { object ObjCIdType : ObjCNonNullReferenceType() {
override val extras: Extras = emptyExtras()
override fun render(attrsAndName: String) = "id".withAttrsAndName(attrsAndName) override fun render(attrsAndName: String) = "id".withAttrsAndName(attrsAndName)
} }
object ObjCInstanceType : ObjCNonNullReferenceType() { object ObjCInstanceType : ObjCNonNullReferenceType() {
override val extras: Extras = emptyExtras()
override fun render(attrsAndName: String): String = "instancetype".withAttrsAndName(attrsAndName) override fun render(attrsAndName: String): String = "instancetype".withAttrsAndName(attrsAndName)
} }
data class ObjCBlockPointerType( data class ObjCBlockPointerType(
val returnType: ObjCType, val returnType: ObjCType,
val parameterTypes: List<ObjCReferenceType>, val parameterTypes: List<ObjCReferenceType>,
override val extras: Extras = emptyExtras()
) : ObjCNonNullReferenceType() { ) : ObjCNonNullReferenceType() {
override fun render(attrsAndName: String) = returnType.render(buildString { override fun render(attrsAndName: String) = returnType.render(buildString {
append("(^") append("(^")
@@ -103,12 +112,15 @@ data class ObjCBlockPointerType(
} }
object ObjCMetaClassType : ObjCNonNullReferenceType() { object ObjCMetaClassType : ObjCNonNullReferenceType() {
override val extras: Extras = emptyExtras()
override fun render(attrsAndName: String): String = "Class".withAttrsAndName(attrsAndName) override fun render(attrsAndName: String): String = "Class".withAttrsAndName(attrsAndName)
} }
sealed class ObjCPrimitiveType( sealed class ObjCPrimitiveType(
val cName: String, val cName: String,
) : ObjCType() { ) : ObjCType() {
override val extras: Extras = emptyExtras()
object NSUInteger : ObjCPrimitiveType("NSUInteger") object NSUInteger : ObjCPrimitiveType("NSUInteger")
object BOOL : ObjCPrimitiveType("BOOL") object BOOL : ObjCPrimitiveType("BOOL")
object unichar : ObjCPrimitiveType("unichar") object unichar : ObjCPrimitiveType("unichar")
@@ -140,6 +152,7 @@ sealed class ObjCPrimitiveType(
data class ObjCPointerType( data class ObjCPointerType(
val pointee: ObjCType, val pointee: ObjCType,
val nullable: Boolean = false, val nullable: Boolean = false,
override val extras: Extras = emptyExtras()
) : ObjCType() { ) : ObjCType() {
override fun render(attrsAndName: String) = override fun render(attrsAndName: String) =
pointee.render( pointee.render(
@@ -154,6 +167,7 @@ data class ObjCPointerType(
} }
object ObjCVoidType : ObjCType() { object ObjCVoidType : ObjCType() {
override val extras: Extras = emptyExtras()
override fun render(attrsAndName: String) = "void".withAttrsAndName(attrsAndName) override fun render(attrsAndName: String) = "void".withAttrsAndName(attrsAndName)
} }