Support exposing Kotlin methods as Objective-C actions and outlets
This commit is contained in:
committed by
SvyatoslavScherbina
parent
2f30c15b45
commit
5a7e3e20b4
@@ -62,7 +62,11 @@ inline fun <T : ObjCObject?> interpretObjCPointerOrNull(rawPtr: NativePtr): T? =
|
||||
null
|
||||
}
|
||||
|
||||
inline fun <T : ObjCObject?> interpretObjCPointer(rawPtr: NativePtr): T? = interpretObjCPointerOrNull<T>(rawPtr)!!
|
||||
inline fun <T : ObjCObject> interpretObjCPointer(rawPtr: NativePtr): T = if (rawPtr != nativeNullPtr) {
|
||||
ObjCPointerHolder(rawPtr).uncheckedCast<T>()
|
||||
} else {
|
||||
throw NullPointerException()
|
||||
}
|
||||
|
||||
inline val ObjCObject.rawPtr: NativePtr get() = (this.uncheckedCast<ObjCPointerHolder>()).rawPtr
|
||||
inline val ObjCObject?.rawPtr: NativePtr get() = if (this != null) {
|
||||
@@ -105,6 +109,10 @@ annotation class ObjCConstructor(val initSelector: String)
|
||||
@Retention(AnnotationRetention.BINARY)
|
||||
annotation class InteropStubs()
|
||||
|
||||
@Target(AnnotationTarget.FUNCTION)
|
||||
@Retention(AnnotationRetention.SOURCE)
|
||||
private annotation class ObjCMethodImp(val selector: String, val encoding: String)
|
||||
|
||||
@konan.internal.ExportForCompiler
|
||||
private fun <T : ObjCObject> allocObjCObject(clazz: NativePtr): T {
|
||||
val rawResult = objc_allocWithZone(clazz)
|
||||
|
||||
@@ -28,4 +28,20 @@ inline fun <R> autoreleasepool(block: () -> R): R {
|
||||
// TODO: null checks
|
||||
var <T : ObjCObject?> ObjCObjectVar<T>.value: T
|
||||
get() = interpretObjCPointerOrNull<T>(nativeMemUtils.getNativePtr(this)).uncheckedCast<T>()
|
||||
set(value) = nativeMemUtils.putNativePtr(this, value.rawPtr)
|
||||
set(value) = nativeMemUtils.putNativePtr(this, value.rawPtr)
|
||||
|
||||
/**
|
||||
* Makes Kotlin method in Objective-C class accessible through Objective-C dispatch
|
||||
* to be used as action sent by control in UIKit or AppKit.
|
||||
*/
|
||||
@Target(AnnotationTarget.FUNCTION)
|
||||
@Retention(AnnotationRetention.SOURCE)
|
||||
annotation class ObjCAction
|
||||
|
||||
/**
|
||||
* Makes Kotlin property in Objective-C class settable through Objective-C dispatch
|
||||
* to be used as IB outlet.
|
||||
*/
|
||||
@Target(AnnotationTarget.PROPERTY)
|
||||
@Retention(AnnotationRetention.SOURCE)
|
||||
annotation class ObjCOutlet
|
||||
|
||||
+9
@@ -152,6 +152,15 @@ internal class InteropBuiltIns(builtIns: KonanBuiltIns) {
|
||||
val getObjCMessenger = packageScope.getContributedFunctions("getMessenger").single()
|
||||
val getObjCMessengerLU = packageScope.getContributedFunctions("getMessengerLU").single()
|
||||
|
||||
val interpretObjCPointerOrNull = packageScope.getContributedFunctions("interpretObjCPointerOrNull").single()
|
||||
val interpretObjCPointer = packageScope.getContributedFunctions("interpretObjCPointer").single()
|
||||
|
||||
val objCAction = packageScope.getContributedClassifier("ObjCAction") as ClassDescriptor
|
||||
|
||||
val objCOutlet = packageScope.getContributedClassifier("ObjCOutlet") as ClassDescriptor
|
||||
|
||||
val objCMethodImp = packageScope.getContributedClassifier("ObjCMethodImp") as ClassDescriptor
|
||||
|
||||
}
|
||||
|
||||
private fun MemberScope.getContributedVariables(name: String) =
|
||||
|
||||
+21
@@ -22,6 +22,8 @@ import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.ExternalOverridabilityCondition
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.*
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.TypeUtils
|
||||
|
||||
private val interopPackageName = InteropBuiltIns.FqNames.packageName
|
||||
private val objCObjectFqName = interopPackageName.child(Name.identifier("ObjCObject"))
|
||||
@@ -34,6 +36,12 @@ fun ClassDescriptor.isObjCClass(): Boolean =
|
||||
this.getAllSuperClassifiers().any { it.fqNameSafe == objCObjectFqName } &&
|
||||
this.containingDeclaration.fqNameSafe != interopPackageName
|
||||
|
||||
fun KotlinType.isObjCObjectType(): Boolean =
|
||||
TypeUtils.getClassDescriptor(this)
|
||||
?.getAllSuperClassifiers()
|
||||
?.any { it.fqNameSafe == objCObjectFqName }
|
||||
?: false
|
||||
|
||||
fun ClassDescriptor.isExternalObjCClass(): Boolean = this.isObjCClass() &&
|
||||
this.parentsWithSelf.filterIsInstance<ClassDescriptor>().any {
|
||||
it.annotations.findAnnotation(externalObjCClassFqName) != null
|
||||
@@ -153,4 +161,17 @@ class ObjCOverridabilityCondition : ExternalOverridabilityCondition {
|
||||
return true
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun inferObjCSelector(descriptor: FunctionDescriptor): String = if (descriptor.valueParameters.isEmpty()) {
|
||||
descriptor.name.asString()
|
||||
} else {
|
||||
buildString {
|
||||
append(descriptor.name)
|
||||
append(':')
|
||||
descriptor.valueParameters.drop(1).forEach {
|
||||
append(it.name)
|
||||
append(':')
|
||||
}
|
||||
}
|
||||
}
|
||||
+6
@@ -65,6 +65,12 @@ internal class KonanSymbols(context: Context, val symbolTable: SymbolTable): Sym
|
||||
symbolTable.referenceSimpleFunction(function)
|
||||
}
|
||||
|
||||
val interopInterpretObjCPointer =
|
||||
symbolTable.referenceSimpleFunction(context.interopBuiltIns.interpretObjCPointer)
|
||||
|
||||
val interopInterpretObjCPointerOrNull =
|
||||
symbolTable.referenceSimpleFunction(context.interopBuiltIns.interpretObjCPointerOrNull)
|
||||
|
||||
val getNativeNullPtr = symbolTable.referenceSimpleFunction(context.builtIns.getNativeNullPtr)
|
||||
|
||||
val boxFunctions = ValueType.values().associate {
|
||||
|
||||
+2
-2
@@ -176,10 +176,10 @@ internal interface ContextUtils : RuntimeAware {
|
||||
/**
|
||||
* Address of entry point of [llvmFunction].
|
||||
*/
|
||||
val FunctionDescriptor.entryPointAddress: ConstValue
|
||||
val FunctionDescriptor.entryPointAddress: ConstPointer
|
||||
get() {
|
||||
val result = LLVMConstBitCast(this.llvmFunction, int8TypePtr)!!
|
||||
return constValue(result)
|
||||
return constPointer(result)
|
||||
}
|
||||
|
||||
val ClassDescriptor.typeInfoPtr: ConstPointer
|
||||
|
||||
+1
-1
@@ -176,7 +176,7 @@ internal class RTTIGeneratorVisitor(context: Context) : IrElementVisitorVoid {
|
||||
generator.generate(descriptor)
|
||||
|
||||
if (descriptor.isKotlinObjCClass()) {
|
||||
kotlinObjCClassInfoGenerator.generate(descriptor)
|
||||
kotlinObjCClassInfoGenerator.generate(declaration)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+32
-7
@@ -20,24 +20,28 @@ import llvm.LLVMStoreSizeOfType
|
||||
import org.jetbrains.kotlin.backend.konan.Context
|
||||
import org.jetbrains.kotlin.backend.konan.ObjCMethodInfo
|
||||
import org.jetbrains.kotlin.backend.konan.descriptors.contributedMethods
|
||||
import org.jetbrains.kotlin.backend.konan.descriptors.getStringValue
|
||||
import org.jetbrains.kotlin.backend.konan.getObjCMethodInfo
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ConstructorDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.isFinalClass
|
||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassNotAny
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperInterfaces
|
||||
|
||||
internal class KotlinObjCClassInfoGenerator(override val context: Context) : ContextUtils {
|
||||
fun generate(descriptor: ClassDescriptor) {
|
||||
fun generate(irClass: IrClass) {
|
||||
val descriptor = irClass.descriptor
|
||||
assert(descriptor.isFinalClass)
|
||||
|
||||
val objCLLvmDeclarations = context.llvmDeclarations.forClass(descriptor).objCDeclarations!!
|
||||
|
||||
val instanceMethods = descriptor.generateMethodDescs()
|
||||
val instanceMethods = descriptor.generateOverridingMethodDescs() + irClass.generateImpMethodDescs()
|
||||
|
||||
val companionObjectDescriptor = descriptor.companionObjectDescriptor
|
||||
val classMethods = companionObjectDescriptor?.generateMethodDescs() ?: emptyList()
|
||||
val classMethods = companionObjectDescriptor?.generateOverridingMethodDescs() ?: emptyList()
|
||||
|
||||
val superclassName = descriptor.getSuperClassNotAny()!!.name.asString()
|
||||
val protocolNames = descriptor.getSuperInterfaces().map { it.name.asString().removeSuffix("Protocol") }
|
||||
@@ -79,16 +83,37 @@ internal class KotlinObjCClassInfoGenerator(override val context: Context) : Con
|
||||
objCLLvmDeclarations.bodyOffsetGlobal.setInitializer(Int32(0))
|
||||
}
|
||||
|
||||
private fun createMethodDesc(selector: String, encoding: String, imp: ConstPointer) = Struct(
|
||||
runtime.objCMethodDescription,
|
||||
staticData.cStringLiteral(selector),
|
||||
staticData.cStringLiteral(encoding),
|
||||
imp
|
||||
)
|
||||
|
||||
private fun generateMethodDesc(info: ObjCMethodInfo): ConstValue {
|
||||
return Struct(runtime.objCMethodDescription,
|
||||
staticData.cStringLiteral(info.selector),
|
||||
staticData.cStringLiteral(info.encoding),
|
||||
return createMethodDesc(
|
||||
info.selector,
|
||||
info.encoding,
|
||||
constPointer(context.llvm.externalFunction(info.imp, functionType(voidType))).bitcast(int8TypePtr)
|
||||
)
|
||||
}
|
||||
|
||||
private fun ClassDescriptor.generateMethodDescs(): List<ConstValue> =
|
||||
private fun ClassDescriptor.generateOverridingMethodDescs(): List<ConstValue> =
|
||||
this.unsubstitutedMemberScope.contributedMethods.filter {
|
||||
it.kind.isReal && it !is ConstructorDescriptor
|
||||
}.mapNotNull { it.getObjCMethodInfo() }.map { generateMethodDesc(it) }
|
||||
|
||||
private fun IrClass.generateImpMethodDescs(): List<ConstValue> = this.declarations
|
||||
.filterIsInstance<IrSimpleFunction>()
|
||||
.mapNotNull {
|
||||
val annotation =
|
||||
it.descriptor.annotations.findAnnotation(context.interopBuiltIns.objCMethodImp.fqNameSafe) ?:
|
||||
return@mapNotNull null
|
||||
|
||||
createMethodDesc(
|
||||
annotation.getStringValue("selector"),
|
||||
annotation.getStringValue("encoding"),
|
||||
it.descriptor.entryPointAddress
|
||||
)
|
||||
}
|
||||
}
|
||||
+215
-10
@@ -18,36 +18,41 @@ package org.jetbrains.kotlin.backend.konan.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.descriptors.allParameters
|
||||
import org.jetbrains.kotlin.backend.common.lower.IrBuildingTransformer
|
||||
import org.jetbrains.kotlin.backend.common.lower.at
|
||||
import org.jetbrains.kotlin.backend.common.lower.irBlock
|
||||
import org.jetbrains.kotlin.backend.common.lower.*
|
||||
import org.jetbrains.kotlin.backend.common.peek
|
||||
import org.jetbrains.kotlin.backend.common.pop
|
||||
import org.jetbrains.kotlin.backend.common.push
|
||||
import org.jetbrains.kotlin.backend.konan.*
|
||||
import org.jetbrains.kotlin.backend.konan.descriptors.getStringValue
|
||||
import org.jetbrains.kotlin.backend.konan.descriptors.isInterface
|
||||
import org.jetbrains.kotlin.backend.konan.descriptors.synthesizedName
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptorImpl
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationsImpl
|
||||
import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl
|
||||
import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl
|
||||
import org.jetbrains.kotlin.ir.IrStatement
|
||||
import org.jetbrains.kotlin.ir.builders.*
|
||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.*
|
||||
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
||||
import org.jetbrains.kotlin.ir.util.defaultType
|
||||
import org.jetbrains.kotlin.ir.util.functions
|
||||
import org.jetbrains.kotlin.ir.util.getArguments
|
||||
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.OverridingUtil
|
||||
import org.jetbrains.kotlin.resolve.constants.StringValue
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassNotAny
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.TypeUtils
|
||||
import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf
|
||||
import org.jetbrains.kotlin.types.typeUtil.isUnit
|
||||
|
||||
internal class InteropLoweringPart1(val context: Context) : IrBuildingTransformer(context), FileLoweringPass {
|
||||
|
||||
@@ -87,7 +92,7 @@ internal class InteropLoweringPart1(val context: Context) : IrBuildingTransforme
|
||||
|
||||
override fun visitClass(declaration: IrClass): IrStatement {
|
||||
if (declaration.descriptor.isKotlinObjCClass()) {
|
||||
checkKotlinObjCClass(declaration)
|
||||
lowerKotlinObjCClass(declaration)
|
||||
}
|
||||
|
||||
outerClasses.push(declaration)
|
||||
@@ -98,6 +103,204 @@ internal class InteropLoweringPart1(val context: Context) : IrBuildingTransforme
|
||||
}
|
||||
}
|
||||
|
||||
private fun lowerKotlinObjCClass(irClass: IrClass) {
|
||||
checkKotlinObjCClass(irClass)
|
||||
|
||||
val interop = context.interopBuiltIns
|
||||
|
||||
irClass.declarations.mapNotNull {
|
||||
when {
|
||||
it is IrSimpleFunction && it.descriptor.annotations.hasAnnotation(interop.objCAction) ->
|
||||
generateActionImp(it)
|
||||
|
||||
it is IrProperty && it.descriptor.annotations.hasAnnotation(interop.objCOutlet) ->
|
||||
generateOutletSetterImp(it)
|
||||
|
||||
else -> null
|
||||
}
|
||||
}.let { irClass.declarations.addAll(it) }
|
||||
}
|
||||
|
||||
private fun generateActionImp(function: IrSimpleFunction): IrSimpleFunction {
|
||||
val action = "@${context.interopBuiltIns.objCAction.name}"
|
||||
|
||||
function.extensionReceiverParameter?.let {
|
||||
context.reportCompilationError("$action method must not have extension receiver",
|
||||
currentFile, it)
|
||||
}
|
||||
|
||||
function.valueParameters.forEach {
|
||||
val kotlinType = it.descriptor.type
|
||||
if (!kotlinType.isObjCObjectType()) {
|
||||
context.reportCompilationError("Unexpected $action method parameter type: $kotlinType\n" +
|
||||
"Only Objective-C object types are supported here",
|
||||
currentFile, it)
|
||||
}
|
||||
}
|
||||
|
||||
val returnType = function.descriptor.returnType!!
|
||||
|
||||
if (!returnType.isUnit()) {
|
||||
context.reportCompilationError("Unexpected $action method return type: $returnType\n" +
|
||||
"Only 'Unit' is supported here",
|
||||
currentFile, function
|
||||
)
|
||||
}
|
||||
|
||||
return generateFunctionImp(inferObjCSelector(function.descriptor), function)
|
||||
}
|
||||
|
||||
private fun generateOutletSetterImp(property: IrProperty): IrSimpleFunction {
|
||||
val descriptor = property.descriptor
|
||||
|
||||
val outlet = "@${context.interopBuiltIns.objCOutlet.name}"
|
||||
|
||||
if (!descriptor.isVar) {
|
||||
context.reportCompilationError("$outlet property must be var",
|
||||
currentFile, property)
|
||||
}
|
||||
|
||||
property.getter?.extensionReceiverParameter?.let {
|
||||
context.reportCompilationError("$outlet must not have extension receiver",
|
||||
currentFile, it)
|
||||
}
|
||||
|
||||
val type = descriptor.type
|
||||
if (!type.isObjCObjectType()) {
|
||||
context.reportCompilationError("Unexpected $outlet type: $type\n" +
|
||||
"Only Objective-C object types are supported here",
|
||||
currentFile, property)
|
||||
}
|
||||
|
||||
val name = descriptor.name.asString()
|
||||
val selector = "set${name.capitalize()}:"
|
||||
|
||||
return generateFunctionImp(selector, property.setter!!)
|
||||
}
|
||||
|
||||
private fun getMethodSignatureEncoding(function: IrFunction): String {
|
||||
assert(function.extensionReceiverParameter == null)
|
||||
assert(function.valueParameters.all { it.type.isObjCObjectType() })
|
||||
assert(function.descriptor.returnType!!.isUnit())
|
||||
|
||||
// Note: these values are valid for x86_64 and arm64.
|
||||
return when (function.valueParameters.size) {
|
||||
0 -> "v16@0:8"
|
||||
1 -> "v24@0:8@16"
|
||||
2 -> "v32@0:8@16@24"
|
||||
else -> context.reportCompilationError("Only 0, 1 or 2 parameters are supported here",
|
||||
currentFile, function
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun generateFunctionImp(selector: String, function: IrFunction): IrSimpleFunction {
|
||||
val signatureEncoding = getMethodSignatureEncoding(function)
|
||||
|
||||
val returnType = function.descriptor.returnType!!
|
||||
assert(returnType.isUnit())
|
||||
|
||||
val nativePtrType = context.builtIns.nativePtr.defaultType
|
||||
|
||||
val parameterTypes = mutableListOf(nativePtrType) // id self
|
||||
|
||||
parameterTypes.add(nativePtrType) // SEL _cmd
|
||||
|
||||
function.valueParameters.mapTo(parameterTypes) {
|
||||
when {
|
||||
it.descriptor.type.isObjCObjectType() -> nativePtrType
|
||||
else -> TODO()
|
||||
}
|
||||
}
|
||||
|
||||
// Annotations to be detected in KotlinObjCClassInfoGenerator:
|
||||
val annotations = createObjCMethodImpAnnotations(selector = selector, encoding = signatureEncoding)
|
||||
|
||||
val newDescriptor = SimpleFunctionDescriptorImpl.create(
|
||||
function.descriptor.containingDeclaration,
|
||||
annotations,
|
||||
("imp:" + selector).synthesizedName,
|
||||
CallableMemberDescriptor.Kind.SYNTHESIZED,
|
||||
SourceElement.NO_SOURCE
|
||||
)
|
||||
|
||||
val valueParameters = parameterTypes.mapIndexed { index, it ->
|
||||
ValueParameterDescriptorImpl(
|
||||
newDescriptor,
|
||||
null,
|
||||
index,
|
||||
Annotations.EMPTY,
|
||||
Name.identifier("p$index"),
|
||||
it,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
null,
|
||||
SourceElement.NO_SOURCE
|
||||
)
|
||||
}
|
||||
|
||||
newDescriptor.initialize(
|
||||
null, null,
|
||||
emptyList(),
|
||||
valueParameters,
|
||||
returnType,
|
||||
Modality.FINAL,
|
||||
Visibilities.PRIVATE
|
||||
)
|
||||
|
||||
val newFunction = IrFunctionImpl(
|
||||
function.startOffset, function.endOffset,
|
||||
IrDeclarationOrigin.DEFINED,
|
||||
newDescriptor
|
||||
).apply { createParameterDeclarations() }
|
||||
|
||||
val builder = context.createIrBuilder(newFunction.symbol)
|
||||
newFunction.body = builder.irBlockBody(newFunction) {
|
||||
+irCall(function.symbol).apply {
|
||||
dispatchReceiver = interpretObjCPointer(
|
||||
irGet(newFunction.valueParameters[0].symbol),
|
||||
function.dispatchReceiverParameter!!.type
|
||||
)
|
||||
|
||||
function.valueParameters.forEachIndexed { index, parameter ->
|
||||
putValueArgument(index,
|
||||
interpretObjCPointer(
|
||||
irGet(newFunction.valueParameters[index + 2].symbol),
|
||||
parameter.type
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return newFunction
|
||||
}
|
||||
|
||||
private fun IrBuilderWithScope.interpretObjCPointer(expression: IrExpression, type: KotlinType): IrExpression {
|
||||
val callee: IrFunctionSymbol = if (TypeUtils.isNullableType(type)) {
|
||||
symbols.interopInterpretObjCPointerOrNull
|
||||
} else {
|
||||
symbols.interopInterpretObjCPointer
|
||||
}
|
||||
|
||||
return irCall(callee, listOf(type)).apply {
|
||||
putValueArgument(0, expression)
|
||||
}
|
||||
}
|
||||
|
||||
private fun createObjCMethodImpAnnotations(selector: String, encoding: String): Annotations {
|
||||
val annotation = AnnotationDescriptorImpl(
|
||||
context.interopBuiltIns.objCMethodImp.defaultType,
|
||||
mapOf("selector" to selector, "encoding" to encoding)
|
||||
.mapKeys { Name.identifier(it.key) }
|
||||
.mapValues { StringValue(it.value, context.builtIns) },
|
||||
SourceElement.NO_SOURCE
|
||||
)
|
||||
|
||||
return AnnotationsImpl(listOf(annotation))
|
||||
}
|
||||
|
||||
private fun checkKotlinObjCClass(irClass: IrClass) {
|
||||
val kind = irClass.descriptor.kind
|
||||
if (kind != ClassKind.CLASS && kind != ClassKind.OBJECT) {
|
||||
@@ -597,4 +800,6 @@ private fun IrBuilder.irFloat(value: Float) =
|
||||
IrConstImpl.float(startOffset, endOffset, context.builtIns.floatType, value)
|
||||
|
||||
private fun IrBuilder.irDouble(value: Double) =
|
||||
IrConstImpl.double(startOffset, endOffset, context.builtIns.doubleType, value)
|
||||
IrConstImpl.double(startOffset, endOffset, context.builtIns.doubleType, value)
|
||||
|
||||
private fun Annotations.hasAnnotation(descriptor: ClassDescriptor) = this.hasAnnotation(descriptor.fqNameSafe)
|
||||
|
||||
Reference in New Issue
Block a user