[K/N] De-duplicate code for mangling objc interop function names

Extract the duplicated functionality to the
`ObjCFunctionNameMangleComputer` class.
This commit is contained in:
Sergej Jaskiewicz
2023-08-24 15:13:45 +02:00
committed by teamcity
parent 0fd4f10f6c
commit e3b5dc509c
6 changed files with 185 additions and 133 deletions
@@ -17,13 +17,11 @@ import org.jetbrains.kotlin.backend.common.serialization.mangle.ir.IrMangleCompu
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.objcinterop.*
import org.jetbrains.kotlin.ir.types.getClass
import org.jetbrains.kotlin.ir.util.hasAnnotation
import org.jetbrains.kotlin.name.NativeRuntimeNames
import org.jetbrains.kotlin.name.NativeStandardInteropNames
private val annotationsToTreatAsExported = listOf(
val ANNOTATIONS_TO_TREAT_AS_EXPORTED = listOf(
NativeRuntimeNames.Annotations.symbolNameClassId,
NativeRuntimeNames.Annotations.gcUnsafeCallClassId,
NativeRuntimeNames.Annotations.exportForCppRuntimeClassId,
@@ -31,9 +29,6 @@ private val annotationsToTreatAsExported = listOf(
NativeRuntimeNames.Annotations.exportForCompilerClassId,
)
private val IrConstructor.isObjCConstructor: Boolean
get() = hasAnnotation(NativeStandardInteropNames.objCConstructorClassId)
abstract class AbstractKonanIrMangler(
private val withReturnType: Boolean,
private val allowOutOfScopeTypeParameters: Boolean = false
@@ -46,7 +41,7 @@ abstract class AbstractKonanIrMangler(
override fun IrDeclaration.isPlatformSpecificExport(): Boolean {
if (this is IrSimpleFunction) if (isFakeOverride) return false
return annotationsToTreatAsExported.any(this::hasAnnotation)
return ANNOTATIONS_TO_TREAT_AS_EXPORTED.any(this::hasAnnotation)
}
private inner class KonanIrExportChecker(compatibleMode: Boolean) : IrExportCheckerVisitor(compatibleMode) {
@@ -65,43 +60,13 @@ abstract class AbstractKonanIrMangler(
override fun addReturnType(): Boolean = withReturnType
override fun IrFunction.platformSpecificFunctionName(): String? {
(if (this is IrConstructor && this.isObjCConstructor) this.getObjCInitMethod() else this)?.getObjCMethodInfo()
?.let {
return buildString {
if (extensionReceiverParameter != null) {
append(extensionReceiverParameter!!.type.getClass()!!.name)
append(MangleConstant.FQN_SEPARATOR)
}
append(MangleConstant.OBJC_MARK)
append(it.selector)
if (this@platformSpecificFunctionName is IrConstructor && this@platformSpecificFunctionName.isObjCConstructor) {
append(MangleConstant.OBJC_CONSTRUCTOR_MARK)
}
if ((this@platformSpecificFunctionName as? IrSimpleFunction)?.correspondingPropertySymbol != null) {
append(MangleConstant.OBJC_PROPERTY_ACCESSOR_MARK)
}
}
}
return null
}
override fun makePlatformSpecificFunctionNameMangleComputer(function: IrFunction) = IrObjCFunctionNameMangleComputer(function)
override fun IrFunction.platformSpecificFunctionMarks(): List<String> = when (origin) {
IrDeclarationOrigin.LOWERED_SUSPEND_FUNCTION -> listOfSuspendFunctionMark
else -> emptyList()
}
override fun IrFunction.specialValueParamPrefix(param: IrValueParameter): String {
// TODO: there are clashes originating from ObjectiveC interop.
// kotlinx.cinterop.ObjCClassOf<T>.create(format: kotlin.String): T defined in platform.Foundation in file Foundation.kt
// and
// kotlinx.cinterop.ObjCClassOf<T>.create(string: kotlin.String): T defined in platform.Foundation in file Foundation.kt
return if (this.hasObjCMethodAnnotation || this.hasObjCFactoryAnnotation || this.isObjCClassMethod()) "${param.name}:" else ""
}
companion object {
val listOfSuspendFunctionMark = listOf(MangleConstant.SUSPEND_FUNCTION_MARK)
}
@@ -124,7 +89,7 @@ abstract class AbstractKonanDescriptorMangler : DescriptorBasedKotlinManglerImpl
if (kind == CallableMemberDescriptor.Kind.FAKE_OVERRIDE) return false
}
return annotationsToTreatAsExported.any { annotations.hasAnnotation(it.asSingleFqName()) }
return ANNOTATIONS_TO_TREAT_AS_EXPORTED.any { annotations.hasAnnotation(it.asSingleFqName()) }
}
@@ -132,32 +97,8 @@ abstract class AbstractKonanDescriptorMangler : DescriptorBasedKotlinManglerImpl
private class KonanDescriptorMangleComputer(builder: StringBuilder, mode: MangleMode) : DescriptorMangleComputer(builder, mode) {
override fun copy(newMode: MangleMode): DescriptorMangleComputer = KonanDescriptorMangleComputer(builder, newMode)
override fun FunctionDescriptor.platformSpecificFunctionName(): String? {
(if (this is ConstructorDescriptor && this.isObjCConstructor) this.getObjCInitMethod() else this)?.getObjCMethodInfo()
?.let {
return buildString {
if (extensionReceiverParameter != null) {
append(extensionReceiverParameter!!.type.constructor.declarationDescriptor!!.name)
append(MangleConstant.FQN_SEPARATOR)
}
append(MangleConstant.OBJC_MARK)
append(it.selector)
if (this@platformSpecificFunctionName is ConstructorDescriptor && this@platformSpecificFunctionName.isObjCConstructor) {
append(MangleConstant.OBJC_CONSTRUCTOR_MARK)
}
if (this@platformSpecificFunctionName is PropertyAccessorDescriptor) {
append(MangleConstant.OBJC_PROPERTY_ACCESSOR_MARK)
}
}
}
return null
}
override fun FunctionDescriptor.specialValueParamPrefix(param: ValueParameterDescriptor): String {
return if (this.hasObjCMethodAnnotation || this.hasObjCFactoryAnnotation || this.isObjCClassMethod()) "${param.name}:" else ""
}
override fun makePlatformSpecificFunctionNameMangleComputer(function: FunctionDescriptor) =
DescriptorObjCFunctionNameMangleComputer(function)
}
}
@@ -0,0 +1,114 @@
/*
* Copyright 2010-2023 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.backend.konan.serialization
import org.jetbrains.kotlin.backend.common.serialization.mangle.MangleConstant
import org.jetbrains.kotlin.backend.common.serialization.mangle.PlatformSpecificFunctionNameMangleComputer
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI
import org.jetbrains.kotlin.ir.declarations.IrConstructor
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
import org.jetbrains.kotlin.ir.declarations.IrValueParameter
import org.jetbrains.kotlin.ir.objcinterop.*
import org.jetbrains.kotlin.ir.types.getClass
import org.jetbrains.kotlin.ir.util.hasAnnotation
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.name.NativeStandardInteropNames
import org.jetbrains.kotlin.native.interop.ObjCMethodInfo
abstract class ObjCFunctionNameMangleComputer<ValueParameter : Any> : PlatformSpecificFunctionNameMangleComputer<ValueParameter> {
abstract fun getObjCMethodInfo(): ObjCMethodInfo?
abstract fun getExtensionReceiverClassName(): Name?
abstract fun isObjCConstructor(): Boolean
abstract fun isPropertyAccessor(): Boolean
abstract fun hasObjCMethodAnnotation(): Boolean
abstract fun hasObjCFactoryAnnotation(): Boolean
abstract fun isObjCClassMethod(): Boolean
abstract fun getValueParameterName(valueParameter: ValueParameter): Name
final override fun computePlatformSpecificFunctionName(): String? {
val objcMethodInfo = getObjCMethodInfo() ?: return null
return buildString {
getExtensionReceiverClassName()?.let {
append(it)
append(MangleConstant.FQN_SEPARATOR)
}
append(MangleConstant.OBJC_MARK)
append(objcMethodInfo.selector)
if (isObjCConstructor()) {
append(MangleConstant.OBJC_CONSTRUCTOR_MARK)
}
if (isPropertyAccessor()) {
append(MangleConstant.OBJC_PROPERTY_ACCESSOR_MARK)
}
}
}
final override fun computePlatformSpecificValueParameterPrefix(valueParameter: ValueParameter): String =
if (hasObjCMethodAnnotation() || hasObjCFactoryAnnotation() || isObjCClassMethod()) {
"${getValueParameterName(valueParameter)}:"
} else {
""
}
}
@ObsoleteDescriptorBasedAPI
class DescriptorObjCFunctionNameMangleComputer(
private val function: FunctionDescriptor
) : ObjCFunctionNameMangleComputer<ValueParameterDescriptor>() {
override fun getObjCMethodInfo(): ObjCMethodInfo? =
(if (function is ConstructorDescriptor && function.isObjCConstructor) function.getObjCInitMethod() else function)
?.getObjCMethodInfo()
override fun getExtensionReceiverClassName(): Name? =
function.extensionReceiverParameter?.run { type.constructor.declarationDescriptor!!.name }
override fun isObjCConstructor(): Boolean =
function is ConstructorDescriptor && function.isObjCConstructor
override fun isPropertyAccessor(): Boolean =
function is PropertyAccessorDescriptor
override fun hasObjCMethodAnnotation(): Boolean = function.annotations.hasAnnotation(objCMethodFqName)
override fun hasObjCFactoryAnnotation(): Boolean = function.annotations.hasAnnotation(objCFactoryFqName)
override fun isObjCClassMethod(): Boolean = function.containingDeclaration.let { it is ClassDescriptor && it.isObjCClass() }
override fun getValueParameterName(valueParameter: ValueParameterDescriptor): Name = valueParameter.name
}
class IrObjCFunctionNameMangleComputer(private val function: IrFunction) : ObjCFunctionNameMangleComputer<IrValueParameter>() {
override fun getObjCMethodInfo(): ObjCMethodInfo? =
(if (function is IrConstructor && function.isObjCConstructor) function.getObjCInitMethod() else function)?.getObjCMethodInfo()
override fun getExtensionReceiverClassName(): Name? =
function.extensionReceiverParameter?.run { type.getClass()!!.name }
override fun isObjCConstructor(): Boolean =
function is IrConstructor && function.isObjCConstructor
override fun isPropertyAccessor(): Boolean =
(function as? IrSimpleFunction)?.correspondingPropertySymbol != null
override fun hasObjCMethodAnnotation(): Boolean = function.hasAnnotation(NativeStandardInteropNames.objCMethodClassId)
override fun hasObjCFactoryAnnotation(): Boolean = function.hasAnnotation(NativeStandardInteropNames.objCFactoryClassId)
override fun isObjCClassMethod(): Boolean = function.isObjCClassMethod()
override fun getValueParameterName(valueParameter: IrValueParameter): Name = valueParameter.name
}