[ObjCExport] Translate superClass and superClass generics for class and objects

^KT-65384 Verification Pending
This commit is contained in:
Sebastian Sellmair
2024-02-07 10:49:42 +01:00
committed by Space Team
parent c22149c642
commit 5b11308d1b
15 changed files with 224 additions and 83 deletions
@@ -25,4 +25,4 @@ internal fun KtClassOrObjectSymbol.getDeclaredSuperInterfaceSymbols(): List<KtCl
.filter { !it.isCloneable } // TODO: Write unit test for this
.filter { superInterface -> superInterface.classKind == KtClassKind.INTERFACE }
.toList()
}
}
@@ -7,9 +7,7 @@ package org.jetbrains.kotlin.objcexport.analysisApiUtils
import org.jetbrains.kotlin.analysis.api.KtAnalysisSession
import org.jetbrains.kotlin.analysis.api.symbols.KtClassOrObjectSymbol
import org.jetbrains.kotlin.analysis.api.types.KtClassErrorType
import org.jetbrains.kotlin.analysis.api.types.KtClassType
import org.jetbrains.kotlin.analysis.api.types.KtClassTypeQualifier
import org.jetbrains.kotlin.analysis.api.types.KtNonErrorClassType
/**
* Tries to find the superclass [KtClassOrObjectSymbol] symbol which is *not* kotlin.Any
@@ -28,20 +26,32 @@ import org.jetbrains.kotlin.analysis.api.types.KtClassTypeQualifier
*/
context(KtAnalysisSession)
internal fun KtClassOrObjectSymbol.getSuperClassSymbolNotAny(): KtClassOrObjectSymbol? {
return getSuperClassTypeNotAny()?.expandedClassSymbol
}
/**
* Tries to find the supertype of this [KtClassOrObjectSymbol] which is a superclass (not Any)
* ```kotlin
* abstract class A
*
* class B: A
*
* fun example() {
* val symbolOfB = // ...
* val typeRepresentingA = symbolOfB.getSuperClassTypeNotAny()
* }
* ```
*/
context(KtAnalysisSession)
internal fun KtClassOrObjectSymbol.getSuperClassTypeNotAny(): KtNonErrorClassType? {
return superTypes.firstNotNullOfOrNull find@{ superType ->
if (superType.isAny) return@find null
if (superType.isError && superType is KtClassErrorType) {
//Header should have just a Base type in case unresolved super type
return@find null
}
if (superType is KtClassType) {
val classifier = superType.qualifiers.firstNotNullOfOrNull { qualifier ->
(qualifier as? KtClassTypeQualifier.KtResolvedClassTypeQualifier)?.symbol
if (superType.isAny || superType.isError) return@find null
if (superType is KtNonErrorClassType) {
val classSymbol = superType.expandedClassSymbol ?: return@find null
if (classSymbol.classKind.isClass) {
return superType
}
if (classifier is KtClassOrObjectSymbol && classifier.classKind.isClass) return@find classifier
}
null
}
}
}
@@ -0,0 +1,37 @@
/*
* 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.symbols.KtClassOrObjectSymbol
import org.jetbrains.kotlin.analysis.api.types.KtNonErrorClassType
import org.jetbrains.kotlin.backend.konan.objcexport.ObjCExportClassOrProtocolName
import org.jetbrains.kotlin.backend.konan.objcexport.ObjCNonNullReferenceType
import org.jetbrains.kotlin.objcexport.analysisApiUtils.getDefaultSuperClassOrProtocolName
import org.jetbrains.kotlin.objcexport.analysisApiUtils.getSuperClassTypeNotAny
internal data class KtObjCSuperClassTranslation(
val superClassName: ObjCExportClassOrProtocolName,
val superClassGenerics: List<ObjCNonNullReferenceType>,
)
context(KtAnalysisSession, KtObjCExportSession)
internal fun KtClassOrObjectSymbol.translateSuperClass(): KtObjCSuperClassTranslation {
val superClassType = getSuperClassTypeNotAny()
val superClassName = superClassType?.getSuperClassName() ?: getDefaultSuperClassOrProtocolName()
val superClassGenerics: List<ObjCNonNullReferenceType> = superTypes
.filterIsInstance<KtNonErrorClassType>()
.find { type ->
val classSymbol = type.classSymbol as? KtClassOrObjectSymbol ?: return@find false
classSymbol.classKind.isClass
}
?.ownTypeArguments
.orEmpty()
.mapNotNull { typeProjection -> typeProjection.type?.mapToReferenceTypeIgnoringNullability() }
return KtObjCSuperClassTranslation(superClassName, superClassGenerics)
}
@@ -1,18 +0,0 @@
/*
* 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.symbols.KtClassOrObjectSymbol
import org.jetbrains.kotlin.backend.konan.objcexport.ObjCProtocol
import org.jetbrains.kotlin.objcexport.analysisApiUtils.getDeclaredSuperInterfaceSymbols
context(KtAnalysisSession, KtObjCExportSession)
internal fun KtClassOrObjectSymbol.translateSuperInterfaces(): List<ObjCProtocol> {
return getDeclaredSuperInterfaceSymbols().mapNotNull { superInterfaceSymbol ->
superInterfaceSymbol.translateToObjCProtocol()
}
}
@@ -4,10 +4,10 @@ import org.jetbrains.kotlin.analysis.api.KtAnalysisSession
import org.jetbrains.kotlin.analysis.api.symbols.KtClassKind
import org.jetbrains.kotlin.analysis.api.symbols.KtClassOrObjectSymbol
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtSymbolWithModality
import org.jetbrains.kotlin.analysis.api.symbols.nameOrAnonymous
import org.jetbrains.kotlin.analysis.api.types.KtNonErrorClassType
import org.jetbrains.kotlin.backend.konan.objcexport.*
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.objcexport.analysisApiUtils.getDefaultSuperClassOrProtocolName
import org.jetbrains.kotlin.objcexport.analysisApiUtils.getSuperClassSymbolNotAny
import org.jetbrains.kotlin.objcexport.analysisApiUtils.isVisibleInObjC
context(KtAnalysisSession, KtObjCExportSession)
@@ -15,9 +15,6 @@ fun KtClassOrObjectSymbol.translateToObjCClass(): ObjCClass? {
require(classKind == KtClassKind.CLASS)
if (!isVisibleInObjC()) return null
val superClass = getSuperClassSymbolNotAny()
val kotlinAnyName = getDefaultSuperClassOrProtocolName()
val superName = if (superClass == null) kotlinAnyName else getSuperClassName()
val enumKind = this.classKind == KtClassKind.ENUM_CLASS
val final = if (this is KtSymbolWithModality) this.modality == Modality.FINAL else false
val attributes = if (enumKind || final) listOf(OBJC_SUBCLASSING_RESTRICTED) else emptyList()
@@ -25,6 +22,8 @@ fun KtClassOrObjectSymbol.translateToObjCClass(): ObjCClass? {
val name = getObjCClassOrProtocolName()
val comment: ObjCComment? = annotationsList.translateToObjCComment()
val origin: ObjCExportStubOrigin = getObjCExportStubOrigin()
val superClass = translateSuperClass()
val superProtocols: List<String> = superProtocols()
val members: List<ObjCExportStub> = getMemberScope().getCallableSymbols().plus(getMemberScope().getConstructors())
@@ -33,20 +32,25 @@ fun KtClassOrObjectSymbol.translateToObjCClass(): ObjCClass? {
.toList()
val categoryName: String? = null
val generics: List<ObjCGenericTypeDeclaration> = emptyList()
val superClassGenerics: List<ObjCNonNullReferenceType> = emptyList()
val generics: List<ObjCGenericTypeDeclaration> = typeParameters.map { typeParameter ->
ObjCGenericTypeParameterDeclaration(
typeParameter.nameOrAnonymous.asString().toValidObjCSwiftIdentifier(),
ObjCVariance.fromKotlinVariance(typeParameter.variance)
)
}
return ObjCInterfaceImpl(
name.objCName,
comment,
origin,
attributes,
superProtocols,
members,
categoryName,
generics,
superName.objCName,
superClassGenerics
name = name.objCName,
comment = comment,
origin = origin,
attributes = attributes,
superProtocols = superProtocols,
members = members,
categoryName = categoryName,
generics = generics,
superClass = superClass.superClassName.objCName,
superClassGenerics = superClass.superClassGenerics
)
}
@@ -60,10 +64,8 @@ private fun abbreviate(name: String): String {
return normalizedName
}
/**
* See issue KT-65384
* And K1 implementation [org.jetbrains.kotlin.backend.konan.objcexport.ObjCExportTranslatorImpl.translateClass]
*/
private fun KtClassOrObjectSymbol.getSuperClassName(): ObjCExportClassOrProtocolName {
return ObjCExportClassOrProtocolName("UnimplementedSwiftName", "UnimplementedObjCName")
context(KtAnalysisSession, KtObjCExportSession)
internal fun KtNonErrorClassType.getSuperClassName(): ObjCExportClassOrProtocolName? {
val classSymbol = expandedClassSymbol ?: return null
return classSymbol.getObjCClassOrProtocolName()
}
@@ -47,7 +47,6 @@ fun translateToObjCHeader(files: List<KtFile>): ObjCHeader {
/* Add the classId to already processed classIds and do not redo if already processed */
val stub = translatedClassifiers.getOrPut(classId) {
val translatedObjCClassOrProtocol = when (symbol.classKind) {
KtClassKind.INTERFACE -> symbol.translateToObjCProtocol()
KtClassKind.CLASS -> symbol.translateToObjCClass()
@@ -56,7 +55,11 @@ fun translateToObjCHeader(files: List<KtFile>): ObjCHeader {
} ?: return result
symbol.getDeclaredSuperInterfaceSymbols().forEach { superInterfaceSymbol ->
result.addAll(process(superInterfaceSymbol))
result.addAll(process(superInterfaceSymbol, true))
}
symbol.getSuperClassSymbolNotAny()?.let { superClassSymbol ->
process(superClassSymbol, true)
}
result.add(translatedObjCClassOrProtocol)
@@ -123,10 +126,6 @@ fun translateToObjCHeader(files: List<KtFile>): ObjCHeader {
classForwardDeclarations.add(errorForwardClass)
}
protocolForwardDeclarations += stubs
.filterIsInstance<ObjCClass>()
.flatMap { it.superProtocols }
return ObjCHeader(
stubs = stubs,
classForwardDeclarations = classForwardDeclarations,
@@ -6,8 +6,6 @@ import org.jetbrains.kotlin.analysis.api.symbols.KtClassOrObjectSymbol
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtSymbolWithModality
import org.jetbrains.kotlin.backend.konan.objcexport.*
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.objcexport.analysisApiUtils.getDefaultSuperClassOrProtocolName
import org.jetbrains.kotlin.objcexport.analysisApiUtils.getSuperClassSymbolNotAny
import org.jetbrains.kotlin.objcexport.analysisApiUtils.isVisibleInObjC
context(KtAnalysisSession, KtObjCExportSession)
@@ -15,9 +13,6 @@ fun KtClassOrObjectSymbol.translateToObjCObject(): ObjCClass? {
require(classKind == KtClassKind.OBJECT)
if (!isVisibleInObjC()) return null
val superClass = getSuperClassSymbolNotAny()
val kotlinAnyName = getDefaultSuperClassOrProtocolName()
val superName = if (superClass == null) kotlinAnyName else throw RuntimeException("Super class translation isn't implemented yet")
val enumKind = this.classKind == KtClassKind.ENUM_CLASS
val final = if (this is KtSymbolWithModality) this.modality == Modality.FINAL else false
val attributes = if (enumKind || final) listOf(OBJC_SUBCLASSING_RESTRICTED) else emptyList()
@@ -28,25 +23,26 @@ fun KtClassOrObjectSymbol.translateToObjCObject(): ObjCClass? {
val superProtocols: List<String> = superProtocols()
val categoryName: String? = null
val generics: List<ObjCGenericTypeDeclaration> = emptyList()
val superClassGenerics: List<ObjCNonNullReferenceType> = emptyList()
val objectMembers = getDefaultMembers()
val superClass = translateSuperClass()
getMemberScope().getCallableSymbols()
.sortedWith(StableCallableOrder)
.flatMap { it.translateToObjCExportStubs() }
.forEach { objectMembers.add(it) }
return ObjCInterfaceImpl(
name.objCName,
comment,
origin,
attributes,
superProtocols,
objectMembers,
categoryName,
generics,
superName.objCName,
superClassGenerics
name = name.objCName,
comment = comment,
origin = origin,
attributes = attributes,
superProtocols = superProtocols,
members = objectMembers,
categoryName = categoryName,
generics = generics,
superClass = superClass.superClassName.objCName,
superClassGenerics = superClass.superClassGenerics
)
}
@@ -13,7 +13,6 @@ import org.jetbrains.kotlin.backend.konan.objcexport.ObjCProtocol
import org.jetbrains.kotlin.backend.konan.objcexport.ObjCProtocolImpl
import org.jetbrains.kotlin.backend.konan.objcexport.toNameAttributes
import org.jetbrains.kotlin.objcexport.analysisApiUtils.getDeclaredSuperInterfaceSymbols
import org.jetbrains.kotlin.objcexport.analysisApiUtils.isCloneable
import org.jetbrains.kotlin.objcexport.analysisApiUtils.isVisibleInObjC
context(KtAnalysisSession, KtObjCExportSession)
@@ -45,7 +44,6 @@ fun KtClassOrObjectSymbol.translateToObjCProtocol(): ObjCProtocol? {
context(KtAnalysisSession, KtObjCExportSession)
internal fun KtClassOrObjectSymbol.superProtocols(): List<String> {
return getDeclaredSuperInterfaceSymbols()
.filter { superInterface -> !superInterface.isCloneable }
.map { superInterface -> superInterface.getObjCClassOrProtocolName().objCName }
.toList()
}
@@ -60,7 +60,7 @@ internal fun KtType.translateToObjCReferenceType(): ObjCReferenceType {
* [org.jetbrains.kotlin.backend.konan.objcexport.ObjCExportTranslatorImpl.mapReferenceTypeIgnoringNullability]
*/
context(KtAnalysisSession, KtObjCExportSession)
private fun KtType.mapToReferenceTypeIgnoringNullability(): ObjCNonNullReferenceType {
internal fun KtType.mapToReferenceTypeIgnoringNullability(): ObjCNonNullReferenceType {
val fullyExpandedType = fullyExpandedType
val classId = (fullyExpandedType as? KtNonErrorClassType)?.classId
@@ -63,7 +63,7 @@ class ForwardedClassesAndProtocolsDependenciesTest(
fun getInterface(): InterfaceB = error("error")
""",
protocols = setOf("InterfaceB", "InterfaceA"),
classes = setOf("ClassB")
classes = setOf("ClassB", "ClassA")
)
}