[ObjCExport] Translate ObjCObject types, respecting the @ExternalObjCClass annotation

KT-65891 Fixed
This commit is contained in:
Sebastian Sellmair
2024-02-20 11:39:31 +01:00
committed by Space Team
parent a5baf42422
commit 622a88ff26
3 changed files with 141 additions and 1 deletions
@@ -0,0 +1,89 @@
/*
* 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
import org.jetbrains.kotlin.analysis.api.KtAnalysisSession
import org.jetbrains.kotlin.analysis.api.annotations.hasAnnotation
import org.jetbrains.kotlin.analysis.api.symbols.KtClassKind
import org.jetbrains.kotlin.analysis.api.symbols.KtClassOrObjectSymbol
import org.jetbrains.kotlin.analysis.api.symbols.nameOrAnonymous
import org.jetbrains.kotlin.analysis.api.types.KtNonErrorClassType
import org.jetbrains.kotlin.analysis.api.types.KtType
import org.jetbrains.kotlin.backend.konan.objcexport.*
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.name.NativeForwardDeclarationKind
import org.jetbrains.kotlin.name.NativeStandardInteropNames
import org.jetbrains.kotlin.name.NativeStandardInteropNames.cInteropPackage
import org.jetbrains.kotlin.objcexport.analysisApiUtils.getDeclaredSuperInterfaceSymbols
import org.jetbrains.kotlin.objcexport.analysisApiUtils.getSuperClassSymbolNotAny
import org.jetbrains.kotlin.objcexport.analysisApiUtils.objCErrorType
import org.jetbrains.kotlin.objcexport.extras.withRequiresForwardDeclaration
/**
* ClassId for 'kotlinx.cinterop.ObjCClass'
*/
private val objCClassClassId = ClassId(cInteropPackage, Name.identifier("ObjCClass"))
/**
* ClassId for 'kotlinx.cinterop.ObjCProtocol'
*/
private val objCProtocolClassId = ClassId(cInteropPackage, Name.identifier("ObjCProtocol"))
/**
* Special type translation for types that implement `ObjCObject`:
* Such types cannot be directly translated but need to use a supertype that is explicitly marked with an
* `@ExternalObjCClass` annotation. (See [org.jetbrains.kotlin.objcexport.analysisApiUtils.isObjCObjectType]
*/
context(KtAnalysisSession, KtObjCExportSession)
internal fun KtType.translateToObjCObjectType(): ObjCNonNullReferenceType {
if (this !is KtNonErrorClassType) return objCErrorType
val classSymbol = this.classSymbol as? KtClassOrObjectSymbol ?: return ObjCIdType
return classSymbol.translateToObjCObjectType()
}
context(KtAnalysisSession, KtObjCExportSession)
private fun KtClassOrObjectSymbol.translateToObjCObjectType(): ObjCNonNullReferenceType {
if (isObjCMetaClass()) return ObjCMetaClassType
if (isObjCProtocolClass()) return ObjCClassType("Protocol").withRequiresForwardDeclaration()
if (isExternalObjCClass() || isObjCForwardDeclaration()) {
return if (classKind == KtClassKind.INTERFACE) {
ObjCProtocolType(nameOrAnonymous.asString().removeSuffix("Protocol")).withRequiresForwardDeclaration()
} else {
ObjCClassType(nameOrAnonymous.asString()).withRequiresForwardDeclaration()
}
}
return getSuperClassSymbolNotAny()?.translateToObjCObjectType() ?: ObjCIdType
}
context(KtAnalysisSession)
private fun KtClassOrObjectSymbol.isObjCMetaClass(): Boolean {
if (classIdIfNonLocal == objCClassClassId) return true
return getDeclaredSuperInterfaceSymbols().any { superInterfaceSymbol -> superInterfaceSymbol.isObjCMetaClass() }
}
context(KtAnalysisSession)
private fun KtClassOrObjectSymbol.isObjCProtocolClass(): Boolean {
if (classIdIfNonLocal == objCProtocolClassId) return true
return getDeclaredSuperInterfaceSymbols().any { superInterfaceSymbol -> superInterfaceSymbol.isObjCProtocolClass() }
}
context(KtAnalysisSession)
private fun KtClassOrObjectSymbol.isExternalObjCClass(): Boolean {
return hasAnnotation(NativeStandardInteropNames.externalObjCClassClassId)
}
context(KtAnalysisSession)
private fun KtClassOrObjectSymbol.isObjCForwardDeclaration(): Boolean {
val classId = classIdIfNonLocal ?: return false
return when (NativeForwardDeclarationKind.packageFqNameToKind[classId.packageFqName]) {
null, NativeForwardDeclarationKind.Struct -> false
NativeForwardDeclarationKind.ObjCProtocol, NativeForwardDeclarationKind.ObjCClass -> true
}
}
@@ -89,7 +89,7 @@ internal fun KtType.mapToReferenceTypeIgnoringNullability(): ObjCNonNullReferenc
if (isObjCObjectType()) {
// KT-65891: mapObjCObjectReferenceTypeIgnoringNullability
return ObjCIdType
return translateToObjCObjectType()
}
/* Check if inline type represents 'regular' inline class */