[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
+1
@@ -7,6 +7,7 @@
|
|||||||
<w>instantiator</w>
|
<w>instantiator</w>
|
||||||
<w>interops</w>
|
<w>interops</w>
|
||||||
<w>klibrary</w>
|
<w>klibrary</w>
|
||||||
|
<w>namer</w>
|
||||||
<w>undispatched</w>
|
<w>undispatched</w>
|
||||||
</words>
|
</words>
|
||||||
</dictionary>
|
</dictionary>
|
||||||
|
|||||||
@@ -337,6 +337,8 @@ val projectsUsedInIntelliJKotlinPlugin =
|
|||||||
arrayOf(
|
arrayOf(
|
||||||
":native:base",
|
":native:base",
|
||||||
":native:objcexport-header-generator",
|
":native:objcexport-header-generator",
|
||||||
|
":native:objcexport-header-generator-k1",
|
||||||
|
":native:objcexport-header-generator-analysis-api",
|
||||||
":compiler:ir.serialization.native"
|
":compiler:ir.serialization.native"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -156,6 +156,7 @@ dependencies {
|
|||||||
|
|
||||||
compilerApi project(":kotlin-native:utilities:basic-utils")
|
compilerApi project(":kotlin-native:utilities:basic-utils")
|
||||||
compilerApi project(":native:objcexport-header-generator")
|
compilerApi project(":native:objcexport-header-generator")
|
||||||
|
compilerApi project(":native:objcexport-header-generator-k1")
|
||||||
compilerApi project(":native:base")
|
compilerApi project(":native:base")
|
||||||
|
|
||||||
compilerImplementation project(":kotlin-compiler")
|
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.backend.konan.objcexport.dumpObjCHeader
|
||||||
import org.jetbrains.kotlin.container.*
|
import org.jetbrains.kotlin.container.*
|
||||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
|
||||||
import org.jetbrains.kotlin.psi.KtFile
|
import org.jetbrains.kotlin.psi.KtFile
|
||||||
import org.jetbrains.kotlin.resolve.deprecation.DeprecationResolver
|
import org.jetbrains.kotlin.resolve.deprecation.DeprecationResolver
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -27,8 +27,8 @@ internal val ProduceObjCExportInterfacePhase = createSimpleNamedCompilerPhase<Ph
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal data class CreateObjCFrameworkInput(
|
internal data class CreateObjCFrameworkInput(
|
||||||
val moduleDescriptor: ModuleDescriptor,
|
val moduleDescriptor: ModuleDescriptor,
|
||||||
val exportedInterface: ObjCExportedInterface,
|
val exportedInterface: ObjCExportedInterface,
|
||||||
)
|
)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+36
-36
@@ -346,9 +346,9 @@ internal class ObjCExportCodeGenerator(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun ObjCExportFunctionGenerationContext.objCBlockPointerToKotlin(
|
private fun ObjCExportFunctionGenerationContext.objCBlockPointerToKotlin(
|
||||||
value: LLVMValueRef,
|
value: LLVMValueRef,
|
||||||
typeBridge: BlockPointerBridge,
|
typeBridge: BlockPointerBridge,
|
||||||
resultLifetime: Lifetime
|
resultLifetime: Lifetime
|
||||||
) = callFromBridge(
|
) = callFromBridge(
|
||||||
blockToKotlinFunctionConverter(typeBridge),
|
blockToKotlinFunctionConverter(typeBridge),
|
||||||
listOf(value),
|
listOf(value),
|
||||||
@@ -356,14 +356,14 @@ internal class ObjCExportCodeGenerator(
|
|||||||
)
|
)
|
||||||
|
|
||||||
internal fun ObjCExportFunctionGenerationContext.kotlinFunctionToRetainedObjCBlockPointer(
|
internal fun ObjCExportFunctionGenerationContext.kotlinFunctionToRetainedObjCBlockPointer(
|
||||||
typeBridge: BlockPointerBridge,
|
typeBridge: BlockPointerBridge,
|
||||||
value: LLVMValueRef
|
value: LLVMValueRef
|
||||||
) = callFromBridge(kotlinFunctionToRetainedBlockConverter(typeBridge), listOf(value))
|
) = callFromBridge(kotlinFunctionToRetainedBlockConverter(typeBridge), listOf(value))
|
||||||
|
|
||||||
fun ObjCExportFunctionGenerationContext.objCToKotlin(
|
fun ObjCExportFunctionGenerationContext.objCToKotlin(
|
||||||
value: LLVMValueRef,
|
value: LLVMValueRef,
|
||||||
typeBridge: TypeBridge,
|
typeBridge: TypeBridge,
|
||||||
resultLifetime: Lifetime
|
resultLifetime: Lifetime
|
||||||
): LLVMValueRef = when (typeBridge) {
|
): LLVMValueRef = when (typeBridge) {
|
||||||
is ReferenceBridge -> objCReferenceToKotlin(value, resultLifetime)
|
is ReferenceBridge -> objCReferenceToKotlin(value, resultLifetime)
|
||||||
is BlockPointerBridge -> objCBlockPointerToKotlin(value, typeBridge, resultLifetime)
|
is BlockPointerBridge -> objCBlockPointerToKotlin(value, typeBridge, resultLifetime)
|
||||||
@@ -894,10 +894,10 @@ private fun ObjCExportFunctionGenerationContextBuilder.setupBridgeDebugInfo() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private inline fun ObjCExportCodeGenerator.generateObjCImpBy(
|
private inline fun ObjCExportCodeGenerator.generateObjCImpBy(
|
||||||
methodBridge: MethodBridge,
|
methodBridge: MethodBridge,
|
||||||
debugInfo: Boolean = false,
|
debugInfo: Boolean = false,
|
||||||
suffix: String,
|
suffix: String,
|
||||||
genBody: ObjCExportFunctionGenerationContext.() -> Unit
|
genBody: ObjCExportFunctionGenerationContext.() -> Unit
|
||||||
): LlvmCallable {
|
): LlvmCallable {
|
||||||
val functionType = objCFunctionType(generationState, methodBridge)
|
val functionType = objCFunctionType(generationState, methodBridge)
|
||||||
val functionName = "objc2kotlin_$suffix"
|
val functionName = "objc2kotlin_$suffix"
|
||||||
@@ -923,11 +923,11 @@ private fun ObjCExportCodeGenerator.generateAbstractObjCImp(methodBridge: Method
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun ObjCExportCodeGenerator.generateObjCImp(
|
private fun ObjCExportCodeGenerator.generateObjCImp(
|
||||||
target: IrFunction?,
|
target: IrFunction?,
|
||||||
baseMethod: IrFunction,
|
baseMethod: IrFunction,
|
||||||
methodBridge: MethodBridge,
|
methodBridge: MethodBridge,
|
||||||
isVirtual: Boolean = false,
|
isVirtual: Boolean = false,
|
||||||
customBridgeSuffix: String? = null,
|
customBridgeSuffix: String? = null,
|
||||||
) = if (target == null) {
|
) = if (target == null) {
|
||||||
generateAbstractObjCImp(methodBridge, baseMethod)
|
generateAbstractObjCImp(methodBridge, baseMethod)
|
||||||
} else {
|
} else {
|
||||||
@@ -953,11 +953,11 @@ private fun ObjCExportCodeGenerator.generateObjCImp(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun ObjCExportCodeGenerator.generateObjCImp(
|
private fun ObjCExportCodeGenerator.generateObjCImp(
|
||||||
methodBridge: MethodBridge,
|
methodBridge: MethodBridge,
|
||||||
isDirect: Boolean,
|
isDirect: Boolean,
|
||||||
baseMethod: IrFunction? = null,
|
baseMethod: IrFunction? = null,
|
||||||
bridgeSuffix: String,
|
bridgeSuffix: String,
|
||||||
callKotlin: ObjCExportFunctionGenerationContext.(
|
callKotlin: ObjCExportFunctionGenerationContext.(
|
||||||
args: List<LLVMValueRef>,
|
args: List<LLVMValueRef>,
|
||||||
resultLifetime: Lifetime,
|
resultLifetime: Lifetime,
|
||||||
exceptionHandler: ExceptionHandler
|
exceptionHandler: ExceptionHandler
|
||||||
@@ -1802,8 +1802,8 @@ private inline fun ObjCExportCodeGenerator.generateObjCToKotlinSyntheticGetter(
|
|||||||
): ObjCExportCodeGenerator.ObjCToKotlinMethodAdapter {
|
): ObjCExportCodeGenerator.ObjCToKotlinMethodAdapter {
|
||||||
|
|
||||||
val methodBridge = MethodBridge(
|
val methodBridge = MethodBridge(
|
||||||
MethodBridge.ReturnValue.Mapped(ReferenceBridge),
|
MethodBridge.ReturnValue.Mapped(ReferenceBridge),
|
||||||
MethodBridgeReceiver.Static, valueParameters = emptyList()
|
MethodBridgeReceiver.Static, valueParameters = emptyList()
|
||||||
)
|
)
|
||||||
|
|
||||||
val functionType = objCFunctionType(generationState, methodBridge)
|
val functionType = objCFunctionType(generationState, methodBridge)
|
||||||
@@ -1818,9 +1818,9 @@ private inline fun ObjCExportCodeGenerator.generateObjCToKotlinSyntheticGetter(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun ObjCExportCodeGenerator.objCToKotlinMethodAdapter(
|
private fun ObjCExportCodeGenerator.objCToKotlinMethodAdapter(
|
||||||
selector: String,
|
selector: String,
|
||||||
methodBridge: MethodBridge,
|
methodBridge: MethodBridge,
|
||||||
imp: LlvmCallable
|
imp: LlvmCallable
|
||||||
): ObjCExportCodeGenerator.ObjCToKotlinMethodAdapter {
|
): ObjCExportCodeGenerator.ObjCToKotlinMethodAdapter {
|
||||||
selectorsToDefine[selector] = methodBridge
|
selectorsToDefine[selector] = methodBridge
|
||||||
|
|
||||||
@@ -1844,9 +1844,9 @@ private fun ObjCExportCodeGenerator.createObjectInstanceAdapter(
|
|||||||
assert(!objectClass.isUnit())
|
assert(!objectClass.isUnit())
|
||||||
|
|
||||||
val methodBridge = MethodBridge(
|
val methodBridge = MethodBridge(
|
||||||
returnBridge = MethodBridge.ReturnValue.Mapped(ReferenceBridge),
|
returnBridge = MethodBridge.ReturnValue.Mapped(ReferenceBridge),
|
||||||
receiver = MethodBridgeReceiver.Static,
|
receiver = MethodBridgeReceiver.Static,
|
||||||
valueParameters = emptyList()
|
valueParameters = emptyList()
|
||||||
)
|
)
|
||||||
|
|
||||||
val function = context.getObjectClassInstanceFunction(objectClass)
|
val function = context.getObjectClassInstanceFunction(objectClass)
|
||||||
@@ -1876,9 +1876,9 @@ private fun ObjCExportCodeGenerator.createEnumValuesOrEntriesAdapter(
|
|||||||
selector: String
|
selector: String
|
||||||
): ObjCExportCodeGenerator.ObjCToKotlinMethodAdapter {
|
): ObjCExportCodeGenerator.ObjCToKotlinMethodAdapter {
|
||||||
val methodBridge = MethodBridge(
|
val methodBridge = MethodBridge(
|
||||||
returnBridge = MethodBridge.ReturnValue.Mapped(ReferenceBridge),
|
returnBridge = MethodBridge.ReturnValue.Mapped(ReferenceBridge),
|
||||||
receiver = MethodBridgeReceiver.Static,
|
receiver = MethodBridgeReceiver.Static,
|
||||||
valueParameters = emptyList()
|
valueParameters = emptyList()
|
||||||
)
|
)
|
||||||
|
|
||||||
val imp = generateObjCImp(function, function, methodBridge, isVirtual = false)
|
val imp = generateObjCImp(function, function, methodBridge, isVirtual = false)
|
||||||
@@ -1888,9 +1888,9 @@ private fun ObjCExportCodeGenerator.createEnumValuesOrEntriesAdapter(
|
|||||||
|
|
||||||
private fun ObjCExportCodeGenerator.createThrowableAsErrorAdapter(): ObjCExportCodeGenerator.ObjCToKotlinMethodAdapter {
|
private fun ObjCExportCodeGenerator.createThrowableAsErrorAdapter(): ObjCExportCodeGenerator.ObjCToKotlinMethodAdapter {
|
||||||
val methodBridge = MethodBridge(
|
val methodBridge = MethodBridge(
|
||||||
returnBridge = MethodBridge.ReturnValue.Mapped(ReferenceBridge),
|
returnBridge = MethodBridge.ReturnValue.Mapped(ReferenceBridge),
|
||||||
receiver = MethodBridgeReceiver.Instance,
|
receiver = MethodBridgeReceiver.Instance,
|
||||||
valueParameters = emptyList()
|
valueParameters = emptyList()
|
||||||
)
|
)
|
||||||
|
|
||||||
val imp = generateObjCImpBy(methodBridge, suffix = "ThrowableAsError") {
|
val imp = generateObjCImpBy(methodBridge, suffix = "ThrowableAsError") {
|
||||||
|
|||||||
+3
-3
@@ -14,9 +14,9 @@ import org.jetbrains.kotlin.konan.target.Family
|
|||||||
* Builds Apple bundle directory.
|
* Builds Apple bundle directory.
|
||||||
*/
|
*/
|
||||||
internal class BundleBuilder(
|
internal class BundleBuilder(
|
||||||
private val config: KonanConfig,
|
private val config: KonanConfig,
|
||||||
private val infoPListBuilder: InfoPListBuilder,
|
private val infoPListBuilder: InfoPListBuilder,
|
||||||
private val mainPackageGuesser: MainPackageGuesser,
|
private val mainPackageGuesser: MainPackageGuesser,
|
||||||
) {
|
) {
|
||||||
fun build(
|
fun build(
|
||||||
moduleDescriptor: ModuleDescriptor,
|
moduleDescriptor: ModuleDescriptor,
|
||||||
|
|||||||
+5
-5
@@ -14,11 +14,11 @@ import org.jetbrains.kotlin.konan.target.Family
|
|||||||
* Constructs an Apple framework without a binary.
|
* Constructs an Apple framework without a binary.
|
||||||
*/
|
*/
|
||||||
internal class FrameworkBuilder(
|
internal class FrameworkBuilder(
|
||||||
private val config: KonanConfig,
|
private val config: KonanConfig,
|
||||||
private val infoPListBuilder: InfoPListBuilder,
|
private val infoPListBuilder: InfoPListBuilder,
|
||||||
private val moduleMapBuilder: ModuleMapBuilder,
|
private val moduleMapBuilder: ModuleMapBuilder,
|
||||||
private val objCHeaderWriter: ObjCHeaderWriter,
|
private val objCHeaderWriter: ObjCHeaderWriter,
|
||||||
private val mainPackageGuesser: MainPackageGuesser,
|
private val mainPackageGuesser: MainPackageGuesser,
|
||||||
) {
|
) {
|
||||||
fun build(
|
fun build(
|
||||||
moduleDescriptor: ModuleDescriptor,
|
moduleDescriptor: ModuleDescriptor,
|
||||||
|
|||||||
+6
-6
@@ -26,9 +26,9 @@ internal class InfoPListBuilder(
|
|||||||
private val configuration = config.configuration
|
private val configuration = config.configuration
|
||||||
|
|
||||||
fun build(
|
fun build(
|
||||||
name: String,
|
name: String,
|
||||||
mainPackageGuesser: MainPackageGuesser,
|
mainPackageGuesser: MainPackageGuesser,
|
||||||
moduleDescriptor: ModuleDescriptor,
|
moduleDescriptor: ModuleDescriptor,
|
||||||
): String {
|
): String {
|
||||||
val bundleId = computeBundleID(name, mainPackageGuesser, moduleDescriptor)
|
val bundleId = computeBundleID(name, mainPackageGuesser, moduleDescriptor)
|
||||||
|
|
||||||
@@ -124,9 +124,9 @@ internal class InfoPListBuilder(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun computeBundleID(
|
private fun computeBundleID(
|
||||||
bundleName: String,
|
bundleName: String,
|
||||||
mainPackageGuesser: MainPackageGuesser,
|
mainPackageGuesser: MainPackageGuesser,
|
||||||
moduleDescriptor: ModuleDescriptor,
|
moduleDescriptor: ModuleDescriptor,
|
||||||
): String {
|
): String {
|
||||||
val deprecatedBundleIdOption = configuration[KonanConfigKeys.BUNDLE_ID]
|
val deprecatedBundleIdOption = configuration[KonanConfigKeys.BUNDLE_ID]
|
||||||
val bundleIdOption = configuration[BinaryOptions.bundleId]
|
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.
|
* Populate framework directory with headers, module and info.plist.
|
||||||
*/
|
*/
|
||||||
internal fun createObjCFramework(
|
internal fun createObjCFramework(
|
||||||
config: KonanConfig,
|
config: KonanConfig,
|
||||||
moduleDescriptor: ModuleDescriptor,
|
moduleDescriptor: ModuleDescriptor,
|
||||||
exportedInterface: ObjCExportedInterface,
|
exportedInterface: ObjCExportedInterface,
|
||||||
frameworkDirectory: File
|
frameworkDirectory: File
|
||||||
) {
|
) {
|
||||||
val frameworkName = frameworkDirectory.name.removeSuffix(CompilerOutputKind.FRAMEWORK.suffix())
|
val frameworkName = frameworkDirectory.name.removeSuffix(CompilerOutputKind.FRAMEWORK.suffix())
|
||||||
val frameworkBuilder = FrameworkBuilder(
|
val frameworkBuilder = FrameworkBuilder(
|
||||||
config,
|
config,
|
||||||
infoPListBuilder = InfoPListBuilder(config),
|
infoPListBuilder = InfoPListBuilder(config),
|
||||||
moduleMapBuilder = ModuleMapBuilder(),
|
moduleMapBuilder = ModuleMapBuilder(),
|
||||||
objCHeaderWriter = ObjCHeaderWriter(),
|
objCHeaderWriter = ObjCHeaderWriter(),
|
||||||
mainPackageGuesser = MainPackageGuesser(),
|
mainPackageGuesser = MainPackageGuesser(),
|
||||||
)
|
)
|
||||||
frameworkBuilder.build(
|
frameworkBuilder.build(
|
||||||
moduleDescriptor,
|
moduleDescriptor,
|
||||||
@@ -135,10 +135,10 @@ internal fun createTestBundle(
|
|||||||
|
|
||||||
// TODO: No need for such class in dynamic driver.
|
// TODO: No need for such class in dynamic driver.
|
||||||
internal class ObjCExport(
|
internal class ObjCExport(
|
||||||
private val generationState: NativeGenerationState,
|
private val generationState: NativeGenerationState,
|
||||||
private val moduleDescriptor: ModuleDescriptor,
|
private val moduleDescriptor: ModuleDescriptor,
|
||||||
private val exportedInterface: ObjCExportedInterface?,
|
private val exportedInterface: ObjCExportedInterface?,
|
||||||
private val codeSpec: ObjCExportCodeSpec?
|
private val codeSpec: ObjCExportCodeSpec?
|
||||||
) {
|
) {
|
||||||
private val config = generationState.config
|
private val config = generationState.config
|
||||||
private val target get() = config.target
|
private val target get() = config.target
|
||||||
|
|||||||
@@ -164,6 +164,7 @@ dependencies {
|
|||||||
distPack project(':kotlin-native:Interop:Skia')
|
distPack project(':kotlin-native:Interop:Skia')
|
||||||
distPack project(':kotlin-native:backend.native')
|
distPack project(':kotlin-native:backend.native')
|
||||||
distPack project(':native:objcexport-header-generator')
|
distPack project(':native:objcexport-header-generator')
|
||||||
|
distPack project(':native:objcexport-header-generator-k1')
|
||||||
distPack project(':native:base')
|
distPack project(':native:base')
|
||||||
distPack project(':kotlin-native:utilities:cli-runner')
|
distPack project(':kotlin-native:utilities:cli-runner')
|
||||||
distPack project(':kotlin-native:utilities:basic-utils')
|
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 {
|
plugins {
|
||||||
kotlin("jvm")
|
kotlin("jvm")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sourceSets {
|
||||||
|
"main" { projectDefault() }
|
||||||
|
"test" { projectDefault() }
|
||||||
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation(intellijCore())
|
api(intellijCore())
|
||||||
implementation(project(":compiler:cli-base"))
|
api(project(":native:base"))
|
||||||
implementation(project(":compiler:cli-common"))
|
api(project(":core:compiler.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"))
|
|
||||||
|
|
||||||
testImplementation(libs.junit.jupiter.api)
|
testApi(libs.junit.jupiter.api)
|
||||||
testImplementation(libs.junit.jupiter.params)
|
testApi(libs.junit.jupiter.engine)
|
||||||
testImplementation(project(":compiler:tests-common", "tests-jar"))
|
testApi(libs.junit.jupiter.params)
|
||||||
|
testApi(project(":compiler:tests-common", "tests-jar"))
|
||||||
testRuntimeOnly(libs.junit.jupiter.engine)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
kotlin {
|
kotlin {
|
||||||
@@ -26,8 +26,40 @@ kotlin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
nativeTest("test", tag = null) {
|
/* Configure tests */
|
||||||
useJUnitPlatform()
|
|
||||||
systemProperty("projectDir", projectDir.absolutePath)
|
testsJar()
|
||||||
workingDir(rootProject.projectDir)
|
|
||||||
|
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 {
|
interface ObjCExportNamer {
|
||||||
data class ClassOrProtocolName(val swiftName: String, val objCName: String, val binaryName: String = objCName)
|
data class ClassOrProtocolName(
|
||||||
data class PropertyName(val swiftName: String, val objCName: String)
|
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 {
|
interface Configuration {
|
||||||
val topLevelNamePrefix: String
|
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.
|
* 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
|
package org.jetbrains.kotlin.backend.konan.objcexport
|
||||||
|
|
||||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
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
|
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
* that can be found in the LICENSE file.
|
* 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
|
package org.jetbrains.kotlin.backend.konan.objcexport
|
||||||
+33
-2
@@ -6,15 +6,46 @@
|
|||||||
package org.jetbrains.kotlin.backend.konan.testUtils
|
package org.jetbrains.kotlin.backend.konan.testUtils
|
||||||
|
|
||||||
import com.intellij.openapi.Disposable
|
import com.intellij.openapi.Disposable
|
||||||
|
import com.intellij.openapi.util.Disposer
|
||||||
import org.jetbrains.kotlin.backend.konan.UnitSuspendFunctionObjCExport
|
import org.jetbrains.kotlin.backend.konan.UnitSuspendFunctionObjCExport
|
||||||
import org.jetbrains.kotlin.backend.konan.objcexport.*
|
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.builtins.DefaultBuiltIns
|
||||||
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
|
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
|
||||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
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
|
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)
|
val headerGenerator = createObjCExportHeaderGenerator(disposable, root)
|
||||||
headerGenerator.translateModuleDeclarations()
|
headerGenerator.translateModuleDeclarations()
|
||||||
return headerGenerator.build().joinToString(System.lineSeparator())
|
return headerGenerator.build().joinToString(System.lineSeparator())
|
||||||
+1
-1
@@ -105,7 +105,7 @@ private object DependenciesContainerImpl : CommonDependenciesContainer {
|
|||||||
private val klibFactory = KlibMetadataFactories(::KonanBuiltIns, DynamicTypeDeserializer)
|
private val klibFactory = KlibMetadataFactories(::KonanBuiltIns, DynamicTypeDeserializer)
|
||||||
|
|
||||||
private val stdlibModuleDescriptor = klibFactory.DefaultDeserializedDescriptorFactory.createDescriptor(
|
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(),
|
languageVersionSettings = createLanguageVersionSettings(),
|
||||||
builtIns = DefaultBuiltIns.Instance,
|
builtIns = DefaultBuiltIns.Instance,
|
||||||
storageManager = LockBasedStorageManager.NO_LOCKS,
|
storageManager = LockBasedStorageManager.NO_LOCKS,
|
||||||
-1
@@ -52,7 +52,6 @@ interface InlineSourceTestEnvironment {
|
|||||||
val testTempDir: File
|
val testTempDir: File
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
interface InlineSourceCodeCollector {
|
interface InlineSourceCodeCollector {
|
||||||
fun source(@Language("kotlin") sourceCode: String)
|
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
|
package org.jetbrains.kotlin.backend.konan.objcexport
|
||||||
|
|
||||||
import com.intellij.psi.PsiElement
|
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.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 {
|
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
|
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
* that can be found in the LICENSE file.
|
* 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
|
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
|
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
* that can be found in the LICENSE file.
|
* 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
|
package org.jetbrains.kotlin.backend.konan.objcexport
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.backend.konan.InternalKotlinNativeApi
|
||||||
|
|
||||||
object StubRenderer {
|
object StubRenderer {
|
||||||
fun render(stub: ObjCExportStub): List<String> = render(stub, false)
|
fun render(stub: ObjCExportStub): List<String> = render(stub, false)
|
||||||
|
|
||||||
@@ -21,7 +23,8 @@ object StubRenderer {
|
|||||||
return kDoc.size
|
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 {
|
stub.run {
|
||||||
val (kDocEnding, commentBlockEnding) = if (comment?.contentLines == null) {
|
val (kDocEnding, commentBlockEnding) = if (comment?.contentLines == null) {
|
||||||
Pair("*/", null) // Close kDoc with `*/`, and print nothing after empty comment
|
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
|
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
* that can be found in the LICENSE file.
|
* 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
|
package org.jetbrains.kotlin.backend.konan.objcexport
|
||||||
|
|
||||||
import org.jetbrains.kotlin.backend.konan.InternalKotlinNativeApi
|
import org.jetbrains.kotlin.backend.konan.InternalKotlinNativeApi
|
||||||
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
|
|
||||||
import org.jetbrains.kotlin.types.Variance
|
import org.jetbrains.kotlin.types.Variance
|
||||||
|
|
||||||
sealed class ObjCType {
|
sealed class ObjCType {
|
||||||
@@ -67,12 +66,8 @@ sealed class ObjCGenericTypeUsage : ObjCNonNullReferenceType() {
|
|||||||
data class ObjCGenericTypeRawUsage(override val typeName: String) : ObjCGenericTypeUsage()
|
data class ObjCGenericTypeRawUsage(override val typeName: String) : ObjCGenericTypeUsage()
|
||||||
|
|
||||||
data class ObjCGenericTypeParameterUsage(
|
data class ObjCGenericTypeParameterUsage(
|
||||||
val typeParameterDescriptor: TypeParameterDescriptor,
|
|
||||||
val namer: ObjCExportNamer,
|
|
||||||
) : ObjCGenericTypeUsage() {
|
|
||||||
override val typeName: String
|
override val typeName: String
|
||||||
get() = namer.getTypeParameterName(typeParameterDescriptor)
|
) : ObjCGenericTypeUsage()
|
||||||
}
|
|
||||||
|
|
||||||
data class ObjCProtocolType(
|
data class ObjCProtocolType(
|
||||||
val protocolName: String,
|
val protocolName: String,
|
||||||
@@ -203,14 +198,9 @@ data class ObjCGenericTypeRawDeclaration(
|
|||||||
) : ObjCGenericTypeDeclaration()
|
) : ObjCGenericTypeDeclaration()
|
||||||
|
|
||||||
data class ObjCGenericTypeParameterDeclaration(
|
data class ObjCGenericTypeParameterDeclaration(
|
||||||
val typeParameterDescriptor: TypeParameterDescriptor,
|
override val typeName: String,
|
||||||
val namer: ObjCExportNamer,
|
|
||||||
) : ObjCGenericTypeDeclaration() {
|
|
||||||
override val typeName: String
|
|
||||||
get() = namer.getTypeParameterName(typeParameterDescriptor)
|
|
||||||
override val variance: ObjCVariance
|
override val variance: ObjCVariance
|
||||||
get() = ObjCVariance.fromKotlinVariance(typeParameterDescriptor.variance)
|
) : ObjCGenericTypeDeclaration()
|
||||||
}
|
|
||||||
|
|
||||||
@InternalKotlinNativeApi
|
@InternalKotlinNativeApi
|
||||||
fun ObjCType.makeNullableIfReferenceOrPointer(): ObjCType = when (this) {
|
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
|
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
* that can be found in the LICENSE file.
|
* 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")
|
@file:JvmName("ObjCExportStubKt")
|
||||||
|
|
||||||
package org.jetbrains.kotlin.backend.konan.objcexport
|
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"))
|
@Deprecated("Use 'ObjCExportStub' instead", replaceWith = ReplaceWith("ObjCExportStub"))
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
typealias Stub<@Suppress("UNUSED_TYPEALIAS_PARAMETER") T> = ObjCExportStub
|
typealias Stub<@Suppress("UNUSED_TYPEALIAS_PARAMETER") T> = ObjCExportStub
|
||||||
@@ -77,23 +72,7 @@ class ObjCProtocolImpl(
|
|||||||
override val attributes: List<String>,
|
override val attributes: List<String>,
|
||||||
override val superProtocols: List<String>,
|
override val superProtocols: List<String>,
|
||||||
override val members: List<ObjCExportStub>,
|
override val members: List<ObjCExportStub>,
|
||||||
) : ObjCProtocol() {
|
) : 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
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
class ObjCInterfaceImpl(
|
class ObjCInterfaceImpl(
|
||||||
override val name: String,
|
override val name: String,
|
||||||
@@ -106,31 +85,7 @@ class ObjCInterfaceImpl(
|
|||||||
override val generics: List<ObjCGenericTypeDeclaration>,
|
override val generics: List<ObjCGenericTypeDeclaration>,
|
||||||
override val superClass: String?,
|
override val superClass: String?,
|
||||||
override val superClassGenerics: List<ObjCNonNullReferenceType>,
|
override val superClassGenerics: List<ObjCNonNullReferenceType>,
|
||||||
) : ObjCInterface() {
|
) : 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
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
class ObjCMethod(
|
class ObjCMethod(
|
||||||
override val comment: ObjCComment?,
|
override val comment: ObjCComment?,
|
||||||
@@ -141,43 +96,15 @@ class ObjCMethod(
|
|||||||
val parameters: List<ObjCParameter>,
|
val parameters: List<ObjCParameter>,
|
||||||
val attributes: List<String>,
|
val attributes: List<String>,
|
||||||
) : ObjCExportStub {
|
) : 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)
|
override val name: String = buildMethodName(selectors, parameters)
|
||||||
}
|
}
|
||||||
|
|
||||||
class ObjCParameter private constructor(
|
class ObjCParameter(
|
||||||
override val name: String,
|
override val name: String,
|
||||||
override val origin: ObjCExportStubOrigin?,
|
override val origin: ObjCExportStubOrigin?,
|
||||||
val type: ObjCType,
|
val type: ObjCType,
|
||||||
|
val todo: Nothing?
|
||||||
) : ObjCExportStub {
|
) : ObjCExportStub {
|
||||||
|
|
||||||
constructor(
|
|
||||||
name: String,
|
|
||||||
descriptor: ParameterDescriptor?,
|
|
||||||
type: ObjCType,
|
|
||||||
) : this(
|
|
||||||
name = name,
|
|
||||||
origin = ObjCExportStubOrigin(descriptor),
|
|
||||||
type = type
|
|
||||||
)
|
|
||||||
|
|
||||||
override val comment: Nothing? = null
|
override val comment: Nothing? = null
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -190,27 +117,7 @@ class ObjCProperty(
|
|||||||
val setterName: String? = null,
|
val setterName: String? = null,
|
||||||
val getterName: String? = null,
|
val getterName: String? = null,
|
||||||
val declarationAttributes: List<String> = emptyList(),
|
val declarationAttributes: List<String> = emptyList(),
|
||||||
) : ObjCExportStub {
|
) : 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
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun buildMethodName(selectors: List<String>, parameters: List<ObjCParameter>): String =
|
private fun buildMethodName(selectors: List<String>, parameters: List<ObjCParameter>): String =
|
||||||
if (selectors.size == 1 && parameters.size == 0) {
|
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"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+3
@@ -9,3 +9,6 @@ private const val konanHomePropertyKey = "kotlin.internal.native.test.nativeHome
|
|||||||
|
|
||||||
val konanHomePath: String
|
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
|
import java.io.File
|
||||||
|
|
||||||
val projectDir = File(System.getProperty("projectDir"))
|
val testDataDir = File("native/objcexport-header-generator/testData")
|
||||||
val testDataDir = projectDir.resolve("src/test/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(
|
listOf(
|
||||||
":native:base",
|
":native:base",
|
||||||
":native:objcexport-header-generator",
|
":native:objcexport-header-generator",
|
||||||
|
":native:objcexport-header-generator-k1",
|
||||||
|
":native:objcexport-header-generator-analysis-api",
|
||||||
":compiler:ir.serialization.native"
|
":compiler:ir.serialization.native"
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -265,6 +265,10 @@ fun Project.projectTest(
|
|||||||
}.apply { configure(body) }
|
}.apply { configure(body) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun Test.enableJunit5ExtensionsAutodetection() {
|
||||||
|
systemProperty("junit.jupiter.extensions.autodetection.enabled", "true")
|
||||||
|
}
|
||||||
|
|
||||||
val defaultMaxMemoryPerTestWorkerMb = 1600
|
val defaultMaxMemoryPerTestWorkerMb = 1600
|
||||||
val reservedMemoryMb = 9000 // system processes, gradle daemon, kotlin daemon, etc ...
|
val reservedMemoryMb = 9000 // system processes, gradle daemon, kotlin daemon, etc ...
|
||||||
|
|
||||||
|
|||||||
@@ -112,6 +112,8 @@ include ":benchmarks",
|
|||||||
":native:executors",
|
":native:executors",
|
||||||
":native:base",
|
":native:base",
|
||||||
":native:objcexport-header-generator",
|
":native:objcexport-header-generator",
|
||||||
|
":native:objcexport-header-generator-k1",
|
||||||
|
":native:objcexport-header-generator-analysis-api",
|
||||||
":core:compiler.common",
|
":core:compiler.common",
|
||||||
":core:compiler.common.jvm",
|
":core:compiler.common.jvm",
|
||||||
":core:compiler.common.js",
|
":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').projectDir = "$rootDir/native/commonizer" as File
|
||||||
project(":native:kotlin-klib-commonizer-api").projectDir = "$rootDir/native/commonizer-api" 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: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(':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-android-extensions').projectDir = "$rootDir/prepare/android-extensions-compiler-gradle" as File
|
||||||
project(':kotlin-parcelize-compiler').projectDir = "$rootDir/prepare/parcelize-compiler-gradle" as File
|
project(':kotlin-parcelize-compiler').projectDir = "$rootDir/prepare/parcelize-compiler-gradle" as File
|
||||||
|
|||||||
Reference in New Issue
Block a user