[ObjCExport] Support translation of enum classes
^KT-64953 Fixed
This commit is contained in:
committed by
Space Team
parent
2fb6815d7f
commit
a2d76d739c
+1
-1
@@ -25,7 +25,7 @@ context(KtAnalysisSession)
|
||||
internal fun KtNamedClassOrObjectSymbol.getInlineTargetTypeOrNull(): KtType? {
|
||||
if (!isInlineIncludingKotlinNativeSpecialClasses()) return null
|
||||
|
||||
val constructor = getMemberScope().getConstructors()
|
||||
val constructor = getDeclaredMemberScope().getConstructors()
|
||||
.find { constructor -> constructor.isPrimary && constructor.valueParameters.size == 1 }
|
||||
?: return null
|
||||
|
||||
|
||||
+5
-11
@@ -1,10 +1,7 @@
|
||||
package org.jetbrains.kotlin.objcexport.analysisApiUtils
|
||||
|
||||
import org.jetbrains.kotlin.analysis.api.KtAnalysisSession
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.KtCallableSymbol
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.KtFunctionLikeSymbol
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.KtFunctionSymbol
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.KtPropertySymbol
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.*
|
||||
import org.jetbrains.kotlin.analysis.api.types.KtFunctionalType
|
||||
import org.jetbrains.kotlin.analysis.api.types.KtType
|
||||
import org.jetbrains.kotlin.backend.konan.KonanPrimitiveType
|
||||
@@ -35,7 +32,7 @@ internal fun KtFunctionLikeSymbol.getFunctionMethodBridge(): MethodBridge {
|
||||
}
|
||||
|
||||
context(KtAnalysisSession, KtObjCExportSession)
|
||||
internal fun KtPropertySymbol.getPropertyMethodBridge(): MethodBridge {
|
||||
internal fun KtVariableLikeSymbol.getPropertyMethodBridge(): MethodBridge {
|
||||
return MethodBridge(
|
||||
bridgeReturnType(),
|
||||
receiverType,
|
||||
@@ -143,12 +140,9 @@ private fun KtCallableSymbol.bridgeReturnType(): MethodBridge.ReturnValue {
|
||||
return MethodBridge.ReturnValue.Suspend
|
||||
}
|
||||
|
||||
//TODO: handle hashCode
|
||||
// descriptor.containingDeclaration.let { it is ClassDescriptor && KotlinBuiltIns.isAny(it) } &&
|
||||
// descriptor.name.asString() == "hashCode" -> {
|
||||
// assert(!convertExceptionsToErrors)
|
||||
// MethodBridge.ReturnValue.HashCode
|
||||
// }
|
||||
if (isHashCode) {
|
||||
return MethodBridge.ReturnValue.HashCode
|
||||
}
|
||||
|
||||
//TODO: handle getter
|
||||
// descriptor is PropertyGetterDescriptor -> {
|
||||
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* 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.analysisApiUtils
|
||||
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.KtSymbol
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.KtSymbolOrigin
|
||||
|
||||
/**
|
||||
* @return `true` when the declaration is considered a `fake override`.
|
||||
* K2 will differentiate fake-overrides into 'intersection override' and 'substitution override'
|
||||
* `false` if the symbol is not a fake override
|
||||
*
|
||||
* See:
|
||||
* - [org.jetbrains.kotlin.descriptors.CallableMemberDescriptor.Kind.isReal]
|
||||
* - [KtSymbolOrigin.INTERSECTION_OVERRIDE]
|
||||
* - [KtSymbolOrigin.SUBSTITUTION_OVERRIDE]
|
||||
*/
|
||||
internal val KtSymbol.isFakeOverride: Boolean
|
||||
get() {
|
||||
val origin = this.origin
|
||||
if (origin == KtSymbolOrigin.INTERSECTION_OVERRIDE) return true
|
||||
if (origin == KtSymbolOrigin.SUBSTITUTION_OVERRIDE) return true
|
||||
return false
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* 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.analysisApiUtils
|
||||
|
||||
import org.jetbrains.kotlin.analysis.api.KtAnalysisSession
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.KtCallableSymbol
|
||||
import org.jetbrains.kotlin.name.CallableId
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.name.StandardClassIds
|
||||
|
||||
private val hashCodeCallableId = CallableId(StandardClassIds.Any, Name.identifier("hashCode"))
|
||||
|
||||
context(KtAnalysisSession)
|
||||
internal val KtCallableSymbol.isHashCode: Boolean
|
||||
get() = this.callableIdIfNonLocal == hashCodeCallableId ||
|
||||
getAllOverriddenSymbols().any { overriddenSymbol -> overriddenSymbol.callableIdIfNonLocal == hashCodeCallableId }
|
||||
-52
@@ -1,52 +0,0 @@
|
||||
package org.jetbrains.kotlin.objcexport.analysisApiUtils
|
||||
|
||||
import org.jetbrains.kotlin.analysis.api.KtAnalysisSession
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.*
|
||||
|
||||
context(KtAnalysisSession)
|
||||
internal fun KtClassOrObjectSymbol.getAllMembers(): List<KtSymbol> {
|
||||
return getMemberScope()
|
||||
.getAllSymbols()
|
||||
.sortedBy { sortMembers(it) }
|
||||
.filter { member -> member.isVisibleInObjC() }
|
||||
.toList()
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns members explicitly defined in the symbol. All super methods are excluded.
|
||||
*
|
||||
* Also handles edge case with covariant method overwrite:
|
||||
*
|
||||
* ```
|
||||
* interface A {
|
||||
* fun hello(): Any
|
||||
* }
|
||||
*
|
||||
* interface B: A {
|
||||
* override fun hello(): String
|
||||
* }
|
||||
*
|
||||
* B.getBaseMembers().isEmpty() == true
|
||||
* ```
|
||||
*
|
||||
* More context is around [org.jetbrains.kotlin.backend.konan.objcexport.ObjCExportMapperKt.isBaseMethod]
|
||||
*/
|
||||
context(KtAnalysisSession)
|
||||
internal fun KtClassOrObjectSymbol.getDeclaredMembers(): List<KtSymbol> {
|
||||
return getDeclaredMemberScope()
|
||||
.getAllSymbols()
|
||||
.sortedBy { sortMembers(it) }
|
||||
.filter { member ->
|
||||
member.isVisibleInObjC() && (member !is KtCallableSymbol || member.getAllOverriddenSymbols().isEmpty())
|
||||
}
|
||||
.toList()
|
||||
}
|
||||
|
||||
/**
|
||||
* Temp workaround of [org.jetbrains.kotlin.backend.konan.objcexport.ObjCExportTranslatorKt.makeMethodsOrderStable]
|
||||
*/
|
||||
private fun sortMembers(it: KtDeclarationSymbol) = when (it) {
|
||||
is KtConstructorSymbol -> 0
|
||||
is KtFunctionSymbol -> 1
|
||||
else -> 2
|
||||
}
|
||||
+3
-3
@@ -6,12 +6,12 @@
|
||||
package org.jetbrains.kotlin.objcexport
|
||||
|
||||
import org.jetbrains.kotlin.analysis.api.KtAnalysisSession
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.KtPropertySymbol
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.KtVariableLikeSymbol
|
||||
import org.jetbrains.kotlin.backend.konan.objcexport.ObjCExportPropertyName
|
||||
|
||||
|
||||
context(KtAnalysisSession, KtObjCExportSession)
|
||||
fun KtPropertySymbol.getObjCPropertyName(): ObjCExportPropertyName {
|
||||
context(KtAnalysisSession)
|
||||
fun KtVariableLikeSymbol.getObjCPropertyName(): ObjCExportPropertyName {
|
||||
val resolveObjCNameAnnotation = resolveObjCNameAnnotation()
|
||||
|
||||
return ObjCExportPropertyName(
|
||||
|
||||
+86
@@ -0,0 +1,86 @@
|
||||
package org.jetbrains.kotlin.objcexport
|
||||
|
||||
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.KtEnumEntrySymbol
|
||||
import org.jetbrains.kotlin.backend.konan.objcexport.*
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
context(KtAnalysisSession, KtObjCExportSession)
|
||||
internal fun KtClassOrObjectSymbol.translateEnumMembers(): List<ObjCExportStub> {
|
||||
if (classKind != KtClassKind.ENUM_CLASS) return emptyList()
|
||||
return getEnumEntries() + listOf(getEnumValuesMethod(), getEnumEntriesProperty())
|
||||
}
|
||||
|
||||
context(KtAnalysisSession, KtObjCExportSession)
|
||||
private fun KtClassOrObjectSymbol.getEnumEntries(): List<ObjCProperty> {
|
||||
val staticMembers = this.getStaticDeclaredMemberScope().getCallableSymbols().toList()
|
||||
return staticMembers.filterIsInstance<KtEnumEntrySymbol>().map { entry ->
|
||||
|
||||
val entryName = entry.getEnumEntryName(false)
|
||||
val swiftName = entry.getEnumEntryName(true)
|
||||
ObjCProperty(
|
||||
name = entryName,
|
||||
comment = null,
|
||||
origin = null,
|
||||
type = entry.returnType.mapToReferenceTypeIgnoringNullability(),
|
||||
propertyAttributes = listOf("class", "readonly"),
|
||||
declarationAttributes = listOf(swiftNameAttribute(swiftName))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* [org.jetbrains.kotlin.backend.konan.objcexport.ObjCExportTranslatorImpl.buildEnumValuesMethod]
|
||||
*/
|
||||
context(KtAnalysisSession, KtObjCExportSession)
|
||||
private fun KtClassOrObjectSymbol.getEnumValuesMethod(): ObjCMethod {
|
||||
val valuesFunctionSymbol = getStaticMemberScope().getCallableSymbols(Name.identifier("values")).firstOrNull()
|
||||
return ObjCMethod(
|
||||
comment = null,
|
||||
isInstanceMethod = false,
|
||||
returnType = valuesFunctionSymbol?.returnType?.translateToObjCReferenceType() ?: ObjCIdType,
|
||||
selectors = listOf("values"),
|
||||
parameters = emptyList(),
|
||||
attributes = listOf(swiftNameAttribute("values()")),
|
||||
origin = null
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* [org.jetbrains.kotlin.backend.konan.objcexport.ObjCExportTranslatorImpl.buildEnumEntriesProperty]
|
||||
*/
|
||||
context(KtAnalysisSession, KtObjCExportSession)
|
||||
private fun KtClassOrObjectSymbol.getEnumEntriesProperty(): ObjCProperty {
|
||||
val entriesSymbol = getStaticMemberScope().getCallableSymbols(Name.identifier("entries")).firstOrNull()
|
||||
|
||||
return ObjCProperty(
|
||||
name = "entries",
|
||||
comment = null,
|
||||
type = entriesSymbol?.returnType?.translateToObjCReferenceType() ?: ObjCIdType,
|
||||
propertyAttributes = listOf("class", "readonly"),
|
||||
declarationAttributes = listOf(swiftNameAttribute("entries")),
|
||||
origin = null,
|
||||
setterName = null,
|
||||
getterName = null
|
||||
)
|
||||
}
|
||||
|
||||
context(KtAnalysisSession)
|
||||
private fun KtEnumEntrySymbol.getEnumEntryName(forSwift: Boolean): String {
|
||||
|
||||
val propertyName: String = getObjCPropertyName().run {
|
||||
when {
|
||||
forSwift -> this.swiftName
|
||||
else -> this.objCName
|
||||
}
|
||||
}
|
||||
|
||||
// FOO_BAR_BAZ -> fooBarBaz:
|
||||
val name = propertyName.split('_').mapIndexed { index, s ->
|
||||
val lower = s.lowercase()
|
||||
if (index == 0) lower else lower.replaceFirstChar(Char::uppercaseChar)
|
||||
}.joinToString("").toIdentifier()
|
||||
return name
|
||||
}
|
||||
+31
-10
@@ -8,7 +8,7 @@ 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.hasExportForCompilerAnnotation
|
||||
import org.jetbrains.kotlin.name.StandardClassIds
|
||||
import org.jetbrains.kotlin.objcexport.analysisApiUtils.isVisibleInObjC
|
||||
|
||||
context(KtAnalysisSession, KtObjCExportSession)
|
||||
@@ -27,14 +27,27 @@ fun KtClassOrObjectSymbol.translateToObjCClass(): ObjCClass? {
|
||||
|
||||
val superClass = translateSuperClass()
|
||||
val superProtocols: List<String> = superProtocols()
|
||||
val constructors = getMemberScope().getConstructors().filter { !it.hasExportForCompilerAnnotation }
|
||||
|
||||
val members = getMemberScope().getCallableSymbols().plus(constructors)
|
||||
.sortedWith(StableCallableOrder)
|
||||
.flatMap { it.translateToObjCExportStubs() }
|
||||
.toMutableList()
|
||||
val members = buildList<ObjCExportStub> {
|
||||
/* The order of members tries to replicate the K1 implementation explicitly */
|
||||
this += translateToObjCConstructors()
|
||||
|
||||
if (needsCompanionProperty) members.add(buildCompanionProperty())
|
||||
if (needsCompanionProperty) {
|
||||
this += buildCompanionProperty()
|
||||
}
|
||||
|
||||
/* Special case so far: Just for 'Enum' we actually want to add this clone method to match K1 */
|
||||
if (classIdIfNonLocal == StandardClassIds.Enum) {
|
||||
this += cloneMethod
|
||||
}
|
||||
|
||||
this += getDeclaredMemberScope().getCallableSymbols().sortedWith(StableCallableOrder)
|
||||
.mapNotNull { it.translateToObjCExportStub() }
|
||||
|
||||
if (classKind == KtClassKind.ENUM_CLASS) {
|
||||
this += translateEnumMembers()
|
||||
}
|
||||
}
|
||||
|
||||
val categoryName: String? = null
|
||||
|
||||
@@ -59,10 +72,18 @@ fun KtClassOrObjectSymbol.translateToObjCClass(): ObjCClass? {
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
|
||||
context(KtAnalysisSession, KtObjCExportSession)
|
||||
internal fun KtNonErrorClassType.getSuperClassName(): ObjCExportClassOrProtocolName? {
|
||||
val classSymbol = expandedClassSymbol ?: return null
|
||||
return classSymbol.getObjCClassOrProtocolName()
|
||||
}
|
||||
}
|
||||
|
||||
private val cloneMethod = ObjCMethod(
|
||||
selectors = listOf("clone"),
|
||||
comment = ObjCComment(contentLines = listOf("@note This method has protected visibility in Kotlin source and is intended only for use by subclasses.")),
|
||||
origin = null,
|
||||
returnType = ObjCIdType,
|
||||
parameters = emptyList(),
|
||||
isInstanceMethod = true,
|
||||
attributes = listOf(swiftNameAttribute("clone()"))
|
||||
)
|
||||
|
||||
+26
-8
@@ -1,23 +1,31 @@
|
||||
package org.jetbrains.kotlin.objcexport
|
||||
|
||||
import org.jetbrains.kotlin.analysis.api.KtAnalysisSession
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.KtConstructorSymbol
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.KtClassKind
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.KtClassOrObjectSymbol
|
||||
import org.jetbrains.kotlin.backend.konan.descriptors.arrayTypes
|
||||
import org.jetbrains.kotlin.backend.konan.objcexport.ObjCInstanceType
|
||||
import org.jetbrains.kotlin.backend.konan.objcexport.ObjCMethod
|
||||
import org.jetbrains.kotlin.backend.konan.objcexport.ObjCParameter
|
||||
import org.jetbrains.kotlin.backend.konan.objcexport.ObjCRawType
|
||||
import org.jetbrains.kotlin.objcexport.analysisApiUtils.isArrayConstructor
|
||||
import org.jetbrains.kotlin.objcexport.analysisApiUtils.getSuperClassSymbolNotAny
|
||||
import org.jetbrains.kotlin.objcexport.analysisApiUtils.hasExportForCompilerAnnotation
|
||||
import org.jetbrains.kotlin.objcexport.analysisApiUtils.isVisibleInObjC
|
||||
|
||||
context(KtAnalysisSession, KtObjCExportSession)
|
||||
fun KtConstructorSymbol.translateToObjCConstructors(): List<ObjCMethod> {
|
||||
if (!isVisibleInObjC()) return emptyList()
|
||||
fun KtClassOrObjectSymbol.translateToObjCConstructors(): List<ObjCMethod> {
|
||||
val result = mutableListOf<ObjCMethod>()
|
||||
|
||||
result.add(buildObjCMethod())
|
||||
|
||||
if (isArrayConstructor) {
|
||||
/* Translate declared constructors */
|
||||
result += getDeclaredMemberScope().getConstructors()
|
||||
.filter { !it.hasExportForCompilerAnnotation }
|
||||
.filter { it.isVisibleInObjC() }
|
||||
.map { it.buildObjCMethod() }
|
||||
|
||||
/* Create special 'alloc' constructors */
|
||||
if (this.classIdIfNonLocal?.asFqNameString() in arrayTypes ||
|
||||
classKind.isObject || classKind == KtClassKind.ENUM_CLASS
|
||||
) {
|
||||
result.add(
|
||||
ObjCMethod(
|
||||
comment = null,
|
||||
@@ -43,6 +51,16 @@ fun KtConstructorSymbol.translateToObjCConstructors(): List<ObjCMethod> {
|
||||
)
|
||||
}
|
||||
|
||||
// Hide "unimplemented" super constructors:
|
||||
getSuperClassSymbolNotAny()?.getMemberScope()?.getConstructors().orEmpty()
|
||||
.filter { it.isVisibleInObjC() }
|
||||
.forEach { superClassConstructor ->
|
||||
val translatedSuperClassConstructor = superClassConstructor.buildObjCMethod(unavailable = true)
|
||||
if (result.none { it.name == translatedSuperClassConstructor.name }) {
|
||||
result.add(translatedSuperClassConstructor)
|
||||
}
|
||||
}
|
||||
|
||||
if (result.size == 1 && result.first().name == "init") {
|
||||
result.add(
|
||||
ObjCMethod(
|
||||
@@ -60,4 +78,4 @@ fun KtConstructorSymbol.translateToObjCConstructors(): List<ObjCMethod> {
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
+5
-7
@@ -2,17 +2,15 @@ package org.jetbrains.kotlin.objcexport
|
||||
|
||||
import org.jetbrains.kotlin.analysis.api.KtAnalysisSession
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.KtCallableSymbol
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.KtConstructorSymbol
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.KtFunctionSymbol
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.KtPropertySymbol
|
||||
import org.jetbrains.kotlin.backend.konan.objcexport.ObjCExportStub
|
||||
|
||||
context(KtAnalysisSession, KtObjCExportSession)
|
||||
internal fun KtCallableSymbol.translateToObjCExportStubs(): List<ObjCExportStub> {
|
||||
internal fun KtCallableSymbol.translateToObjCExportStub(): ObjCExportStub? {
|
||||
return when (this) {
|
||||
is KtConstructorSymbol -> translateToObjCConstructors()
|
||||
is KtPropertySymbol -> listOfNotNull(translateToObjCProperty())
|
||||
is KtFunctionSymbol -> listOfNotNull(translateToObjCMethod())
|
||||
else -> emptyList()
|
||||
is KtPropertySymbol -> translateToObjCProperty()
|
||||
is KtFunctionSymbol -> translateToObjCMethod()
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -61,7 +61,7 @@ fun translateToObjCHeader(files: List<KtFile>): ObjCHeader {
|
||||
}
|
||||
|
||||
symbol.getSuperClassSymbolNotAny()?.let { superClassSymbol ->
|
||||
process(superClassSymbol, true)
|
||||
result.addAll(process(superClassSymbol, true))
|
||||
}
|
||||
|
||||
result.add(translatedObjCClassOrProtocol)
|
||||
|
||||
+12
-15
@@ -6,12 +6,14 @@ import com.intellij.openapi.util.io.FileUtil
|
||||
import org.jetbrains.kotlin.analysis.api.KtAnalysisSession
|
||||
import org.jetbrains.kotlin.analysis.api.annotations.annotationInfos
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.*
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtNamedSymbol
|
||||
import org.jetbrains.kotlin.backend.konan.InternalKotlinNativeApi
|
||||
import org.jetbrains.kotlin.backend.konan.KonanFqNames
|
||||
import org.jetbrains.kotlin.backend.konan.objcexport.*
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.name.NameUtils
|
||||
import org.jetbrains.kotlin.objcexport.Predefined.anyMethodSelectors
|
||||
import org.jetbrains.kotlin.objcexport.Predefined.anyMethodSwiftNames
|
||||
import org.jetbrains.kotlin.objcexport.analysisApiUtils.*
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
|
||||
@@ -19,12 +21,10 @@ internal val KtCallableSymbol.isConstructor: Boolean
|
||||
get() = this is KtConstructorSymbol
|
||||
|
||||
context(KtAnalysisSession, KtObjCExportSession)
|
||||
fun KtFunctionSymbol.translateToObjCMethod(
|
||||
): ObjCMethod? {
|
||||
fun KtFunctionSymbol.translateToObjCMethod(): ObjCMethod? {
|
||||
if (!isVisibleInObjC()) return null
|
||||
if (anyMethodSelectors.containsKey(this.name)) return null //temp, find replacement for org.jetbrains.kotlin.descriptors.CallableMemberDescriptor.Kind.isReal
|
||||
if (isFakeOverride) return null
|
||||
if (isClone) return null
|
||||
|
||||
return buildObjCMethod()
|
||||
}
|
||||
|
||||
@@ -110,9 +110,10 @@ internal fun KtCallableSymbol.isRefinedInSwift(): Boolean = when {
|
||||
|
||||
context(KtAnalysisSession, KtObjCExportSession)
|
||||
internal fun KtFunctionLikeSymbol.getSwiftName(methodBridge: MethodBridge): String {
|
||||
|
||||
//assert(mapper.isBaseMethod(method)) //TODO: implement isBaseMethod
|
||||
getPredefined(this, Predefined.anyMethodSwiftNames)?.let { return it }
|
||||
if (this is KtNamedSymbol) {
|
||||
anyMethodSwiftNames[name]?.let { return it }
|
||||
}
|
||||
|
||||
val parameters = methodBridge.valueParametersAssociated(this)
|
||||
val method = this
|
||||
@@ -172,12 +173,6 @@ private fun splitSelector(selector: String): List<String> {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Not implemented [org.jetbrains.kotlin.backend.konan.objcexport.ObjCExportNamerImpl.getPredefined]
|
||||
*/
|
||||
private fun <T : Any> getPredefined(method: KtFunctionLikeSymbol, predefinedForAny: Map<Name, T>): T? {
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
* [org.jetbrains.kotlin.backend.konan.objcexport.ObjCExportNamerImpl.getSelector]
|
||||
@@ -185,7 +180,9 @@ private fun <T : Any> getPredefined(method: KtFunctionLikeSymbol, predefinedForA
|
||||
context(KtAnalysisSession, KtObjCExportSession)
|
||||
fun KtFunctionLikeSymbol.getSelector(methodBridge: MethodBridge): String {
|
||||
|
||||
getPredefined(this, anyMethodSelectors)?.let { return it }
|
||||
if (this is KtNamedSymbol) {
|
||||
anyMethodSelectors[this.name]?.let { return it }
|
||||
}
|
||||
|
||||
val parameters = methodBridge.valueParametersAssociated(this)
|
||||
|
||||
@@ -275,7 +272,7 @@ fun MethodBridge.valueParametersAssociated(
|
||||
}
|
||||
|
||||
private fun String.startsWithWords(words: String) = this.startsWith(words) &&
|
||||
(this.length == words.length || !this[words.length].isLowerCase())
|
||||
(this.length == words.length || !this[words.length].isLowerCase())
|
||||
|
||||
/**
|
||||
* [org.jetbrains.kotlin.backend.konan.objcexport.ObjCExportTranslatorImpl.mapReturnType]
|
||||
@@ -295,7 +292,7 @@ fun KtFunctionLikeSymbol.mapReturnType(returnBridge: MethodBridge.ReturnValue):
|
||||
if (!returnBridge.successMayBeZero) {
|
||||
check(
|
||||
successReturnType is ObjCNonNullReferenceType
|
||||
|| (successReturnType is ObjCPointerType && !successReturnType.nullable)
|
||||
|| (successReturnType is ObjCPointerType && !successReturnType.nullable)
|
||||
) {
|
||||
"Unexpected return type: $successReturnType in $this"
|
||||
}
|
||||
|
||||
+6
-15
@@ -23,14 +23,14 @@ fun KtClassOrObjectSymbol.translateToObjCObject(): ObjCClass? {
|
||||
val superProtocols: List<String> = superProtocols()
|
||||
val categoryName: String? = null
|
||||
val generics: List<ObjCGenericTypeDeclaration> = emptyList()
|
||||
val objectMembers = getDefaultMembers().toMutableList()
|
||||
|
||||
val superClass = translateSuperClass()
|
||||
|
||||
getMemberScope().getCallableSymbols()
|
||||
val objectMembers = mutableListOf<ObjCExportStub>()
|
||||
objectMembers += translateToObjCConstructors()
|
||||
objectMembers += getDefaultMembers()
|
||||
objectMembers += getDeclaredMemberScope().getCallableSymbols()
|
||||
.sortedWith(StableCallableOrder)
|
||||
.flatMap { it.translateToObjCExportStubs() }
|
||||
.forEach { objectMembers.add(it) }
|
||||
.mapNotNull { it.translateToObjCExportStub() }
|
||||
|
||||
return ObjCInterfaceImpl(
|
||||
name = name.objCName,
|
||||
@@ -50,15 +50,6 @@ context(KtAnalysisSession, KtObjCExportSession)
|
||||
private fun KtClassOrObjectSymbol.getDefaultMembers(): List<ObjCExportStub> {
|
||||
|
||||
val result = mutableListOf<ObjCExportStub>()
|
||||
val allocWithZoneParameter = ObjCParameter("zone", null, ObjCRawType("struct _NSZone *"), null)
|
||||
|
||||
result.add(
|
||||
ObjCMethod(null, null, false, ObjCInstanceType, listOf("alloc"), emptyList(), listOf("unavailable"))
|
||||
)
|
||||
|
||||
result.add(
|
||||
ObjCMethod(null, null, false, ObjCInstanceType, listOf("allocWithZone:"), listOf(allocWithZoneParameter), listOf("unavailable"))
|
||||
)
|
||||
|
||||
result.add(
|
||||
ObjCMethod(
|
||||
@@ -114,4 +105,4 @@ context(KtAnalysisSession, KtObjCExportSession)
|
||||
private fun getObjectPropertySelector(descriptor: KtClassOrObjectSymbol): String {
|
||||
val collides = ObjCPropertyNames.objectPropertyName == getObjectInstanceSelector(descriptor)
|
||||
return ObjCPropertyNames.objectPropertyName + (if (collides) "_" else "")
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -24,9 +24,9 @@ fun KtClassOrObjectSymbol.translateToObjCProtocol(): ObjCProtocol? {
|
||||
// TODO: Check error type!
|
||||
val name = getObjCClassOrProtocolName()
|
||||
|
||||
val members = getMemberScope().getCallableSymbols()
|
||||
val members = getDeclaredMemberScope().getCallableSymbols()
|
||||
.sortedWith(StableCallableOrder)
|
||||
.flatMap { it.translateToObjCExportStubs() }
|
||||
.mapNotNull { it.translateToObjCExportStub() }
|
||||
.toList()
|
||||
|
||||
val comment: ObjCComment? = annotationsList.translateToObjCComment()
|
||||
|
||||
+1
-1
@@ -45,7 +45,7 @@ context(KtAnalysisSession, KtObjCExportSession)
|
||||
fun KtFileSymbol.translateToObjCTopLevelInterfaceFileFacade(): ObjCInterface? {
|
||||
val topLevelCallableStubs = getFileScope().getCallableSymbols()
|
||||
.sortedWith(StableCallableOrder)
|
||||
.flatMap { callableSymbol -> callableSymbol.translateToObjCExportStubs() }
|
||||
.mapNotNull { callableSymbol -> callableSymbol.translateToObjCExportStub() }
|
||||
.toList()
|
||||
/* If there are no top level functions or properties, we do not need to export a file facade */
|
||||
.ifEmpty { return null }
|
||||
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* 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.tests
|
||||
|
||||
import org.jetbrains.kotlin.analysis.api.analyze
|
||||
import org.jetbrains.kotlin.name.StandardClassIds
|
||||
import org.jetbrains.kotlin.objcexport.analysisApiUtils.isHashCode
|
||||
import org.jetbrains.kotlin.objcexport.testUtils.InlineSourceCodeAnalysis
|
||||
import org.jetbrains.kotlin.objcexport.testUtils.getClassOrFail
|
||||
import org.jetbrains.kotlin.objcexport.testUtils.getFunctionOrFail
|
||||
import org.junit.jupiter.api.Test
|
||||
import kotlin.test.assertFalse
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
class IsHashCodeTest(
|
||||
private val inlineSourceCodeAnalysis: InlineSourceCodeAnalysis,
|
||||
) {
|
||||
|
||||
@Test
|
||||
fun `test - Any - hashCode`() {
|
||||
val file = inlineSourceCodeAnalysis.createKtFile("")
|
||||
analyze(file) {
|
||||
val anySymbol = getClassOrObjectSymbolByClassId(StandardClassIds.Any) ?: error("Missing kotlin.Any")
|
||||
val hashCodeSymbol = anySymbol.getFunctionOrFail("hashCode")
|
||||
assertTrue(hashCodeSymbol.isHashCode)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test - data class hashCode`() {
|
||||
val file = inlineSourceCodeAnalysis.createKtFile("data class Foo(val x: Int)")
|
||||
analyze(file) {
|
||||
val fooSymbol = file.getClassOrFail("Foo")
|
||||
val hashCodeSymbol = fooSymbol.getFunctionOrFail("hashCode")
|
||||
assertTrue(hashCodeSymbol.isHashCode)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test - overridden hashCode`() {
|
||||
val file = inlineSourceCodeAnalysis.createKtFile(
|
||||
"""
|
||||
class Foo {
|
||||
override fun hashCode() = 42
|
||||
}
|
||||
""".trimIndent()
|
||||
)
|
||||
|
||||
analyze(file) {
|
||||
val hashCodeSymbol = file.getClassOrFail("Foo").getFunctionOrFail("hashCode")
|
||||
assertTrue(hashCodeSymbol.isHashCode)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test - Any equals`() {
|
||||
val file = inlineSourceCodeAnalysis.createKtFile("")
|
||||
analyze(file) {
|
||||
val anySymbol = getClassOrObjectSymbolByClassId(StandardClassIds.Any) ?: error("Missing kotlin.Any")
|
||||
val hashCodeSymbol = anySymbol.getFunctionOrFail("equals")
|
||||
assertFalse(hashCodeSymbol.isHashCode)
|
||||
}
|
||||
}
|
||||
}
|
||||
-1
@@ -44,7 +44,6 @@ class ObjCExportHeaderGeneratorTest(private val generator: HeaderGenerator) {
|
||||
}
|
||||
|
||||
@Test
|
||||
@TodoAnalysisApi
|
||||
fun `test - simpleEnumClass`() {
|
||||
doTest(headersTestDataDir.resolve("simpleEnumClass"))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user