[ObjCExport] Split ObjCExport into K1 and Analysis Api implementation
FL-23390 ^KT-64168 Fixed
This commit is contained in:
committed by
Space Team
parent
3e57265fcb
commit
e409c60780
Generated
+2
-1
@@ -7,7 +7,8 @@
|
||||
<w>instantiator</w>
|
||||
<w>interops</w>
|
||||
<w>klibrary</w>
|
||||
<w>namer</w>
|
||||
<w>undispatched</w>
|
||||
</words>
|
||||
</dictionary>
|
||||
</component>
|
||||
</component>
|
||||
@@ -337,6 +337,8 @@ val projectsUsedInIntelliJKotlinPlugin =
|
||||
arrayOf(
|
||||
":native:base",
|
||||
":native:objcexport-header-generator",
|
||||
":native:objcexport-header-generator-k1",
|
||||
":native:objcexport-header-generator-analysis-api",
|
||||
":compiler:ir.serialization.native"
|
||||
)
|
||||
|
||||
|
||||
@@ -156,6 +156,7 @@ dependencies {
|
||||
|
||||
compilerApi project(":kotlin-native:utilities:basic-utils")
|
||||
compilerApi project(":native:objcexport-header-generator")
|
||||
compilerApi project(":native:objcexport-header-generator-k1")
|
||||
compilerApi project(":native:base")
|
||||
|
||||
compilerImplementation project(":kotlin-compiler")
|
||||
|
||||
-1
@@ -13,7 +13,6 @@ import org.jetbrains.kotlin.backend.konan.objcexport.ObjCExportProblemCollector
|
||||
import org.jetbrains.kotlin.backend.konan.objcexport.dumpObjCHeader
|
||||
import org.jetbrains.kotlin.container.*
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.resolve.deprecation.DeprecationResolver
|
||||
|
||||
|
||||
+2
-2
@@ -27,8 +27,8 @@ internal val ProduceObjCExportInterfacePhase = createSimpleNamedCompilerPhase<Ph
|
||||
}
|
||||
|
||||
internal data class CreateObjCFrameworkInput(
|
||||
val moduleDescriptor: ModuleDescriptor,
|
||||
val exportedInterface: ObjCExportedInterface,
|
||||
val moduleDescriptor: ModuleDescriptor,
|
||||
val exportedInterface: ObjCExportedInterface,
|
||||
)
|
||||
|
||||
/**
|
||||
|
||||
+36
-36
@@ -346,9 +346,9 @@ internal class ObjCExportCodeGenerator(
|
||||
}
|
||||
|
||||
private fun ObjCExportFunctionGenerationContext.objCBlockPointerToKotlin(
|
||||
value: LLVMValueRef,
|
||||
typeBridge: BlockPointerBridge,
|
||||
resultLifetime: Lifetime
|
||||
value: LLVMValueRef,
|
||||
typeBridge: BlockPointerBridge,
|
||||
resultLifetime: Lifetime
|
||||
) = callFromBridge(
|
||||
blockToKotlinFunctionConverter(typeBridge),
|
||||
listOf(value),
|
||||
@@ -356,14 +356,14 @@ internal class ObjCExportCodeGenerator(
|
||||
)
|
||||
|
||||
internal fun ObjCExportFunctionGenerationContext.kotlinFunctionToRetainedObjCBlockPointer(
|
||||
typeBridge: BlockPointerBridge,
|
||||
value: LLVMValueRef
|
||||
typeBridge: BlockPointerBridge,
|
||||
value: LLVMValueRef
|
||||
) = callFromBridge(kotlinFunctionToRetainedBlockConverter(typeBridge), listOf(value))
|
||||
|
||||
fun ObjCExportFunctionGenerationContext.objCToKotlin(
|
||||
value: LLVMValueRef,
|
||||
typeBridge: TypeBridge,
|
||||
resultLifetime: Lifetime
|
||||
value: LLVMValueRef,
|
||||
typeBridge: TypeBridge,
|
||||
resultLifetime: Lifetime
|
||||
): LLVMValueRef = when (typeBridge) {
|
||||
is ReferenceBridge -> objCReferenceToKotlin(value, resultLifetime)
|
||||
is BlockPointerBridge -> objCBlockPointerToKotlin(value, typeBridge, resultLifetime)
|
||||
@@ -894,10 +894,10 @@ private fun ObjCExportFunctionGenerationContextBuilder.setupBridgeDebugInfo() {
|
||||
}
|
||||
|
||||
private inline fun ObjCExportCodeGenerator.generateObjCImpBy(
|
||||
methodBridge: MethodBridge,
|
||||
debugInfo: Boolean = false,
|
||||
suffix: String,
|
||||
genBody: ObjCExportFunctionGenerationContext.() -> Unit
|
||||
methodBridge: MethodBridge,
|
||||
debugInfo: Boolean = false,
|
||||
suffix: String,
|
||||
genBody: ObjCExportFunctionGenerationContext.() -> Unit
|
||||
): LlvmCallable {
|
||||
val functionType = objCFunctionType(generationState, methodBridge)
|
||||
val functionName = "objc2kotlin_$suffix"
|
||||
@@ -923,11 +923,11 @@ private fun ObjCExportCodeGenerator.generateAbstractObjCImp(methodBridge: Method
|
||||
}
|
||||
|
||||
private fun ObjCExportCodeGenerator.generateObjCImp(
|
||||
target: IrFunction?,
|
||||
baseMethod: IrFunction,
|
||||
methodBridge: MethodBridge,
|
||||
isVirtual: Boolean = false,
|
||||
customBridgeSuffix: String? = null,
|
||||
target: IrFunction?,
|
||||
baseMethod: IrFunction,
|
||||
methodBridge: MethodBridge,
|
||||
isVirtual: Boolean = false,
|
||||
customBridgeSuffix: String? = null,
|
||||
) = if (target == null) {
|
||||
generateAbstractObjCImp(methodBridge, baseMethod)
|
||||
} else {
|
||||
@@ -953,11 +953,11 @@ private fun ObjCExportCodeGenerator.generateObjCImp(
|
||||
}
|
||||
|
||||
private fun ObjCExportCodeGenerator.generateObjCImp(
|
||||
methodBridge: MethodBridge,
|
||||
isDirect: Boolean,
|
||||
baseMethod: IrFunction? = null,
|
||||
bridgeSuffix: String,
|
||||
callKotlin: ObjCExportFunctionGenerationContext.(
|
||||
methodBridge: MethodBridge,
|
||||
isDirect: Boolean,
|
||||
baseMethod: IrFunction? = null,
|
||||
bridgeSuffix: String,
|
||||
callKotlin: ObjCExportFunctionGenerationContext.(
|
||||
args: List<LLVMValueRef>,
|
||||
resultLifetime: Lifetime,
|
||||
exceptionHandler: ExceptionHandler
|
||||
@@ -1802,8 +1802,8 @@ private inline fun ObjCExportCodeGenerator.generateObjCToKotlinSyntheticGetter(
|
||||
): ObjCExportCodeGenerator.ObjCToKotlinMethodAdapter {
|
||||
|
||||
val methodBridge = MethodBridge(
|
||||
MethodBridge.ReturnValue.Mapped(ReferenceBridge),
|
||||
MethodBridgeReceiver.Static, valueParameters = emptyList()
|
||||
MethodBridge.ReturnValue.Mapped(ReferenceBridge),
|
||||
MethodBridgeReceiver.Static, valueParameters = emptyList()
|
||||
)
|
||||
|
||||
val functionType = objCFunctionType(generationState, methodBridge)
|
||||
@@ -1818,9 +1818,9 @@ private inline fun ObjCExportCodeGenerator.generateObjCToKotlinSyntheticGetter(
|
||||
}
|
||||
|
||||
private fun ObjCExportCodeGenerator.objCToKotlinMethodAdapter(
|
||||
selector: String,
|
||||
methodBridge: MethodBridge,
|
||||
imp: LlvmCallable
|
||||
selector: String,
|
||||
methodBridge: MethodBridge,
|
||||
imp: LlvmCallable
|
||||
): ObjCExportCodeGenerator.ObjCToKotlinMethodAdapter {
|
||||
selectorsToDefine[selector] = methodBridge
|
||||
|
||||
@@ -1844,9 +1844,9 @@ private fun ObjCExportCodeGenerator.createObjectInstanceAdapter(
|
||||
assert(!objectClass.isUnit())
|
||||
|
||||
val methodBridge = MethodBridge(
|
||||
returnBridge = MethodBridge.ReturnValue.Mapped(ReferenceBridge),
|
||||
receiver = MethodBridgeReceiver.Static,
|
||||
valueParameters = emptyList()
|
||||
returnBridge = MethodBridge.ReturnValue.Mapped(ReferenceBridge),
|
||||
receiver = MethodBridgeReceiver.Static,
|
||||
valueParameters = emptyList()
|
||||
)
|
||||
|
||||
val function = context.getObjectClassInstanceFunction(objectClass)
|
||||
@@ -1876,9 +1876,9 @@ private fun ObjCExportCodeGenerator.createEnumValuesOrEntriesAdapter(
|
||||
selector: String
|
||||
): ObjCExportCodeGenerator.ObjCToKotlinMethodAdapter {
|
||||
val methodBridge = MethodBridge(
|
||||
returnBridge = MethodBridge.ReturnValue.Mapped(ReferenceBridge),
|
||||
receiver = MethodBridgeReceiver.Static,
|
||||
valueParameters = emptyList()
|
||||
returnBridge = MethodBridge.ReturnValue.Mapped(ReferenceBridge),
|
||||
receiver = MethodBridgeReceiver.Static,
|
||||
valueParameters = emptyList()
|
||||
)
|
||||
|
||||
val imp = generateObjCImp(function, function, methodBridge, isVirtual = false)
|
||||
@@ -1888,9 +1888,9 @@ private fun ObjCExportCodeGenerator.createEnumValuesOrEntriesAdapter(
|
||||
|
||||
private fun ObjCExportCodeGenerator.createThrowableAsErrorAdapter(): ObjCExportCodeGenerator.ObjCToKotlinMethodAdapter {
|
||||
val methodBridge = MethodBridge(
|
||||
returnBridge = MethodBridge.ReturnValue.Mapped(ReferenceBridge),
|
||||
receiver = MethodBridgeReceiver.Instance,
|
||||
valueParameters = emptyList()
|
||||
returnBridge = MethodBridge.ReturnValue.Mapped(ReferenceBridge),
|
||||
receiver = MethodBridgeReceiver.Instance,
|
||||
valueParameters = emptyList()
|
||||
)
|
||||
|
||||
val imp = generateObjCImpBy(methodBridge, suffix = "ThrowableAsError") {
|
||||
|
||||
+3
-3
@@ -14,9 +14,9 @@ import org.jetbrains.kotlin.konan.target.Family
|
||||
* Builds Apple bundle directory.
|
||||
*/
|
||||
internal class BundleBuilder(
|
||||
private val config: KonanConfig,
|
||||
private val infoPListBuilder: InfoPListBuilder,
|
||||
private val mainPackageGuesser: MainPackageGuesser,
|
||||
private val config: KonanConfig,
|
||||
private val infoPListBuilder: InfoPListBuilder,
|
||||
private val mainPackageGuesser: MainPackageGuesser,
|
||||
) {
|
||||
fun build(
|
||||
moduleDescriptor: ModuleDescriptor,
|
||||
|
||||
+5
-5
@@ -14,11 +14,11 @@ import org.jetbrains.kotlin.konan.target.Family
|
||||
* Constructs an Apple framework without a binary.
|
||||
*/
|
||||
internal class FrameworkBuilder(
|
||||
private val config: KonanConfig,
|
||||
private val infoPListBuilder: InfoPListBuilder,
|
||||
private val moduleMapBuilder: ModuleMapBuilder,
|
||||
private val objCHeaderWriter: ObjCHeaderWriter,
|
||||
private val mainPackageGuesser: MainPackageGuesser,
|
||||
private val config: KonanConfig,
|
||||
private val infoPListBuilder: InfoPListBuilder,
|
||||
private val moduleMapBuilder: ModuleMapBuilder,
|
||||
private val objCHeaderWriter: ObjCHeaderWriter,
|
||||
private val mainPackageGuesser: MainPackageGuesser,
|
||||
) {
|
||||
fun build(
|
||||
moduleDescriptor: ModuleDescriptor,
|
||||
|
||||
+6
-6
@@ -26,9 +26,9 @@ internal class InfoPListBuilder(
|
||||
private val configuration = config.configuration
|
||||
|
||||
fun build(
|
||||
name: String,
|
||||
mainPackageGuesser: MainPackageGuesser,
|
||||
moduleDescriptor: ModuleDescriptor,
|
||||
name: String,
|
||||
mainPackageGuesser: MainPackageGuesser,
|
||||
moduleDescriptor: ModuleDescriptor,
|
||||
): String {
|
||||
val bundleId = computeBundleID(name, mainPackageGuesser, moduleDescriptor)
|
||||
|
||||
@@ -124,9 +124,9 @@ internal class InfoPListBuilder(
|
||||
}
|
||||
|
||||
private fun computeBundleID(
|
||||
bundleName: String,
|
||||
mainPackageGuesser: MainPackageGuesser,
|
||||
moduleDescriptor: ModuleDescriptor,
|
||||
bundleName: String,
|
||||
mainPackageGuesser: MainPackageGuesser,
|
||||
moduleDescriptor: ModuleDescriptor,
|
||||
): String {
|
||||
val deprecatedBundleIdOption = configuration[KonanConfigKeys.BUNDLE_ID]
|
||||
val bundleIdOption = configuration[BinaryOptions.bundleId]
|
||||
|
||||
+13
-13
@@ -101,18 +101,18 @@ private class ObjCExportCompilerProblemCollector(val context: PhaseContext) : Ob
|
||||
* Populate framework directory with headers, module and info.plist.
|
||||
*/
|
||||
internal fun createObjCFramework(
|
||||
config: KonanConfig,
|
||||
moduleDescriptor: ModuleDescriptor,
|
||||
exportedInterface: ObjCExportedInterface,
|
||||
frameworkDirectory: File
|
||||
config: KonanConfig,
|
||||
moduleDescriptor: ModuleDescriptor,
|
||||
exportedInterface: ObjCExportedInterface,
|
||||
frameworkDirectory: File
|
||||
) {
|
||||
val frameworkName = frameworkDirectory.name.removeSuffix(CompilerOutputKind.FRAMEWORK.suffix())
|
||||
val frameworkBuilder = FrameworkBuilder(
|
||||
config,
|
||||
infoPListBuilder = InfoPListBuilder(config),
|
||||
moduleMapBuilder = ModuleMapBuilder(),
|
||||
objCHeaderWriter = ObjCHeaderWriter(),
|
||||
mainPackageGuesser = MainPackageGuesser(),
|
||||
config,
|
||||
infoPListBuilder = InfoPListBuilder(config),
|
||||
moduleMapBuilder = ModuleMapBuilder(),
|
||||
objCHeaderWriter = ObjCHeaderWriter(),
|
||||
mainPackageGuesser = MainPackageGuesser(),
|
||||
)
|
||||
frameworkBuilder.build(
|
||||
moduleDescriptor,
|
||||
@@ -135,10 +135,10 @@ internal fun createTestBundle(
|
||||
|
||||
// TODO: No need for such class in dynamic driver.
|
||||
internal class ObjCExport(
|
||||
private val generationState: NativeGenerationState,
|
||||
private val moduleDescriptor: ModuleDescriptor,
|
||||
private val exportedInterface: ObjCExportedInterface?,
|
||||
private val codeSpec: ObjCExportCodeSpec?
|
||||
private val generationState: NativeGenerationState,
|
||||
private val moduleDescriptor: ModuleDescriptor,
|
||||
private val exportedInterface: ObjCExportedInterface?,
|
||||
private val codeSpec: ObjCExportCodeSpec?
|
||||
) {
|
||||
private val config = generationState.config
|
||||
private val target get() = config.target
|
||||
|
||||
@@ -164,6 +164,7 @@ dependencies {
|
||||
distPack project(':kotlin-native:Interop:Skia')
|
||||
distPack project(':kotlin-native:backend.native')
|
||||
distPack project(':native:objcexport-header-generator')
|
||||
distPack project(':native:objcexport-header-generator-k1')
|
||||
distPack project(':native:base')
|
||||
distPack project(':kotlin-native:utilities:cli-runner')
|
||||
distPack project(':kotlin-native:utilities:basic-utils')
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
# ObjC Export Header generator
|
||||
This tool is used for 'translating' Kotlin code into ObjC 'stubs' and ultimately rendering ObjC header files.
|
||||
|
||||
## Usage
|
||||
|
||||
### CLI: Building .framework files
|
||||
The CLI will use this module for building the corresponding .framework binaries from Kotlin. This method will operate on previously
|
||||
built .klib binaries (with fully validated frontend). The 'klibs' will be deserialized and headers and bridges between
|
||||
Kotlin and ObjC will be built. This mode currently operates on K1 based descriptors
|
||||
|
||||
### IDE: Providing Kotlin <-> ObjC/Swift cross language support
|
||||
In order for Fleet to provide tooling that is capable of refactoring symbols between Kotlin and ObjC, this tool is used.
|
||||
|
||||
Example:
|
||||
|
||||
given the following Kotlin code
|
||||
|
||||
```kotlin
|
||||
@ObjCName("FooObjC")
|
||||
class Foo
|
||||
```
|
||||
|
||||
and the following Swift usage
|
||||
|
||||
```swift
|
||||
func bar() {
|
||||
FooObjC()
|
||||
}
|
||||
```
|
||||
refactoring inside either Kotlin or Swift will be consistent across Kotlin and Swift.
|
||||
|
||||
|
||||
## Two Implementations (K1, Analysis Api)
|
||||
|
||||
There are currently two implementations for this tool
|
||||
|
||||
### K1
|
||||
This is the K1 (descriptor based) implementation that is currently used by the CLI and K1 based IDEs.
|
||||
|
||||
### Analysis Api (WiP)
|
||||
This implementation is currently 'work in progress' and shall replace the K1 usage in the IDE later.
|
||||
This implementation _could_ theoretically also replace the K1 implementation if necessary.
|
||||
|
||||
|
||||
## Testing
|
||||
|
||||
### Run all tests
|
||||
```
|
||||
./gradlew :native:objcexport-header-generator:check
|
||||
```
|
||||
|
||||
The most important test is [ObjCExportHeaderGeneratorTest.kt](test%2Forg%2Fjetbrains%2Fkotlin%2Fbackend%2Fkonan%2Ftests%2FObjCExportHeaderGeneratorTest.kt)
|
||||
as this test defines the contract of how a header shall be generated from a given Kotlin input. This test can run against
|
||||
both implementations.
|
||||
|
||||
```
|
||||
./gradlew :native:objcexport-header-generator:testK1
|
||||
./gradlew :native:objcexport-header-generator:testAnalysisApi
|
||||
```
|
||||
|
||||
Note: Since the Analysis Api implementation is WIP yet, this test can be used for debugging, but is not fully implemented yet.
|
||||
@@ -1,23 +1,23 @@
|
||||
@file:Suppress("HasPlatformType")
|
||||
|
||||
plugins {
|
||||
kotlin("jvm")
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
"main" { projectDefault() }
|
||||
"test" { projectDefault() }
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(intellijCore())
|
||||
implementation(project(":compiler:cli-base"))
|
||||
implementation(project(":compiler:cli-common"))
|
||||
implementation(project(":compiler:ir.objcinterop"))
|
||||
implementation(project(":compiler:ir.serialization.native"))
|
||||
implementation(project(":core:compiler.common.native"))
|
||||
implementation(project(":core:descriptors"))
|
||||
implementation(project(":native:base"))
|
||||
implementation(project(":native:kotlin-native-utils"))
|
||||
api(intellijCore())
|
||||
api(project(":native:base"))
|
||||
api(project(":core:compiler.common"))
|
||||
|
||||
testImplementation(libs.junit.jupiter.api)
|
||||
testImplementation(libs.junit.jupiter.params)
|
||||
testImplementation(project(":compiler:tests-common", "tests-jar"))
|
||||
|
||||
testRuntimeOnly(libs.junit.jupiter.engine)
|
||||
testApi(libs.junit.jupiter.api)
|
||||
testApi(libs.junit.jupiter.engine)
|
||||
testApi(libs.junit.jupiter.params)
|
||||
testApi(project(":compiler:tests-common", "tests-jar"))
|
||||
}
|
||||
|
||||
kotlin {
|
||||
@@ -26,8 +26,40 @@ kotlin {
|
||||
}
|
||||
}
|
||||
|
||||
nativeTest("test", tag = null) {
|
||||
useJUnitPlatform()
|
||||
systemProperty("projectDir", projectDir.absolutePath)
|
||||
workingDir(rootProject.projectDir)
|
||||
/* Configure tests */
|
||||
|
||||
testsJar()
|
||||
|
||||
val k1TestRuntimeClasspath by configurations.creating
|
||||
val analysisApiRuntimeClasspath by configurations.creating
|
||||
|
||||
dependencies {
|
||||
k1TestRuntimeClasspath(project(":native:objcexport-header-generator-k1"))
|
||||
k1TestRuntimeClasspath(projectTests(":native:objcexport-header-generator-k1"))
|
||||
|
||||
analysisApiRuntimeClasspath(project(":native:objcexport-header-generator-analysis-api"))
|
||||
analysisApiRuntimeClasspath(projectTests(":native:objcexport-header-generator-analysis-api"))
|
||||
}
|
||||
|
||||
tasks.test.configure {
|
||||
enabled = false
|
||||
}
|
||||
|
||||
nativeTest("testK1", tag = null) {
|
||||
useJUnitPlatform()
|
||||
enableJunit5ExtensionsAutodetection()
|
||||
classpath += k1TestRuntimeClasspath
|
||||
}
|
||||
|
||||
nativeTest("testAnalysisApi", tag = null) {
|
||||
useJUnitPlatform()
|
||||
enableJunit5ExtensionsAutodetection()
|
||||
testClassesDirs += files(sourceSets.test.map { it.output.classesDirs })
|
||||
classpath += analysisApiRuntimeClasspath
|
||||
}
|
||||
|
||||
tasks.check.configure {
|
||||
dependsOn("testK1")
|
||||
dependsOn(":native:objcexport-header-generator-k1:check")
|
||||
dependsOn(":native:objcexport-header-generator-analysis-api:check")
|
||||
}
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
plugins {
|
||||
kotlin("jvm")
|
||||
}
|
||||
|
||||
kotlin {
|
||||
compilerOptions {
|
||||
/* Required to use Analysis Api */
|
||||
freeCompilerArgs.add("-Xcontext-receivers")
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
api(project(":native:objcexport-header-generator"))
|
||||
api(project(":analysis:analysis-api"))
|
||||
|
||||
testImplementation(projectTests(":native:objcexport-header-generator"))
|
||||
testApi(project(":analysis:analysis-api-standalone"))
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
"main" { projectDefault() }
|
||||
"test" { projectDefault() }
|
||||
}
|
||||
|
||||
testsJar()
|
||||
|
||||
nativeTest("test", tag = null) {
|
||||
useJUnitPlatform()
|
||||
enableJunit5ExtensionsAutodetection()
|
||||
}
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* 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.objcexport
|
||||
|
||||
import org.jetbrains.kotlin.analysis.api.KtAnalysisSession
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.KtClassLikeSymbol
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.KtPropertySymbol
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.nameOrAnonymous
|
||||
import org.jetbrains.kotlin.backend.konan.objcexport.ObjCExportClassOrProtocolName
|
||||
import org.jetbrains.kotlin.backend.konan.objcexport.ObjCExportPropertyName
|
||||
|
||||
interface KtObjCExportNamer {
|
||||
context(KtAnalysisSession)
|
||||
fun getClassOrProtocolName(symbol: KtClassLikeSymbol): ObjCExportClassOrProtocolName
|
||||
|
||||
context(KtAnalysisSession)
|
||||
fun getPropertyName(symbol: KtPropertySymbol): ObjCExportPropertyName
|
||||
}
|
||||
|
||||
fun ObjCExportNamer(): KtObjCExportNamer {
|
||||
return ObjCExportNamerImpl()
|
||||
}
|
||||
|
||||
private class ObjCExportNamerImpl : KtObjCExportNamer {
|
||||
context(KtAnalysisSession)
|
||||
override fun getClassOrProtocolName(symbol: KtClassLikeSymbol): ObjCExportClassOrProtocolName {
|
||||
val resolvedObjCNameAnnotation = symbol.resolveObjCNameAnnotation()
|
||||
|
||||
return ObjCExportClassOrProtocolName(
|
||||
objCName = resolvedObjCNameAnnotation.objCName ?: symbol.nameOrAnonymous.asString(),
|
||||
swiftName = resolvedObjCNameAnnotation.swiftName ?: symbol.nameOrAnonymous.asString()
|
||||
)
|
||||
}
|
||||
|
||||
context(KtAnalysisSession)
|
||||
override fun getPropertyName(symbol: KtPropertySymbol): ObjCExportPropertyName {
|
||||
val resolveObjCNameAnnotation = symbol.resolveObjCNameAnnotation()
|
||||
|
||||
return ObjCExportPropertyName(
|
||||
objCName = resolveObjCNameAnnotation.objCName ?: symbol.name.asString(),
|
||||
swiftName = resolveObjCNameAnnotation.swiftName ?: symbol.name.asString()
|
||||
)
|
||||
}
|
||||
}
|
||||
+72
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* 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.objcexport
|
||||
|
||||
import org.jetbrains.kotlin.analysis.api.KtAnalysisSession
|
||||
import org.jetbrains.kotlin.analysis.api.annotations.KtConstantAnnotationValue
|
||||
import org.jetbrains.kotlin.analysis.api.base.KtConstantValue
|
||||
import org.jetbrains.kotlin.analysis.api.base.KtConstantValue.KtStringConstantValue
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtAnnotatedSymbol
|
||||
import org.jetbrains.kotlin.backend.konan.KonanFqNames
|
||||
|
||||
/**
|
||||
* Represents the values resolved from the [kotlin.native.ObjCName] annotation.
|
||||
*
|
||||
* ### Example
|
||||
*
|
||||
* **Given a class Foo**
|
||||
* ```kotlin
|
||||
* @ObjCName("FooObjC", "FooSwift", true)
|
||||
* class Foo
|
||||
* ```
|
||||
*
|
||||
* **Given class Foo being analyzed**
|
||||
* ```kotlin
|
||||
* val foo = getFooClassOrObjectSymbol()
|
||||
* // ^
|
||||
* // Imaginary method to get the symbol 'Foo' from above
|
||||
*
|
||||
* val resolvedObjCNameAnnotation = foo.resolveObjCNameAnnotation()
|
||||
* // ^
|
||||
* // objCName = "FooObjC"
|
||||
* // swiftName = "FooSwift"
|
||||
* // isExaclt = true
|
||||
* ```
|
||||
*/
|
||||
internal class KtResolvedObjCNameAnnotation(
|
||||
val objCName: String?,
|
||||
val swiftName: String?,
|
||||
val isExact: Boolean,
|
||||
)
|
||||
|
||||
context(KtAnalysisSession)
|
||||
internal fun KtAnnotatedSymbol.resolveObjCNameAnnotation(): KtResolvedObjCNameAnnotation {
|
||||
var objCName: String? = null
|
||||
var swiftName: String? = null
|
||||
var isExact = false
|
||||
|
||||
annotationsList.annotations.find { it.classId?.asSingleFqName() == KonanFqNames.objCName }?.let { annotation ->
|
||||
annotation.arguments.forEach { argument ->
|
||||
when (argument.name.identifier) {
|
||||
"name" -> objCName = argument.expression.let { it as? KtConstantAnnotationValue }
|
||||
?.constantValue?.let { it as KtStringConstantValue }
|
||||
?.value
|
||||
"swiftName" -> swiftName = argument.expression.let { it as? KtConstantAnnotationValue }
|
||||
?.constantValue?.let { it as KtStringConstantValue }
|
||||
?.value
|
||||
"exact" -> isExact = argument.expression.let { it as? KtConstantAnnotationValue }
|
||||
?.constantValue?.let { it as KtConstantValue.KtBooleanConstantValue }
|
||||
?.value ?: isExact
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return KtResolvedObjCNameAnnotation(
|
||||
objCName = objCName,
|
||||
swiftName = swiftName,
|
||||
isExact = isExact
|
||||
)
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* 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.objcexport.testUtils
|
||||
|
||||
import org.jetbrains.kotlin.backend.konan.tests.ObjCExportHeaderGeneratorTest.HeaderGenerator
|
||||
import org.junit.jupiter.api.extension.ExtensionContext
|
||||
import org.junit.jupiter.api.extension.ParameterContext
|
||||
import org.junit.jupiter.api.extension.ParameterResolver
|
||||
import java.io.File
|
||||
|
||||
class AnalysisApiHeaderGeneratorExtension : ParameterResolver {
|
||||
override fun supportsParameter(parameterContext: ParameterContext, extensionContext: ExtensionContext): Boolean {
|
||||
return parameterContext.parameter.type == HeaderGenerator::class.java
|
||||
}
|
||||
|
||||
override fun resolveParameter(parameterContext: ParameterContext, extensionContext: ExtensionContext): Any {
|
||||
return AnalysisApiHeaderGenerator
|
||||
}
|
||||
}
|
||||
|
||||
object AnalysisApiHeaderGenerator : HeaderGenerator {
|
||||
override fun generateHeaders(root: File): String {
|
||||
TODO("Analysis Api based header generation in not yet implemented")
|
||||
}
|
||||
}
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* 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.objcexport.testUtils
|
||||
|
||||
import org.intellij.lang.annotations.Language
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.junit.jupiter.api.extension.AfterEachCallback
|
||||
import org.junit.jupiter.api.extension.ExtensionContext
|
||||
import org.junit.jupiter.api.extension.ExtensionContext.Namespace
|
||||
import org.junit.jupiter.api.extension.ParameterContext
|
||||
import org.junit.jupiter.api.extension.ParameterResolver
|
||||
import java.io.File
|
||||
import java.nio.file.Files
|
||||
|
||||
/**
|
||||
* Provides ability to quickly write tests with 'inline source code' aka passing Kotlin source code as String.
|
||||
*
|
||||
* This interface can be injected into any test class constructor.
|
||||
*
|
||||
* ### Example
|
||||
* ```
|
||||
* class MyTest(
|
||||
* private val inlineSourceCodeAnalysis: InlineSourceCodeAnalysis
|
||||
* ) {
|
||||
* @Test
|
||||
* fun `test - something important`() {
|
||||
* val myFile = inlineSourceCodeAnalysis.createKtFile("class Foo")
|
||||
* analyze(myFile) {
|
||||
* // Use analysis session to write advanced tests
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
interface InlineSourceCodeAnalysis {
|
||||
fun createKtFile(@Language("kotlin") sourceCode: String): KtFile
|
||||
}
|
||||
|
||||
/**
|
||||
* Extension used to inject an instance of [InlineSourceCodeAnalysis] into tests.
|
||||
*/
|
||||
class InlineSourceCodeAnalysisExtension : ParameterResolver, AfterEachCallback {
|
||||
private companion object {
|
||||
val namespace: Namespace = Namespace.create(Any())
|
||||
val tempDirKey = Any()
|
||||
}
|
||||
|
||||
override fun supportsParameter(parameterContext: ParameterContext, extensionContext: ExtensionContext): Boolean {
|
||||
return parameterContext.parameter.type == InlineSourceCodeAnalysis::class.java
|
||||
}
|
||||
|
||||
override fun resolveParameter(parameterContext: ParameterContext, extensionContext: ExtensionContext): Any {
|
||||
val temporaryDirectory = Files.createTempDirectory("inlineSourceCode").toFile()
|
||||
extensionContext.getStore(namespace.append(extensionContext.requiredTestClass)).put(tempDirKey, temporaryDirectory)
|
||||
return InlineSourceCodeAnalysisImpl(temporaryDirectory)
|
||||
}
|
||||
|
||||
override fun afterEach(context: ExtensionContext) {
|
||||
context.getStore(namespace.append(context.requiredTestClass))?.get(tempDirKey, File::class.java)?.deleteRecursively()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple implementation [InlineSourceCodeAnalysis]
|
||||
*/
|
||||
private class InlineSourceCodeAnalysisImpl(private val tempDir: File) : InlineSourceCodeAnalysis {
|
||||
override fun createKtFile(@Language("kotlin") sourceCode: String): KtFile {
|
||||
return createStandaloneAnalysisApiSession(tempDir, listOf(sourceCode))
|
||||
.modulesWithFiles.entries.single()
|
||||
.value.single() as KtFile
|
||||
}
|
||||
}
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* 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.objcexport.testUtils
|
||||
|
||||
import org.jetbrains.kotlin.analysis.api.KtAnalysisApiInternals
|
||||
import org.jetbrains.kotlin.analysis.api.lifetime.KtLifetimeTokenProvider
|
||||
import org.jetbrains.kotlin.analysis.api.standalone.KtAlwaysAccessibleLifetimeTokenProvider
|
||||
import org.jetbrains.kotlin.analysis.api.standalone.StandaloneAnalysisAPISession
|
||||
import org.jetbrains.kotlin.analysis.api.standalone.buildStandaloneAnalysisAPISession
|
||||
import org.jetbrains.kotlin.analysis.project.structure.builder.buildKtLibraryModule
|
||||
import org.jetbrains.kotlin.analysis.project.structure.builder.buildKtSourceModule
|
||||
import org.jetbrains.kotlin.backend.konan.testUtils.kotlinNativeStdlibPath
|
||||
import org.jetbrains.kotlin.konan.target.HostManager
|
||||
import org.jetbrains.kotlin.platform.konan.NativePlatforms
|
||||
import java.io.File
|
||||
import kotlin.io.path.Path
|
||||
|
||||
/**
|
||||
* Creates a standalone analysis session from Kotlin source code passed as [kotlinSources]
|
||||
*/
|
||||
fun createStandaloneAnalysisApiSession(
|
||||
tempDir: File,
|
||||
kotlinSources: List<String>,
|
||||
): StandaloneAnalysisAPISession {
|
||||
val testModuleRoot = tempDir.resolve("testModule")
|
||||
testModuleRoot.mkdirs()
|
||||
|
||||
kotlinSources.forEachIndexed { index, kotlinSource ->
|
||||
testModuleRoot.resolve("TestSources$index.kt").apply {
|
||||
writeText(kotlinSource)
|
||||
}
|
||||
}
|
||||
return createStandaloneAnalysisApiSession(listOf(testModuleRoot))
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a standalone analysis session from [kotlinFiles] on disk.
|
||||
* The Kotlin/Native stdlib will be provided as dependency
|
||||
*/
|
||||
fun createStandaloneAnalysisApiSession(kotlinFiles: List<File>): StandaloneAnalysisAPISession {
|
||||
val currentArchitectureTarget = HostManager.host
|
||||
val nativePlatform = NativePlatforms.nativePlatformByTargets(listOf(currentArchitectureTarget))
|
||||
return buildStandaloneAnalysisAPISession {
|
||||
@OptIn(KtAnalysisApiInternals::class)
|
||||
registerProjectService(KtLifetimeTokenProvider::class.java, KtAlwaysAccessibleLifetimeTokenProvider())
|
||||
|
||||
buildKtModuleProvider {
|
||||
platform = nativePlatform
|
||||
val kLib = addModule(
|
||||
buildKtLibraryModule {
|
||||
addBinaryRoot(Path(kotlinNativeStdlibPath))
|
||||
platform = nativePlatform
|
||||
libraryName = "klib"
|
||||
}
|
||||
)
|
||||
addModule(
|
||||
buildKtSourceModule {
|
||||
addSourceRoots(kotlinFiles.map { it.toPath() })
|
||||
addRegularDependency(kLib)
|
||||
platform = nativePlatform
|
||||
moduleName = "source"
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* 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.objcexport.tests
|
||||
|
||||
import org.jetbrains.kotlin.analysis.api.analyze
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.KtNamedClassOrObjectSymbol
|
||||
import org.jetbrains.kotlin.backend.konan.objcexport.ObjCExportClassOrProtocolName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.objcexport.ObjCExportNamer
|
||||
import org.jetbrains.kotlin.objcexport.testUtils.InlineSourceCodeAnalysis
|
||||
import org.junit.jupiter.api.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
class KtObjCExportNamerTest(
|
||||
private val inlineSourceCodeAnalysis: InlineSourceCodeAnalysis,
|
||||
) {
|
||||
|
||||
private val namer = ObjCExportNamer()
|
||||
|
||||
@Test
|
||||
fun `test - simple class`() {
|
||||
val foo = inlineSourceCodeAnalysis.createKtFile("class Foo")
|
||||
analyze(foo) {
|
||||
val fooSymbol = foo.getFileSymbol().getFileScope()
|
||||
.getClassifierSymbols(Name.identifier("Foo"))
|
||||
.single() as KtNamedClassOrObjectSymbol
|
||||
|
||||
assertEquals(
|
||||
ObjCExportClassOrProtocolName("Foo", "Foo"),
|
||||
namer.getClassOrProtocolName(fooSymbol)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* 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.objcexport.tests
|
||||
|
||||
import org.jetbrains.kotlin.objcexport.resolveObjCNameAnnotation
|
||||
import org.jetbrains.kotlin.analysis.api.analyze
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.KtClassLikeSymbol
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.KtFunctionSymbol
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.objcexport.testUtils.InlineSourceCodeAnalysis
|
||||
import org.junit.jupiter.api.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertFalse
|
||||
import kotlin.test.assertNull
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
class KtResolvedObjCNameAnnotationTest(
|
||||
private val inlineSourceCodeAnalysis: InlineSourceCodeAnalysis,
|
||||
) {
|
||||
|
||||
@Test
|
||||
fun `test - class - no ObjCName annotation`() {
|
||||
val ktFile = inlineSourceCodeAnalysis.createKtFile("class Foo")
|
||||
analyze(ktFile) {
|
||||
val fooSymbol = ktFile.getFileSymbol().getFileScope().getClassifierSymbols(Name.identifier("Foo")).single() as KtClassLikeSymbol
|
||||
val resolvedObjCAnnotation = fooSymbol.resolveObjCNameAnnotation()
|
||||
assertNull(resolvedObjCAnnotation.swiftName)
|
||||
assertNull(resolvedObjCAnnotation.objCName)
|
||||
assertFalse(resolvedObjCAnnotation.isExact)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test - class - with ObjCName annotation`() {
|
||||
val ktFile = inlineSourceCodeAnalysis.createKtFile(
|
||||
"""
|
||||
@kotlin.native.ObjCName("FooObjC", "FooSwift", true)
|
||||
class Foo
|
||||
""".trimIndent()
|
||||
)
|
||||
analyze(ktFile) {
|
||||
val fooSymbol = ktFile.getFileSymbol().getFileScope().getClassifierSymbols(Name.identifier("Foo")).single() as KtClassLikeSymbol
|
||||
val resolvedObjCAnnotation = fooSymbol.resolveObjCNameAnnotation()
|
||||
assertEquals("FooObjC", resolvedObjCAnnotation.objCName)
|
||||
assertEquals("FooSwift", resolvedObjCAnnotation.swiftName)
|
||||
assertTrue(resolvedObjCAnnotation.isExact)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test - function - with ObjCName annotation`() {
|
||||
val ktFile = inlineSourceCodeAnalysis.createKtFile(
|
||||
"""
|
||||
@kotlin.native.ObjCName("fooObjC", "fooSwift", true)
|
||||
fun foo() = Unit
|
||||
""".trimIndent()
|
||||
)
|
||||
analyze(ktFile) {
|
||||
val fooSymbol = ktFile.getFileSymbol().getFileScope().getCallableSymbols(Name.identifier("foo")).single() as KtFunctionSymbol
|
||||
val resolvedObjCAnnotation = fooSymbol.resolveObjCNameAnnotation()
|
||||
assertEquals("fooObjC", resolvedObjCAnnotation.objCName)
|
||||
assertEquals("fooSwift", resolvedObjCAnnotation.swiftName)
|
||||
assertTrue(resolvedObjCAnnotation.isExact)
|
||||
}
|
||||
}
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
org.jetbrains.kotlin.objcexport.testUtils.AnalysisApiHeaderGeneratorExtension
|
||||
org.jetbrains.kotlin.objcexport.testUtils.InlineSourceCodeAnalysisExtension
|
||||
@@ -0,0 +1,31 @@
|
||||
plugins {
|
||||
kotlin("jvm")
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
"main" { projectDefault() }
|
||||
"test" { projectDefault() }
|
||||
}
|
||||
|
||||
dependencies {
|
||||
api(project(":native:objcexport-header-generator"))
|
||||
implementation(project(":compiler:cli-base"))
|
||||
implementation(project(":compiler:ir.objcinterop"))
|
||||
implementation(project(":compiler:ir.serialization.native"))
|
||||
implementation(project(":core:descriptors"))
|
||||
|
||||
testImplementation(projectTests(":native:objcexport-header-generator"))
|
||||
}
|
||||
|
||||
kotlin {
|
||||
compilerOptions {
|
||||
optIn.add("org.jetbrains.kotlin.backend.konan.InternalKotlinNativeApi")
|
||||
}
|
||||
}
|
||||
|
||||
testsJar()
|
||||
|
||||
nativeTest("test", tag = null) {
|
||||
useJUnitPlatform()
|
||||
enableJunit5ExtensionsAutodetection()
|
||||
}
|
||||
+10
-2
@@ -46,8 +46,16 @@ internal interface ObjCExportNameTranslator {
|
||||
}
|
||||
|
||||
interface ObjCExportNamer {
|
||||
data class ClassOrProtocolName(val swiftName: String, val objCName: String, val binaryName: String = objCName)
|
||||
data class PropertyName(val swiftName: String, val objCName: String)
|
||||
data class ClassOrProtocolName(
|
||||
override val swiftName: String,
|
||||
override val objCName: String,
|
||||
override val binaryName: String = objCName,
|
||||
) : ObjCExportClassOrProtocolName
|
||||
|
||||
data class PropertyName(
|
||||
override val swiftName: String,
|
||||
override val objCName: String,
|
||||
) : ObjCExportPropertyName
|
||||
|
||||
interface Configuration {
|
||||
val topLevelNamePrefix: String
|
||||
+111
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* 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.objcexport
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.serialization.extractSerializedKdocString
|
||||
import org.jetbrains.kotlin.backend.common.serialization.metadata.findKDocString
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.resolve.source.PsiSourceElement
|
||||
|
||||
fun ObjCExportStubOrigin(descriptor: DeclarationDescriptor?): ObjCExportStubOrigin? {
|
||||
if (descriptor == null) return null
|
||||
|
||||
if (descriptor is DeclarationDescriptorWithSource) {
|
||||
return ObjCExportStubOrigin.Source(descriptor.name, descriptor.findKDocString(), (descriptor.source as? PsiSourceElement)?.psi)
|
||||
}
|
||||
|
||||
assert(descriptor is DeserializedDescriptor) { "Expected '$descriptor' to implement ${DeserializedDescriptor::class.simpleName}" }
|
||||
return ObjCExportStubOrigin.Binary(descriptor.name, descriptor.extractSerializedKdocString())
|
||||
}
|
||||
|
||||
fun ObjCProtocolImpl(
|
||||
name: String,
|
||||
descriptor: ClassDescriptor,
|
||||
superProtocols: List<String>,
|
||||
members: List<ObjCExportStub>,
|
||||
attributes: List<String> = emptyList(),
|
||||
comment: ObjCComment? = null,
|
||||
) = ObjCProtocolImpl(
|
||||
name = name,
|
||||
comment = comment,
|
||||
origin = ObjCExportStubOrigin(descriptor),
|
||||
attributes = attributes,
|
||||
superProtocols = superProtocols,
|
||||
members = members
|
||||
)
|
||||
|
||||
fun ObjCInterfaceImpl(
|
||||
name: String,
|
||||
generics: List<ObjCGenericTypeDeclaration> = emptyList(),
|
||||
descriptor: ClassDescriptor? = null,
|
||||
superClass: String? = null,
|
||||
superClassGenerics: List<ObjCNonNullReferenceType> = emptyList(),
|
||||
superProtocols: List<String> = emptyList(),
|
||||
categoryName: String? = null,
|
||||
members: List<ObjCExportStub> = emptyList(),
|
||||
attributes: List<String> = emptyList(),
|
||||
comment: ObjCComment? = null,
|
||||
) = ObjCInterfaceImpl(
|
||||
name = name,
|
||||
comment = comment,
|
||||
origin = ObjCExportStubOrigin(descriptor),
|
||||
attributes = attributes,
|
||||
superProtocols = superProtocols,
|
||||
members = members,
|
||||
categoryName = categoryName,
|
||||
generics = generics,
|
||||
superClass = superClass,
|
||||
superClassGenerics = superClassGenerics
|
||||
)
|
||||
|
||||
fun ObjCMethod(
|
||||
descriptor: DeclarationDescriptor?,
|
||||
isInstanceMethod: Boolean,
|
||||
returnType: ObjCType,
|
||||
selectors: List<String>,
|
||||
parameters: List<ObjCParameter>,
|
||||
attributes: List<String>,
|
||||
comment: ObjCComment? = null,
|
||||
) = ObjCMethod(
|
||||
comment = comment,
|
||||
origin = ObjCExportStubOrigin(descriptor),
|
||||
isInstanceMethod = isInstanceMethod,
|
||||
returnType = returnType,
|
||||
selectors = selectors,
|
||||
parameters = parameters,
|
||||
attributes = attributes
|
||||
)
|
||||
|
||||
fun ObjCParameter(
|
||||
name: String,
|
||||
descriptor: ParameterDescriptor?,
|
||||
type: ObjCType,
|
||||
) = ObjCParameter(
|
||||
name = name,
|
||||
origin = ObjCExportStubOrigin(descriptor),
|
||||
type = type,
|
||||
todo = null
|
||||
)
|
||||
|
||||
fun ObjCProperty(
|
||||
name: String,
|
||||
descriptor: DeclarationDescriptorWithSource?,
|
||||
type: ObjCType,
|
||||
propertyAttributes: List<String>,
|
||||
setterName: String? = null,
|
||||
getterName: String? = null,
|
||||
declarationAttributes: List<String> = emptyList(),
|
||||
comment: ObjCComment? = null,
|
||||
) = ObjCProperty(
|
||||
name = name,
|
||||
comment = comment,
|
||||
origin = ObjCExportStubOrigin(descriptor),
|
||||
type = type,
|
||||
propertyAttributes = propertyAttributes,
|
||||
setterName = setterName,
|
||||
getterName = getterName,
|
||||
declarationAttributes = declarationAttributes
|
||||
)
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* 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.
|
||||
*/
|
||||
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* 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.objcexport
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
|
||||
|
||||
fun ObjCGenericTypeParameterUsage(
|
||||
typeParameterDescriptor: TypeParameterDescriptor,
|
||||
namer: ObjCExportNamer,
|
||||
) = ObjCGenericTypeParameterUsage(
|
||||
typeName = namer.getTypeParameterName(typeParameterDescriptor)
|
||||
)
|
||||
|
||||
fun ObjCGenericTypeParameterDeclaration(
|
||||
typeParameterDescriptor: TypeParameterDescriptor,
|
||||
namer: ObjCExportNamer,
|
||||
) = ObjCGenericTypeParameterDeclaration(
|
||||
typeName = namer.getTypeParameterName(typeParameterDescriptor),
|
||||
variance = ObjCVariance.fromKotlinVariance(typeParameterDescriptor.variance)
|
||||
)
|
||||
+5
@@ -1,3 +1,8 @@
|
||||
/*
|
||||
* 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.objcexport
|
||||
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the LICENSE file.
|
||||
* 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.objcexport
|
||||
+33
-2
@@ -6,15 +6,46 @@
|
||||
package org.jetbrains.kotlin.backend.konan.testUtils
|
||||
|
||||
import com.intellij.openapi.Disposable
|
||||
import com.intellij.openapi.util.Disposer
|
||||
import org.jetbrains.kotlin.backend.konan.UnitSuspendFunctionObjCExport
|
||||
import org.jetbrains.kotlin.backend.konan.objcexport.*
|
||||
import org.jetbrains.kotlin.backend.konan.tests.ObjCExportHeaderGeneratorTest
|
||||
import org.jetbrains.kotlin.builtins.DefaultBuiltIns
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import org.junit.jupiter.api.extension.AfterEachCallback
|
||||
import org.junit.jupiter.api.extension.ExtensionContext
|
||||
import org.junit.jupiter.api.extension.ParameterContext
|
||||
import org.junit.jupiter.api.extension.ParameterResolver
|
||||
import java.io.File
|
||||
|
||||
object Fe10ObjCExportHeaderGenerator : AbstractObjCExportHeaderGeneratorTest.ObjCExportHeaderGenerator {
|
||||
override fun generateHeaders(disposable: Disposable, root: File): String {
|
||||
|
||||
class Fe10HeaderGeneratorExtension : ParameterResolver, AfterEachCallback {
|
||||
|
||||
companion object {
|
||||
val namespace = ExtensionContext.Namespace.create(Fe10HeaderGeneratorExtension::class)
|
||||
val disposableKey = "disposable"
|
||||
}
|
||||
|
||||
override fun supportsParameter(parameterContext: ParameterContext, extensionContext: ExtensionContext): Boolean {
|
||||
return parameterContext.parameter.type == ObjCExportHeaderGeneratorTest.HeaderGenerator::class.java
|
||||
}
|
||||
|
||||
override fun resolveParameter(parameterContext: ParameterContext, extensionContext: ExtensionContext): Any {
|
||||
val disposable = Disposer.newDisposable()
|
||||
extensionContext.getStore(namespace).put(disposableKey, disposable)
|
||||
return Fe10HeaderGeneratorImpl(disposable)
|
||||
}
|
||||
|
||||
override fun afterEach(context: ExtensionContext) {
|
||||
val disposable = context.getStore(namespace).get(disposableKey, Disposable::class.java) ?: return
|
||||
Disposer.dispose(disposable)
|
||||
}
|
||||
}
|
||||
|
||||
private class Fe10HeaderGeneratorImpl(private val disposable: Disposable) :
|
||||
ObjCExportHeaderGeneratorTest.HeaderGenerator {
|
||||
override fun generateHeaders(root: File): String {
|
||||
val headerGenerator = createObjCExportHeaderGenerator(disposable, root)
|
||||
headerGenerator.translateModuleDeclarations()
|
||||
return headerGenerator.build().joinToString(System.lineSeparator())
|
||||
+1
-1
@@ -105,7 +105,7 @@ private object DependenciesContainerImpl : CommonDependenciesContainer {
|
||||
private val klibFactory = KlibMetadataFactories(::KonanBuiltIns, DynamicTypeDeserializer)
|
||||
|
||||
private val stdlibModuleDescriptor = klibFactory.DefaultDeserializedDescriptorFactory.createDescriptor(
|
||||
library = resolveSingleFileKlib(org.jetbrains.kotlin.konan.file.File("$konanHomePath/klib/common/stdlib")),
|
||||
library = resolveSingleFileKlib(org.jetbrains.kotlin.konan.file.File(kotlinNativeStdlibPath)),
|
||||
languageVersionSettings = createLanguageVersionSettings(),
|
||||
builtIns = DefaultBuiltIns.Instance,
|
||||
storageManager = LockBasedStorageManager.NO_LOCKS,
|
||||
-1
@@ -52,7 +52,6 @@ interface InlineSourceTestEnvironment {
|
||||
val testTempDir: File
|
||||
}
|
||||
|
||||
|
||||
interface InlineSourceCodeCollector {
|
||||
fun source(@Language("kotlin") sourceCode: String)
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
org.jetbrains.kotlin.backend.konan.testUtils.Fe10HeaderGeneratorExtension
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* 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.objcexport
|
||||
|
||||
sealed interface ObjCExportName {
|
||||
val swiftName: String
|
||||
val objCName: String
|
||||
}
|
||||
|
||||
interface ObjCExportClassOrProtocolName : ObjCExportName {
|
||||
val binaryName: String
|
||||
}
|
||||
|
||||
interface ObjCExportPropertyName : ObjCExportName
|
||||
|
||||
fun ObjCExportClassOrProtocolName(
|
||||
swiftName: String,
|
||||
objCName: String,
|
||||
binaryName: String = objCName,
|
||||
): ObjCExportClassOrProtocolName = ObjCExportClassOrProtocolNameImpl(
|
||||
swiftName = swiftName,
|
||||
objCName = objCName,
|
||||
binaryName = binaryName
|
||||
)
|
||||
|
||||
private data class ObjCExportClassOrProtocolNameImpl(
|
||||
override val swiftName: String,
|
||||
override val objCName: String,
|
||||
override val binaryName: String,
|
||||
) : ObjCExportClassOrProtocolName
|
||||
|
||||
fun ObjCExportPropertyName(
|
||||
swiftName: String,
|
||||
objCName: String,
|
||||
): ObjCExportPropertyName = ObjCExportPropertyNameImpl(
|
||||
swiftName = swiftName,
|
||||
objCName = objCName
|
||||
)
|
||||
|
||||
private data class ObjCExportPropertyNameImpl(
|
||||
override val swiftName: String,
|
||||
override val objCName: String,
|
||||
) : ObjCExportPropertyName
|
||||
+1
-17
@@ -6,24 +6,8 @@
|
||||
package org.jetbrains.kotlin.backend.konan.objcexport
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.backend.common.serialization.extractSerializedKdocString
|
||||
import org.jetbrains.kotlin.backend.common.serialization.metadata.findKDocString
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptorWithSource
|
||||
import org.jetbrains.kotlin.descriptors.DeserializedDescriptor
|
||||
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.source.PsiSourceElement
|
||||
|
||||
fun ObjCExportStubOrigin(descriptor: DeclarationDescriptor?): ObjCExportStubOrigin? {
|
||||
if (descriptor == null) return null
|
||||
|
||||
if (descriptor is DeclarationDescriptorWithSource) {
|
||||
return ObjCExportStubOrigin.Source(descriptor.name, descriptor.findKDocString(), (descriptor.source as? PsiSourceElement)?.psi)
|
||||
}
|
||||
|
||||
assert(descriptor is DeserializedDescriptor) { "Expected '$descriptor' to implement ${DeserializedDescriptor::class.simpleName}" }
|
||||
return ObjCExportStubOrigin.Binary(descriptor.name, descriptor.extractSerializedKdocString())
|
||||
}
|
||||
|
||||
sealed class ObjCExportStubOrigin {
|
||||
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright 2010-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the LICENSE file.
|
||||
* 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.objcexport
|
||||
+6
-3
@@ -1,10 +1,12 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the LICENSE file.
|
||||
* 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.objcexport
|
||||
|
||||
import org.jetbrains.kotlin.backend.konan.InternalKotlinNativeApi
|
||||
|
||||
object StubRenderer {
|
||||
fun render(stub: ObjCExportStub): List<String> = render(stub, false)
|
||||
|
||||
@@ -21,7 +23,8 @@ object StubRenderer {
|
||||
return kDoc.size
|
||||
}
|
||||
|
||||
internal fun render(stub: ObjCExportStub, shouldExportKDoc: Boolean): List<String> = collect {
|
||||
@InternalKotlinNativeApi
|
||||
fun render(stub: ObjCExportStub, shouldExportKDoc: Boolean): List<String> = collect {
|
||||
stub.run {
|
||||
val (kDocEnding, commentBlockEnding) = if (comment?.contentLines == null) {
|
||||
Pair("*/", null) // Close kDoc with `*/`, and print nothing after empty comment
|
||||
+5
-15
@@ -1,12 +1,11 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the LICENSE file.
|
||||
* 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.objcexport
|
||||
|
||||
import org.jetbrains.kotlin.backend.konan.InternalKotlinNativeApi
|
||||
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
|
||||
sealed class ObjCType {
|
||||
@@ -67,12 +66,8 @@ sealed class ObjCGenericTypeUsage : ObjCNonNullReferenceType() {
|
||||
data class ObjCGenericTypeRawUsage(override val typeName: String) : ObjCGenericTypeUsage()
|
||||
|
||||
data class ObjCGenericTypeParameterUsage(
|
||||
val typeParameterDescriptor: TypeParameterDescriptor,
|
||||
val namer: ObjCExportNamer,
|
||||
) : ObjCGenericTypeUsage() {
|
||||
override val typeName: String
|
||||
get() = namer.getTypeParameterName(typeParameterDescriptor)
|
||||
}
|
||||
) : ObjCGenericTypeUsage()
|
||||
|
||||
data class ObjCProtocolType(
|
||||
val protocolName: String,
|
||||
@@ -203,14 +198,9 @@ data class ObjCGenericTypeRawDeclaration(
|
||||
) : ObjCGenericTypeDeclaration()
|
||||
|
||||
data class ObjCGenericTypeParameterDeclaration(
|
||||
val typeParameterDescriptor: TypeParameterDescriptor,
|
||||
val namer: ObjCExportNamer,
|
||||
) : ObjCGenericTypeDeclaration() {
|
||||
override val typeName: String
|
||||
get() = namer.getTypeParameterName(typeParameterDescriptor)
|
||||
override val typeName: String,
|
||||
override val variance: ObjCVariance
|
||||
get() = ObjCVariance.fromKotlinVariance(typeParameterDescriptor.variance)
|
||||
}
|
||||
) : ObjCGenericTypeDeclaration()
|
||||
|
||||
@InternalKotlinNativeApi
|
||||
fun ObjCType.makeNullableIfReferenceOrPointer(): ObjCType = when (this) {
|
||||
+7
-100
@@ -1,17 +1,12 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the LICENSE file.
|
||||
* 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.
|
||||
*/
|
||||
|
||||
@file:JvmName("ObjCExportStubKt")
|
||||
|
||||
package org.jetbrains.kotlin.backend.konan.objcexport
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptorWithSource
|
||||
import org.jetbrains.kotlin.descriptors.ParameterDescriptor
|
||||
|
||||
@Deprecated("Use 'ObjCExportStub' instead", replaceWith = ReplaceWith("ObjCExportStub"))
|
||||
@Suppress("unused")
|
||||
typealias Stub<@Suppress("UNUSED_TYPEALIAS_PARAMETER") T> = ObjCExportStub
|
||||
@@ -77,23 +72,7 @@ class ObjCProtocolImpl(
|
||||
override val attributes: List<String>,
|
||||
override val superProtocols: List<String>,
|
||||
override val members: List<ObjCExportStub>,
|
||||
) : ObjCProtocol() {
|
||||
constructor(
|
||||
name: String,
|
||||
descriptor: ClassDescriptor,
|
||||
superProtocols: List<String>,
|
||||
members: List<ObjCExportStub>,
|
||||
attributes: List<String> = emptyList(),
|
||||
comment: ObjCComment? = null,
|
||||
) : this(
|
||||
name = name,
|
||||
comment = comment,
|
||||
origin = ObjCExportStubOrigin(descriptor),
|
||||
attributes = attributes,
|
||||
superProtocols = superProtocols,
|
||||
members = members
|
||||
)
|
||||
}
|
||||
) : ObjCProtocol()
|
||||
|
||||
class ObjCInterfaceImpl(
|
||||
override val name: String,
|
||||
@@ -106,31 +85,7 @@ class ObjCInterfaceImpl(
|
||||
override val generics: List<ObjCGenericTypeDeclaration>,
|
||||
override val superClass: String?,
|
||||
override val superClassGenerics: List<ObjCNonNullReferenceType>,
|
||||
) : ObjCInterface() {
|
||||
constructor(
|
||||
name: String,
|
||||
generics: List<ObjCGenericTypeDeclaration> = emptyList(),
|
||||
descriptor: ClassDescriptor? = null,
|
||||
superClass: String? = null,
|
||||
superClassGenerics: List<ObjCNonNullReferenceType> = emptyList(),
|
||||
superProtocols: List<String> = emptyList(),
|
||||
categoryName: String? = null,
|
||||
members: List<ObjCExportStub> = emptyList(),
|
||||
attributes: List<String> = emptyList(),
|
||||
comment: ObjCComment? = null,
|
||||
) : this(
|
||||
name = name,
|
||||
comment = comment,
|
||||
origin = ObjCExportStubOrigin(descriptor),
|
||||
attributes = attributes,
|
||||
superProtocols = superProtocols,
|
||||
members = members,
|
||||
categoryName = categoryName,
|
||||
generics = generics,
|
||||
superClass = superClass,
|
||||
superClassGenerics = superClassGenerics
|
||||
)
|
||||
}
|
||||
) : ObjCInterface()
|
||||
|
||||
class ObjCMethod(
|
||||
override val comment: ObjCComment?,
|
||||
@@ -141,43 +96,15 @@ class ObjCMethod(
|
||||
val parameters: List<ObjCParameter>,
|
||||
val attributes: List<String>,
|
||||
) : ObjCExportStub {
|
||||
constructor(
|
||||
descriptor: DeclarationDescriptor?,
|
||||
isInstanceMethod: Boolean,
|
||||
returnType: ObjCType,
|
||||
selectors: List<String>,
|
||||
parameters: List<ObjCParameter>,
|
||||
attributes: List<String>,
|
||||
comment: ObjCComment? = null,
|
||||
) : this(
|
||||
comment = comment,
|
||||
origin = ObjCExportStubOrigin(descriptor),
|
||||
isInstanceMethod = isInstanceMethod,
|
||||
returnType = returnType,
|
||||
selectors = selectors,
|
||||
parameters = parameters,
|
||||
attributes = attributes
|
||||
)
|
||||
|
||||
override val name: String = buildMethodName(selectors, parameters)
|
||||
}
|
||||
|
||||
class ObjCParameter private constructor(
|
||||
class ObjCParameter(
|
||||
override val name: String,
|
||||
override val origin: ObjCExportStubOrigin?,
|
||||
val type: ObjCType,
|
||||
val todo: Nothing?
|
||||
) : ObjCExportStub {
|
||||
|
||||
constructor(
|
||||
name: String,
|
||||
descriptor: ParameterDescriptor?,
|
||||
type: ObjCType,
|
||||
) : this(
|
||||
name = name,
|
||||
origin = ObjCExportStubOrigin(descriptor),
|
||||
type = type
|
||||
)
|
||||
|
||||
override val comment: Nothing? = null
|
||||
}
|
||||
|
||||
@@ -190,27 +117,7 @@ class ObjCProperty(
|
||||
val setterName: String? = null,
|
||||
val getterName: String? = null,
|
||||
val declarationAttributes: List<String> = emptyList(),
|
||||
) : ObjCExportStub {
|
||||
constructor(
|
||||
name: String,
|
||||
descriptor: DeclarationDescriptorWithSource?,
|
||||
type: ObjCType,
|
||||
propertyAttributes: List<String>,
|
||||
setterName: String? = null,
|
||||
getterName: String? = null,
|
||||
declarationAttributes: List<String> = emptyList(),
|
||||
comment: ObjCComment? = null,
|
||||
) : this(
|
||||
name = name,
|
||||
comment = comment,
|
||||
origin = ObjCExportStubOrigin(descriptor),
|
||||
type = type,
|
||||
propertyAttributes = propertyAttributes,
|
||||
setterName = setterName,
|
||||
getterName = getterName,
|
||||
declarationAttributes = declarationAttributes
|
||||
)
|
||||
}
|
||||
) : ObjCExportStub
|
||||
|
||||
private fun buildMethodName(selectors: List<String>, parameters: List<ObjCParameter>): String =
|
||||
if (selectors.size == 1 && parameters.size == 0) {
|
||||
-39
@@ -1,39 +0,0 @@
|
||||
/*
|
||||
* 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.testUtils
|
||||
|
||||
import com.intellij.openapi.Disposable
|
||||
import com.intellij.openapi.util.Disposer
|
||||
import org.jetbrains.kotlin.test.KotlinTestUtils
|
||||
import org.junit.After
|
||||
import java.io.File
|
||||
import kotlin.test.fail
|
||||
|
||||
abstract class AbstractObjCExportHeaderGeneratorTest(
|
||||
private val generator: ObjCExportHeaderGenerator,
|
||||
) {
|
||||
|
||||
fun interface ObjCExportHeaderGenerator {
|
||||
fun generateHeaders(disposable: Disposable, root: File): String
|
||||
}
|
||||
|
||||
private val testRootDisposable = Disposer.newDisposable("${AbstractObjCExportHeaderGeneratorTest::class.simpleName}.testRootDisposable")
|
||||
protected val objCExportTestDataDir = testDataDir.resolve("objcexport")
|
||||
|
||||
@After
|
||||
fun dispose() {
|
||||
Disposer.dispose(testRootDisposable)
|
||||
}
|
||||
|
||||
|
||||
protected fun doTest(root: File) {
|
||||
if (!root.isDirectory) fail("Expected ${root.absolutePath} to be directory")
|
||||
val generatedHeaders = generator.generateHeaders(testRootDisposable, root)
|
||||
KotlinTestUtils.assertEqualsToFile(root.resolve("!${root.nameWithoutExtension}.h"), generatedHeaders)
|
||||
}
|
||||
}
|
||||
|
||||
abstract class AbstractFE10ObjCExportHeaderGeneratorTest : AbstractObjCExportHeaderGeneratorTest(Fe10ObjCExportHeaderGenerator)
|
||||
-110
@@ -1,110 +0,0 @@
|
||||
/*
|
||||
* 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.tests
|
||||
|
||||
import org.jetbrains.kotlin.backend.konan.objcexport.ObjCExportHeaderGenerator
|
||||
import org.jetbrains.kotlin.backend.konan.testUtils.AbstractFE10ObjCExportHeaderGeneratorTest
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
/**
|
||||
* ## Test Scope
|
||||
* This test will cover the generation of 'objc' headers.
|
||||
* The corresponding class in would be [ObjCExportHeaderGenerator].
|
||||
*
|
||||
* The input of the test are Kotlin source files;
|
||||
* The output is the generated header files;
|
||||
* The output will be compared to already checked in golden files.
|
||||
*
|
||||
* ## How to create a new test
|
||||
* Every test has a corresponding 'root' directory.
|
||||
* All directories are found in `backend.native/functionalTest/testData/objcexport`.
|
||||
*
|
||||
* 1) Create new root directory (e.g. myTest) in testData/objcexport
|
||||
* 2) Place kotlin files into the directory e.g. testData/objcexport/myTest/Foo.kt
|
||||
* 3) Create a test function and call ` doTest(objCExportTestDataDir.resolve("myTest"))`
|
||||
* 4) The first invocation will fail the test, but generates the header that can be checked in (if sufficient)
|
||||
*/
|
||||
class Fe10ObjCExportHeaderGeneratorTest : AbstractFE10ObjCExportHeaderGeneratorTest() {
|
||||
@Test
|
||||
fun `test - simpleClass`() {
|
||||
doTest(objCExportTestDataDir.resolve("simpleClass"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test - simpleInterface`() {
|
||||
doTest(objCExportTestDataDir.resolve("simpleInterface"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test - simpleEnumClass`() {
|
||||
doTest(objCExportTestDataDir.resolve("simpleEnumClass"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test - simpleObject`() {
|
||||
doTest(objCExportTestDataDir.resolve("simpleObject"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test - topLevelFunction`() {
|
||||
doTest(objCExportTestDataDir.resolve("topLevelFunction"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test - topLevelProperty`() {
|
||||
doTest(objCExportTestDataDir.resolve("topLevelProperty"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test - sameClassNameInDifferentPackage`() {
|
||||
doTest(objCExportTestDataDir.resolve("sameClassNameInDifferentPackage"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test - samePropertyAndFunctionName`() {
|
||||
doTest(objCExportTestDataDir.resolve("samePropertyAndFunctionName"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test - classImplementingInterface`() {
|
||||
doTest(objCExportTestDataDir.resolve("classImplementingInterface"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test - interfaceImplementingInterface`() {
|
||||
doTest(objCExportTestDataDir.resolve("interfaceImplementingInterface"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test - classWithObjCNameAnnotation`() {
|
||||
doTest(objCExportTestDataDir.resolve("classWithObjCNameAnnotation"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test - functionWithObjCNameAnnotation`() {
|
||||
doTest(objCExportTestDataDir.resolve("functionWithObjCNameAnnotation"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test - classWithKDoc`() {
|
||||
doTest(objCExportTestDataDir.resolve("classWithKDoc"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test - classWithHidesFromObjCAnnotation`() {
|
||||
doTest(objCExportTestDataDir.resolve("classWithHidesFromObjCAnnotation"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test - functionWithThrowsAnnotation`() {
|
||||
doTest(objCExportTestDataDir.resolve("functionWithThrowsAnnotation"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test - functionWithErrorType`() {
|
||||
doTest(objCExportTestDataDir.resolve("functionWithErrorType"))
|
||||
}
|
||||
}
|
||||
+4
-1
@@ -8,4 +8,7 @@ package org.jetbrains.kotlin.backend.konan.testUtils
|
||||
private const val konanHomePropertyKey = "kotlin.internal.native.test.nativeHome"
|
||||
|
||||
val konanHomePath: String
|
||||
get() = System.getProperty(konanHomePropertyKey) ?: error("Missing System property: '$konanHomePropertyKey'")
|
||||
get() = System.getProperty(konanHomePropertyKey) ?: error("Missing System property: '$konanHomePropertyKey'")
|
||||
|
||||
val kotlinNativeStdlibPath: String
|
||||
get() = "$konanHomePath/klib/common/stdlib"
|
||||
+2
-2
@@ -7,5 +7,5 @@ package org.jetbrains.kotlin.backend.konan.testUtils
|
||||
|
||||
import java.io.File
|
||||
|
||||
val projectDir = File(System.getProperty("projectDir"))
|
||||
val testDataDir = projectDir.resolve("src/test/testData")
|
||||
val testDataDir = File("native/objcexport-header-generator/testData")
|
||||
val headersTestDataDir = testDataDir.resolve("headers")
|
||||
+122
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
* 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.tests
|
||||
|
||||
import org.jetbrains.kotlin.backend.konan.testUtils.headersTestDataDir
|
||||
import org.jetbrains.kotlin.test.KotlinTestUtils
|
||||
import org.junit.jupiter.api.Test
|
||||
import java.io.File
|
||||
import kotlin.test.fail
|
||||
|
||||
/**
|
||||
* ## Test Scope
|
||||
* This test will cover the generation of 'ObjC' headers.
|
||||
*
|
||||
* The input of the test are Kotlin source files;
|
||||
* The output is the generated header files;
|
||||
* The output will be compared to already checked in golden files.
|
||||
*
|
||||
* ## How to create a new test
|
||||
* Every test has a corresponding 'root' directory.
|
||||
* All directories are found in `native/objcexport-header-generator/testData/headers`.
|
||||
*
|
||||
* 1) Create new root directory (e.g. myTest) in testData/headers
|
||||
* 2) Place kotlin files into the directory e.g. testData/headers/myTest/Foo.kt
|
||||
* 3) Create a test function and call ` doTest(headersTestDataDir.resolve("myTest"))`
|
||||
* 4) The first invocation will fail the test, but generates the header that can be checked in (if sufficient)
|
||||
*/
|
||||
class ObjCExportHeaderGeneratorTest(val generator: HeaderGenerator) {
|
||||
|
||||
@Test
|
||||
fun `test - simpleClass`() {
|
||||
doTest(headersTestDataDir.resolve("simpleClass"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test - simpleInterface`() {
|
||||
doTest(headersTestDataDir.resolve("simpleInterface"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test - simpleEnumClass`() {
|
||||
doTest(headersTestDataDir.resolve("simpleEnumClass"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test - simpleObject`() {
|
||||
doTest(headersTestDataDir.resolve("simpleObject"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test - topLevelFunction`() {
|
||||
doTest(headersTestDataDir.resolve("topLevelFunction"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test - topLevelProperty`() {
|
||||
doTest(headersTestDataDir.resolve("topLevelProperty"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test - sameClassNameInDifferentPackage`() {
|
||||
doTest(headersTestDataDir.resolve("sameClassNameInDifferentPackage"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test - samePropertyAndFunctionName`() {
|
||||
doTest(headersTestDataDir.resolve("samePropertyAndFunctionName"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test - classImplementingInterface`() {
|
||||
doTest(headersTestDataDir.resolve("classImplementingInterface"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test - interfaceImplementingInterface`() {
|
||||
doTest(headersTestDataDir.resolve("interfaceImplementingInterface"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test - classWithObjCNameAnnotation`() {
|
||||
doTest(headersTestDataDir.resolve("classWithObjCNameAnnotation"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test - functionWithObjCNameAnnotation`() {
|
||||
doTest(headersTestDataDir.resolve("functionWithObjCNameAnnotation"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test - classWithKDoc`() {
|
||||
doTest(headersTestDataDir.resolve("classWithKDoc"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test - classWithHidesFromObjCAnnotation`() {
|
||||
doTest(headersTestDataDir.resolve("classWithHidesFromObjCAnnotation"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test - functionWithThrowsAnnotation`() {
|
||||
doTest(headersTestDataDir.resolve("functionWithThrowsAnnotation"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test - functionWithErrorType`() {
|
||||
doTest(headersTestDataDir.resolve("functionWithErrorType"))
|
||||
}
|
||||
|
||||
fun interface HeaderGenerator {
|
||||
fun generateHeaders(root: File): String
|
||||
}
|
||||
|
||||
private fun doTest(root: File) {
|
||||
if (!root.isDirectory) fail("Expected ${root.absolutePath} to be directory")
|
||||
val generatedHeaders = generator.generateHeaders(root)
|
||||
KotlinTestUtils.assertEqualsToFile(root.resolve("!${root.nameWithoutExtension}.h"), generatedHeaders)
|
||||
}
|
||||
}
|
||||
+2
@@ -6,6 +6,8 @@ publishJarsForIde(
|
||||
listOf(
|
||||
":native:base",
|
||||
":native:objcexport-header-generator",
|
||||
":native:objcexport-header-generator-k1",
|
||||
":native:objcexport-header-generator-analysis-api",
|
||||
":compiler:ir.serialization.native"
|
||||
)
|
||||
)
|
||||
|
||||
@@ -265,6 +265,10 @@ fun Project.projectTest(
|
||||
}.apply { configure(body) }
|
||||
}
|
||||
|
||||
fun Test.enableJunit5ExtensionsAutodetection() {
|
||||
systemProperty("junit.jupiter.extensions.autodetection.enabled", "true")
|
||||
}
|
||||
|
||||
val defaultMaxMemoryPerTestWorkerMb = 1600
|
||||
val reservedMemoryMb = 9000 // system processes, gradle daemon, kotlin daemon, etc ...
|
||||
|
||||
|
||||
@@ -112,6 +112,8 @@ include ":benchmarks",
|
||||
":native:executors",
|
||||
":native:base",
|
||||
":native:objcexport-header-generator",
|
||||
":native:objcexport-header-generator-k1",
|
||||
":native:objcexport-header-generator-analysis-api",
|
||||
":core:compiler.common",
|
||||
":core:compiler.common.jvm",
|
||||
":core:compiler.common.js",
|
||||
@@ -695,6 +697,8 @@ project(':native:frontend.native').projectDir = "$rootDir/native/frontend" as Fi
|
||||
project(':native:kotlin-klib-commonizer').projectDir = "$rootDir/native/commonizer" as File
|
||||
project(":native:kotlin-klib-commonizer-api").projectDir = "$rootDir/native/commonizer-api" as File
|
||||
project(':native:kotlin-klib-commonizer-embeddable').projectDir = "$rootDir/native/commonizer-embeddable" as File
|
||||
project(':native:objcexport-header-generator-k1').projectDir = "$rootDir/native/objcexport-header-generator/impl/k1" as File
|
||||
project(':native:objcexport-header-generator-analysis-api').projectDir = "$rootDir/native/objcexport-header-generator/impl/analysis-api" as File
|
||||
project(':plugins:android-extensions-compiler').projectDir = "$rootDir/plugins/android-extensions/android-extensions-compiler" as File
|
||||
project(':kotlin-android-extensions').projectDir = "$rootDir/prepare/android-extensions-compiler-gradle" as File
|
||||
project(':kotlin-parcelize-compiler').projectDir = "$rootDir/prepare/parcelize-compiler-gradle" as File
|
||||
|
||||
Reference in New Issue
Block a user