diff --git a/.gitignore b/.gitignore
index caac4238..9d1879fd 100644
--- a/.gitignore
+++ b/.gitignore
@@ -18,6 +18,7 @@ build
!.idea/codeStyles/*
!.idea/icon.svg
!.idea/detekt.xml
+!.idea/kotlinTestDataPluginTestDataPaths.xml
.DS_Store
diff --git a/.idea/kotlinTestDataPluginTestDataPaths.xml b/.idea/kotlinTestDataPluginTestDataPaths.xml
new file mode 100644
index 00000000..3d2ddced
--- /dev/null
+++ b/.idea/kotlinTestDataPluginTestDataPaths.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/build.gradle.kts b/build.gradle.kts
index c8873ab0..3c690453 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -30,8 +30,7 @@ apiValidation {
ignoredProjects.addAll(
listOf(
- "codegen-tests-jvm",
- "codegen-tests-mpp",
+ "compiler-plugin-tests",
"krpc-test",
"utils",
)
diff --git a/compiler-plugin/compiler-plugin-backend/src/main/core/kotlinx/rpc/codegen/RPCIrPlugin.kt b/compiler-plugin/compiler-plugin-backend/src/main/core/kotlinx/rpc/codegen/RPCIrPlugin.kt
deleted file mode 100644
index 3ad1c0d8..00000000
--- a/compiler-plugin/compiler-plugin-backend/src/main/core/kotlinx/rpc/codegen/RPCIrPlugin.kt
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright 2023-2024 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
- */
-
-package kotlinx.rpc.codegen
-
-import kotlinx.rpc.codegen.extension.RPCIrExtension
-import org.jetbrains.kotlin.backend.common.extensions.IrGenerationExtension
-import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
-import org.jetbrains.kotlin.cli.common.messages.MessageCollector
-import org.jetbrains.kotlin.config.CompilerConfiguration
-
-object RPCIrPlugin {
- fun provideExtension(configuration: CompilerConfiguration): IrGenerationExtension {
- val logger = configuration.get(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY, MessageCollector.NONE)
- val versionSpecificApi = VersionSpecificApi.INSTANCE
-
- return RPCIrExtension(logger, versionSpecificApi)
- }
-}
diff --git a/compiler-plugin/compiler-plugin-backend/src/main/core/kotlinx/rpc/codegen/extension/RPCIrExtension.kt b/compiler-plugin/compiler-plugin-backend/src/main/core/kotlinx/rpc/codegen/extension/RPCIrExtension.kt
index a2235cf6..6a45a044 100644
--- a/compiler-plugin/compiler-plugin-backend/src/main/core/kotlinx/rpc/codegen/extension/RPCIrExtension.kt
+++ b/compiler-plugin/compiler-plugin-backend/src/main/core/kotlinx/rpc/codegen/extension/RPCIrExtension.kt
@@ -7,18 +7,19 @@ package kotlinx.rpc.codegen.extension
import kotlinx.rpc.codegen.VersionSpecificApi
import org.jetbrains.kotlin.backend.common.extensions.IrGenerationExtension
import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext
+import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
+import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
-internal class RPCIrExtension(
- private val logger: MessageCollector,
- private val versionSpecificApi: VersionSpecificApi,
-) : IrGenerationExtension {
+class RPCIrExtension(configuration: CompilerConfiguration) : IrGenerationExtension {
+ private val logger = configuration.get(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY, MessageCollector.NONE)
+
override fun generate(
moduleFragment: IrModuleFragment,
pluginContext: IrPluginContext,
) {
- val context = RPCIrContext(pluginContext, versionSpecificApi)
+ val context = RPCIrContext(pluginContext, VersionSpecificApi.INSTANCE)
val processor = RPCIrServiceProcessor(logger)
moduleFragment.transform(processor, context)
diff --git a/compiler-plugin/compiler-plugin-backend/src/main/core/kotlinx/rpc/codegen/extension/RPCStubGenerator.kt b/compiler-plugin/compiler-plugin-backend/src/main/core/kotlinx/rpc/codegen/extension/RPCStubGenerator.kt
index ac7c80dc..4e34f798 100644
--- a/compiler-plugin/compiler-plugin-backend/src/main/core/kotlinx/rpc/codegen/extension/RPCStubGenerator.kt
+++ b/compiler-plugin/compiler-plugin-backend/src/main/core/kotlinx/rpc/codegen/extension/RPCStubGenerator.kt
@@ -5,6 +5,7 @@
package kotlinx.rpc.codegen.extension
import kotlinx.rpc.codegen.VersionSpecificApi
+import kotlinx.rpc.codegen.VersionSpecificApiImpl.copyToVS
import kotlinx.rpc.codegen.common.rpcMethodClassName
import kotlinx.rpc.codegen.common.rpcMethodClassNameKsp
import org.jetbrains.kotlin.backend.common.lower.DeclarationIrBuilder
@@ -1274,7 +1275,7 @@ internal class RPCStubGenerator(
it.name == OperatorNameConventions.EQUALS
}.symbol
- dispatchReceiverParameter = anyClass.thisReceiver
+ dispatchReceiverParameter = anyClass.copyThisReceiver(this@apply)
addValueParameter {
name = Name.identifier("other")
@@ -1295,7 +1296,7 @@ internal class RPCStubGenerator(
it.name == OperatorNameConventions.HASH_CODE
}.symbol
- dispatchReceiverParameter = anyClass.thisReceiver
+ dispatchReceiverParameter = anyClass.copyThisReceiver(this@apply)
}
addFunction {
@@ -1311,10 +1312,13 @@ internal class RPCStubGenerator(
it.name == OperatorNameConventions.TO_STRING
}.symbol
- dispatchReceiverParameter = anyClass.thisReceiver
+ dispatchReceiverParameter = anyClass.copyThisReceiver(this@apply)
}
}
+ private fun IrClass.copyThisReceiver(function: IrFunction) =
+ thisReceiver?.copyToVS(function, origin = IrDeclarationOrigin.DEFINED)
+
private fun stringConst(value: String) = IrConstImpl.string(
startOffset = UNDEFINED_OFFSET,
endOffset = UNDEFINED_OFFSET,
diff --git a/compiler-plugin/compiler-plugin-cli/src/main/latest/kotlinx/rpc/codegen/RPCCompilerPlugin.kt b/compiler-plugin/compiler-plugin-cli/src/main/latest/kotlinx/rpc/codegen/RPCCompilerPlugin.kt
index 63ac652b..5f725c7e 100644
--- a/compiler-plugin/compiler-plugin-cli/src/main/latest/kotlinx/rpc/codegen/RPCCompilerPlugin.kt
+++ b/compiler-plugin/compiler-plugin-cli/src/main/latest/kotlinx/rpc/codegen/RPCCompilerPlugin.kt
@@ -4,6 +4,7 @@
package kotlinx.rpc.codegen
+import kotlinx.rpc.codegen.extension.RPCIrExtension
import org.jetbrains.kotlin.backend.common.extensions.IrGenerationExtension
import org.jetbrains.kotlin.compiler.plugin.CliOption
import org.jetbrains.kotlin.compiler.plugin.CommandLineProcessor
@@ -21,16 +22,17 @@ class RPCCommandLineProcessor : CommandLineProcessor {
@OptIn(ExperimentalCompilerApi::class)
class RPCCompilerPlugin : CompilerPluginRegistrar() {
- init {
- VersionSpecificApi.INSTANCE = VersionSpecificApiImpl
- }
-
override val supportsK2: Boolean = true
override fun ExtensionStorage.registerExtensions(configuration: CompilerConfiguration) {
- val irExtension = RPCIrPlugin.provideExtension(configuration)
-
- IrGenerationExtension.registerExtension(irExtension)
- FirExtensionRegistrarAdapter.registerExtension(FirRPCExtensionRegistrar(configuration))
+ registerRpcExtensions(configuration)
}
}
+
+@OptIn(ExperimentalCompilerApi::class)
+fun CompilerPluginRegistrar.ExtensionStorage.registerRpcExtensions(configuration: CompilerConfiguration) {
+ VersionSpecificApi.INSTANCE = VersionSpecificApiImpl
+
+ IrGenerationExtension.registerExtension(RPCIrExtension(configuration))
+ FirExtensionRegistrarAdapter.registerExtension(FirRPCExtensionRegistrar(configuration))
+}
diff --git a/core/src/commonMain/kotlin/kotlinx/rpc/UninitializedRPCFieldException.kt b/core/src/commonMain/kotlin/kotlinx/rpc/UninitializedRPCFieldException.kt
new file mode 100644
index 00000000..49db36cf
--- /dev/null
+++ b/core/src/commonMain/kotlin/kotlinx/rpc/UninitializedRPCFieldException.kt
@@ -0,0 +1,16 @@
+/*
+ * Copyright 2023-2024 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.rpc
+
+import kotlin.reflect.KProperty
+
+/**
+ * Thrown when an uninitialized field of an RPC interface is accessed.
+ *
+ * Use [awaitFieldInitialization] to await for the field initialization
+ */
+public class UninitializedRPCFieldException(serviceName: String, property: KProperty<*>): Exception() {
+ override val message: String = "${property.name} field of RPC service \"$serviceName\" in not initialized"
+}
diff --git a/core/src/commonMain/kotlin/kotlinx/rpc/awaitFieldInitialization.kt b/core/src/commonMain/kotlin/kotlinx/rpc/awaitFieldInitialization.kt
new file mode 100644
index 00000000..4ad34b8d
--- /dev/null
+++ b/core/src/commonMain/kotlin/kotlinx/rpc/awaitFieldInitialization.kt
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2023-2024 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.rpc
+
+import kotlinx.rpc.internal.RPCDeferredField
+import kotlinx.rpc.internal.RPCServiceFieldsProvider
+import kotlinx.rpc.internal.findRPCStubProvider
+import kotlinx.rpc.internal.safeCast
+import kotlin.reflect.KClass
+
+/**
+ * Waits for the initialization of an RPC field in the generated client:
+ *
+ * ```kotlin
+ * interface MyService : RPC {
+ * val stateFlow: StateFlow
+ * }
+ *
+ * val service = rpcClient.withService()
+ * val currentValue = service.awaitFieldInitialization { stateFlow }.value
+ * ```
+ *
+ * @param T service type
+ * @param R field type
+ * @param getter function that returns the field of the context service to wait for.
+ * @return service filed after it was initialized.
+ */
+public suspend fun T.awaitFieldInitialization(getter: T.() -> R): R {
+ val field = getter()
+
+ if (field is RPCDeferredField<*>) {
+ @Suppress("UNCHECKED_CAST")
+ return (field as RPCDeferredField).await()
+ }
+
+ error("Please choose required field for a valid RPC client generated by RPCClient.withService method")
+}
+
+/**
+ * Waits for the initialization of all RPC fields in the generated client:
+ *
+ * ```kotlin
+ * interface MyService : RPC {
+ * val stateFlow1: StateFlow
+ * val stateFlow2: StateFlow
+ * }
+ *
+ * val service = rpcClient.withService()
+ * val currentValue = service.awaitFieldInitialization()
+ * // fields `stateFlow1` and `stateFlow2` are initialized
+ * ```
+ *
+ * @param T service type
+ * @return specified service, after all of it's field were initialized.
+ */
+public suspend inline fun T.awaitFieldInitialization(): T {
+ return awaitFieldInitialization(T::class)
+}
+
+/**
+ * Waits for the initialization of all RPC fields in the generated client:
+ *
+ * ```kotlin
+ * interface MyService : RPC {
+ * val stateFlow1: StateFlow
+ * val stateFlow2: StateFlow
+ * }
+ *
+ * val service = rpcClient.withService()
+ * val currentValue = service.awaitFieldInitialization(MyService::class)
+ * // fields `stateFlow1` and `stateFlow2` are initialized
+ * ```
+ *
+ * @param T service type
+ * @param kClass [KClass] of the [T] type.
+ * @return specified service, after all of it's field were initialized.
+ */
+public suspend fun T.awaitFieldInitialization(kClass: KClass): T {
+ findRPCStubProvider>(kClass, RPCServiceFieldsProvider::class.safeCast())
+ .rpcFields(this)
+ .forEach { field ->
+ field.await()
+ }
+
+ return this
+}
diff --git a/core/src/commonMain/kotlin/kotlinx/rpc/withService.kt b/core/src/commonMain/kotlin/kotlinx/rpc/withService.kt
new file mode 100644
index 00000000..3b5180b9
--- /dev/null
+++ b/core/src/commonMain/kotlin/kotlinx/rpc/withService.kt
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2023-2024 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.rpc
+
+import kotlinx.atomicfu.atomic
+import kotlinx.rpc.internal.RPCStubServiceProvider
+import kotlinx.rpc.internal.findRPCStubProvider
+import kotlinx.rpc.internal.kClass
+import kotlinx.rpc.internal.safeCast
+import kotlin.reflect.KClass
+import kotlin.reflect.KType
+
+/**
+ * Creates instance of the generated service [T], that is able to communicate with server using RPCClient.
+ *
+ * [awaitFieldInitialization] method can be used on that instance.
+ *
+ * @param T the exact type of the service to be created.
+ * @return instance of the generated service.
+ */
+public inline fun RPCClient.withService(): T {
+ return withService(T::class)
+}
+
+/**
+ * Creates instance of the generated service [T], that is able to communicate with server using RPCClient.
+ *
+ * [awaitFieldInitialization] method can be used on that instance.
+ *
+ * @param T the exact type of the service to be created.
+ * @param serviceKType [KType] of the service to be created.
+ * @return instance of the generated service.
+ */
+public fun RPCClient.withService(serviceKType: KType): T {
+ return withService(serviceKType.kClass())
+}
+
+/**
+ * Counter for locally added services.
+ * Used to differentiate uniques local services, regardless of their type.
+ */
+private val SERVICE_ID = atomic(0L)
+
+/**
+ * Creates instance of the generated service [T], that is able to communicate with server using RPCClient.
+ *
+ * [awaitFieldInitialization] method can be used on that instance.
+ *
+ * @param T the exact type of the service to be created.
+ * @param serviceKClass [KClass] of the service to be created.
+ * @return instance of the generated service.
+ */
+public fun RPCClient.withService(serviceKClass: KClass): T {
+ val provider = findRPCStubProvider>(
+ kClass = serviceKClass,
+ resultKClass = RPCStubServiceProvider::class.safeCast(),
+ )
+
+ val id = SERVICE_ID.incrementAndGet()
+
+ return provider.withClient(id, this)
+}
diff --git a/krpc/krpc-client/src/commonMain/kotlin/kotlinx/rpc/client/RPCClientUtils.kt b/krpc/krpc-client/src/commonMain/kotlin/kotlinx/rpc/client/RPCClientUtils.kt
index 04e827f9..6eddb7d6 100644
--- a/krpc/krpc-client/src/commonMain/kotlin/kotlinx/rpc/client/RPCClientUtils.kt
+++ b/krpc/krpc-client/src/commonMain/kotlin/kotlinx/rpc/client/RPCClientUtils.kt
@@ -4,63 +4,35 @@
package kotlinx.rpc.client
-import kotlinx.atomicfu.atomic
import kotlinx.rpc.RPC
import kotlinx.rpc.RPCClient
-import kotlinx.rpc.internal.RPCStubServiceProvider
-import kotlinx.rpc.internal.findRPCStubProvider
-import kotlinx.rpc.internal.kClass
-import kotlinx.rpc.internal.safeCast
+import kotlinx.rpc.withService
import kotlin.reflect.KClass
import kotlin.reflect.KType
-/**
- * Creates instance of the generated service [T], that is able to communicate with server using RPCClient.
- *
- * [awaitFieldInitialization] method can be used on that instance.
- *
- * @param T exact type of the service to be created.
- * @return instance of the generated service.
- */
+@Deprecated(
+ message = "withService was moved to kotlinx-rpc-core, to kotlinx.rpc package",
+ level = DeprecationLevel.WARNING,
+ replaceWith = ReplaceWith("withService()", "kotlinx.rpc.withService")
+)
public inline fun RPCClient.withService(): T {
- return withService(T::class)
+ return withService()
}
-/**
- * Creates instance of the generated service [T], that is able to communicate with server using RPCClient.
- *
- * [awaitFieldInitialization] method can be used on that instance.
- *
- * @param T exact type of the service to be created.
- * @param serviceKType [KType] of the service to be created.
- * @return instance of the generated service.
- */
+@Deprecated(
+ message = "withService was moved to kotlinx-rpc-core, to kotlinx.rpc package",
+ level = DeprecationLevel.WARNING,
+ replaceWith = ReplaceWith("withService(serviceKType)", "kotlinx.rpc.withService")
+)
public fun RPCClient.withService(serviceKType: KType): T {
- return withService(serviceKType.kClass())
+ return withService(serviceKType)
}
-/**
- * Counter for locally added services.
- * Used to differentiate uniques local services, regardless of their type.
- */
-private val SERVICE_ID = atomic(0L)
-
-/**
- * Creates instance of the generated service [T], that is able to communicate with server using RPCClient.
- *
- * [awaitFieldInitialization] method can be used on that instance.
- *
- * @param T exact type of the service to be created.
- * @param serviceKClass [KClass] of the service to be created.
- * @return instance of the generated service.
- */
+@Deprecated(
+ message = "withService was moved to kotlinx-rpc-core, to kotlinx.rpc package",
+ level = DeprecationLevel.WARNING,
+ replaceWith = ReplaceWith("withService(serviceKClass)", "kotlinx.rpc.withService")
+)
public fun RPCClient.withService(serviceKClass: KClass): T {
- val provider = findRPCStubProvider>(
- kClass = serviceKClass,
- resultKClass = RPCStubServiceProvider::class.safeCast(),
- )
-
- val id = SERVICE_ID.incrementAndGet()
-
- return provider.withClient(id, this)
+ return withService(serviceKClass)
}
diff --git a/krpc/krpc-client/src/commonMain/kotlin/kotlinx/rpc/client/UninitializedRPCFieldException.kt b/krpc/krpc-client/src/commonMain/kotlin/kotlinx/rpc/client/UninitializedRPCFieldException.kt
index 58b94558..80d18fcd 100644
--- a/krpc/krpc-client/src/commonMain/kotlin/kotlinx/rpc/client/UninitializedRPCFieldException.kt
+++ b/krpc/krpc-client/src/commonMain/kotlin/kotlinx/rpc/client/UninitializedRPCFieldException.kt
@@ -4,13 +4,20 @@
package kotlinx.rpc.client
+import kotlinx.rpc.UninitializedRPCFieldException
import kotlin.reflect.KProperty
-/**
- * Thrown when an uninitialized field of an RPC interface is accessed.
- *
- * Use [awaitFieldInitialization] to await for the field initialization
- */
+@Deprecated(
+ message = "UninitializedRPCFieldException was moved to kotlinx-rpc-core, to kotlinx.rpc package",
+ level = DeprecationLevel.WARNING,
+ replaceWith = ReplaceWith(
+ "UninitializedRPCFieldException(serviceName, property)",
+ "kotlinx.rpc.UninitializedRPCFieldException",
+ )
+)
public class UninitializedRPCFieldException(serviceName: String, property: KProperty<*>): Exception() {
- override val message: String = "${property.name} field of RPC service \"$serviceName\" in not initialized"
+ private val inner = UninitializedRPCFieldException(serviceName, property)
+
+ override val message: String = inner.message
+ override val cause: Throwable? = inner.cause
}
diff --git a/krpc/krpc-client/src/commonMain/kotlin/kotlinx/rpc/client/awaitFieldInitialization.kt b/krpc/krpc-client/src/commonMain/kotlin/kotlinx/rpc/client/awaitFieldInitialization.kt
index 7483218f..0dc08d95 100644
--- a/krpc/krpc-client/src/commonMain/kotlin/kotlinx/rpc/client/awaitFieldInitialization.kt
+++ b/krpc/krpc-client/src/commonMain/kotlin/kotlinx/rpc/client/awaitFieldInitialization.kt
@@ -2,88 +2,37 @@
* Copyright 2023-2024 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
*/
+@file:Suppress("RedundantSuspendModifier", "UnusedReceiverParameter", "UNUSED_PARAMETER")
+
package kotlinx.rpc.client
import kotlinx.rpc.RPC
-import kotlinx.rpc.internal.RPCDeferredField
-import kotlinx.rpc.internal.RPCServiceFieldsProvider
-import kotlinx.rpc.internal.findRPCStubProvider
-import kotlinx.rpc.internal.safeCast
+import kotlinx.rpc.awaitFieldInitialization
import kotlin.reflect.KClass
-/**
- * Waits for the initialization of an RPC field in the generated client:
- *
- * ```kotlin
- * interface MyService : RPC {
- * val stateFlow: StateFlow
- * }
- *
- * val service = rpcClient.withService()
- * val currentValue = service.awaitFieldInitialization { stateFlow }.value
- * ```
- *
- * @param T service type
- * @param R field type
- * @param getter function that returns the field of the context service to wait for.
- * @return service filed after it was initialized.
- */
+@Deprecated(
+ message = "awaitFieldInitialization was moved to kotlinx-rpc-core, to kotlinx.rpc package",
+ level = DeprecationLevel.WARNING,
+ replaceWith = ReplaceWith("awaitFieldInitialization(getter)", "kotlinx.rpc.awaitFieldInitialization")
+)
public suspend fun T.awaitFieldInitialization(getter: T.() -> R): R {
- val field = getter()
-
- if (field is RPCDeferredField<*>) {
- @Suppress("UNCHECKED_CAST")
- return (field as RPCDeferredField).await()
- }
-
- error("Please choose required field for a valid RPC client generated by RPCClient.withService method")
+ return awaitFieldInitialization(getter)
}
-/**
- * Waits for the initialization of all RPC fields in the generated client:
- *
- * ```kotlin
- * interface MyService : RPC {
- * val stateFlow1: StateFlow
- * val stateFlow2: StateFlow
- * }
- *
- * val service = rpcClient.withService()
- * val currentValue = service.awaitFieldInitialization()
- * // fields `stateFlow1` and `stateFlow2` are initialized
- * ```
- *
- * @param T service type
- * @return specified service, after all of it's field were initialized.
- */
+@Deprecated(
+ message = "awaitFieldInitialization was moved to kotlinx-rpc-core, to kotlinx.rpc package",
+ level = DeprecationLevel.ERROR,
+ replaceWith = ReplaceWith("awaitFieldInitialization()", "kotlinx.rpc.awaitFieldInitialization")
+)
public suspend inline fun T.awaitFieldInitialization(): T {
- return awaitFieldInitialization(T::class)
+ return awaitFieldInitialization()
}
-/**
- * Waits for the initialization of all RPC fields in the generated client:
- *
- * ```kotlin
- * interface MyService : RPC {
- * val stateFlow1: StateFlow
- * val stateFlow2: StateFlow
- * }
- *
- * val service = rpcClient.withService()
- * val currentValue = service.awaitFieldInitialization(MyService::class)
- * // fields `stateFlow1` and `stateFlow2` are initialized
- * ```
- *
- * @param T service type
- * @param kClass [KClass] of the [T] type.
- * @return specified service, after all of it's field were initialized.
- */
+@Deprecated(
+ message = "awaitFieldInitialization was moved to kotlinx-rpc-core, to kotlinx.rpc package",
+ level = DeprecationLevel.ERROR,
+ replaceWith = ReplaceWith("awaitFieldInitialization(kClass)", "kotlinx.rpc.awaitFieldInitialization")
+)
public suspend fun T.awaitFieldInitialization(kClass: KClass): T {
- findRPCStubProvider>(kClass, RPCServiceFieldsProvider::class.safeCast())
- .rpcFields(this)
- .forEach { field ->
- field.await()
- }
-
- return this
+ return awaitFieldInitialization(kClass)
}
diff --git a/krpc/krpc-client/src/commonMain/kotlin/kotlinx/rpc/client/internal/RPCFieldProvider.kt b/krpc/krpc-client/src/commonMain/kotlin/kotlinx/rpc/client/internal/RPCFieldProvider.kt
index 75f16029..36910d9c 100644
--- a/krpc/krpc-client/src/commonMain/kotlin/kotlinx/rpc/client/internal/RPCFieldProvider.kt
+++ b/krpc/krpc-client/src/commonMain/kotlin/kotlinx/rpc/client/internal/RPCFieldProvider.kt
@@ -6,7 +6,7 @@ package kotlinx.rpc.client.internal
import kotlinx.coroutines.CompletableDeferred
import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.rpc.client.UninitializedRPCFieldException
+import kotlinx.rpc.UninitializedRPCFieldException
import kotlin.reflect.KProperty
internal class RPCFieldProvider(
diff --git a/krpc/krpc-ktor/krpc-ktor-core/src/jvmTest/kotlin/kotlinx/rpc/transport/ktor/KtorTransportTest.kt b/krpc/krpc-ktor/krpc-ktor-core/src/jvmTest/kotlin/kotlinx/rpc/transport/ktor/KtorTransportTest.kt
index 53c1389f..b415f619 100644
--- a/krpc/krpc-ktor/krpc-ktor-core/src/jvmTest/kotlin/kotlinx/rpc/transport/ktor/KtorTransportTest.kt
+++ b/krpc/krpc-ktor/krpc-ktor-core/src/jvmTest/kotlin/kotlinx/rpc/transport/ktor/KtorTransportTest.kt
@@ -10,13 +10,13 @@ import io.ktor.server.application.*
import io.ktor.server.testing.*
import kotlinx.coroutines.cancel
import kotlinx.rpc.RPC
-import kotlinx.rpc.client.withService
import kotlinx.rpc.serialization.json
import kotlinx.rpc.transport.ktor.client.installRPC
import kotlinx.rpc.transport.ktor.client.rpc
import kotlinx.rpc.transport.ktor.client.rpcConfig
import kotlinx.rpc.transport.ktor.server.RPC
import kotlinx.rpc.transport.ktor.server.rpc
+import kotlinx.rpc.withService
import org.junit.Assert.assertEquals
import kotlin.coroutines.CoroutineContext
import kotlin.test.Test
diff --git a/krpc/krpc-test/src/jvmMain/kotlin/kotlinx/rpc/test/KRPCTransportTestBase.kt b/krpc/krpc-test/src/jvmMain/kotlin/kotlinx/rpc/test/KRPCTransportTestBase.kt
index a7e1efc4..879f1314 100644
--- a/krpc/krpc-test/src/jvmMain/kotlin/kotlinx/rpc/test/KRPCTransportTestBase.kt
+++ b/krpc/krpc-test/src/jvmMain/kotlin/kotlinx/rpc/test/KRPCTransportTestBase.kt
@@ -10,8 +10,6 @@ import kotlinx.coroutines.*
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.*
import kotlinx.rpc.*
-import kotlinx.rpc.client.awaitFieldInitialization
-import kotlinx.rpc.client.withService
import kotlinx.rpc.serialization.RPCSerialFormatConfiguration
import kotlinx.rpc.server.KRPCServer
import org.junit.Assert.assertEquals
diff --git a/krpc/krpc-test/src/jvmTest/kotlin/kotlinx/rpc/test/ProtocolTestBase.kt b/krpc/krpc-test/src/jvmTest/kotlin/kotlinx/rpc/test/ProtocolTestBase.kt
index 7af40068..a560bbf8 100644
--- a/krpc/krpc-test/src/jvmTest/kotlin/kotlinx/rpc/test/ProtocolTestBase.kt
+++ b/krpc/krpc-test/src/jvmTest/kotlin/kotlinx/rpc/test/ProtocolTestBase.kt
@@ -11,7 +11,6 @@ import kotlinx.coroutines.test.TestResult
import kotlinx.coroutines.test.TestScope
import kotlinx.rpc.*
import kotlinx.rpc.client.KRPCClient
-import kotlinx.rpc.client.withService
import kotlinx.rpc.internal.hex.hexToReadableBinary
import kotlinx.rpc.internal.logging.CommonLogger
import kotlinx.rpc.internal.logging.DumpLogger
diff --git a/krpc/krpc-test/src/jvmTest/kotlin/kotlinx/rpc/test/TransportTest.kt b/krpc/krpc-test/src/jvmTest/kotlin/kotlinx/rpc/test/TransportTest.kt
index 50d91a17..454a3ef4 100644
--- a/krpc/krpc-test/src/jvmTest/kotlin/kotlinx/rpc/test/TransportTest.kt
+++ b/krpc/krpc-test/src/jvmTest/kotlin/kotlinx/rpc/test/TransportTest.kt
@@ -7,7 +7,6 @@ package kotlinx.rpc.test
import junit.framework.TestCase.assertEquals
import kotlinx.coroutines.*
import kotlinx.rpc.*
-import kotlinx.rpc.client.withService
import kotlinx.rpc.serialization.json
import java.util.concurrent.atomic.AtomicInteger
import kotlin.coroutines.CoroutineContext
diff --git a/krpc/krpc-test/src/jvmTest/kotlin/kotlinx/rpc/test/api/ApiVersioningTest.kt b/krpc/krpc-test/src/jvmTest/kotlin/kotlinx/rpc/test/api/ApiVersioningTest.kt
index 747c0297..0b35e0b4 100644
--- a/krpc/krpc-test/src/jvmTest/kotlin/kotlinx/rpc/test/api/ApiVersioningTest.kt
+++ b/krpc/krpc-test/src/jvmTest/kotlin/kotlinx/rpc/test/api/ApiVersioningTest.kt
@@ -7,7 +7,7 @@ package kotlinx.rpc.test.api
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.take
import kotlinx.coroutines.flow.toList
-import kotlinx.rpc.client.awaitFieldInitialization
+import kotlinx.rpc.awaitFieldInitialization
import kotlinx.rpc.internal.transport.CancellationType
import kotlinx.rpc.internal.transport.RPCMessage
import kotlinx.rpc.internal.transport.RPCPlugin
diff --git a/krpc/krpc-test/src/jvmTest/kotlin/kotlinx/rpc/test/api/WireSamplingTestScope.kt b/krpc/krpc-test/src/jvmTest/kotlin/kotlinx/rpc/test/api/WireSamplingTestScope.kt
index dc4a8106..cf587b88 100644
--- a/krpc/krpc-test/src/jvmTest/kotlin/kotlinx/rpc/test/api/WireSamplingTestScope.kt
+++ b/krpc/krpc-test/src/jvmTest/kotlin/kotlinx/rpc/test/api/WireSamplingTestScope.kt
@@ -12,7 +12,6 @@ import kotlinx.coroutines.test.TestResult
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runTest
import kotlinx.rpc.*
-import kotlinx.rpc.client.withService
import kotlinx.rpc.internal.hex.hexToByteArrayInternal
import kotlinx.rpc.internal.hex.hexToReadableBinary
import kotlinx.rpc.internal.logging.CommonLogger
diff --git a/krpc/krpc-test/src/jvmTest/kotlin/kotlinx/rpc/test/cancellation/CancellationTest.kt b/krpc/krpc-test/src/jvmTest/kotlin/kotlinx/rpc/test/cancellation/CancellationTest.kt
index 178fd862..5e28b3e1 100644
--- a/krpc/krpc-test/src/jvmTest/kotlin/kotlinx/rpc/test/cancellation/CancellationTest.kt
+++ b/krpc/krpc-test/src/jvmTest/kotlin/kotlinx/rpc/test/cancellation/CancellationTest.kt
@@ -8,10 +8,10 @@ import kotlinx.coroutines.*
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.toList
-import kotlinx.rpc.client.withService
import kotlinx.rpc.internal.STREAM_SCOPES_ENABLED
import kotlinx.rpc.invokeOnStreamScopeCompletion
import kotlinx.rpc.streamScoped
+import kotlinx.rpc.withService
import kotlin.test.*
class CancellationTest {
diff --git a/krpc/krpc-test/src/jvmTest/kotlin/kotlinx/rpc/test/cancellation/CancellationToolkit.kt b/krpc/krpc-test/src/jvmTest/kotlin/kotlinx/rpc/test/cancellation/CancellationToolkit.kt
index 5f1a2d88..188c9bd8 100644
--- a/krpc/krpc-test/src/jvmTest/kotlin/kotlinx/rpc/test/cancellation/CancellationToolkit.kt
+++ b/krpc/krpc-test/src/jvmTest/kotlin/kotlinx/rpc/test/cancellation/CancellationToolkit.kt
@@ -7,14 +7,10 @@ package kotlinx.rpc.test.cancellation
import kotlinx.coroutines.*
import kotlinx.coroutines.test.TestResult
import kotlinx.coroutines.test.runTest
-import kotlinx.rpc.RPCConfigBuilder
-import kotlinx.rpc.client.withService
+import kotlinx.rpc.*
import kotlinx.rpc.internal.logging.CommonLogger
import kotlinx.rpc.internal.logging.DumpLogger
import kotlinx.rpc.internal.logging.DumpLoggerContainer
-import kotlinx.rpc.registerService
-import kotlinx.rpc.rpcClientConfig
-import kotlinx.rpc.rpcServerConfig
import kotlinx.rpc.serialization.json
import kotlinx.rpc.test.KRPCTestClient
import kotlinx.rpc.test.KRPCTestServer
diff --git a/settings.gradle.kts b/settings.gradle.kts
index efb6032a..c2d663e2 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -58,5 +58,5 @@ includePublic(":krpc:krpc-ktor:krpc-ktor-core")
includePublic(":krpc:krpc-ktor:krpc-ktor-server")
includePublic(":krpc:krpc-ktor:krpc-ktor-client")
-include(":tests:codegen-tests:codegen-tests-mpp")
-include(":tests:codegen-tests:codegen-tests-jvm")
+include(":tests")
+include(":tests:compiler-plugin-tests")
diff --git a/tests/codegen-tests/codegen-tests-jvm/build.gradle.kts b/tests/codegen-tests/codegen-tests-jvm/build.gradle.kts
deleted file mode 100644
index e45f33d7..00000000
--- a/tests/codegen-tests/codegen-tests-jvm/build.gradle.kts
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright 2023-2024 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
- */
-
-import org.jetbrains.kotlin.gradle.dsl.ExplicitApiMode
-
-plugins {
- alias(libs.plugins.conventions.jvm)
- alias(libs.plugins.serialization)
- alias(libs.plugins.ksp)
- alias(libs.plugins.kotlinx.rpc)
-}
-
-dependencies {
- implementation(projects.krpc.krpcClient)
- implementation(projects.krpc.krpcServer)
-
- implementation(projects.tests.codegenTests.codegenTestsMpp)
-
- implementation(libs.kotlin.stdlib)
- implementation(libs.kotlin.reflect)
- implementation(libs.coroutines.core)
- implementation(libs.serialization.core)
-
- testImplementation(libs.kotlin.test)
- testImplementation(libs.slf4j.api)
- testImplementation(libs.logback.classic)
-}
-
-kotlin {
- explicitApi = ExplicitApiMode.Disabled
-}
diff --git a/tests/codegen-tests/codegen-tests-jvm/src/main/kotlin/kotlinx/rpc/Main.kt b/tests/codegen-tests/codegen-tests-jvm/src/main/kotlin/kotlinx/rpc/Main.kt
deleted file mode 100644
index 296e94c1..00000000
--- a/tests/codegen-tests/codegen-tests-jvm/src/main/kotlin/kotlinx/rpc/Main.kt
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright 2023-2024 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
- */
-
-@file:Suppress("unused")
-
-package kotlinx.rpc
-
-import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.SharedFlow
-import kotlinx.coroutines.flow.StateFlow
-import kotlinx.coroutines.runBlocking
-import kotlinx.rpc.client.withService
-
-interface MainService : RPC, EmptyService {
- @RPCEagerField
- override val flow: Flow
-
- override val stateFlow: StateFlow
-
- override val sharedFlow: SharedFlow
-
- override suspend fun empty()
-}
-
-interface FieldOnly : RPC {
- val flow: Flow
-}
-
-fun main(): Unit = runBlocking {
- testService()
- testService()
- testService()
-
- stubEngine.withService().flow
-}
diff --git a/tests/codegen-tests/codegen-tests-jvm/src/main/kotlin/kotlinx/rpc/RootService.kt b/tests/codegen-tests/codegen-tests-jvm/src/main/kotlin/kotlinx/rpc/RootService.kt
deleted file mode 100644
index 486d593c..00000000
--- a/tests/codegen-tests/codegen-tests-jvm/src/main/kotlin/kotlinx/rpc/RootService.kt
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright 2023-2024 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
- */
-
-@file:Suppress("unused", "detekt.MissingPackageDeclaration")
-
-package kotlinx.rpc
-
-import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.SharedFlow
-import kotlinx.coroutines.flow.StateFlow
-import kotlinx.serialization.Serializable
-
-interface RootService : EmptyService, RPC {
- suspend fun rootCall(data: RootData): RootResponse
-
- override val flow: Flow
-
- override val stateFlow: StateFlow
-
- override val sharedFlow: SharedFlow
-
- override suspend fun empty()
-}
-
-@Serializable
-class RootData(val hello: String)
-
-@Serializable
-class RootResponse(val world: String)
diff --git a/tests/codegen-tests/codegen-tests-jvm/src/test/kotlin/kotlinx/rpc/MainTest.kt b/tests/codegen-tests/codegen-tests-jvm/src/test/kotlin/kotlinx/rpc/MainTest.kt
deleted file mode 100644
index 4fe4d40b..00000000
--- a/tests/codegen-tests/codegen-tests-jvm/src/test/kotlin/kotlinx/rpc/MainTest.kt
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright 2023-2024 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
- */
-
-package kotlinx.rpc
-
-import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.SharedFlow
-import kotlinx.coroutines.flow.StateFlow
-import kotlinx.coroutines.runBlocking
-import kotlin.test.Test
-
-interface MainServiceTest : RPC, EmptyService {
- override suspend fun empty()
-
- override val flow: Flow
-
- override val sharedFlow: SharedFlow
-
- override val stateFlow: StateFlow
-}
-
-class MainTest {
- @Test
- fun test() = testServices()
-
- private inline fun testServices()
- where S1 : RPC, S2 : RPC, S3 : RPC,
- S1 : EmptyService, S2 : EmptyService, S3 : EmptyService =
- runBlocking {
- testService()
- testService()
- testService()
- }
-}
diff --git a/tests/codegen-tests/codegen-tests-mpp/build.gradle.kts b/tests/codegen-tests/codegen-tests-mpp/build.gradle.kts
deleted file mode 100644
index b1b4b040..00000000
--- a/tests/codegen-tests/codegen-tests-mpp/build.gradle.kts
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright 2023-2024 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
- */
-
-import org.jetbrains.kotlin.gradle.dsl.ExplicitApiMode
-
-plugins {
- alias(libs.plugins.conventions.kmp)
- alias(libs.plugins.ksp)
- alias(libs.plugins.kotlinx.rpc)
- alias(libs.plugins.serialization)
-}
-
-kotlin {
- sourceSets {
- val commonMain by getting {
- dependencies {
- implementation(libs.coroutines.core)
- implementation(libs.serialization.core)
- implementation(libs.kotlin.reflect)
-
- implementation(projects.krpc.krpcLogging)
- implementation(projects.krpc.krpcClient)
- implementation(projects.krpc.krpcServer)
- }
- }
-
- val commonTest by getting {
- dependencies {
- implementation(libs.kotlin.test)
- }
- }
-
- val jvmTest by getting {
- dependencies {
- implementation(libs.slf4j.api)
- implementation(libs.logback.classic)
- }
- }
- }
-
- js {
- binaries.executable()
- browser {
- commonWebpackConfig {
- this.sourceMaps = true
- }
- }
- }
-
- explicitApi = ExplicitApiMode.Disabled
-}
-
diff --git a/tests/codegen-tests/codegen-tests-mpp/src/commonMain/kotlin/kotlinx/rpc/Common.kt b/tests/codegen-tests/codegen-tests-mpp/src/commonMain/kotlin/kotlinx/rpc/Common.kt
deleted file mode 100644
index af859fc7..00000000
--- a/tests/codegen-tests/codegen-tests-mpp/src/commonMain/kotlin/kotlinx/rpc/Common.kt
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright 2023-2024 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
- */
-
-package kotlinx.rpc
-
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.Job
-import kotlinx.coroutines.flow.*
-import kotlinx.rpc.client.withService
-import kotlinx.rpc.internal.logging.CommonLogger
-import kotlinx.rpc.server.internal.rpcServiceMethodSerializationTypeOf
-import kotlin.coroutines.CoroutineContext
-import kotlin.reflect.typeOf
-
-val logger by lazy {
- CommonLogger.logger("KSPGeneratorTest")
-}
-
-interface EmptyService {
- val flow: Flow
-
- val sharedFlow: SharedFlow
-
- val stateFlow: StateFlow
-
- suspend fun empty()
-}
-
-val stubEngine = object : RPCClient {
- override val coroutineContext: CoroutineContext = Job()
-
- override suspend fun call(call: RPCCall): T {
- logger.info { "Called ${call.callableName}" }
- error("ok")
- }
-
- override fun registerPlainFlowField(serviceScope: CoroutineScope, field: RPCField): Flow {
- logger.info { "registered flow: ${field.name}" }
- return flow { }
- }
-
- override fun registerSharedFlowField(serviceScope: CoroutineScope, field: RPCField): SharedFlow {
- logger.info { "registered flow: ${field.name}" }
- return MutableSharedFlow(1)
- }
-
- override fun registerStateFlowField(serviceScope: CoroutineScope, field: RPCField): StateFlow {
- logger.info { "registered flow: ${field.name}" }
-
- @Suppress("UNCHECKED_CAST")
- return MutableStateFlow(null) as StateFlow
- }
-
- override fun provideStubContext(serviceId: Long): CoroutineContext {
- return coroutineContext
- }
-}
-
-interface CommonService : RPC, EmptyService {
- override val flow: Flow
-
- override val sharedFlow: SharedFlow
-
- override val stateFlow: StateFlow
-
- override suspend fun empty()
-}
-
-suspend inline fun testService() where T : RPC, T : EmptyService {
- val test: suspend T.() -> Unit = {
- runCatching {
- empty()
- }
-
- flow
- sharedFlow
- stateFlow
- }
-
- stubEngine.withService().test()
- stubEngine.withService(typeOf()).test()
- stubEngine.withService(T::class).test()
-
- logger.info { rpcServiceMethodSerializationTypeOf("empty") }
- logger.info { rpcServiceMethodSerializationTypeOf(typeOf(), "empty") }
-}
diff --git a/tests/codegen-tests/codegen-tests-mpp/src/commonTest/kotlin/kotlinx/rpc/CommonTest.kt b/tests/codegen-tests/codegen-tests-mpp/src/commonTest/kotlin/kotlinx/rpc/CommonTest.kt
deleted file mode 100644
index 49d74ca3..00000000
--- a/tests/codegen-tests/codegen-tests-mpp/src/commonTest/kotlin/kotlinx/rpc/CommonTest.kt
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright 2023-2024 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
- */
-
-package kotlinx.rpc
-
-import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.SharedFlow
-import kotlinx.coroutines.flow.StateFlow
-
-interface CommonTestService : RPC, EmptyService {
- override suspend fun empty()
-
- override val flow: Flow
-
- override val sharedFlow: SharedFlow
-
- override val stateFlow: StateFlow
-}
-
-abstract class CommonTestSuite {
- abstract fun runAsync(body: suspend () -> Unit): TestResult
-
- inline fun testServices(): TestResult
- where S1 : RPC, S2 : RPC, S3 : RPC, S4 : RPC,
- S1 : EmptyService, S2 : EmptyService, S3 : EmptyService, S4 : EmptyService =
- runAsync {
- testService()
- testService()
- testService()
- testService()
- }
-}
diff --git a/tests/codegen-tests/codegen-tests-mpp/src/jsMain/kotlin/kotlinx/rpc/Js.kt b/tests/codegen-tests/codegen-tests-mpp/src/jsMain/kotlin/kotlinx/rpc/Js.kt
deleted file mode 100644
index 92c89b78..00000000
--- a/tests/codegen-tests/codegen-tests-mpp/src/jsMain/kotlin/kotlinx/rpc/Js.kt
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright 2023-2024 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
- */
-
-@file:Suppress("detekt.MatchingDeclarationName")
-
-package kotlinx.rpc
-
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.SharedFlow
-import kotlinx.coroutines.flow.StateFlow
-import kotlinx.coroutines.launch
-
-interface JsService : RPC, EmptyService {
- override suspend fun empty()
-
- override val flow: Flow
-
- override val sharedFlow: SharedFlow
-
- override val stateFlow: StateFlow
-}
-
-fun main() {
- CoroutineScope(Dispatchers.Main).launch {
- testService()
- testService()
- }
-}
diff --git a/tests/codegen-tests/codegen-tests-mpp/src/jsMain/resources/index.html b/tests/codegen-tests/codegen-tests-mpp/src/jsMain/resources/index.html
deleted file mode 100644
index 1134dd1d..00000000
--- a/tests/codegen-tests/codegen-tests-mpp/src/jsMain/resources/index.html
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-
-
-
-
- Kotlin JS kRPC Sample
-
-
-
-
-
diff --git a/tests/codegen-tests/codegen-tests-mpp/src/jsTest/kotlin/kotlinx/rpc/JsTest.kt b/tests/codegen-tests/codegen-tests-mpp/src/jsTest/kotlin/kotlinx/rpc/JsTest.kt
deleted file mode 100644
index 51c4325e..00000000
--- a/tests/codegen-tests/codegen-tests-mpp/src/jsTest/kotlin/kotlinx/rpc/JsTest.kt
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright 2023-2024 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
- */
-
-package kotlinx.rpc
-
-import kotlinx.coroutines.*
-import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.SharedFlow
-import kotlinx.coroutines.flow.StateFlow
-import kotlin.js.Promise
-import kotlin.test.Test
-
-interface JsTestService : RPC, EmptyService {
- override suspend fun empty()
-
- override val flow: Flow
-
- override val sharedFlow: SharedFlow
-
- override val stateFlow: StateFlow
-}
-
-class JsTest : CommonTestSuite>() {
- @OptIn(DelicateCoroutinesApi::class)
- override fun runAsync(body: suspend () -> Unit): Promise {
- @Suppress("detekt.GlobalCoroutineUsage")
- return GlobalScope.async(
- Dispatchers.Unconfined,
- block = { body() }
- ).asPromise()
- }
-
- @Test
- fun test() = testServices()
-}
diff --git a/tests/codegen-tests/codegen-tests-mpp/src/jvmMain/kotlin/kotlinx/rpc/Jvm.kt b/tests/codegen-tests/codegen-tests-mpp/src/jvmMain/kotlin/kotlinx/rpc/Jvm.kt
deleted file mode 100644
index 7726529d..00000000
--- a/tests/codegen-tests/codegen-tests-mpp/src/jvmMain/kotlin/kotlinx/rpc/Jvm.kt
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright 2023-2024 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
- */
-
-@file:Suppress("detekt.MatchingDeclarationName")
-
-package kotlinx.rpc
-
-import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.SharedFlow
-import kotlinx.coroutines.flow.StateFlow
-import kotlinx.coroutines.runBlocking
-
-interface JvmService : RPC, EmptyService {
- override suspend fun empty()
-
- override val flow: Flow
-
- override val sharedFlow: SharedFlow
-
- override val stateFlow: StateFlow
-}
-
-fun main() = runBlocking {
- testService()
- testService()
-}
diff --git a/tests/codegen-tests/codegen-tests-mpp/src/jvmTest/kotlin/kotlinx/rpc/JvmTest.kt b/tests/codegen-tests/codegen-tests-mpp/src/jvmTest/kotlin/kotlinx/rpc/JvmTest.kt
deleted file mode 100644
index a578aa8a..00000000
--- a/tests/codegen-tests/codegen-tests-mpp/src/jvmTest/kotlin/kotlinx/rpc/JvmTest.kt
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright 2023-2024 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
- */
-
-package kotlinx.rpc
-
-import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.SharedFlow
-import kotlinx.coroutines.flow.StateFlow
-import kotlinx.coroutines.runBlocking
-import org.junit.Test
-
-interface JvmTestService : RPC, EmptyService {
- override suspend fun empty()
-
- override val flow: Flow
-
- override val sharedFlow: SharedFlow
-
- override val stateFlow: StateFlow
-}
-
-class JvmTest : CommonTestSuite() {
- override fun runAsync(body: suspend () -> Unit) = runBlocking { body() }
-
- @Test
- fun test() = testServices()
-}
diff --git a/tests/codegen-tests/codegen-tests-mpp/src/nativeMain/kotlin/kotlinx/rpc/native/Native.kt b/tests/codegen-tests/codegen-tests-mpp/src/nativeMain/kotlin/kotlinx/rpc/native/Native.kt
deleted file mode 100644
index afaef1a2..00000000
--- a/tests/codegen-tests/codegen-tests-mpp/src/nativeMain/kotlin/kotlinx/rpc/native/Native.kt
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright 2023-2024 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
- */
-
-@file:Suppress("detekt.MatchingDeclarationName")
-
-package kotlinx.rpc.native
-
-import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.SharedFlow
-import kotlinx.coroutines.flow.StateFlow
-import kotlinx.coroutines.runBlocking
-import kotlinx.rpc.CommonService
-import kotlinx.rpc.EmptyService
-import kotlinx.rpc.RPC
-import kotlinx.rpc.testService
-
-interface NativeService : RPC, EmptyService {
- override suspend fun empty()
-
- override val flow: Flow
-
- override val sharedFlow: SharedFlow
-
- override val stateFlow: StateFlow
-}
-
-fun main() = runBlocking {
- testService()
- testService()
-}
diff --git a/tests/codegen-tests/codegen-tests-mpp/src/nativeTest/kotlin/kotlinx/rpc/native/NativeTest.kt b/tests/codegen-tests/codegen-tests-mpp/src/nativeTest/kotlin/kotlinx/rpc/native/NativeTest.kt
deleted file mode 100644
index fb630ecf..00000000
--- a/tests/codegen-tests/codegen-tests-mpp/src/nativeTest/kotlin/kotlinx/rpc/native/NativeTest.kt
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright 2023-2024 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
- */
-
-package kotlinx.rpc.native
-
-import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.SharedFlow
-import kotlinx.coroutines.flow.StateFlow
-import kotlinx.coroutines.runBlocking
-import kotlinx.rpc.*
-import kotlin.test.Test
-
-interface NativeTestService : RPC, EmptyService {
- override suspend fun empty()
-
- override val flow: Flow
-
- override val sharedFlow: SharedFlow
-
- override val stateFlow: StateFlow
-}
-
-class NativeTest : CommonTestSuite() {
- override fun runAsync(body: suspend () -> Unit) = runBlocking { body() }
-
- @Test
- fun test() = testServices()
-}
diff --git a/tests/compiler-plugin-tests/build.gradle.kts b/tests/compiler-plugin-tests/build.gradle.kts
new file mode 100644
index 00000000..156e075d
--- /dev/null
+++ b/tests/compiler-plugin-tests/build.gradle.kts
@@ -0,0 +1,174 @@
+/*
+ * Copyright 2023-2024 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+import org.jetbrains.kotlin.gradle.dsl.ExplicitApiMode
+import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
+
+plugins {
+ java
+ alias(libs.plugins.conventions.jvm)
+}
+
+// this setup – courtesy of https://github.com/demiurg906/kotlin-compiler-plugin-template/tree/master
+
+repositories {
+ maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/bootstrap")
+ maven("https://www.jetbrains.com/intellij-repository/releases")
+ maven("https://cache-redirector.jetbrains.com/intellij-dependencies")
+}
+
+sourceSets {
+ test {
+ java.srcDir("src/test-gen")
+ }
+}
+
+kotlin {
+ explicitApi = ExplicitApiMode.Disabled
+}
+
+/**
+ * I should probably explain this.
+ *
+ * `kotlin-compiler` dependency has its inner dependency on `libs.intellij.util`.
+ * In fact, it packs all necessary classes inside its jar (making it fat in some sense).
+ * Amongst these packed classes there is `com.intellij.openapi.util.io.NioFiles`, which is used by the tests' runtime.
+ *
+ * `NioFiles` is problematic.
+ * It was packed with kotlin-compiler jar, but Proguard which excluded `deleteRecursively` method from it.
+ * It this method is called.
+ * So tests fail with:
+ * ```
+ * java.lang.NoSuchMethodError: com.intellij.openapi.util.io.NioFiles.deleteRecursively(Ljava/nio/file/Path;)V
+ * ```
+ *
+ * To mitigate, we need to load the proper `NioFiles` with all methods from the jar,
+ * which wasn't striped by the Proguard.
+ * This jar is `libs.intellij.util`.
+ * But to load the class from it, we need to guarantee
+ * that this jar is present earlier in the classloader's list, than the `kotlin-compiler` jar.
+ *
+ * `kotlin-compiler-embeddable` does pack the class inside its jar.
+ * But if you try to use it, you would eventually get `java.lang.VerifyError: Bad type on operand stack`
+ * and you don't want to fix it.
+ *
+ * So here we are.
+ * This is bad, but hey, it is working!
+ */
+val testPriorityRuntimeClasspath: Configuration = configurations.create("testPriorityRuntimeClasspath")
+
+sourceSets.test.configure {
+ runtimeClasspath = testPriorityRuntimeClasspath + sourceSets.test.get().runtimeClasspath
+}
+
+dependencies {
+ @Suppress("UnstableApiUsage")
+ testPriorityRuntimeClasspath(libs.intellij.util) { isTransitive = false }
+
+ implementation(projects.core)
+
+ testRuntimeOnly(libs.kotlin.test)
+ testRuntimeOnly(libs.kotlin.script.runtime)
+ testRuntimeOnly(libs.kotlin.annotations.jvm)
+
+ testImplementation(libs.serialization.plugin)
+ testImplementation(libs.compiler.plugin.cli)
+
+ testImplementation(libs.kotlin.reflect)
+ testImplementation(libs.kotlin.compiler)
+ testImplementation(libs.kotlin.compiler.test.framework)
+
+ testImplementation(libs.junit4)
+
+ testImplementation(platform(libs.junit5.bom))
+ testImplementation(libs.junit5.jupiter)
+ testImplementation(libs.junit5.platform.commons)
+ testImplementation(libs.junit5.platform.launcher)
+ testImplementation(libs.junit5.platform.runner)
+ testImplementation(libs.junit5.platform.suite.api)
+}
+
+val globalRootDir: String by extra
+
+testDataRuntimeDependencies(
+ libs.coroutines.core,
+ libs.serialization.core,
+)
+
+tasks.test {
+ dependsOn(tasks.getByName("jar"))
+ dependsOn(project(":core").tasks.getByName("jvmJar"))
+ dependsOn(project(":utils").tasks.getByName("jvmJar"))
+
+ useJUnitPlatform()
+
+ doFirst {
+ systemProperty("kotlinx.rpc.globalRootDir", globalRootDir)
+
+ val updateData = (project.findProperty("kotlin.test.update.test.data") as? String) ?: "false"
+ systemProperty("kotlin.test.update.test.data", updateData)
+
+ setJarPathAsProperty("org.jetbrains.kotlin.test.kotlin-stdlib", "kotlin-stdlib")
+ setJarPathAsProperty("org.jetbrains.kotlin.test.kotlin-stdlib-jdk8", "kotlin-stdlib-jdk8")
+ setJarPathAsProperty("org.jetbrains.kotlin.test.kotlin-reflect", "kotlin-reflect")
+ setJarPathAsProperty("org.jetbrains.kotlin.test.kotlin-test", "kotlin-test")
+ setJarPathAsProperty("org.jetbrains.kotlin.test.kotlin-script-runtime", "kotlin-script-runtime")
+ setJarPathAsProperty("org.jetbrains.kotlin.test.kotlin-annotations-jvm", "kotlin-annotations-jvm")
+ }
+}
+
+tasks.withType().configureEach {
+ compilerOptions {
+ optIn.add("org.jetbrains.kotlin.compiler.plugin.ExperimentalCompilerApi")
+ optIn.add("org.jetbrains.kotlin.ir.symbols.UnsafeDuringIrConstructionAPI")
+ }
+}
+
+val generateTests by tasks.creating(JavaExec::class) {
+ classpath = sourceSets.test.get().runtimeClasspath
+ mainClass.set("kotlinx.rpc.codegen.test.GenerateTestsKt")
+}
+
+tasks.named("compileTestKotlin").configure {
+ finalizedBy(generateTests)
+}
+
+fun testDataRuntimeDependencies(vararg dependencyNotations: Provider) {
+ dependencyNotations.forEach {
+ dependencies.implementation(it)
+ }
+
+ tasks.test {
+ doFirst {
+ setJarPathAsProperty(
+ propName = "kotlinx.rpc.test.data.classpath.dependencies",
+ jarNames = dependencyNotations.map { it.get().name + "-jvm" }.toTypedArray(),
+ searchIn = project.configurations.runtimeClasspath,
+ )
+ }
+ }
+}
+
+fun Test.setJarPathAsProperty(
+ propName: String,
+ vararg jarNames: String,
+ searchIn: NamedDomainObjectProvider = project.configurations.testRuntimeClasspath,
+) {
+ val includedRegex = jarNames.toSet().joinToString("|", "(", ")") { jarName ->
+ "$jarName-\\d.*jar"
+ }.toRegex()
+
+ val path = searchIn.get()
+ .files
+ .filter { includedRegex.matches(it.name) }
+ .takeIf { it.isNotEmpty() }
+ ?.joinToString(File.pathSeparator) { it.absolutePath }
+ ?: run {
+ logger.warn("Can't find any of ${jarNames.joinToString()} in ${searchIn.get().name}")
+ return
+ }
+
+ logger.info("Setting prop $propName=$path")
+ systemProperty(propName, path)
+}
diff --git a/tests/compiler-plugin-tests/src/main/kotlin/kotlinx/rpc/codegen/test/TestRpcClient.kt b/tests/compiler-plugin-tests/src/main/kotlin/kotlinx/rpc/codegen/test/TestRpcClient.kt
new file mode 100644
index 00000000..77a88086
--- /dev/null
+++ b/tests/compiler-plugin-tests/src/main/kotlin/kotlinx/rpc/codegen/test/TestRpcClient.kt
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2023-2024 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.rpc.codegen.test
+
+import kotlinx.coroutines.*
+import kotlinx.coroutines.flow.*
+import kotlinx.rpc.RPCCall
+import kotlinx.rpc.RPCClient
+import kotlinx.rpc.RPCField
+import kotlin.coroutines.CoroutineContext
+
+@Suppress("UNCHECKED_CAST", "unused")
+object TestRpcClient : RPCClient {
+ override val coroutineContext: CoroutineContext = Job()
+
+ override suspend fun call(call: RPCCall): T {
+ return "call_42" as T
+ }
+
+ override fun registerPlainFlowField(serviceScope: CoroutineScope, field: RPCField): Flow {
+ return flow { emit("registerPlainFlowField_42") } as Flow
+ }
+
+ @OptIn(DelicateCoroutinesApi::class)
+ @Suppress("detekt.GlobalCoroutineUsage")
+ override fun registerSharedFlowField(serviceScope: CoroutineScope, field: RPCField): SharedFlow {
+ return MutableSharedFlow(1).also {
+ GlobalScope.launch { it.emit("registerSharedFlowField_42") }
+ } as SharedFlow
+ }
+
+ override fun registerStateFlowField(serviceScope: CoroutineScope, field: RPCField): StateFlow {
+ return MutableStateFlow("registerStateFlowField_42") as StateFlow
+ }
+
+ override fun provideStubContext(serviceId: Long): CoroutineContext {
+ return coroutineContext
+ }
+}
diff --git a/tests/compiler-plugin-tests/src/test-gen/kotlinx/rpc/codegen/test/runners/BoxTestGenerated.java b/tests/compiler-plugin-tests/src/test-gen/kotlinx/rpc/codegen/test/runners/BoxTestGenerated.java
new file mode 100644
index 00000000..6f549748
--- /dev/null
+++ b/tests/compiler-plugin-tests/src/test-gen/kotlinx/rpc/codegen/test/runners/BoxTestGenerated.java
@@ -0,0 +1,57 @@
+
+
+/*
+ * Copyright 2023-2024 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.rpc.codegen.test.runners;
+
+import com.intellij.testFramework.TestDataPath;
+import org.jetbrains.kotlin.test.TargetBackend;
+import org.jetbrains.kotlin.test.TestMetadata;
+import org.jetbrains.kotlin.test.util.KtTestUtil;
+import org.junit.jupiter.api.Test;
+
+import java.io.File;
+import java.util.regex.Pattern;
+
+/** This class is generated by {@link kotlinx.rpc.codegen.test.GenerateTestsKt}. DO NOT MODIFY MANUALLY */
+@SuppressWarnings("all")
+@TestMetadata("src/testData/box")
+@TestDataPath("$PROJECT_ROOT")
+public class BoxTestGenerated extends AbstractBoxTest {
+ @Test
+ public void testAllFilesPresentInBox() {
+ KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("src/testData/box"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
+ }
+
+ @Test
+ @TestMetadata("customParameterTypes.kt")
+ public void testCustomParameterTypes() {
+ runTest("src/testData/box/customParameterTypes.kt");
+ }
+
+ @Test
+ @TestMetadata("fields.kt")
+ public void testFields() {
+ runTest("src/testData/box/fields.kt");
+ }
+
+ @Test
+ @TestMetadata("flowParameter.kt")
+ public void testFlowParameter() {
+ runTest("src/testData/box/flowParameter.kt");
+ }
+
+ @Test
+ @TestMetadata("multiModule.kt")
+ public void testMultiModule() {
+ runTest("src/testData/box/multiModule.kt");
+ }
+
+ @Test
+ @TestMetadata("simple.kt")
+ public void testSimple() {
+ runTest("src/testData/box/simple.kt");
+ }
+}
diff --git a/tests/compiler-plugin-tests/src/test/kotlin/kotlinx/rpc/codegen/test/GenerateTests.kt b/tests/compiler-plugin-tests/src/test/kotlin/kotlinx/rpc/codegen/test/GenerateTests.kt
new file mode 100644
index 00000000..c828d595
--- /dev/null
+++ b/tests/compiler-plugin-tests/src/test/kotlin/kotlinx/rpc/codegen/test/GenerateTests.kt
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2023-2024 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.rpc.codegen.test
+
+import kotlinx.rpc.codegen.test.runners.AbstractBoxTest
+import org.jetbrains.kotlin.generators.generateTestGroupSuiteWithJUnit5
+
+fun main() {
+ generateTestGroupSuiteWithJUnit5 {
+ testGroup(testDataRoot = "src/testData", testsRoot = "src/test-gen") {
+ // todo enable after diagnostics are done
+// testClass {
+// model("diagnostics")
+// }
+
+ testClass {
+ model("box")
+ }
+ }
+ }
+}
diff --git a/tests/compiler-plugin-tests/src/test/kotlin/kotlinx/rpc/codegen/test/runners/AbstractBoxTest.kt b/tests/compiler-plugin-tests/src/test/kotlin/kotlinx/rpc/codegen/test/runners/AbstractBoxTest.kt
new file mode 100644
index 00000000..bd3eeb16
--- /dev/null
+++ b/tests/compiler-plugin-tests/src/test/kotlin/kotlinx/rpc/codegen/test/runners/AbstractBoxTest.kt
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2023-2024 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.rpc.codegen.test.runners
+
+import org.jetbrains.kotlin.platform.jvm.JvmPlatforms
+import org.jetbrains.kotlin.test.FirParser
+import org.jetbrains.kotlin.test.TargetBackend
+import org.jetbrains.kotlin.test.backend.BlackBoxCodegenSuppressor
+import org.jetbrains.kotlin.test.backend.handlers.IrTextDumpHandler
+import org.jetbrains.kotlin.test.backend.handlers.IrTreeVerifierHandler
+import org.jetbrains.kotlin.test.backend.handlers.JvmBoxRunner
+import org.jetbrains.kotlin.test.backend.ir.JvmIrBackendFacade
+import org.jetbrains.kotlin.test.builders.TestConfigurationBuilder
+import org.jetbrains.kotlin.test.builders.fir2IrStep
+import org.jetbrains.kotlin.test.builders.irHandlersStep
+import org.jetbrains.kotlin.test.builders.jvmArtifactsHandlersStep
+import org.jetbrains.kotlin.test.directives.CodegenTestDirectives.DUMP_IR
+import org.jetbrains.kotlin.test.directives.ConfigurationDirectives.WITH_STDLIB
+import org.jetbrains.kotlin.test.directives.JvmEnvironmentConfigurationDirectives.WITH_REFLECT
+import org.jetbrains.kotlin.test.directives.configureFirParser
+import org.jetbrains.kotlin.test.model.DependencyKind
+import org.jetbrains.kotlin.test.runners.RunnerWithTargetBackendForTestGeneratorMarker
+
+/*
+ * Containers of different directives, which can be used in tests:
+ * - ModuleStructureDirectives
+ * - LanguageSettingsDirectives
+ * - DiagnosticsDirectives
+ * - CodegenTestDirectives
+ *
+ * All of them are located in `org.jetbrains.kotlin.test.directives` package
+ */
+open class AbstractBoxTest : BaseTestRunner(), RunnerWithTargetBackendForTestGeneratorMarker {
+ override val targetBackend: TargetBackend
+ get() = TargetBackend.JVM_IR
+
+ override fun TestConfigurationBuilder.configuration() {
+ configureFirParser(FirParser.LightTree)
+
+ defaultDirectives {
+ +DUMP_IR
+ +WITH_STDLIB
+ +WITH_REFLECT
+ }
+
+ commonFirWithPluginFrontendConfiguration()
+
+ globalDefaults {
+ targetBackend = TargetBackend.JVM_IR
+ targetPlatform = JvmPlatforms.defaultJvmPlatform
+ dependencyKind = DependencyKind.Binary
+ }
+
+ fir2IrStep()
+ irHandlersStep {
+ useHandlers(
+ ::IrTextDumpHandler,
+ ::IrTreeVerifierHandler,
+ )
+ }
+ facadeStep(::JvmIrBackendFacade)
+ jvmArtifactsHandlersStep {
+ useHandlers(::JvmBoxRunner)
+ }
+
+ useAfterAnalysisCheckers(::BlackBoxCodegenSuppressor)
+ }
+}
diff --git a/tests/compiler-plugin-tests/src/test/kotlin/kotlinx/rpc/codegen/test/runners/AbstractDiagnosticTest.kt b/tests/compiler-plugin-tests/src/test/kotlin/kotlinx/rpc/codegen/test/runners/AbstractDiagnosticTest.kt
new file mode 100644
index 00000000..fe39e147
--- /dev/null
+++ b/tests/compiler-plugin-tests/src/test/kotlin/kotlinx/rpc/codegen/test/runners/AbstractDiagnosticTest.kt
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2023-2024 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.rpc.codegen.test.runners
+
+import org.jetbrains.kotlin.test.FirParser
+import org.jetbrains.kotlin.test.builders.TestConfigurationBuilder
+import org.jetbrains.kotlin.test.directives.configureFirParser
+import org.jetbrains.kotlin.test.services.EnvironmentBasedStandardLibrariesPathProvider
+import org.jetbrains.kotlin.test.services.KotlinStandardLibrariesPathProvider
+
+abstract class AbstractDiagnosticTest : BaseTestRunner() {
+ override fun TestConfigurationBuilder.configuration() {
+ commonFirWithPluginFrontendConfiguration()
+ configureFirParser(FirParser.Psi)
+ }
+
+ override fun createKotlinStandardLibrariesPathProvider(): KotlinStandardLibrariesPathProvider {
+ return EnvironmentBasedStandardLibrariesPathProvider
+ }
+}
diff --git a/tests/compiler-plugin-tests/src/test/kotlin/kotlinx/rpc/codegen/test/runners/BaseTestRunner.kt b/tests/compiler-plugin-tests/src/test/kotlin/kotlinx/rpc/codegen/test/runners/BaseTestRunner.kt
new file mode 100644
index 00000000..e1a83197
--- /dev/null
+++ b/tests/compiler-plugin-tests/src/test/kotlin/kotlinx/rpc/codegen/test/runners/BaseTestRunner.kt
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2023-2024 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.rpc.codegen.test.runners
+
+import kotlinx.rpc.codegen.test.services.ExtensionRegistrarConfigurator
+import kotlinx.rpc.codegen.test.services.RpcCompileClasspathProvider
+import kotlinx.rpc.codegen.test.services.RpcRuntimeClasspathProvider
+import org.jetbrains.kotlin.test.builders.TestConfigurationBuilder
+import org.jetbrains.kotlin.test.directives.FirDiagnosticsDirectives
+import org.jetbrains.kotlin.test.directives.JvmEnvironmentConfigurationDirectives
+import org.jetbrains.kotlin.test.initIdeaConfiguration
+import org.jetbrains.kotlin.test.runners.AbstractKotlinCompilerTest
+import org.jetbrains.kotlin.test.runners.baseFirDiagnosticTestConfiguration
+import org.jetbrains.kotlin.test.services.EnvironmentBasedStandardLibrariesPathProvider
+import org.jetbrains.kotlin.test.services.KotlinStandardLibrariesPathProvider
+import org.junit.jupiter.api.BeforeAll
+
+abstract class BaseTestRunner : AbstractKotlinCompilerTest() {
+ companion object {
+ @BeforeAll
+ @JvmStatic
+ fun setUp() {
+ initIdeaConfiguration()
+ }
+ }
+
+ override fun createKotlinStandardLibrariesPathProvider(): KotlinStandardLibrariesPathProvider {
+ return EnvironmentBasedStandardLibrariesPathProvider
+ }
+}
+
+fun TestConfigurationBuilder.commonFirWithPluginFrontendConfiguration() {
+ baseFirDiagnosticTestConfiguration()
+
+ defaultDirectives {
+ +FirDiagnosticsDirectives.ENABLE_PLUGIN_PHASES
+ +FirDiagnosticsDirectives.FIR_DUMP
+ +JvmEnvironmentConfigurationDirectives.FULL_JDK
+ }
+
+ useConfigurators(
+ ::RpcCompileClasspathProvider,
+ ::ExtensionRegistrarConfigurator,
+ )
+
+ useCustomRuntimeClasspathProviders(
+ ::RpcRuntimeClasspathProvider,
+ )
+}
diff --git a/tests/compiler-plugin-tests/src/test/kotlin/kotlinx/rpc/codegen/test/services/ExtensionRegistrarConfigurator.kt b/tests/compiler-plugin-tests/src/test/kotlin/kotlinx/rpc/codegen/test/services/ExtensionRegistrarConfigurator.kt
new file mode 100644
index 00000000..0b7a3850
--- /dev/null
+++ b/tests/compiler-plugin-tests/src/test/kotlin/kotlinx/rpc/codegen/test/services/ExtensionRegistrarConfigurator.kt
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2023-2024 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.rpc.codegen.test.services
+
+import kotlinx.rpc.codegen.registerRpcExtensions
+import org.jetbrains.kotlin.compiler.plugin.CompilerPluginRegistrar
+import org.jetbrains.kotlin.config.CompilerConfiguration
+import org.jetbrains.kotlin.test.model.TestModule
+import org.jetbrains.kotlin.test.services.EnvironmentConfigurator
+import org.jetbrains.kotlin.test.services.TestServices
+import org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationComponentRegistrar
+
+class ExtensionRegistrarConfigurator(testServices: TestServices) : EnvironmentConfigurator(testServices) {
+ override fun CompilerPluginRegistrar.ExtensionStorage.registerCompilerExtensions(
+ module: TestModule,
+ configuration: CompilerConfiguration
+ ) {
+ registerRpcExtensions(configuration)
+
+ // libs
+ SerializationComponentRegistrar.registerExtensions(this)
+ }
+}
diff --git a/tests/compiler-plugin-tests/src/test/kotlin/kotlinx/rpc/codegen/test/services/RpcClasspathProviders.kt b/tests/compiler-plugin-tests/src/test/kotlin/kotlinx/rpc/codegen/test/services/RpcClasspathProviders.kt
new file mode 100644
index 00000000..9856baae
--- /dev/null
+++ b/tests/compiler-plugin-tests/src/test/kotlin/kotlinx/rpc/codegen/test/services/RpcClasspathProviders.kt
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2023-2024 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.rpc.codegen.test.services
+
+import org.jetbrains.kotlin.cli.jvm.config.addJvmClasspathRoot
+import org.jetbrains.kotlin.config.CompilerConfiguration
+import org.jetbrains.kotlin.test.model.TestModule
+import org.jetbrains.kotlin.test.services.EnvironmentConfigurator
+import org.jetbrains.kotlin.test.services.RuntimeClasspathProvider
+import org.jetbrains.kotlin.test.services.TestServices
+import org.jetbrains.kotlin.test.services.assertions
+import java.io.File
+import java.io.FilenameFilter
+
+private val globalRootDir: String = System.getProperty("kotlinx.rpc.globalRootDir")
+ ?: error("Global root dir is not specified")
+
+private class RuntimeDependency(
+ val dir: String,
+ val name: String,
+) {
+ val filter = FilenameFilter { _, filename ->
+ filename.startsWith(name) && filename.endsWith(".jar")
+ }
+}
+
+private object RpcClasspathProvider {
+ private val TEST_RUNTIME = RuntimeDependency("build/libs/", "compiler-plugin-test")
+ private val CORE_JVM = RuntimeDependency("$globalRootDir/core/build/libs/", "core-jvm")
+ private val UTILS_JVM = RuntimeDependency("$globalRootDir/utils/build/libs/", "utils-jvm")
+
+ private const val RUNTIME_DEPENDENCIES_PROPERTY = "kotlinx.rpc.test.data.classpath.dependencies"
+ private val runtimeDependenciesPaths = System.getProperty(RUNTIME_DEPENDENCIES_PROPERTY)
+ ?.split(File.pathSeparator)
+ ?.map { File(it) }
+ ?: error("Runtime dependencies are not specified")
+
+ fun provideClasspath(testServices: TestServices): List {
+ val additionalDependencies = listOf(
+ TEST_RUNTIME,
+ CORE_JVM,
+ UTILS_JVM,
+ ).map { it.getFile(testServices) }
+
+ return runtimeDependenciesPaths + additionalDependencies
+ }
+
+ private fun RuntimeDependency.getFile(testServices: TestServices): File {
+ fun failMessage(): String {
+ return "Jar file with '$name' runtime API does not exist. " +
+ "Please run corresponding gradle :jar (or :jvmJar) task"
+ }
+
+ val libDir = File(dir)
+ testServices.assertions.assertTrue(libDir.exists() && libDir.isDirectory, ::failMessage)
+ val jar = libDir.listFiles(filter)?.firstOrNull()
+ ?: testServices.assertions.fail(::failMessage)
+
+ return jar
+ }
+}
+
+class RpcCompileClasspathProvider(testServices: TestServices) : EnvironmentConfigurator(testServices) {
+ override fun configureCompilerConfiguration(configuration: CompilerConfiguration, module: TestModule) {
+ RpcClasspathProvider.provideClasspath(testServices).forEach {
+ configuration.addJvmClasspathRoot(it)
+ }
+ }
+}
+
+class RpcRuntimeClasspathProvider(testServices: TestServices) : RuntimeClasspathProvider(testServices) {
+ override fun runtimeClassPaths(module: TestModule): List {
+ return RpcClasspathProvider.provideClasspath(testServices)
+ }
+}
diff --git a/tests/compiler-plugin-tests/src/testData/box/customParameterTypes.fir.ir.txt b/tests/compiler-plugin-tests/src/testData/box/customParameterTypes.fir.ir.txt
new file mode 100644
index 00000000..41702034
--- /dev/null
+++ b/tests/compiler-plugin-tests/src/testData/box/customParameterTypes.fir.ir.txt
@@ -0,0 +1,1132 @@
+FILE fqName: fileName:/customParameterTypes.kt
+ CLASS CLASS name:TestData modality:FINAL visibility:public [data] superTypes:[kotlin.Any]
+ annotations:
+ Serializable(with = )
+ $this: VALUE_PARAMETER INSTANCE_RECEIVER name: type:.TestData
+ PROPERTY name:value visibility:public modality:FINAL [val]
+ FIELD PROPERTY_BACKING_FIELD name:value type:kotlin.String visibility:private [final]
+ EXPRESSION_BODY
+ GET_VAR 'value: kotlin.String declared in .TestData.' type=kotlin.String origin=INITIALIZE_PROPERTY_FROM_PARAMETER
+ FUN DEFAULT_PROPERTY_ACCESSOR name: visibility:public modality:FINAL <> ($this:.TestData) returnType:kotlin.String
+ correspondingProperty: PROPERTY name:value visibility:public modality:FINAL [val]
+ $this: VALUE_PARAMETER name: type:.TestData
+ BLOCK_BODY
+ RETURN type=kotlin.Nothing from='public final fun (): kotlin.String declared in .TestData'
+ GET_FIELD 'FIELD PROPERTY_BACKING_FIELD name:value type:kotlin.String visibility:private [final]' type=kotlin.String origin=null
+ receiver: GET_VAR ': .TestData declared in .TestData.' type=.TestData origin=null
+ CLASS GENERATED[org.jetbrains.kotlinx.serialization.compiler.fir.SerializationPluginKey] OBJECT name:Companion modality:FINAL visibility:public [companion] superTypes:[kotlin.Any]
+ $this: VALUE_PARAMETER INSTANCE_RECEIVER name: type:.TestData.Companion
+ CONSTRUCTOR GENERATED[org.jetbrains.kotlinx.serialization.compiler.fir.SerializationPluginKey] visibility:private <> () returnType:.TestData.Companion [primary]
+ BLOCK_BODY
+ DELEGATING_CONSTRUCTOR_CALL 'public constructor () declared in kotlin.Any'
+ INSTANCE_INITIALIZER_CALL classDescriptor='CLASS GENERATED[org.jetbrains.kotlinx.serialization.compiler.fir.SerializationPluginKey] OBJECT name:Companion modality:FINAL visibility:public [companion] superTypes:[kotlin.Any]'
+ FUN FAKE_OVERRIDE name:equals visibility:public modality:OPEN <> ($this:kotlin.Any, other:kotlin.Any?) returnType:kotlin.Boolean [fake_override,operator]
+ overridden:
+ public open fun equals (other: kotlin.Any?): kotlin.Boolean declared in kotlin.Any
+ $this: VALUE_PARAMETER name: type:kotlin.Any
+ VALUE_PARAMETER name:other index:0 type:kotlin.Any?
+ FUN FAKE_OVERRIDE name:hashCode visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.Int [fake_override]
+ overridden:
+ public open fun hashCode (): kotlin.Int declared in kotlin.Any
+ $this: VALUE_PARAMETER name: type:kotlin.Any
+ FUN FAKE_OVERRIDE name:toString visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.String [fake_override]
+ overridden:
+ public open fun toString (): kotlin.String declared in kotlin.Any
+ $this: VALUE_PARAMETER name: type:kotlin.Any
+ FUN GENERATED[org.jetbrains.kotlinx.serialization.compiler.fir.SerializationPluginKey] name:serializer visibility:public modality:FINAL <> ($this:.TestData.Companion) returnType:kotlinx.serialization.KSerializer<.TestData>
+ $this: VALUE_PARAMETER name: type:.TestData.Companion
+ BLOCK_BODY
+ RETURN type=kotlin.Nothing from='public final fun serializer (): kotlinx.serialization.KSerializer<.TestData> declared in .TestData.Companion'
+ GET_OBJECT 'CLASS KOTLINX_SERIALIZATION OBJECT name:$serializer modality:FINAL visibility:public superTypes:[kotlinx.serialization.internal.GeneratedSerializer<.TestData>]' type=.TestData.$serializer
+ CLASS KOTLINX_SERIALIZATION OBJECT name:$serializer modality:FINAL visibility:public superTypes:[kotlinx.serialization.internal.GeneratedSerializer<.TestData>]
+ annotations:
+ Deprecated(message = "This synthesized declaration should not be used directly", replaceWith = , level = GET_ENUM 'ENUM_ENTRY IR_EXTERNAL_DECLARATION_STUB name:HIDDEN' type=kotlin.DeprecationLevel)
+ $this: VALUE_PARAMETER INSTANCE_RECEIVER name: type:.TestData.$serializer
+ PROPERTY GENERATED[org.jetbrains.kotlinx.serialization.compiler.fir.SerializationPluginKey] name:descriptor visibility:public modality:FINAL [val]
+ overridden:
+ public abstract descriptor: kotlinx.serialization.descriptors.SerialDescriptor
+ FIELD PROPERTY_BACKING_FIELD name:descriptor type:kotlinx.serialization.descriptors.SerialDescriptor visibility:private [final]
+ FUN DEFAULT_PROPERTY_ACCESSOR name: visibility:public modality:FINAL <> ($this:.TestData.$serializer) returnType:kotlinx.serialization.descriptors.SerialDescriptor
+ correspondingProperty: PROPERTY GENERATED[org.jetbrains.kotlinx.serialization.compiler.fir.SerializationPluginKey] name:descriptor visibility:public modality:FINAL [val]
+ overridden:
+ public abstract fun (): kotlinx.serialization.descriptors.SerialDescriptor declared in kotlinx.serialization.internal.GeneratedSerializer
+ $this: VALUE_PARAMETER name: type:.TestData.$serializer
+ BLOCK_BODY
+ RETURN type=kotlin.Nothing from='public final fun (): kotlinx.serialization.descriptors.SerialDescriptor declared in .TestData.$serializer'
+ GET_FIELD 'FIELD PROPERTY_BACKING_FIELD name:descriptor type:kotlinx.serialization.descriptors.SerialDescriptor visibility:private [final]' type=kotlinx.serialization.descriptors.SerialDescriptor origin=null
+ receiver: GET_VAR ': .TestData.$serializer declared in .TestData.$serializer.' type=.TestData.$serializer origin=null
+ ANONYMOUS_INITIALIZER isStatic=false
+ BLOCK_BODY
+ VAR IR_TEMPORARY_VARIABLE name:tmp_0 type:kotlinx.serialization.internal.PluginGeneratedSerialDescriptor [val]
+ CONSTRUCTOR_CALL 'public constructor (serialName: kotlin.String, generatedSerializer: kotlinx.serialization.internal.GeneratedSerializer<*>?, elementsCount: kotlin.Int) declared in kotlinx.serialization.internal.PluginGeneratedSerialDescriptor' type=kotlinx.serialization.internal.PluginGeneratedSerialDescriptor origin=null
+ serialName: CONST String type=kotlin.String value="TestData"
+ generatedSerializer: GET_VAR ': .TestData.$serializer declared in .TestData.$serializer' type=.TestData.$serializer origin=null
+ elementsCount: CONST Int type=kotlin.Int value=1
+ CALL 'public final fun addElement (name: kotlin.String, isOptional: kotlin.Boolean): kotlin.Unit declared in kotlinx.serialization.internal.PluginGeneratedSerialDescriptor' type=kotlin.Unit origin=null
+ $this: GET_VAR 'val tmp_0: kotlinx.serialization.internal.PluginGeneratedSerialDescriptor declared in .TestData.$serializer' type=kotlinx.serialization.internal.PluginGeneratedSerialDescriptor origin=null
+ name: CONST String type=kotlin.String value="value"
+ isOptional: CONST Boolean type=kotlin.Boolean value=false
+ SET_FIELD 'FIELD PROPERTY_BACKING_FIELD name:descriptor type:kotlinx.serialization.descriptors.SerialDescriptor visibility:private [final]' type=kotlin.Unit origin=null
+ receiver: GET_VAR ': .TestData.$serializer declared in .TestData.$serializer' type=.TestData.$serializer origin=null
+ value: GET_VAR 'val tmp_0: kotlinx.serialization.internal.PluginGeneratedSerialDescriptor declared in .TestData.$serializer' type=kotlinx.serialization.internal.PluginGeneratedSerialDescriptor origin=null
+ CONSTRUCTOR GENERATED[org.jetbrains.kotlinx.serialization.compiler.fir.SerializationPluginKey] visibility:private <> () returnType:.TestData.$serializer [primary]
+ BLOCK_BODY
+ DELEGATING_CONSTRUCTOR_CALL 'public constructor () declared in kotlin.Any'
+ INSTANCE_INITIALIZER_CALL classDescriptor='CLASS KOTLINX_SERIALIZATION OBJECT name:$serializer modality:FINAL visibility:public superTypes:[kotlinx.serialization.internal.GeneratedSerializer<.TestData>]'
+ FUN FAKE_OVERRIDE name:equals visibility:public modality:OPEN <> ($this:kotlin.Any, other:kotlin.Any?) returnType:kotlin.Boolean [fake_override,operator]
+ overridden:
+ public open fun equals (other: kotlin.Any?): kotlin.Boolean declared in kotlinx.serialization.internal.GeneratedSerializer
+ $this: VALUE_PARAMETER name: type:kotlin.Any
+ VALUE_PARAMETER name:other index:0 type:kotlin.Any?
+ FUN FAKE_OVERRIDE name:hashCode visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.Int [fake_override]
+ overridden:
+ public open fun hashCode (): kotlin.Int declared in kotlinx.serialization.internal.GeneratedSerializer
+ $this: VALUE_PARAMETER name: type:kotlin.Any
+ FUN FAKE_OVERRIDE name:toString visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.String [fake_override]
+ overridden:
+ public open fun toString (): kotlin.String declared in kotlinx.serialization.internal.GeneratedSerializer
+ $this: VALUE_PARAMETER name: type:kotlin.Any
+ FUN FAKE_OVERRIDE name:typeParametersSerializers visibility:public modality:OPEN <> ($this:kotlinx.serialization.internal.GeneratedSerializer<.TestData>) returnType:kotlin.Array> [fake_override]
+ overridden:
+ public open fun typeParametersSerializers (): kotlin.Array> declared in kotlinx.serialization.internal.GeneratedSerializer
+ $this: VALUE_PARAMETER name: type:kotlinx.serialization.internal.GeneratedSerializer<.TestData>
+ FUN GENERATED[org.jetbrains.kotlinx.serialization.compiler.fir.SerializationPluginKey] name:childSerializers visibility:public modality:FINAL <> ($this:.TestData.$serializer) returnType:kotlin.Array>
+ overridden:
+ public abstract fun childSerializers (): kotlin.Array> declared in kotlinx.serialization.internal.GeneratedSerializer
+ $this: VALUE_PARAMETER name: type:.TestData.$serializer
+ BLOCK_BODY
+ RETURN type=kotlin.Nothing from='public final fun childSerializers (): kotlin.Array> declared in .TestData.$serializer'
+ CALL 'public final fun arrayOf (vararg elements: T of kotlin.arrayOf): kotlin.Array declared in kotlin' type=kotlin.Array> origin=null
+ : kotlinx.serialization.KSerializer<*>
+ elements: VARARG type=kotlin.Array> varargElementType=kotlinx.serialization.KSerializer<*>
+ GET_OBJECT 'CLASS IR_EXTERNAL_DECLARATION_STUB OBJECT name:StringSerializer modality:FINAL visibility:internal superTypes:[kotlinx.serialization.KSerializer]' type=kotlinx.serialization.internal.StringSerializer
+ FUN GENERATED[org.jetbrains.kotlinx.serialization.compiler.fir.SerializationPluginKey] name:deserialize visibility:public modality:FINAL <> ($this:.TestData.$serializer, decoder:kotlinx.serialization.encoding.Decoder) returnType:.TestData
+ overridden:
+ public abstract fun deserialize (decoder: kotlinx.serialization.encoding.Decoder): T of kotlinx.serialization.internal.GeneratedSerializer declared in kotlinx.serialization.internal.GeneratedSerializer
+ $this: VALUE_PARAMETER name: type:.TestData.$serializer
+ VALUE_PARAMETER name:decoder index:0 type:kotlinx.serialization.encoding.Decoder
+ BLOCK_BODY
+ VAR IR_TEMPORARY_VARIABLE name:tmp_1 type:kotlinx.serialization.descriptors.SerialDescriptor [val]
+ CALL 'public final fun (): kotlinx.serialization.descriptors.SerialDescriptor declared in .TestData.$serializer' type=kotlinx.serialization.descriptors.SerialDescriptor origin=GET_PROPERTY
+ $this: GET_VAR ': .TestData.$serializer declared in .TestData.$serializer.deserialize' type=.TestData.$serializer origin=null
+ VAR IR_TEMPORARY_VARIABLE name:tmp_2 type:kotlin.Boolean [var]
+ CONST Boolean type=kotlin.Boolean value=true
+ VAR IR_TEMPORARY_VARIABLE name:tmp_3 type:kotlin.Int [var]
+ CONST Int type=kotlin.Int value=0
+ VAR IR_TEMPORARY_VARIABLE name:tmp_4 type:kotlin.Int [var]
+ CONST Int type=kotlin.Int value=0
+ VAR IR_TEMPORARY_VARIABLE name:tmp_5 type:kotlin.String? [var]
+ CONST Null type=kotlin.String? value=null
+ VAR IR_TEMPORARY_VARIABLE name:tmp_6 type:kotlinx.serialization.encoding.CompositeDecoder [val]
+ CALL 'public abstract fun beginStructure (descriptor: kotlinx.serialization.descriptors.SerialDescriptor): kotlinx.serialization.encoding.CompositeDecoder declared in kotlinx.serialization.encoding.Decoder' type=kotlinx.serialization.encoding.CompositeDecoder origin=null
+ $this: GET_VAR 'decoder: kotlinx.serialization.encoding.Decoder declared in .TestData.$serializer.deserialize' type=kotlinx.serialization.encoding.Decoder origin=null
+ descriptor: GET_VAR 'val tmp_1: kotlinx.serialization.descriptors.SerialDescriptor declared in .TestData.$serializer.deserialize' type=kotlinx.serialization.descriptors.SerialDescriptor origin=null
+ WHEN type=kotlin.Unit origin=null
+ BRANCH
+ if: CALL 'public open fun decodeSequentially (): kotlin.Boolean declared in kotlinx.serialization.encoding.CompositeDecoder' type=kotlin.Boolean origin=null
+ $this: GET_VAR 'val tmp_6: kotlinx.serialization.encoding.CompositeDecoder declared in .TestData.$serializer.deserialize' type=kotlinx.serialization.encoding.CompositeDecoder origin=null
+ then: BLOCK type=kotlin.Unit origin=null
+ BLOCK type=kotlin.Unit origin=null
+ SET_VAR 'var tmp_5: kotlin.String? declared in .TestData.$serializer.deserialize' type=kotlin.Unit origin=EQ
+ CALL 'public abstract fun decodeStringElement (descriptor: kotlinx.serialization.descriptors.SerialDescriptor, index: kotlin.Int): kotlin.String declared in kotlinx.serialization.encoding.CompositeDecoder' type=kotlin.String origin=null
+ $this: GET_VAR 'val tmp_6: kotlinx.serialization.encoding.CompositeDecoder declared in .TestData.$serializer.deserialize' type=kotlinx.serialization.encoding.CompositeDecoder origin=null
+ descriptor: GET_VAR 'val tmp_1: kotlinx.serialization.descriptors.SerialDescriptor declared in .TestData.$serializer.deserialize' type=kotlinx.serialization.descriptors.SerialDescriptor origin=null
+ index: CONST Int type=kotlin.Int value=0
+ SET_VAR 'var tmp_4: kotlin.Int declared in .TestData.$serializer.deserialize' type=kotlin.Unit origin=EQ
+ CALL 'public final fun or (other: kotlin.Int): kotlin.Int declared in kotlin.Int' type=kotlin.Int origin=null
+ $this: GET_VAR 'var tmp_4: kotlin.Int declared in .TestData.$serializer.deserialize' type=kotlin.Int origin=null
+ other: CONST Int type=kotlin.Int value=1
+ BRANCH
+ if: CONST Boolean type=kotlin.Boolean value=true
+ then: WHILE label=null origin=null
+ condition: GET_VAR 'var tmp_2: kotlin.Boolean declared in .TestData.$serializer.deserialize' type=kotlin.Boolean origin=null
+ body: BLOCK type=kotlin.Unit origin=null
+ SET_VAR 'var tmp_3: kotlin.Int declared in .TestData.$serializer.deserialize' type=kotlin.Unit origin=EQ
+ CALL 'public abstract fun decodeElementIndex (descriptor: kotlinx.serialization.descriptors.SerialDescriptor): kotlin.Int declared in kotlinx.serialization.encoding.CompositeDecoder' type=kotlin.Int origin=null
+ $this: GET_VAR 'val tmp_6: kotlinx.serialization.encoding.CompositeDecoder declared in .TestData.$serializer.deserialize' type=kotlinx.serialization.encoding.CompositeDecoder origin=null
+ descriptor: GET_VAR 'val tmp_1: kotlinx.serialization.descriptors.SerialDescriptor declared in .TestData.$serializer.deserialize' type=kotlinx.serialization.descriptors.SerialDescriptor origin=null
+ WHEN type=kotlin.Unit origin=null
+ BRANCH
+ if: CALL 'public final fun EQEQ (arg0: kotlin.Any?, arg1: kotlin.Any?): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=EQEQ
+ arg0: GET_VAR 'var tmp_3: kotlin.Int declared in .TestData.$serializer.deserialize' type=kotlin.Int origin=null
+ arg1: CONST Int type=kotlin.Int value=-1
+ then: SET_VAR 'var tmp_2: kotlin.Boolean declared in .TestData.$serializer.deserialize' type=kotlin.Unit origin=EQ
+ CONST Boolean type=kotlin.Boolean value=false
+ BRANCH
+ if: CALL 'public final fun EQEQ (arg0: kotlin.Any?, arg1: kotlin.Any?): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=EQEQ
+ arg0: GET_VAR 'var tmp_3: kotlin.Int declared in .TestData.$serializer.deserialize' type=kotlin.Int origin=null
+ arg1: CONST Int type=kotlin.Int value=0
+ then: BLOCK type=kotlin.Unit origin=null
+ SET_VAR 'var tmp_5: kotlin.String? declared in .TestData.$serializer.deserialize' type=kotlin.Unit origin=EQ
+ CALL 'public abstract fun decodeStringElement (descriptor: kotlinx.serialization.descriptors.SerialDescriptor, index: kotlin.Int): kotlin.String declared in kotlinx.serialization.encoding.CompositeDecoder' type=kotlin.String origin=null
+ $this: GET_VAR 'val tmp_6: kotlinx.serialization.encoding.CompositeDecoder declared in .TestData.$serializer.deserialize' type=kotlinx.serialization.encoding.CompositeDecoder origin=null
+ descriptor: GET_VAR 'val tmp_1: kotlinx.serialization.descriptors.SerialDescriptor declared in .TestData.$serializer.deserialize' type=kotlinx.serialization.descriptors.SerialDescriptor origin=null
+ index: CONST Int type=kotlin.Int value=0
+ SET_VAR 'var tmp_4: kotlin.Int declared in .TestData.$serializer.deserialize' type=kotlin.Unit origin=EQ
+ CALL 'public final fun or (other: kotlin.Int): kotlin.Int declared in kotlin.Int' type=kotlin.Int origin=null
+ $this: GET_VAR 'var tmp_4: kotlin.Int declared in .TestData.$serializer.deserialize' type=kotlin.Int origin=null
+ other: CONST Int type=kotlin.Int value=1
+ BRANCH
+ if: CONST Boolean type=kotlin.Boolean value=true
+ then: THROW type=kotlin.Nothing
+ CONSTRUCTOR_CALL 'public constructor (index: kotlin.Int) declared in kotlinx.serialization.UnknownFieldException' type=kotlinx.serialization.UnknownFieldException origin=null
+ index: GET_VAR 'var tmp_3: kotlin.Int declared in .TestData.$serializer.deserialize' type=kotlin.Int origin=null
+ CALL 'public abstract fun endStructure (descriptor: kotlinx.serialization.descriptors.SerialDescriptor): kotlin.Unit declared in kotlinx.serialization.encoding.CompositeDecoder' type=kotlin.Unit origin=null
+ $this: GET_VAR 'val tmp_6: kotlinx.serialization.encoding.CompositeDecoder declared in .TestData.$serializer.deserialize' type=kotlinx.serialization.encoding.CompositeDecoder origin=null
+ descriptor: GET_VAR 'val tmp_1: kotlinx.serialization.descriptors.SerialDescriptor declared in