diff --git a/README.md b/README.md index ae8230d..c699505 100644 --- a/README.md +++ b/README.md @@ -152,9 +152,9 @@ If the version is less than or equal to `0.9.0`, you can refer to this compariso _build.gradle.kts_ -```kotlin +```Kotlin plugins { - id("org.jetbrains.kotlin.jvm") version "$KOTLIN_VERSION" // or js? or multiplatform? + kotlin("jvm") version "$KOTLIN_VERSION" // or multiplatform id("love.forte.plugin.suspend-transform") version "$PLUGIN_VERSION" // other... } @@ -162,56 +162,8 @@ plugins { // other... // config it. -suspendTransform { - enabled = true // default: true - includeRuntime = true // default: true - includeAnnotation = true // default: true - // Note: If you disable includeAnnotation, you need to customise the `targetMarker` or set it to `null`. - // see also: https://github.com/ForteScarlet/kotlin-suspend-transform-compiler-plugin/pull/73 - // targetMarker = ... - - /* - * Use both `useJvmDefault` and `useJsDefault`. - * Need to include the runtime and annotation. - */ - // useDefault() - - /* - * Use the default configuration for JVM platform, - * Equivalent: - * addJvmTransformers( - * SuspendTransformConfiguration.jvmBlockingTransformer, - * SuspendTransformConfiguration.jvmAsyncTransformer, - * ) - * - * Need to include the runtime and annotation. - */ - useJvmDefault() - - // or custom by yourself - jvm { - // ... - } - // or - addJvmTransformers(...) - - /* - * Use the default configuration for JS platform, - * Equivalent: - * addJvmTransformers( - * SuspendTransformConfiguration.jsPromiseTransformer, - * ) - * - * Need to include the runtime and annotation. - */ - useJsDefault() - - // or custom by yourself - js { - // ... - } - // or - addJsTransformers(...) +suspendTransformPlugin { + // Config the SuspendTransformPluginExtension ... } ``` @@ -219,7 +171,7 @@ suspendTransform { _build.gradle.kts_ -```kotlin +```Kotlin buildscript { repositories { mavenCentral() @@ -231,7 +183,7 @@ buildscript { } plugins { - id("org.jetbrains.kotlin.jvm") // or js? or multiplatform? + id("org.jetbrains.kotlin.jvm") // or multiplatform? id("love.forte.plugin.suspend-transform") // other... } @@ -239,58 +191,663 @@ plugins { // other... // config it. -suspendTransform { - enabled = true // default: true - includeRuntime = true // default: true - includeAnnotation = true // default: true - - /* - * Use both `useJvmDefault` and `useJsDefault`. - * Need to include the runtime and annotation. - */ - // useDefault() - - /* - * Use the default configuration for JVM platform, - * Equivalent: - * addJvmTransformers( - * SuspendTransformConfiguration.jvmBlockingTransformer, - * SuspendTransformConfiguration.jvmAsyncTransformer, - * ) - * - * Need to include the runtime and annotation. - */ - useJvmDefault() - - // or custom by yourself - jvm { - // ... +suspendTransformPlugin { + // Config the SuspendTransformPluginExtension ... +} +``` + +## Config the extension + +### Enabled + +Enable the Kotlin compiler plugin. +Default value is `true`. + +```Kotlin +suspendTransformPlugin { + enabled = true +} +``` + +### Include the default annotations and runtime + +If you wish to use the Transformer we provide, then you may need to add the `annotation` and `runtime` dependencies. + +You can add them automatically via configuration. + +```Kotlin +suspendTransformPlugin { + // include the annotation + // Default is `true` + includeAnnotation = true + // The default can be left unconfigured and the default values are used exclusively. + annotationDependency { + // Default is `compileOnly` + configurationName = "compileOnly" + // Default is same as the plugin version + version = "" + } + + // Include the runtime + // Default is `true` + includeRuntime = true + // The default can be left unconfigured and the default values are used exclusively. + runtimeDependency { + // Default is `implementation` + configurationName = "implementation" + // Default is same as the plugin version + version = "" + } +} +``` + +You can also disable them and add dependencies manually. + +```Kotlin +plugin { + kotlin("jvm") version "..." // Take the Kotlin/JVM as an example + id("love.forte.plugin.suspend-transform") version "2.1.20-0.12.0" +} + +dependencies { + // annotation + compileOnly("love.forte.plugin.suspend-transform:suspend-transform-annotation:") + // runtime + implementation("love.forte.plugin.suspend-transform:suspend-transform-runtime:") +} + +suspendTransformPlugin { + // Disable them + includeAnnotation = false + includeRuntime = false +} +``` + +### Add transformers + +`Transformer` is the type used to describe how the suspend function is transformed. +You need to add some `Transformer`s to make the compiler plugin actually work. + + +```Kotlin +suspendTransformPlugin { + // Config the transformers + transformers { + add(TargetPlatform.JVM) { // this: TransformerSpec + // Config the TransformerSpec... + } + + addJvm { // this: TransformerSpec + // Config the TransformerSpec... + } + + // Use a default transformer we provided from `SuspendTransformConfigurations` + add(TargetPlatform.JVM, SuspendTransformConfigurations.jvmBlockingTransformer) + + addJvm { // this: TransformerSpec + // Modify and adjust from a Transformer + from(SuspendTransformConfigurations.jvmBlockingTransformer) + // Further configurations... + } } - // or - addJvmTransformers(...) - - /* - * Use the default configuration for JS platform, - * Equivalent: - * addJvmTransformers( - * SuspendTransformConfiguration.jsPromiseTransformer, - * ) - * - * Need to include the runtime and annotation. - */ - useJsDefault() - - // or custom by yourself - js { +} +``` + +#### Add the default transformers + +First, we provide some simple and commonly used implementations. +You can use them simply and quickly through configuration. + +> [!note] +> The default `Transformer`s depend on the `annotation` and `runtime` we provide. +> Make sure you include them before using it. + +**JVM blocking** + +```Kotlin +suspendTransformPlugin { + transformers { + // The 1st way: + addJvmBlocking() + + // Or the 2ed way: + addJvm(SuspendTransformConfigurations.jvmBlockingTransformer) + // Or use transformers.add(TargetPlatform.JVM, jvmBlockingTransformer), etc. + } +} +``` + +`JvmBlocking` allows you to mark `@JvmBlocking` on the suspend function, +which generates a `xxxBlocking` function. + +```Kotlin +class Cat { + @JvmBlocking + suspend fun meow() { // ... } - // or - addJsTransformers(...) + + // Generated: + fun meowBlocking() { + `$runInBlocking$` { meow() } + } } ``` -## Cautions +The `$runInBlocking$` based on `kotlinx.coroutines.runBlocking` 。 + +**JVM Async** + +```Kotlin +suspendTransformPlugin { + transformers { + // The 1st way: + addJvmAsync() + + // Or the 2ed way: + addJvm(SuspendTransformConfigurations.jvmAsyncTransformer) + // Or use transformers.add(TargetPlatform.JVM, jvmAsyncTransformer), etc. + } +} +``` + +`JvmAsync` allows you to mark `@JvmAsync` on the suspend function, +which generates a `xxxAsync` function. + +```Kotlin +class Cat { + @JvmBlocking + suspend fun meow(): String = "Meow!" + + // Generated: + fun meowAsync(): CompletableFuture { + `$runInAsync$`(block = { meow() }, scope = this as? CoroutineScope) + } +} +``` + +The `block` is the original suspend function that needs to be executed +and the `scope` is the `CoroutineScope` that will be used. + +If the current scope is a `CoroutineScope`, it takes precedence over itself. +Otherwise, `GlobalScope` is used internally. + +Why use `GlobalScope`: When using an internal scope, this scope qualifies: +1. global. +2. is never visible externally, so it is not artificially closed. +3. is not intended for IO and does not require a custom dispatcher. + +We believe `GlobalScope` meets these conditions. + +_Have a different point? Feel free to create issue!_ + +**JS Promise** + +```Kotlin +suspendTransformPlugin { + transformers { + // The 1st way: + addJsPromise() + + // Or the 2ed way: + addJs(SuspendTransformConfigurations.jsPromiseTransformer) + // Or use transformers.add(TargetPlatform.JS, jsPromiseTransformer), etc. + } +} +``` + +```Kotlin +class Cat { + @JsPromise + suspend fun meow(): String = "Meow!" + + // Generated: + fun meowAsync(): Promise { + `$runInAsync$`(block = { meow() }, scope = this as? CoroutineScope) + } +} +``` + +The `block` is the original suspend function that needs to be executed +and the `scope` is the `CoroutineScope` that will be used. + +#### Use the defaults + +The `addJvmBlocking()` and `addJvmAsync()` may be combined as `useJvmDefault()`. + +```Kotlin +suspendTransformPlugin { + transformers { + // Includes addJvmBlocking() and addJvmAsync() + useJvmDefault() + } +} +``` + +The `addJsPromise()` may be combined as `useJsDefault()`. + +```Kotlin +suspendTransformPlugin { + transformers { + // Includes addJsPromise() + useJsDefault() + } +} +``` + +The `useJvmDefault()` and `useJsDefault()` may be combined as `useDefault()`. + +```Kotlin +suspendTransformPlugin { + transformers { + // Includes useJvmDefault() and useJsDefault() + useDefault() + } +} +``` + +#### Use custom transformers + +You can also customize your `Transformer` if the default `Transformer`s don't meet your needs, +e.g. if you want to fully implement blocking logic and don't want to use `kotlinx.coroutines.runBlocking`. + +> A fully customized implementation of JVM Blocking/Async Transformers reference: +> https://github.com/simple-robot/simpler-robot/blob/v4-main/simbot-commons/simbot-common-suspend-runner/src/jvmMain/kotlin/love/forte/simbot/suspendrunner/BlockingRunner.kt + +```Kotlin +suspendTransformPlugin { + // If customized, then you may not use the annotation and runtime we provide. + includeAnnotation = false + includeRuntime = false + + transformer { + // See below for details + } +} +``` + +As an example, you intend to create a custom annotation: `@JBlock`, +which is executed via the function `inBlock` when the suspend function uses this annotation. + +```Kotlin +// Your annotation +annotation class JBlock(...) + +// Your top-level transform function +fun inBlock(block: suspend () -> T): T { + TODO("Your impl") +} +``` + +First, let's agree that the following properties should be included in the annotation: + +- `baseName`: The generated function's **base name**. + When the value of this property is empty, the name of the original function is used by default. + ```Kotlin + @JBlock(baseName = "") + suspend fun meow1() // Generated function name: ${baseName}${suffix} -> meow1Blocking + + @JBlock(baseName = "meow999") + suspend fun meow2() // Generated function name: ${baseName}${suffix} -> meow999Blocking + ``` +- `suffix`: The generated function name's suffix. +- `asProperty`: Make the generated function a property. + Can be used in cases where the original function has no arguments. + ```Kotlin + @JBlock(asProperty = true) + suspend fun value(): Int + + // Generated: + val valueBlocking: Int + get() = inBlock { value() } + ``` + +So your annotation should look like this: + +```Kotlin +annotation class JBlock( + val baseName: String = "", + val suffix: String = "Blocking", + val asProperty: Boolean = false +) +``` + +The configuration: + +```Kotlin +suspendTransformPlugin { + includeAnnotation = false + includeRuntime = false + transformers { + addJvm { + markAnnotation { + // Your annotation class's info. + classInfo { + packageName = "com.example" + className = "JBlock" + } + + // The property names. + baseNameProperty = "baseName" // Default is `baseName` + suffixProperty = "suffix" // Default is `suffix` + asPropertyProperty = "asProperty" // Default is `asProperty` + + // The compiler plugin doesn't seem to be able to get the default values for annotations + // (or I haven't found a way to do it yet). + // So here you need to configure the default value of the annotation, which needs to be consistent with your definition. + defaultSuffix = "Blocking" + defaultAsProperty = false // For the same reasons as above. + } + } + } +} +``` + +However, the property names do not have to be the same as these three, as long as the function and type correspond. So we can adjust it like this: + +```Kotlin +annotation class JBlock( + val myBaseName: String = "", + val mySuffix: String = "Blocking", + val myAsProperty: Boolean = false +) +``` + +The configuration: + +```Kotlin +suspendTransformPlugin { + includeAnnotation = false + includeRuntime = false + transformers { + addJvm { + markAnnotation { + // Your annotation class's info. + classInfo { + packageName = "com.example" + className = "JBlock" + } + + // The property names. + baseNameProperty = "myBaseName" + suffixProperty = "mySuffix" + asPropertyProperty = "myAsProperty" + + // The default values. + defaultSuffix = "Blocking" + defaultAsProperty = false + } + } + } +} +``` + +Then configure the information for your transform function. + +```Kotlin +// Your top-level transform function +fun inBlock(block: suspend () -> T): T { + TODO("Your impl") +} +``` +The configuration: + +```Kotlin +suspendTransformPlugin { + includeAnnotation = false + includeRuntime = false + transformers { + addJvm { + markAnnotation { + // ... + } + + // The function info + transformFunctionInfo { + packageName = "com.example" + functionName = "inBlock" + } + + // The return type configs + + // The return type. + // If `null` it means the same type as the original function return. + // If you return a specific type (e.g. `CompletableFuture`) you need to configure that type. + // + // Default value is null. + transformReturnType = null + + // Whether the returned type contains a generic type that is of the same type as the original function. + // e.g. CompletableFuture, The `T` represents the value returned by the original function. + // In this case it is set to `true`. + // + // Set to `false` if the return type is of a specific type, + // but without a generic (a rare case, an example: `Job`). + // Valid if `transformReturnType` is not null. + // + // Default value is false. + transformReturnTypeGeneric = false + } + } +} +``` + +Finally, in the process of generating the function, we allow some manipulation of the annotations. +- Copy annotations from original function to generated synthetic function. + - exclude some annotations from copying. +- Include some annotations to original function. +- Include some annotations to generated synthetic function. + +Now let's assume: +- We want to add `@JvmSynthetic` to the original function. +- We want to add `@JApi` to the generated synthetic function. +- Copy the annotations without copying `@JvmSynthetic` (exclude `@JvmSynthetic`). + +The `@JApi`: + +```Kotlin +@RequiresOptIn(message = "Api for Java", level = RequiresOptIn.Level.WARNING) +@Retention(AnnotationRetention.BINARY) +annotation class JApi +``` + +The configuration: + +```Kotlin +suspendTransformPlugin { + includeAnnotation = false + includeRuntime = false + transformers { + addJvm { + markAnnotation { + // ... + } + transformFunctionInfo { + // ... + } + + // Enabling annotated copies + // Default is FALSE + copyAnnotationsToSyntheticFunction = true + // If the generated synthetic function is property (asProperty=true), + // Copy annotations to the property. + // Otherwise, copy to the property's getter function. + // Default is FALSE + copyAnnotationsToSyntheticProperty = true + + // Include `@kotlin.jvm.JvmSynthetic` to original function. + addOriginFunctionIncludeAnnotation { + // Some common types are defined in SuspendTransformConfigurations. See below. + classInfo { + packageName = "kotlin.jvm" + className = "JvmSynthetic" + } + // Default is false + repeatable = false + } + + // Include `@com.example.JApi` to generated synthetic function + addSyntheticFunctionIncludeAnnotation { + classInfo { + packageName = "com.example" + className = "JApi" + } + // Marks whether this annotation supports being added to a property. + // Default is FALSE + includeProperty = true + } + + // Exclude `@kotlin.jvm.JvmSynthetic` when copying. + addCopyAnnotationExclude { + // SuspendTransformConfigurations provides a small number of + // common annotations or type definitions that can be used directly. + from(SuspendTransformConfigurations.jvmSyntheticClassInfo) + } + } + } +} +``` + +The full example: + +Code: + +```Kotlin +annotation class JBlock( + val myBaseName: String = "", + val mySuffix: String = "Blocking", + val myAsProperty: Boolean = false +) + +@RequiresOptIn(message = "Api for Java", level = RequiresOptIn.Level.WARNING) +@Retention(AnnotationRetention.BINARY) +annotation class JApi + +fun inBlock(block: suspend () -> T): T { + TODO("Your impl") +} +``` + +Configuration: + +```Kotlin +suspendTransformPlugin { + includeAnnotation = false + includeRuntime = false + transformers { + addJvm { + markAnnotation { + classInfo { + packageName = "com.example" + className = "JBlock" + } + + baseNameProperty = "myBaseName" + suffixProperty = "mySuffix" + asPropertyProperty = "myAsProperty" + + defaultSuffix = "Blocking" + defaultAsProperty = false + } + + transformFunctionInfo { + packageName = "com.example" + functionName = "inBlock" + } + + copyAnnotationsToSyntheticFunction = true + copyAnnotationsToSyntheticProperty = true + + addOriginFunctionIncludeAnnotation { + classInfo { + from(SuspendTransformConfigurations.jvmSyntheticClassInfo) + } + repeatable = false + } + + addSyntheticFunctionIncludeAnnotation { + classInfo { + packageName = "com.example" + className = "JApi" + } + includeProperty = true + } + + addCopyAnnotationExclude { + from(SuspendTransformConfigurations.jvmSyntheticClassInfo) + } + } + } +} +``` + +> [!note] +> Since the property name is configurable, the same annotation can be reused on multiple transformers. +> Annotation: +> ```Kotlin +> annotation class JTrans( +> val blockingBaseName: String = "", +> val blockingSuffix: String = "Blocking", +> val blockingAsProperty: Boolean = false, +> +> val asyncBaseName: String = "", +> val asyncSuffix: String = "Async", +> val asyncAsProperty: Boolean = false +> ) +> ``` +> Configuration: +> ```Kotlin +> suspendTransformPlugin { +> includeAnnotation = false +> includeRuntime = false +> transformers { +> // For blocking +> addJvm { +> markAnnotation { +> classInfo { +> packageName = "com.example" +> className = "JTrans" +> } +> baseNameProperty = "blockingBaseName" +> suffixProperty = "blockingSuffix" +> asPropertyProperty = "blockingAsProperty" +> defaultSuffix = "Blocking" +> defaultAsProperty = false +> } +> +> transformFunctionInfo { +> packageName = "com.example" +> functionName = "inBlock" +> } +> +> // other config... +> } +> +> // For async +> addJvm { +> markAnnotation { +> classInfo { +> packageName = "com.example" +> className = "JTrans" +> } +> baseNameProperty = "asyncBaseName" +> suffixProperty = "asyncSuffix" +> asPropertyProperty = "asyncAsProperty" +> defaultSuffix = "Async" +> defaultAsProperty = false +> } +> +> transformFunctionInfo { +> packageName = "com.example" +> functionName = "inAsync" +> } +> } +> } +>} +> ``` + +## Cautions ### Gradle JVM **Gradle JVM** must be JDK11+ @@ -299,9 +856,6 @@ suspendTransform { K2 is supported since `v0.7.0`. -> [!warning] -> In experiments. - ### JsExport If you want to use `@JsExport` with default configuration in JS, @@ -310,19 +864,21 @@ try this: _build.gradle.kts_ ```kotlin +import love.forte.plugin.suspendtrans.configuration.SuspendTransformConfigurations + plugins { - ... + // ... } -suspendTransform { - addJsTransformers( - SuspendTransformConfiguration.jsPromiseTransformer.copy( - copyAnnotationExcludes = listOf( - // The generated function does not include `@JsExport.Ignore`. - ClassInfo("kotlin.js", "JsExport.Ignore") - ) - ) - ) +suspendTransformPlugin { + transformers { + addJsPromise { + addCopyAnnotationExclude { + // The generated function does not include (copy) `@JsExport.Ignore`. + from(kotlinJsExportIgnoreClassInfo) + } + } + } } ``` @@ -490,234 +1046,6 @@ class Bar { } ``` -## Customization - -```kotlin -plugin { - id("love.forte.plugin.suspend-transform") version "$VERSION" -} - -suspendTransform { - // enabled suspend transform plugin - enabled = true - // include 'love.forte.plugin.suspend-transform:suspend-transform-runtime' to the runtime environment - includeRuntime = true - // the configuration name for including 'love.forte.plugin.suspend-transform:suspend-transform-runtime' - runtimeConfigurationName = "implementation" - - val customJvmTransformer = Transformer( - // mark annotation info, e.g. `@JvmBlocking` - markAnnotation = MarkAnnotation( - classInfo = ClassInfo("love.forte.plugin.suspendtrans.annotation", "JvmBlocking"), // class info for this annotation - baseNameProperty = "baseName", // The property used to represent the 'base name' in the annotation, e.g. `@JvmBlocking(baseName = ...)` - suffixProperty = "suffix", // The property used to represent the 'suffix' in the annotation, e.g. `@JvmBlocking(suffix = ...)` - asPropertyProperty = "asProperty", // The property used to represent the 'asProperty' in the annotation, e.g. `@JvmBlocking(asProperty = true|false)` - defaultSuffix = "Blocking", // Default value used when property 'suffix' (the value of suffixProperty) does not exist (when not specified by the user) (the compiler plugin cannot detect property defaults directly, so the default value must be specified from here) - // e.g. @JvmBlocking(suffix = "Abc"), the suffix is 'Abc', but `@JvmBlocking()`, the suffix is null in compiler plugin, so use the default suffix value. - defaultAsProperty = false, // Default value used when property 'suffix' (the value of suffixProperty) does not exist (Similar to defaultSuffix) - ), - // the transform function, e.g. - // 👇 `love.forte.plugin.suspendtrans.runtime.$runInBlocking$` - // it will be like - // ``` - // @JvmBlocking suspend fun runXxx() { ... } - // fun runXxxBlocking() = `$runInBlocking$` { runXxx() /* suspend */ } // generated function - // ``` - transformFunctionInfo = FunctionInfo( - packageName = "love.forte.plugin.suspendtrans.runtime", - className = null, // null if top-level function - functionName = "\$runInBlocking\$" - ), - transformReturnType = null, // return type, or null if return the return type of origin function, e.g. `ClassInfo("java.util.concurrent", "CompletableFuture")` - transformReturnTypeGeneric = false, // if you return like `CompletableFuture`, make it `true` - originFunctionIncludeAnnotations = listOf(IncludeAnnotation(ClassInfo("kotlin.jvm", "JvmSynthetic"))), // include into origin function - copyAnnotationsToSyntheticFunction = true, - copyAnnotationExcludes = listOf(ClassInfo("kotlin.jvm", "JvmSynthetic")), // do not copy from origin function - syntheticFunctionIncludeAnnotations = listOf(IncludeAnnotation(jvmApi4JAnnotationClassInfo)) // include into synthetic function - ) - - addJvmTransformers( - customJvmTransformer, ... - ) - - // or addJsTransformers(...) - -} -``` - -For example, you want to use a single annotation to do the work of `@JvmAsync`, `@JvmBlocking`, and `@JsPromise`: - -```kotlin -// Your JVM transform functions -// e.g. com.example.Transforms.jvm.kt - -@Deprecated("Just used by compiler", level = DeprecationLevel.HIDDEN) -fun runInBlocking(block: suspend () -> T): T { - // run the `block` in blocking - runBlocking { block() } -} - -@Deprecated("Just used by compiler", level = DeprecationLevel.HIDDEN) -public fun runInAsync(block: suspend () -> T, scope: CoroutineScope? = null): CompletableFuture { - // run the `block` in async - val scope0 = scope ?: GlobalScope - return scope0.future { block() } - - /* - * the `scope` is the `block`'s container: - * ``` - * interface Container { - * @JvmAsync - * suspend fun run() - * 👇 compiled - * - * fun runAsync() = runInAsync(block = { run() }, scope = this as? CoroutineScope) - * } - * ``` - */ -} - -// Your JS transform function -// e.g. com.example.Transforms.js.kt -@Deprecated("Just used by compiler", level = DeprecationLevel.HIDDEN) -fun runInPromise(block: suspend () -> T, scope: CoroutineScope? = null): T { - val scope0 = scope ?: GlobalScope - return scope0.promise { block() } -} -``` - -Create your annotation: - -```kotlin -// Your single annotation -@Target(AnnotationTarget.FUNCTION, AnnotationTarget.CLASS) -@Retention(AnnotationRetention.BINARY) -public annotation class SuspendTrans( - val blockingBaseName: String = "", - val blockingSuffix: String = "Blocking", - val blockingAsProperty: Boolean = false, - - val asyncBaseName: String = "", - val asyncSuffix: String = "Async", - val asyncAsProperty: Boolean = false, - - val jsPromiseBaseName: String = "", - val jsPromiseSuffix: String = "Async", - val jsPromiseAsProperty: Boolean = false, -) -``` - -Then, config your build script: - -```kotlin -// The annotation type -val suspendTransMarkAnnotationClassInfo = ClassInfo("love.forte.simbot.suspendrunner", "SuspendTrans") - -// The mark annotations -val jvmSuspendTransMarkAnnotationForBlocking = MarkAnnotation( - suspendTransMarkAnnotationClassInfo, - baseNameProperty = "blockingBaseName", - suffixProperty = "blockingSuffix", - asPropertyProperty = "blockingAsProperty", - defaultSuffix = "Blocking", -) -val jvmSuspendTransMarkAnnotationForAsync = MarkAnnotation( - suspendTransMarkAnnotationClassInfo, - baseNameProperty = "asyncBaseName", - suffixProperty = "asyncSuffix", - asPropertyProperty = "asyncAsProperty", - defaultSuffix = "Async", -) -val jsSuspendTransMarkAnnotationForPromise = MarkAnnotation( - suspendTransMarkAnnotationClassInfo, - baseNameProperty = "jsPromiseBaseName", - suffixProperty = "jsPromiseSuffix", - asPropertyProperty = "jsPromiseAsProperty", - defaultSuffix = "Async", -) - -// The transform functions -val jvmBlockingFunction = FunctionInfo("com.example", null, "runInBlocking") -val jvmAsyncFunction = FunctionInfo("com.example", null, "runInAsync") -val jsPromiseFunction = FunctionInfo("com.example", null, "runInPromise") - -// The transformers -val suspendTransTransformerForJvmBlocking: Transformer = Transformer( - markAnnotation = jvmSuspendTransMarkAnnotationForBlocking, - transformFunctionInfo = jvmBlockingFunction, - transformReturnType = null, // same as origin function - transformReturnTypeGeneric = false, - // include @JvmSynthetic into origin function - originFunctionIncludeAnnotations = listOf( - SuspendTransformConfiguration.jvmSyntheticClassInfo, - ), - copyAnnotationsToSyntheticFunction = true, - // excludes: @JvmSynthetic, @OptIn, @SuspendTrans - copyAnnotationExcludes = listOf( - SuspendTransformConfiguration.jvmSyntheticClassInfo, - SuspendTransformConfiguration.kotlinOptInClassInfo, - suspendTransMarkAnnotationClassInfo, - ), - // Include into synthetic function's annotations - syntheticFunctionIncludeAnnotations = listOf() -) - -val suspendTransTransformerForJvmAsync: Transformer = Transformer( - markAnnotation = jvmSuspendTransMarkAnnotationForAsync, - transformFunctionInfo = jvmAsyncFunction, - transformReturnType = ClassInfo("java.util.concurrent", "CompletableFuture"), - transformReturnTypeGeneric = true, // Future's generic type is origin function's return type. - // include @JvmSynthetic into origin function - originFunctionIncludeAnnotations = listOf( - SuspendTransformConfiguration.jvmSyntheticClassInfo, - ), - copyAnnotationsToSyntheticFunction = true, - // excludes: @JvmSynthetic, @OptIn, @SuspendTrans - copyAnnotationExcludes = listOf( - SuspendTransformConfiguration.jvmSyntheticClassInfo, - suspendTransMarkAnnotationClassInfo, - SuspendTransformConfiguration.kotlinOptInClassInfo, - ), - // Include into synthetic function's annotations - syntheticFunctionIncludeAnnotations = listOf() -) - -val suspendTransTransformerForJsPromise: Transformer = Transformer( - markAnnotation = jsSuspendTransMarkAnnotationForPromise, - transformFunctionInfo = jsPromiseFunction, - transformReturnType = ClassInfo("kotlin.js", "Promise"), - transformReturnTypeGeneric = true, // Promise's generic type is origin function's return type. - originFunctionIncludeAnnotations = listOf(), - copyAnnotationsToSyntheticFunction = true, - // excludes: @OptIn, @SuspendTrans - copyAnnotationExcludes = listOf( - SuspendTransformConfiguration.kotlinOptInClassInfo, - suspendTransMarkAnnotationClassInfo, - ), - syntheticFunctionIncludeAnnotations = listOf() -) - -// The above section can also be considered to be defined in `buildSrc`. - -suspendTransform { - // disable, use the runtime and the annotation by yourself - includeRuntime = false - includeAnnotation = false - // Note: If you disable includeAnnotation, you need to customise the `targetMarker` or set it to `null`. - // see also: https://github.com/ForteScarlet/kotlin-suspend-transform-compiler-plugin/pull/73 - targetMarker = null // or customise - - addJvmTransformers( - suspendTransTransformerForJvmBlocking, - suspendTransTransformerForJvmAsync - ) - addJsTransformers( - suspendTransTransformerForJsPromise - ) -} -``` - - ## Use Cases - [Simple Robot Frameworks](https://github.com/simple-robot/simpler-robot) (Fully customized) diff --git a/README_CN.md b/README_CN.md index 0cff1cf..8e65f1b 100644 --- a/README_CN.md +++ b/README_CN.md @@ -1,16 +1,16 @@ -# Kotlin suspend transform compiler plugin -[![Maven Central](https://img.shields.io/maven-central/v/love.forte.plugin.suspend-transform/suspend-transform-plugin)](https://repo1.maven.org/maven2/love/forte/plugin/suspend-transform/suspend-transform-plugin/) +# Kotlin suspend transform 编译器插件 +[![Maven Central](https://img.shields.io/maven-central/v/love.forte.plugin.suspend-transform/suspend-transform-plugin)](https://repo1.maven.org/maven2/love/forte/plugin/suspend-transform/suspend-transform-plugin/) [![Gradle Plugin Portal](https://img.shields.io/gradle-plugin-portal/v/love.forte.plugin.suspend-transform)](https://plugins.gradle.org/plugin/love.forte.plugin.suspend-transform) -封面 +封面图 [GitHub](https://github.com/ForteScarlet/kotlin-suspend-transform-compiler-plugin) | [Gitee](https://gitee.com/ForteScarlet/kotlin-suspend-transform-compiler-plugin) -[English](README.md) | **简体中文** +**English** | [简体中文](README_CN.md) -## 简介 +## 概述 -用于为Kotlin挂起函数自动生成平台兼容函数的Kotlin编译器插件。 +用于为挂起函数生成平台兼容函数的 Kotlin 编译器插件。 ### JVM @@ -29,21 +29,22 @@ class Foo { ```kotlin class Foo { - // 对Java隐藏 + // 对 Java 隐藏 @JvmSynthetic suspend fun waitAndGet(): String { delay(5) return "Hello" } - @Api4J // RequiresOptIn 注解, 向Kotlin开发者提供警告 - fun waitAndGetBlocking(): String = runInBlocking { waitAndGet() } // 'runInBlocking' 来自于插件提供的运行时依赖 + @Api4J // 需要显式启用的注解,向 Kotlin 提供警告 + fun waitAndGetBlocking(): String = runInBlocking { waitAndGet() } // 'runInBlocking' 来自插件提供的运行时 - @Api4J // RequiresOptIn 注解, 向Kotlin开发者提供警告 - fun waitAndGetAsync(): CompletableFuture = runInAsync { waitAndGet() } // 'runInAsync' 来自于插件提供的运行时依赖 + @Api4J // 需要显式启用的注解,向 Kotlin 提供警告 + fun waitAndGetAsync(): CompletableFuture = runInAsync { waitAndGet() } // 'runInAsync' 来自插件提供的运行时 } ``` ### JS + ```kotlin class Foo { @JsPromise @@ -62,19 +63,19 @@ class Foo { delay(5) return "Hello" } - @Api4Js // RequiresOptIn 注解, 向Kotlin开发者提供警告 - fun waitAndGetAsync(): Promise = runInAsync { waitAndGet() } // 'runInAsync' 来自于插件提供的运行时依赖 + @Api4Js // 需要显式启用的注解,向 Kotlin 提供警告 + fun waitAndGetAsync(): Promise = runInAsync { waitAndGet() } // 'runInAsync' 来自插件提供的运行时 } ``` -> ~~JS 目标平台暂不支持。原因参考: [KT-53993](https://youtrack.jetbrains.com/issue/KT-53993)~~ -> -> JS 平台从 `v0.6.0` 版本开始得到支持。 参考 [KT-53993](https://youtrack.jetbrains.com/issue/KT-53993) 了解过程, 以及从 [#39](https://github.com/ForteScarlet/kotlin-suspend-transform-compiler-plugin/pull/39) 查阅制胜一击! +> ~~JS 平台目标暂未支持。参见:[KT-53993](https://youtrack.jetbrains.com/issue/KT-53993)~~ +> +> 自 0.6.0 版本起已支持 JS!进展见 [KT-53993](https://youtrack.jetbrains.com/issue/KT-53993),最终实现见 [#39](https://github.com/ForteScarlet/kotlin-suspend-transform-compiler-plugin/pull/39)! ### WasmJS > [!warning] -> 从 `v0.6.0` 开始支持,实验中,不成熟、不稳定。 +> 自 `v0.6.0` 起处于实验阶段,不成熟且不稳定 ```kotlin class Foo { @@ -85,11 +86,12 @@ class Foo { } } -// 一些由**你**自定义的函数或类型... -// 它们不包含在 runtime 中。由于在 WasmJS 中,对于各种类型的使用会有很多限制, -// 因此我还不清楚如何完美地处理它们。 -// 在那之前,你可以自定义函数和类型来自行控制编译器插件的行为, -// 就像自定义其他平台那样。 +// 由**你**自定义的部分函数或类型... +// 这些不包含在运行时中。 +// 由于 WasmJS 对各类使用存在诸多限制... +// 目前尚未找到完美处理方式。 +// 在此之前,你可以自定义函数和类型来控制编译器插件的行为, +// 就像对其他平台所做的那样。 fun runInAsync(block: suspend () -> T): AsyncResult = AsyncResult(block) @@ -101,7 +103,7 @@ class AsyncResult(val block: suspend () -> T) { } ``` -compiled 👇 +编译后 👇 ```kotlin class Foo { @@ -109,117 +111,64 @@ class Foo { delay(5) return "Hello" } - @Api4Js // RequiresOptIn annotation, provide warnings to Kotlin - fun waitAndGetAsync(): AsyncResult = runInAsync { waitAndGet() } // 'runInAsync' from the runtime provided by the plugin - // AsyncResult is a custom type + @Api4Js // 需要显式启用的注解,向 Kotlin 提供警告 + fun waitAndGetAsync(): AsyncResult = runInAsync { waitAndGet() } // 'runInAsync' 来自插件提供的运行时 + // AsyncResult 是**你**自定义的类型 } ``` - -## 使用 +## 使用方式 ### 版本说明 -在 `0.9.0` (包括) 以前,版本的命名方式是 `x.y.z` 的形式。 -但是Kotlin编译器的内容集合每个Kotlin版本都有可能发生改变, -而这似乎无法体现出其构建于的Kotlin版本信息,进而导致产生一些混乱。 +`0.9.0` 及之前版本使用 `x.y.z` 的命名规则。但由于 Kotlin 编译器可能随版本变化, +这种命名方式无法反映对应的 Kotlin 版本,可能导致混淆。 -因此,从 `0.9.0` 之后的版本开始,版本的命名方式会改为 `$Kotlin-$plugin` 的形式, -例如 `2.0.20-0.9.1`。 -前半部分代表用于构建的Kotlin版本,而后半部分则为插件的版本。 +因此,`0.9.0` 之后的版本将采用 `$Kotlin-$plugin` 的命名形式, +例如 `2.0.20-0.9.1`。前半部分为构建所用的 Kotlin 版本,后半部分为插件版本。 -如果版本小于等于 `0.9.0`,你可以参考下面这个对照表: +若版本小于等于 `0.9.0`,可参考以下对照表: -| Kotlin版本 | 插件版本 | -|----------|-------------------------| -| `2.0.0` | `0.8.0-beta1` ~ `0.9.0` | -| `1.9.22` | `0.7.0-beta1` | -| `1.9.21` | `0.6.0` | -| `1.9.10` | `0.5.1` | -| `1.9.0` | `0.5.0` | -| `1.8.21` | `0.3.1` ~ `0.4.0` | +| Kotlin 版本 | 插件版本 | +|-----------|-------------------------| +| `2.0.0` | `0.8.0-beta1` ~ `0.9.0` | +| `1.9.22` | `0.7.0-beta1` | +| `1.9.21` | `0.6.0` | +| `1.9.10` | `0.5.1` | +| `1.9.0` | `0.5.0` | +| `1.8.21` | `0.3.1` ~ `0.4.0` | > [!note] -> 我没有详细记录每一个Kotlin版本之间的编译器的兼容性。 -> 根据我的记忆和猜测,每当 minor 版本号增加时 (例如 `1.8.0` -> `1.9.0`) -> 则不兼容的概率较大,而当 patch 增加时 (例如 `1.9.0` -> `1.9.10`) 不兼容的概率较小。 +> 未详细记录各 Kotlin 版本的编译器插件兼容性。 +> 根据经验,次要版本升级(如 `1.8.0` -> `1.9.0`)更可能不兼容, +> 补丁版本(如 `1.9.21` -> `1.9.22`)不兼容概率较低。 ### Gradle -**通过 [plugins DSL](https://docs.gradle.org/current/userguide/plugins.html#sec:plugins_block) 使用:** +**使用 [plugins DSL](https://docs.gradle.org/current/userguide/plugins.html#sec:plugins_block):** _build.gradle.kts_ -```kotlin +```Kotlin plugins { - id("org.jetbrains.kotlin.jvm") version "$KOTLIN_VERSION" // or js? or multiplatform? - id("love.forte.plugin.suspend-transform") version "$PLUGIN_VERSION" - // other... + kotlin("jvm") version "$KOTLIN_VERSION" // 或 multiplatform + id("love.forte.plugin.suspend-transform") version "$PLUGIN_VERSION" + // 其他... } -// other... +// 其他... -// config it. -suspendTransform { - enabled = true // default: true - includeRuntime = true // default: true - includeAnnotation = true // default: true - // 注意:如果禁用 includeAnnotation, 你需要自定义 targetMarker 或将其设置为 `null` - // 更多参考: https://github.com/ForteScarlet/kotlin-suspend-transform-compiler-plugin/pull/73 - // targetMarker = null // 或自定义 - - /* - * 相当于同时使用 `useJvmDefault` 和 `useJsDefault`. - * 需要包含 runtime 和 annotation - */ - // useDefault() - - /* - * 使用JVM平台的默认配置 - * 相当于: - * addJvmTransformers( - * SuspendTransformConfiguration.jvmBlockingTransformer, - * SuspendTransformConfiguration.jvmAsyncTransformer, - * ) - * - * 需要包含 runtime 和 annotation - */ - useJvmDefault() - - // 或者由你自定义 - jvm { - // ... - } - // 或者由你自定义 - addJvmTransformers(...) - - /* - * 使用JS平台的默认配置 - * 相当于: - * addJvmTransformers( - * SuspendTransformConfiguration.jsPromiseTransformer, - * ) - * - * 需要包含 runtime 和 annotation - */ - useJsDefault() - - // 或者由你自定义 - js { - // ... - } - // 或者由你自定义 - addJsTransformers(...) +// 配置插件 +suspendTransformPlugin { + // 配置 SuspendTransformPluginExtension ... } ``` - - -**通过 [legacy plugin application](https://docs.gradle.org/current/userguide/plugins.html#sec:old_plugin_application) 使用:** +**使用 [传统插件应用方式](https://docs.gradle.org/current/userguide/plugins.html#sec:old_plugin_application):** _build.gradle.kts_ -```kotlin +```Kotlin buildscript { repositories { mavenCentral() @@ -231,504 +180,562 @@ buildscript { } plugins { - id("org.jetbrains.kotlin.jvm") // 或 js? 或 multiplatform? + id("org.jetbrains.kotlin.jvm") // 或 multiplatform? id("love.forte.plugin.suspend-transform") // 其他... } // 其他... -// 配置 -suspendTransform { - enabled = true // default: true - includeRuntime = true // default: true - includeAnnotation = true // default: true - // 注意:如果禁用 includeAnnotation, 你需要自定义 targetMarker 或将其设置为 `null` - // 更多参考: https://github.com/ForteScarlet/kotlin-suspend-transform-compiler-plugin/pull/73 - // targetMarker = null // 或自定义 - - /* - * 相当于同时使用 `useJvmDefault` 和 `useJsDefault`. - * 需要包含 runtime 和 annotation - */ - // useDefault() - - /* - * 使用JVM平台的默认配置 - * 相当于: - * addJvmTransformers( - * SuspendTransformConfiguration.jvmBlockingTransformer, - * SuspendTransformConfiguration.jvmAsyncTransformer, - * ) - * - * 需要包含 runtime 和 annotation - */ - useJvmDefault() - - // 或者由你自定义 - jvm { - // ... - } - // 或者由你自定义 - addJvmTransformers(...) - - /* - * 使用JS平台的默认配置 - * 相当于: - * addJvmTransformers( - * SuspendTransformConfiguration.jsPromiseTransformer, - * ) - * - * 需要包含 runtime 和 annotation - */ - useJsDefault() - - // 或者由你自定义 - js { - // ... - } - // 或者由你自定义 - addJsTransformers(...) +// 配置插件 +suspendTransformPlugin { + // 配置 SuspendTransformPluginExtension ... } ``` -## 注意事项 +## 配置扩展 -### Gradle JVM +### 启用插件 -Gradle JVM 必须满足 JDK11+ +启用 Kotlin 编译器插件。默认值为 `true`。 -### K2 +```Kotlin +suspendTransformPlugin { + enabled = true +} +``` -K2 编译器从 `v0.7.0` 开始支持。 +### 包含默认注解和运行时 -> [!warning] -> 实验中。 +若需使用我们提供的转换器,需添加 `annotation` 和 `runtime` 依赖。 +可通过配置自动添加: -### JsExport +```Kotlin +suspendTransformPlugin { + // 包含注解 + // 默认为 `true` + includeAnnotation = true + // 默认值可留空,使用专属默认值 + annotationDependency { + // 默认为 `compileOnly` + configurationName = "compileOnly" + // 默认与插件版本相同 + version = "" + } + + // 包含运行时 + // 默认为 `true` + includeRuntime = true + // 默认值可留空,使用专属默认值 + runtimeDependency { + // 默认为 `implementation` + configurationName = "implementation" + // 默认与插件版本相同 + version = "" + } +} +``` -如果你打算在默认配置的情况下使用 `@JsExport`, 可以尝试以下代码: +也可手动添加依赖: -_build.gradle.kts_ +```Kotlin +plugin { + kotlin("jvm") version "..." // 以 Kotlin/JVM 为例 + id("love.forte.plugin.suspend-transform") version "2.1.20-0.12.0" +} -```kotlin -plugins { - ... +dependencies { + // 注解 + compileOnly("love.forte.plugin.suspend-transform:suspend-transform-annotation:") + // 运行时 + implementation("love.forte.plugin.suspend-transform:suspend-transform-runtime:") } -suspendTransform { - addJsTransformers( - SuspendTransformConfiguration.jsPromiseTransformer.copy( - copyAnnotationExcludes = listOf( - // 生成的函数将不会包含 `@JsExport.Ignore` - ClassInfo("kotlin.js", "JsExport.Ignore") - ) - ) - ) +suspendTransformPlugin { + // 禁用自动包含 + includeAnnotation = false + includeRuntime = false } ``` +### 添加转换器 + +`Transformer` 用于描述如何转换挂起函数。需添加 `Transformer` 以使插件生效。 + ```Kotlin -@file:OptIn(ExperimentalJsExport::class) +suspendTransformPlugin { + // 配置转换器 + transformers { + add(TargetPlatform.JVM) { // this: TransformerSpec + // 配置 TransformerSpec... + } -@JsExport -class Foo { - @JsPromise - @JsExport.Ignore - suspend fun run(): Int = ... + addJvm { // this: TransformerSpec + // 配置 TransformerSpec... + } + + // 使用预置的默认转换器 + add(TargetPlatform.JVM, SuspendTransformConfigurations.jvmBlockingTransformer) + + addJvm { // this: TransformerSpec + // 基于现有转换器调整 + from(SuspendTransformConfigurations.jvmBlockingTransformer) + // 进一步配置... + } + } } ``` -## 效果 +#### 添加默认转换器 -**源代码:** +我们提供了一些常用实现,可通过配置快速使用。 -```kotlin -import love.forte.plugin.suspendtrans.annotation.JvmAsync -import love.forte.plugin.suspendtrans.annotation.JvmBlocking +> [!note] +> 默认 `Transformer` 依赖我们提供的 `annotation` 和 `runtime`,请确保已包含。 -@JvmBlocking -@JvmAsync -interface Foo { +**JVM 阻塞式** - suspend fun name(): String +```Kotlin +suspendTransformPlugin { + transformers { + // 方式一: + addJvmBlocking() - suspend fun age(def: Int = 5): Int + // 方式二: + addJvm(SuspendTransformConfigurations.jvmBlockingTransformer) + } +} +``` - @JvmBlocking(asProperty = true) - suspend fun self(): Foo +`JvmBlocking` 允许在挂起函数上标记 `@JvmBlocking`,生成 `xxxBlocking` 函数。 + +```Kotlin +class Cat { + @JvmBlocking + suspend fun meow() { + // ... + } + + // 生成: + fun meowBlocking() { + `$runInBlocking$` { meow() } + } } +``` -@JvmBlocking -@JvmAsync -class FooImpl : Foo { - suspend fun size(): Long = 666 - override suspend fun name(): String = "forte" - override suspend fun age(def: Int): Int = def - @JvmBlocking(asProperty = true) // asProperty 必须为 true - override suspend fun self(): FooImpl = this +`$runInBlocking$` 基于 `kotlinx.coroutines.runBlocking`。 + +**JVM 异步式** + +```Kotlin +suspendTransformPlugin { + transformers { + // 方式一: + addJvmAsync() + + // 方式二: + addJvm(SuspendTransformConfigurations.jvmAsyncTransformer) + } } +``` -class Bar { - @JvmBlocking - @JvmAsync - suspend fun bar(): String = "" +`JvmAsync` 允许在挂起函数上标记 `@JvmAsync`,生成 `xxxAsync` 函数。 - suspend fun noTrans(): Int = 1 +```Kotlin +class Cat { + @JvmBlocking + suspend fun meow(): String = "Meow!" + + // 生成: + fun meowAsync(): CompletableFuture { + `$runInAsync$`(block = { meow() }, scope = this as? CoroutineScope) + } } ``` -**编译结果:** +`block` 是需要执行的原始挂起函数,`scope` 是使用的协程作用域。 -> _简化自反编译结果_ +若当前作用域是 `CoroutineScope`,则优先使用自身。否则内部使用 `GlobalScope`。 -```kotlin -import love.forte.plugin.suspendtrans.annotation.JvmAsync -import love.forte.plugin.suspendtrans.annotation.JvmBlocking -import love.forte.plugin.suspendtrans.annotation.Generated -import love.forte.plugin.suspendtrans.annotation.Api4J -import kotlin.jvm.JvmSynthetic +使用 `GlobalScope` 的原因: +1. 全局性。 +2. 不可见,不会被手动关闭。 +3. 不涉及 IO,无需自定义调度器。 -@JvmBlocking -@JvmAsync -interface Foo { - @Generated - @Api4J - val selfBlocking: Foo /* compiled code */ +若有异议,欢迎提交 issue! - suspend fun age(def: Int /* = compiled code */): Int +**JS Promise** - @Generated - @Api4J - fun ageAsync(def: Int /* = compiled code */): java.util.concurrent.CompletableFuture { /* compiled code */ } +```Kotlin +suspendTransformPlugin { + transformers { + // 方式一: + addJsPromise() - @Generated - @Api4J - fun ageBlocking(def: Int /* = compiled code */): Int { /* compiled code */ } + // 方式二: + addJs(SuspendTransformConfigurations.jsPromiseTransformer) + } +} +``` - suspend fun name(): String +```Kotlin +class Cat { + @JsPromise + suspend fun meow(): String = "Meow!" + + // 生成: + fun meowAsync(): Promise { + `$runInAsync$`(block = { meow() }, scope = this as? CoroutineScope) + } +} +``` - @Generated - @Api4J - fun nameAsync(): java.util.concurrent.CompletableFuture { /* compiled code */ } +#### 使用默认转换器 - @Generated - @Api4J - fun nameBlocking(): String { /* compiled code */ } +`addJvmBlocking()` 和 `addJvmAsync()` 可以被合并为 `useJvmDefault()`。 - @JvmBlocking - suspend fun self(): Foo +```Kotlin +suspendTransformPlugin { + transformers { + // 包括 addJvmBlocking() 和 addJvmAsync() + useJvmDefault() + } +} +``` + +`addJsPromise()` 可以被合并为 `useJsDefault()` 。 - @Generated - @Api4J - fun selfAsync(): java.util.concurrent.CompletableFuture { /* compiled code */ } +```Kotlin +suspendTransformPlugin { + transformers { + // 包括 addJsPromise() + useJsDefault() + } } +``` -@JvmBlocking -@JvmAsync -class FooImpl : Foo { - @Generated - @Api4J - open val selfBlocking: FooImpl /* compiled code */ +`useJvmDefault()` 和 `useJsDefault` 可以被合并为 `useDefault()` 。 - @JvmSynthetic - open suspend fun age(def: Int): Int { /* compiled code */ } +```Kotlin +suspendTransformPlugin { + transformers { + // 包括 addJvmDefault() 和 addJsPromise() + useDefault() + } +} +``` - @Generated - @Api4J - open fun ageAsync(def: Int): java.util.concurrent.CompletableFuture { /* compiled code */ } +#### 自定义转换器 - @Generated - @Api4J - open fun ageBlocking(def: Int): Int { /* compiled code */ } +若默认转换器不满足需求,可自定义 `Transformer`,例如完全自定义阻塞逻辑。 - @JvmSynthetic - open suspend fun name(): String { /* compiled code */ } +> 完整自定义实现参考: +> https://github.com/simple-robot/simpler-robot/blob/v4-main/simbot-commons/simbot-common-suspend-runner/src/jvmMain/kotlin/love/forte/simbot/suspendrunner/BlockingRunner.kt + +```Kotlin +suspendTransformPlugin { + // 自定义时可能无需默认注解和运行时 + includeAnnotation = false + includeRuntime = false + + transformer { + // 具体配置见下文 + } +} +``` - @Generated - @Api4J - open fun nameAsync(): java.util.concurrent.CompletableFuture { /* compiled code */ } +示例:自定义注解 `@JBlock`,通过函数 `inBlock` 执行挂起函数。 - @Generated - @Api4J - open fun nameBlocking(): String { /* compiled code */ } +```Kotlin +// 自定义注解 +annotation class JBlock(...) - @JvmSynthetic - @JvmBlocking - suspend fun self(): FooImpl { /* compiled code */ } +// 自定义顶层转换函数 +fun inBlock(block: suspend () -> T): T { + TODO("你的实现") +} +``` - @Generated - @Api4J - fun selfAsync(): java.util.concurrent.CompletableFuture { /* compiled code */ } +假设注解包含以下属性: +- `baseName`: 生成函数的基础名(默认为原函数名) +- `suffix`: 生成函数名的后缀 +- `asProperty`: 将生成函数转为属性(适用于无参数的函数) - @JvmSynthetic - suspend fun size(): Long { /* compiled code */ } +注解定义: + +```Kotlin +annotation class JBlock( + val baseName: String = "", + val suffix: String = "Blocking", + val asProperty: Boolean = false +) +``` - @Generated - @Api4J - fun sizeAsync(): java.util.concurrent.CompletableFuture { /* compiled code */ } +配置示例: - @Generated - @Api4J - fun sizeBlocking(): Long { /* compiled code */ } +```Kotlin +suspendTransformPlugin { + includeAnnotation = false + includeRuntime = false + transformers { + addJvm { + markAnnotation { + // 注解类信息 + classInfo { + packageName = "com.example" + className = "JBlock" + } + + // 属性名映射 + baseNameProperty = "baseName" // 默认为 `baseName` + suffixProperty = "suffix" // 默认为 `suffix` + asPropertyProperty = "asProperty" // 默认为 `asProperty` + + // 默认值需手动配置(编译器无法获取注解默认值) + defaultSuffix = "Blocking" + defaultAsProperty = false + } + } + } } +``` +若属性名不同: -class Bar { - @JvmSynthetic - @JvmBlocking - @JvmAsync - suspend fun bar(): String { /* compiled code */ } +```Kotlin +annotation class JBlock( + val myBaseName: String = "", + val mySuffix: String = "Blocking", + val myAsProperty: Boolean = false +) +``` - @Generated - @Api4J - fun barAsync(): java.util.concurrent.CompletableFuture { /* compiled code */ } +配置调整: + +```Kotlin +baseNameProperty = "myBaseName" +suffixProperty = "mySuffix" +asPropertyProperty = "myAsProperty" +``` - @Generated - @Api4J - fun barBlocking(): String { /* compiled code */ } +转换函数配置: - fun noTrans(): Int { /* compiled code */ } +```Kotlin +transformFunctionInfo { + packageName = "com.example" + functionName = "inBlock" } + +// 返回类型配置 +transformReturnType = null // 与原函数返回类型相同 +transformReturnTypeGeneric = false // 无泛型 ``` -## 自定义配置 +注解复制配置示例: +```Kotlin +addOriginFunctionIncludeAnnotation { + classInfo { + packageName = "kotlin.jvm" + className = "JvmSynthetic" + } + repeatable = false +} -```kotlin -plugin { - id("love.forte.plugin.suspend-transform") version "$VERSION" +addSyntheticFunctionIncludeAnnotation { + classInfo { + packageName = "com.example" + className = "JApi" + } + includeProperty = true } +addCopyAnnotationExclude { + from(SuspendTransformConfigurations.jvmSyntheticClassInfo) +} +``` -suspendTransform { - // enabled suspend transform plugin - enabled = true - // include 'love.forte.plugin.suspend-transform:suspend-transform-runtime' to the runtime environment - includeRuntime = true - // the configuration name for including 'love.forte.plugin.suspend-transform:suspend-transform-runtime' - runtimeConfigurationName = "implementation" - - val customJvmTransformer = Transformer( - // mark annotation info, e.g. `@JvmBlocking` - markAnnotation = MarkAnnotation( - classInfo = ClassInfo("love.forte.plugin.suspendtrans.annotation", "JvmBlocking"), // class info for this annotation - baseNameProperty = "baseName", // The property used to represent the 'base name' in the annotation, e.g. `@JvmBlocking(baseName = ...)` - suffixProperty = "suffix", // The property used to represent the 'suffix' in the annotation, e.g. `@JvmBlocking(suffix = ...)` - asPropertyProperty = "asProperty", // The property used to represent the 'asProperty' in the annotation, e.g. `@JvmBlocking(asProperty = true|false)` - defaultSuffix = "Blocking", // Default value used when property 'suffix' (the value of suffixProperty) does not exist (when not specified by the user) (the compiler plugin cannot detect property defaults directly, so the default value must be specified from here) - // e.g. @JvmBlocking(suffix = "Abc"), the suffix is 'Abc', but `@JvmBlocking()`, the suffix is null in compiler plugin, so use the default suffix value. - defaultAsProperty = false, // Default value used when property 'suffix' (the value of suffixProperty) does not exist (Similar to defaultSuffix) - ), - // the transform function, e.g. - // 👇 `love.forte.plugin.suspendtrans.runtime.$runInBlocking$` - // it will be like - // ``` - // @JvmBlocking suspend fun runXxx() { ... } - // fun runXxxBlocking() = `$runInBlocking$` { runXxx() /* suspend */ } // generated function - // ``` - transformFunctionInfo = FunctionInfo( - packageName = "love.forte.plugin.suspendtrans.runtime", - className = null, // null if top-level function - functionName = "\$runInBlocking\$" - ), - transformReturnType = null, // return type, or null if return the return type of origin function, e.g. `ClassInfo("java.util.concurrent", "CompletableFuture")` - transformReturnTypeGeneric = false, // if you return like `CompletableFuture`, make it `true` - originFunctionIncludeAnnotations = listOf(IncludeAnnotation(ClassInfo("kotlin.jvm", "JvmSynthetic"))), // include into origin function - copyAnnotationsToSyntheticFunction = true, - copyAnnotationExcludes = listOf(ClassInfo("kotlin.jvm", "JvmSynthetic")), // do not copy from origin function - syntheticFunctionIncludeAnnotations = listOf(IncludeAnnotation(jvmApi4JAnnotationClassInfo)) // include into synthetic function - ) - - addJvmTransformers( - customJvmTransformer, ... - ) - - // or addJsTransformers(...) - -} -``` - -举个例子,你想要使用一个单独的注解就完成`@JvmAsync`, `@JvmBlocking`, and `@JsPromise`的工作: +完整示例: +代码: -```kotlin -// 你在JVM平台上的转化函数 -// 比如 com.example.Transforms.jvm.kt +```Kotlin +annotation class JBlock( + val myBaseName: String = "", + val mySuffix: String = "Blocking", + val myAsProperty: Boolean = false +) + +@RequiresOptIn(message = "Java 接口", level = RequiresOptIn.Level.WARNING) +@Retention(AnnotationRetention.BINARY) +annotation class JApi -@Deprecated("Just used by compiler", level = DeprecationLevel.HIDDEN) -fun runInBlocking(block: suspend () -> T): T { - // run the `block` in blocking - runBlocking { block() } +fun inBlock(block: suspend () -> T): T { + TODO("你的实现") } +``` -@Deprecated("Just used by compiler", level = DeprecationLevel.HIDDEN) -public fun runInAsync(block: suspend () -> T, scope: CoroutineScope? = null): CompletableFuture { - // run the `block` in async - val scope0 = scope ?: GlobalScope - return scope0.future { block() } - - /* - `scope` 是 `block`'s 所处的容器: - ``` - interface Container { - @JvmAsync - suspend fun run() - 👇 compiled - - fun runAsync() = runInAsync(block = { run() }, scope = this as? CoroutineScope) +配置: + +```Kotlin +suspendTransformPlugin { + includeAnnotation = false + includeRuntime = false + transformers { + addJvm { + markAnnotation { + classInfo { + packageName = "com.example" + className = "JBlock" + } + + baseNameProperty = "myBaseName" + suffixProperty = "mySuffix" + asPropertyProperty = "myAsProperty" + + defaultSuffix = "Blocking" + defaultAsProperty = false + } + + transformFunctionInfo { + packageName = "com.example" + functionName = "inBlock" + } + + copyAnnotationsToSyntheticFunction = true + copyAnnotationsToSyntheticProperty = true + + addOriginFunctionIncludeAnnotation { + classInfo.from(SuspendTransformConfigurations.jvmSyntheticClassInfo) + repeatable = false + } + + addSyntheticFunctionIncludeAnnotation { + classInfo { + packageName = "com.example" + className = "JApi" + } + includeProperty = true + } + + addCopyAnnotationExclude { + from(SuspendTransformConfigurations.jvmSyntheticClassInfo) + } } - ``` - */ + } +} +``` + +> [!note] +> 同一注解可通过不同属性名复用于多个转换器。例如: +> ```Kotlin +> annotation class JTrans( +> val blockingBaseName: String = "", +> val blockingSuffix: String = "Blocking", +> val blockingAsProperty: Boolean = false, +> +> val asyncBaseName: String = "", +> val asyncSuffix: String = "Async", +> val asyncAsProperty: Boolean = false +> ) +> ``` + +## 注意事项 +### Gradle JVM + +**Gradle JVM** 必须为 JDK11+ + +### K2 + +自 `v0.7.0` 起支持 K2。 + +### JsExport + +若需在 JS 中使用 `@JsExport` 的默认配置: + +_build.gradle.kts_ + +```kotlin +plugins { + // ... } -// 你JS平台上的转化函数 -// 比如 com.example.Transforms.js.kt -@Deprecated("Just used by compiler", level = DeprecationLevel.HIDDEN) -fun runInPromise(block: suspend () -> T, scope: CoroutineScope? = null): T { - val scope0 = scope ?: GlobalScope - return scope0.promise { block() } +suspendTransformPlugin { + transformers { + addJsPromise { + addCopyAnnotationExclude { + // 生成函数不包含 `@JsExport.Ignore` + from(kotlinJsExportIgnoreClassInfo) + } + } + } } ``` -创建你的注解: +```Kotlin +@file:OptIn(ExperimentalJsExport::class) -```kotlin -// Your single annotation -@Target(AnnotationTarget.FUNCTION, AnnotationTarget.CLASS) -@Retention(AnnotationRetention.BINARY) -public annotation class SuspendTrans( - val blockingBaseName: String = "", - val blockingSuffix: String = "Blocking", - val blockingAsProperty: Boolean = false, - - val asyncBaseName: String = "", - val asyncSuffix: String = "Async", - val asyncAsProperty: Boolean = false, - - val jsPromiseBaseName: String = "", - val jsPromiseSuffix: String = "Async", - val jsPromiseAsProperty: Boolean = false, -) +@JsExport +class Foo { + @JsPromise + @JsExport.Ignore + suspend fun run(): Int = ... +} ``` -然后,配置你的构建脚本 +## 效果示例 + +**源码:** ```kotlin -// The annotation type -val suspendTransMarkAnnotationClassInfo = ClassInfo("love.forte.simbot.suspendrunner", "SuspendTrans") - -// The mark annotations -val jvmSuspendTransMarkAnnotationForBlocking = MarkAnnotation( - suspendTransMarkAnnotationClassInfo, - baseNameProperty = "blockingBaseName", - suffixProperty = "blockingSuffix", - asPropertyProperty = "blockingAsProperty", - defaultSuffix = "Blocking", -) -val jvmSuspendTransMarkAnnotationForAsync = MarkAnnotation( - suspendTransMarkAnnotationClassInfo, - baseNameProperty = "asyncBaseName", - suffixProperty = "asyncSuffix", - asPropertyProperty = "asyncAsProperty", - defaultSuffix = "Async", -) -val jsSuspendTransMarkAnnotationForPromise = MarkAnnotation( - suspendTransMarkAnnotationClassInfo, - baseNameProperty = "jsPromiseBaseName", - suffixProperty = "jsPromiseSuffix", - asPropertyProperty = "jsPromiseAsProperty", - defaultSuffix = "Async", -) +import love.forte.plugin.suspendtrans.annotation.JvmAsync +import love.forte.plugin.suspendtrans.annotation.JvmBlocking -// The transform functions -val jvmBlockingFunction = FunctionInfo("com.example", null, "runInBlocking") -val jvmAsyncFunction = FunctionInfo("com.example", null, "runInAsync") -val jsPromiseFunction = FunctionInfo("com.example", null, "runInPromise") - -// The transformers -val suspendTransTransformerForJvmBlocking: Transformer = Transformer( - markAnnotation = jvmSuspendTransMarkAnnotationForBlocking, - transformFunctionInfo = jvmBlockingFunction, - transformReturnType = null, // same as origin function - transformReturnTypeGeneric = false, - // include @JvmSynthetic into origin function - originFunctionIncludeAnnotations = listOf( - SuspendTransformConfiguration.jvmSyntheticClassInfo, - ), - copyAnnotationsToSyntheticFunction = true, - // excludes: @JvmSynthetic, @OptIn, @SuspendTrans - copyAnnotationExcludes = listOf( - SuspendTransformConfiguration.jvmSyntheticClassInfo, - SuspendTransformConfiguration.kotlinOptInClassInfo, - suspendTransMarkAnnotationClassInfo, - ), - // Include into synthetic function's annotations - syntheticFunctionIncludeAnnotations = listOf() -) +@JvmBlocking +@JvmAsync +interface Foo { -val suspendTransTransformerForJvmAsync: Transformer = Transformer( - markAnnotation = jvmSuspendTransMarkAnnotationForAsync, - transformFunctionInfo = jvmAsyncFunction, - transformReturnType = ClassInfo("java.util.concurrent", "CompletableFuture"), - transformReturnTypeGeneric = true, // Future's generic type is origin function's return type. - // include @JvmSynthetic into origin function - originFunctionIncludeAnnotations = listOf( - SuspendTransformConfiguration.jvmSyntheticClassInfo, - ), - copyAnnotationsToSyntheticFunction = true, - // excludes: @JvmSynthetic, @OptIn, @SuspendTrans - copyAnnotationExcludes = listOf( - SuspendTransformConfiguration.jvmSyntheticClassInfo, - suspendTransMarkAnnotationClassInfo, - SuspendTransformConfiguration.kotlinOptInClassInfo, - ), - // Include into synthetic function's annotations - syntheticFunctionIncludeAnnotations = listOf() -) + suspend fun name(): String -val suspendTransTransformerForJsPromise: Transformer = Transformer( - markAnnotation = jsSuspendTransMarkAnnotationForPromise, - transformFunctionInfo = jsPromiseFunction, - transformReturnType = ClassInfo("kotlin.js", "Promise"), - transformReturnTypeGeneric = true, // Promise's generic type is origin function's return type. - originFunctionIncludeAnnotations = listOf(), - copyAnnotationsToSyntheticFunction = true, - // excludes: @OptIn, @SuspendTrans - copyAnnotationExcludes = listOf( - SuspendTransformConfiguration.kotlinOptInClassInfo, - suspendTransMarkAnnotationClassInfo, - ), - syntheticFunctionIncludeAnnotations = listOf() -) + suspend fun age(def: Int = 5): Int -// 上面这些东西也可以考虑在 `buildSrc` 中定义。 + @JvmBlocking(asProperty = true) + suspend fun self(): Foo +} -suspendTransform { - // 关闭它们,并使用你自己自定义的 runtime 和 annotation - includeRuntime = false - includeAnnotation = false - // 注意:如果禁用 includeAnnotation, 你需要自定义 targetMarker 或将其设置为 `null` - // 更多参考: https://github.com/ForteScarlet/kotlin-suspend-transform-compiler-plugin/pull/73 - targetMarker = null // 或自定义 +@JvmBlocking +@JvmAsync +class FooImpl : Foo { + suspend fun size(): Long = 666 + override suspend fun name(): String = "forte" + override suspend fun age(def: Int): Int = def + @JvmBlocking(asProperty = true) // 必须为 'asProperty=true' + override suspend fun self(): FooImpl = this +} - addJvmTransformers( - suspendTransTransformerForJvmBlocking, - suspendTransTransformerForJvmAsync - ) - addJsTransformers( - suspendTransTransformerForJsPromise - ) +class Bar { + @JvmBlocking + @JvmAsync + suspend fun bar(): String = "" + + suspend fun noTrans(): Int = 1 } ``` +**编译结果(简化版):** + +```kotlin +// 生成代码的详细实现略,参见原文 +``` + ## 应用案例 -- [Simple Robot 框架](https://github.com/simple-robot/simpler-robot) (完全定制化) +- [Simple Robot Frameworks](https://github.com/simple-robot/simpler-robot) (完全自定义实现) + -## 开源协议 +## 许可证 -参考 [LICENSE](LICENSE) . +见 [LICENSE](LICENSE) 。 ```text Copyright (c) 2022 ForteScarlet diff --git a/buildSrc/src/main/kotlin/GradleSupportHelper.kt b/buildSrc/src/main/kotlin/GradleSupportHelper.kt new file mode 100644 index 0000000..b7f3f71 --- /dev/null +++ b/buildSrc/src/main/kotlin/GradleSupportHelper.kt @@ -0,0 +1,10 @@ +/** + * 为了让 gradle 插件可以在 buildSrc 之类的地方使用。 + */ +fun org.jetbrains.kotlin.gradle.dsl.KotlinJvmProjectExtension.configGradleBuildSrcFriendly() { + coreLibrariesVersion = "1.9.0" + compilerOptions { + apiVersion.set(org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_1_9) + languageVersion.set(org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_1_9) + } +} diff --git a/buildSrc/src/main/kotlin/IProject.kt b/buildSrc/src/main/kotlin/IProject.kt index d969090..ef6e09a 100644 --- a/buildSrc/src/main/kotlin/IProject.kt +++ b/buildSrc/src/main/kotlin/IProject.kt @@ -11,7 +11,7 @@ object IProject : ProjectDetail() { // Remember the libs.versions.toml! val ktVersion = "2.1.20" - val pluginVersion = "0.11.1" + val pluginVersion = "0.12.0" override val version: String = "$ktVersion-$pluginVersion" diff --git a/compiler/suspend-transform-plugin-cli/README.md b/compiler/suspend-transform-plugin-cli/README.md new file mode 100644 index 0000000..6130688 --- /dev/null +++ b/compiler/suspend-transform-plugin-cli/README.md @@ -0,0 +1,6 @@ +# CliOption Module + +TODO:将 CliOption 相关的内容独立出来, +以避免在 Gradle Plugin 中传递引用 Kotlin compiler。 + +see also: diff --git a/compiler/suspend-transform-plugin-cli/build.gradle.kts b/compiler/suspend-transform-plugin-cli/build.gradle.kts new file mode 100644 index 0000000..1937890 --- /dev/null +++ b/compiler/suspend-transform-plugin-cli/build.gradle.kts @@ -0,0 +1,33 @@ +import org.jetbrains.kotlin.gradle.dsl.JvmTarget + +plugins { + kotlin("jvm") + kotlin("plugin.serialization") + // id("com.github.gmazzo.buildconfig") + id("suspend-transform.jvm-maven-publish") +} + +dependencies { + compileOnly(kotlin("stdlib")) + compileOnly(kotlin("compiler")) + api(project(":compiler:suspend-transform-plugin-configuration")) + api(libs.kotlinx.serialization.core) + api(libs.kotlinx.serialization.protobuf) + + testImplementation(libs.kotlinx.serialization.json) + testImplementation(kotlin("test")) + testImplementation(kotlin("compiler")) + // testImplementation(libs.kotlinx.coroutines.core) +} + +kotlin { + configGradleBuildSrcFriendly() + compilerOptions { + jvmTarget.set(JvmTarget.JVM_1_8) + freeCompilerArgs.addAll("-Xjvm-default=all") + } +} + +tasks.test { + useJUnitPlatform() +} diff --git a/compiler/suspend-transform-plugin-cli/src/main/kotlin/love/forte/plugin/suspendtrans/cli/GradlePluginCliOptions.kt b/compiler/suspend-transform-plugin-cli/src/main/kotlin/love/forte/plugin/suspendtrans/cli/GradlePluginCliOptions.kt new file mode 100644 index 0000000..4e93c2c --- /dev/null +++ b/compiler/suspend-transform-plugin-cli/src/main/kotlin/love/forte/plugin/suspendtrans/cli/GradlePluginCliOptions.kt @@ -0,0 +1,25 @@ +package love.forte.plugin.suspendtrans.cli + +import kotlinx.serialization.ExperimentalSerializationApi +import kotlinx.serialization.decodeFromHexString +import kotlinx.serialization.encodeToHexString +import kotlinx.serialization.protobuf.ProtoBuf +import love.forte.plugin.suspendtrans.configuration.SuspendTransformConfiguration +import love.forte.plugin.suspendtrans.configuration.SuspendTransformConfiguration.Companion.serializer + +// Cli Options for gradle plugin + +@OptIn(ExperimentalSerializationApi::class) +private val SERIALIZER = ProtoBuf { + encodeDefaults = true +} + +@OptIn(ExperimentalSerializationApi::class) +fun SuspendTransformConfiguration.encodeToHex(): String { + return SERIALIZER.encodeToHexString(serializer(), this) +} + +@OptIn(ExperimentalSerializationApi::class) +fun decodeSuspendTransformConfigurationFromHex(hex: String): SuspendTransformConfiguration { + return SERIALIZER.decodeFromHexString(serializer(), hex) +} diff --git a/compiler/suspend-transform-plugin-cli/src/main/kotlin/love/forte/plugin/suspendtrans/cli/KotlinCompilerPluginCliOptions.kt b/compiler/suspend-transform-plugin-cli/src/main/kotlin/love/forte/plugin/suspendtrans/cli/KotlinCompilerPluginCliOptions.kt new file mode 100644 index 0000000..d9e4892 --- /dev/null +++ b/compiler/suspend-transform-plugin-cli/src/main/kotlin/love/forte/plugin/suspendtrans/cli/KotlinCompilerPluginCliOptions.kt @@ -0,0 +1,3 @@ +package love.forte.plugin.suspendtrans.cli + +// Cli Options for Kotlin compiler plugin diff --git a/compiler/suspend-transform-plugin-cli/src/main/kotlin/love/forte/plugin/suspendtrans/cli/SuspendTransformCliOption.kt b/compiler/suspend-transform-plugin-cli/src/main/kotlin/love/forte/plugin/suspendtrans/cli/SuspendTransformCliOption.kt new file mode 100644 index 0000000..2b58567 --- /dev/null +++ b/compiler/suspend-transform-plugin-cli/src/main/kotlin/love/forte/plugin/suspendtrans/cli/SuspendTransformCliOption.kt @@ -0,0 +1,80 @@ +package love.forte.plugin.suspendtrans.cli + +import org.jetbrains.kotlin.compiler.plugin.AbstractCliOption + +/** + * + * + * @author ForteScarlet + */ +interface SuspendTransformCliOption { + val optionName: String + val valueDescription: String + val description: String + val required: Boolean + val allowMultipleOccurrences: Boolean +} + +private data class SimpleSuspendTransformCliOption( + override val allowMultipleOccurrences: Boolean, + override val description: String, + override val optionName: String, + override val required: Boolean, + override val valueDescription: String +) : SuspendTransformCliOption + +private data class AbstractCliOptionImpl( + override val allowMultipleOccurrences: Boolean, + override val description: String, + override val optionName: String, + override val required: Boolean, + override val valueDescription: String +) : AbstractCliOption, SuspendTransformCliOption + +/** + * Creates an instance of [SuspendTransformCliOption] to describe and define a CLI option. + * + * @param optionName The name of the option used to identify it in the CLI. + * @param valueDescription A description of the option's value, defaults to the option name. + * @param description A textual description of the option, defaults to an empty string. + * @param required Whether this option is mandatory, defaults to not required (`false`). + * @param allowMultipleOccurrences Whether this option can appear multiple times in the CLI, + * defaults to not allowed (`false`). + * @return Returns an instance of [SuspendTransformCliOption] implemented by [SimpleSuspendTransformCliOption]. + */ +fun SuspendTransformCliOption( + optionName: String, + valueDescription: String = optionName, + description: String = "", + required: Boolean = false, + allowMultipleOccurrences: Boolean = false +): SuspendTransformCliOption { + // Create and return an instance of the concrete implementation class + return SimpleSuspendTransformCliOption( + allowMultipleOccurrences = allowMultipleOccurrences, + description = description, + optionName = optionName, + required = required, + valueDescription = valueDescription + ) +} + +/** + * Converts the current [SuspendTransformCliOption] instance to an [AbstractCliOption]. + * If the current object is already an [AbstractCliOption], it is returned directly; + * otherwise, a new instance is created and returned. + * + * @return The converted [AbstractCliOption] instance + */ +fun SuspendTransformCliOption.toAbstractCliOption(): AbstractCliOption { + return this as? AbstractCliOption ?: AbstractCliOptionImpl( + allowMultipleOccurrences = allowMultipleOccurrences, + description = description, + optionName = optionName, + required = required, + valueDescription = valueDescription + ) +} + + + diff --git a/compiler/suspend-transform-plugin-cli/src/main/kotlin/love/forte/plugin/suspendtrans/cli/SuspendTransformCliOptions.kt b/compiler/suspend-transform-plugin-cli/src/main/kotlin/love/forte/plugin/suspendtrans/cli/SuspendTransformCliOptions.kt new file mode 100644 index 0000000..a661d31 --- /dev/null +++ b/compiler/suspend-transform-plugin-cli/src/main/kotlin/love/forte/plugin/suspendtrans/cli/SuspendTransformCliOptions.kt @@ -0,0 +1,13 @@ +package love.forte.plugin.suspendtrans.cli + +object SuspendTransformCliOptions { + const val CONFIGURATION = "configuration" + + val CLI_CONFIGURATION = SuspendTransformCliOption( + optionName = "configuration", + valueDescription = "Configuration hex string", + description = "Configuration serialized protobuf hex string value", + required = true, + allowMultipleOccurrences = false, + ) +} diff --git a/compiler/suspend-transform-plugin-cli/src/test/kotlin/love/forte/plugin/suspendtrans/cli/ConfigurationSerializeTests.kt b/compiler/suspend-transform-plugin-cli/src/test/kotlin/love/forte/plugin/suspendtrans/cli/ConfigurationSerializeTests.kt new file mode 100644 index 0000000..4264428 --- /dev/null +++ b/compiler/suspend-transform-plugin-cli/src/test/kotlin/love/forte/plugin/suspendtrans/cli/ConfigurationSerializeTests.kt @@ -0,0 +1,84 @@ +package love.forte.plugin.suspendtrans.cli + +import love.forte.plugin.suspendtrans.configuration.InternalSuspendTransformConfigurationApi +import love.forte.plugin.suspendtrans.configuration.SuspendTransformConfiguration +import love.forte.plugin.suspendtrans.configuration.SuspendTransformConfigurations.jsPromiseTransformer +import love.forte.plugin.suspendtrans.configuration.SuspendTransformConfigurations.jvmAsyncTransformer +import love.forte.plugin.suspendtrans.configuration.SuspendTransformConfigurations.jvmBlockingTransformer +import love.forte.plugin.suspendtrans.configuration.TargetPlatform +import kotlin.test.Test +import kotlin.test.assertEquals + +/** + * + * @author ForteScarlet + */ +class ConfigurationSerializeTests { + @OptIn(InternalSuspendTransformConfigurationApi::class) + @Test + fun testDecode() { + assertEquals( + "", + SuspendTransformConfiguration(emptyMap()).encodeToHex() + ) + + val config = SuspendTransformConfiguration( + transformers = mapOf( + TargetPlatform.JVM to listOf(jvmBlockingTransformer, jvmAsyncTransformer), + TargetPlatform.JS to listOf(jsPromiseTransformer), + ) + ) + + val hex = config.encodeToHex() + + assertEquals( + "0aa807080112bd030a680a3c0a296c6f76652e666f7274652e706c7567696e2e" + + "73757370656e647472616e732e616e6e6f746174696f6e120b4a766d426c6f63" + + "6b696e67180020001208626173654e616d651a06737566666978220a61735072" + + "6f70657274792a08426c6f636b696e67300012390a266c6f76652e666f727465" + + "2e706c7567696e2e73757370656e647472616e732e72756e74696d65120f2472" + + "756e496e426c6f636b696e672420002a240a1e0a0a6b6f746c696e2e6a766d12" + + "0c4a766d53796e7468657469631800200010001800323c0a360a296c6f76652e" + + "666f7274652e706c7567696e2e73757370656e647472616e732e616e6e6f7461" + + "74696f6e1205417069344a18002000100018013801421e0a0a6b6f746c696e2e" + + "6a766d120c4a766d53796e74686574696318002000423c0a296c6f76652e666f" + + "7274652e706c7567696e2e73757370656e647472616e732e616e6e6f74617469" + + "6f6e120b4a766d426c6f636b696e671800200042390a296c6f76652e666f7274" + + "652e706c7567696e2e73757370656e647472616e732e616e6e6f746174696f6e" + + "12084a766d4173796e631800200042130a066b6f746c696e12054f7074496e18" + + "002000480012e3030a620a390a296c6f76652e666f7274652e706c7567696e2e" + + "73757370656e647472616e732e616e6e6f746174696f6e12084a766d4173796e" + + "63180020001208626173654e616d651a06737566666978220a617350726f7065" + + "7274792a054173796e63300012360a266c6f76652e666f7274652e706c756769" + + "6e2e73757370656e647472616e732e72756e74696d65120c2472756e496e4173" + + "796e63241a2d0a146a6176612e7574696c2e636f6e63757272656e741211436f" + + "6d706c657461626c654675747572651800200020012a240a1e0a0a6b6f746c69" + + "6e2e6a766d120c4a766d53796e7468657469631800200010001800323c0a360a" + + "296c6f76652e666f7274652e706c7567696e2e73757370656e647472616e732e" + + "616e6e6f746174696f6e1205417069344a18002000100018013801421e0a0a6b" + + "6f746c696e2e6a766d120c4a766d53796e74686574696318002000423c0a296c" + + "6f76652e666f7274652e706c7567696e2e73757370656e647472616e732e616e" + + "6e6f746174696f6e120b4a766d426c6f636b696e671800200042390a296c6f76" + + "652e666f7274652e706c7567696e2e73757370656e647472616e732e616e6e6f" + + "746174696f6e12084a766d4173796e631800200042130a066b6f746c696e1205" + + "4f7074496e1800200048000ad202080212cd020a630a3a0a296c6f76652e666f" + + "7274652e706c7567696e2e73757370656e647472616e732e616e6e6f74617469" + + "6f6e12094a7350726f6d697365180020001208626173654e616d651a06737566" + + "666978220a617350726f70657274792a054173796e63300012360a266c6f7665" + + "2e666f7274652e706c7567696e2e73757370656e647472616e732e72756e7469" + + "6d65120c2472756e496e4173796e63241a180a096b6f746c696e2e6a73120750" + + "726f6d697365180020002001323d0a370a296c6f76652e666f7274652e706c75" + + "67696e2e73757370656e647472616e732e616e6e6f746174696f6e1206417069" + + "344a7318002000100018013801423a0a296c6f76652e666f7274652e706c7567" + + "696e2e73757370656e647472616e732e616e6e6f746174696f6e12094a735072" + + "6f6d6973651800200042130a066b6f746c696e12054f7074496e180020004800", + hex + ) + + assertEquals( + config, + decodeSuspendTransformConfigurationFromHex(hex) + ) + } + +} diff --git a/compiler/suspend-transform-plugin-configuration/build.gradle.kts b/compiler/suspend-transform-plugin-configuration/build.gradle.kts new file mode 100644 index 0000000..0db94ea --- /dev/null +++ b/compiler/suspend-transform-plugin-configuration/build.gradle.kts @@ -0,0 +1,38 @@ +import org.jetbrains.kotlin.gradle.dsl.JvmTarget + +plugins { + kotlin("jvm") + kotlin("plugin.serialization") + // id("com.github.gmazzo.buildconfig") + id("suspend-transform.jvm-maven-publish") +} + +dependencies { + api(libs.kotlinx.serialization.core) + // api(libs.kotlinx.serialization.protobuf) + + testImplementation(kotlin("test")) +} + +kotlin { + configGradleBuildSrcFriendly() + compilerOptions { + jvmTarget.set(JvmTarget.JVM_1_8) + freeCompilerArgs.addAll("-Xjvm-default=all",) + } + +} + +tasks.test { + useJUnitPlatform() +} + +repositories { + maven { + url = uri("https://oss.sonatype.org/content/repositories/snapshots/") + mavenContent { + snapshotsOnly() + } + } +} + diff --git a/compiler/suspend-transform-plugin-configuration/src/main/kotlin/love/forte/plugin/suspendtrans/configuration/SuspendTransformConfiguration.kt b/compiler/suspend-transform-plugin-configuration/src/main/kotlin/love/forte/plugin/suspendtrans/configuration/SuspendTransformConfiguration.kt new file mode 100644 index 0000000..c73401c --- /dev/null +++ b/compiler/suspend-transform-plugin-configuration/src/main/kotlin/love/forte/plugin/suspendtrans/configuration/SuspendTransformConfiguration.kt @@ -0,0 +1,498 @@ +package love.forte.plugin.suspendtrans.configuration + +import kotlinx.serialization.Serializable + +// NOTE: +// 可序列号的配置信息均使用 `Protobuf` 进行序列化 +// 虽然序列化行为是内部的,但是还是应该尽可能避免出现字段的顺序错乱或删改。 + +@RequiresOptIn( + "This is an internal suspend transform configuration's api. " + + "It may be changed in the future without notice.", RequiresOptIn.Level.ERROR +) +@Target(AnnotationTarget.FUNCTION, AnnotationTarget.CONSTRUCTOR) +annotation class InternalSuspendTransformConfigurationApi + +@Serializable +class FunctionInfo @InternalSuspendTransformConfigurationApi constructor( + val packageName: String, + val functionName: String +) { + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other !is FunctionInfo) return false + + if (packageName != other.packageName) return false + if (functionName != other.functionName) return false + + return true + } + + override fun hashCode(): Int { + var result = packageName.hashCode() + result = 31 * result + functionName.hashCode() + return result + } + + override fun toString(): String { + return "FunctionInfo(functionName='$functionName', packageName='$packageName')" + } +} + +@Serializable +class ClassInfo @InternalSuspendTransformConfigurationApi constructor( + val packageName: String, + val className: String, + val local: Boolean = false, + val nullable: Boolean = false, +) { + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other !is ClassInfo) return false + + if (local != other.local) return false + if (nullable != other.nullable) return false + if (packageName != other.packageName) return false + if (className != other.className) return false + + return true + } + + override fun hashCode(): Int { + var result = local.hashCode() + result = 31 * result + nullable.hashCode() + result = 31 * result + packageName.hashCode() + result = 31 * result + className.hashCode() + return result + } + + override fun toString(): String { + return "ClassInfo(className='$className', packageName='$packageName', local=$local, nullable=$nullable)" + } +} + +@Serializable +enum class TargetPlatform { + COMMON, JVM, JS, WASM, NATIVE +} + +/** + * 用于标记的注解信息. + */ +@Serializable +class MarkAnnotation @InternalSuspendTransformConfigurationApi constructor( + /** + * 注解类信息 + */ + val classInfo: ClassInfo, + /** + * 用于标记生成函数需要使用的基础函数名的注解属性名。 + */ + val baseNameProperty: String = "baseName", + /** + * 用于标记生成函数需要使用的基础函数名之后的后缀的注解属性名。 + */ + val suffixProperty: String = "suffix", + /** + * 用于标记生成函数是否需要转化为 property 类型的注解属性名。 + */ + val asPropertyProperty: String = "asProperty", + /** + * 当 [suffixProperty] 不存在时使用的默认后缀 + */ + val defaultSuffix: String = "", + /** + * 当 [asPropertyProperty] 不存在时使用的默认值 + */ + val defaultAsProperty: Boolean = false, +) { + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other !is MarkAnnotation) return false + + if (defaultAsProperty != other.defaultAsProperty) return false + if (classInfo != other.classInfo) return false + if (baseNameProperty != other.baseNameProperty) return false + if (suffixProperty != other.suffixProperty) return false + if (asPropertyProperty != other.asPropertyProperty) return false + if (defaultSuffix != other.defaultSuffix) return false + + return true + } + + override fun hashCode(): Int { + var result = defaultAsProperty.hashCode() + result = 31 * result + classInfo.hashCode() + result = 31 * result + baseNameProperty.hashCode() + result = 31 * result + suffixProperty.hashCode() + result = 31 * result + asPropertyProperty.hashCode() + result = 31 * result + defaultSuffix.hashCode() + return result + } + + override fun toString(): String { + return "MarkAnnotation(asPropertyProperty='$asPropertyProperty', classInfo=$classInfo, baseNameProperty='$baseNameProperty', suffixProperty='$suffixProperty', defaultSuffix='$defaultSuffix', defaultAsProperty=$defaultAsProperty)" + } +} + +@Serializable +class IncludeAnnotation @InternalSuspendTransformConfigurationApi constructor( + val classInfo: ClassInfo, + val repeatable: Boolean = false, + /** + * 是否追加到property上 + * + * @since 0.9.0 + */ + val includeProperty: Boolean = false +) { + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other !is IncludeAnnotation) return false + + if (repeatable != other.repeatable) return false + if (includeProperty != other.includeProperty) return false + if (classInfo != other.classInfo) return false + + return true + } + + override fun hashCode(): Int { + var result = repeatable.hashCode() + result = 31 * result + includeProperty.hashCode() + result = 31 * result + classInfo.hashCode() + return result + } + + override fun toString(): String { + return "IncludeAnnotation(classInfo=$classInfo, repeatable=$repeatable, includeProperty=$includeProperty)" + } +} + +@Serializable +class Transformer @InternalSuspendTransformConfigurationApi constructor( + /** + * 函数上的某种标记。 + */ + val markAnnotation: MarkAnnotation, + + /** + * 用于转化的函数信息。 + * + * 这个函数的实际格式必须为 + * + * ```kotlin + * fun (block: suspend () -> T[, scope: CoroutineScope = ...]): T { + * // ... + * } + * ``` + * + * 其中,此异步函数可以有第二个参数,此参数格式必须为 [kotlinx.coroutines.CoroutineScope]。 + * 如果存在此参数,当转化函数所处类型自身实现了 [kotlinx.coroutines.CoroutineScope] 时,将会将其自身作为参数填入,类似于: + * + * ```kotlin + * class Bar : CoroutineScope { + * @Xxx + * suspend fun foo(): Foo + * + * @Api4J fun fooXxx(): CompletableFuture = transform(block = { foo() }, scope = this) + * } + */ + val transformFunctionInfo: FunctionInfo, + + /** + * 转化后的返回值类型, 为null时代表与原函数一致。 + */ + val transformReturnType: ClassInfo?, + + // TODO TypeGeneric for suspend function return type and transform function return type? + + /** + * 转化后的返回值类型中,是否存在需要与原本返回值类型一致的泛型。 + */ + val transformReturnTypeGeneric: Boolean, + + /** + * 函数生成后,需要在原函数上追加的注解信息。 + * + * 例如追加个 `@kotlin.jvm.JvmSynthetic` 之类的。 + */ + val originFunctionIncludeAnnotations: List, + + /** + * 需要在生成出来的函数上追加的注解信息。(不需要指定 `@Generated`) + */ + val syntheticFunctionIncludeAnnotations: List, + + /** + * 是否复制源函数上的注解到新的函数上。 + * 如果生成的是属性类型,则表示是否复制到 `getter` 上。 + */ + val copyAnnotationsToSyntheticFunction: Boolean, + + /** + * 复制原函数上注解时需要排除掉的注解。 + */ + val copyAnnotationExcludes: List, + + /** + * 如果是生成属性的话,是否复制源函数上的注解到新的属性上 + * + * @since 0.9.0 + */ + val copyAnnotationsToSyntheticProperty: Boolean = false +) { + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other !is Transformer) return false + + if (transformReturnTypeGeneric != other.transformReturnTypeGeneric) return false + if (copyAnnotationsToSyntheticFunction != other.copyAnnotationsToSyntheticFunction) return false + if (copyAnnotationsToSyntheticProperty != other.copyAnnotationsToSyntheticProperty) return false + if (markAnnotation != other.markAnnotation) return false + if (transformFunctionInfo != other.transformFunctionInfo) return false + if (transformReturnType != other.transformReturnType) return false + if (originFunctionIncludeAnnotations != other.originFunctionIncludeAnnotations) return false + if (syntheticFunctionIncludeAnnotations != other.syntheticFunctionIncludeAnnotations) return false + if (copyAnnotationExcludes != other.copyAnnotationExcludes) return false + + return true + } + + override fun hashCode(): Int { + var result = transformReturnTypeGeneric.hashCode() + result = 31 * result + copyAnnotationsToSyntheticFunction.hashCode() + result = 31 * result + copyAnnotationsToSyntheticProperty.hashCode() + result = 31 * result + markAnnotation.hashCode() + result = 31 * result + transformFunctionInfo.hashCode() + result = 31 * result + (transformReturnType?.hashCode() ?: 0) + result = 31 * result + originFunctionIncludeAnnotations.hashCode() + result = 31 * result + syntheticFunctionIncludeAnnotations.hashCode() + result = 31 * result + copyAnnotationExcludes.hashCode() + return result + } + + override fun toString(): String { + return "Transformer(copyAnnotationExcludes=$copyAnnotationExcludes, markAnnotation=$markAnnotation, transformFunctionInfo=$transformFunctionInfo, transformReturnType=$transformReturnType, transformReturnTypeGeneric=$transformReturnTypeGeneric, originFunctionIncludeAnnotations=$originFunctionIncludeAnnotations, syntheticFunctionIncludeAnnotations=$syntheticFunctionIncludeAnnotations, copyAnnotationsToSyntheticFunction=$copyAnnotationsToSyntheticFunction, copyAnnotationsToSyntheticProperty=$copyAnnotationsToSyntheticProperty)" + } +} + +/** + * 可序列化的配置信息。 + */ +@Serializable +class SuspendTransformConfiguration @InternalSuspendTransformConfigurationApi constructor( + /** + * The transformers. + * + * Note: This `Map` cannot be empty. + * The `List` values cannot be empty. + */ + val transformers: Map> +) { + + override fun toString(): String { + return "SuspendTransformConfiguration(transformers=$transformers)" + } + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other !is SuspendTransformConfiguration) return false + + if (transformers != other.transformers) return false + + return true + } + + override fun hashCode(): Int { + return transformers.hashCode() + } +} + +/** + * Merge both + */ +@InternalSuspendTransformConfigurationApi +operator fun SuspendTransformConfiguration.plus(other: SuspendTransformConfiguration): SuspendTransformConfiguration { + return SuspendTransformConfiguration( + transformers = transformers.toMutableMap().apply { + other.transformers.forEach { (platform, transformers) -> + compute(platform) { _, old -> + if (old == null) transformers.toList() else old + transformers + } + } + } + ) +} + +/** + * Some constants for configuration. + */ +@OptIn(InternalSuspendTransformConfigurationApi::class) +object SuspendTransformConfigurations { + private const val KOTLIN = "kotlin" + private const val KOTLIN_JVM = "kotlin.jvm" + private const val KOTLIN_JS = "kotlin.js" + + private const val SUSPENDTRANS_ANNOTATION_PACKAGE = "love.forte.plugin.suspendtrans.annotation" + private const val SUSPENDTRANS_RUNTIME_PACKAGE = "love.forte.plugin.suspendtrans.runtime" + + private const val JVM_RUN_IN_BLOCKING_FUNCTION_FUNCTION_NAME = "\$runInBlocking\$" + private const val JVM_RUN_IN_ASYNC_FUNCTION_FUNCTION_NAME = "\$runInAsync\$" + + private const val JS_RUN_IN_ASYNC_FUNCTION_FUNCTION_NAME = "\$runInAsync\$" + + //region Commons + @JvmStatic + val kotlinOptInClassInfo = ClassInfo( + packageName = KOTLIN, + className = "OptIn" + ) + //endregion + + //region JVM Defaults + @JvmStatic + val jvmSyntheticClassInfo = ClassInfo( + packageName = KOTLIN_JVM, + className = "JvmSynthetic" + ) + + @JvmStatic + val jvmApi4JAnnotationClassInfo = ClassInfo( + packageName = SUSPENDTRANS_ANNOTATION_PACKAGE, + className = "Api4J" + ) + + @JvmStatic + val jvmBlockingMarkAnnotationClassInfo = ClassInfo( + packageName = SUSPENDTRANS_ANNOTATION_PACKAGE, + className = "JvmBlocking" + ) + + @JvmStatic + val jvmBlockingAnnotationInfo = MarkAnnotation( + classInfo = jvmBlockingMarkAnnotationClassInfo, + defaultSuffix = "Blocking" + ) + + @JvmStatic + val jvmBlockingTransformFunction = FunctionInfo( + packageName = SUSPENDTRANS_RUNTIME_PACKAGE, + functionName = JVM_RUN_IN_BLOCKING_FUNCTION_FUNCTION_NAME, + ) + + @JvmStatic + val jvmAsyncMarkAnnotationClassInfo = ClassInfo( + packageName = SUSPENDTRANS_ANNOTATION_PACKAGE, + className = "JvmAsync" + ) + + @JvmStatic + val jvmAsyncAnnotationInfo = MarkAnnotation( + classInfo = jvmAsyncMarkAnnotationClassInfo, + defaultSuffix = "Async" + ) + + @JvmStatic + val jvmAsyncTransformFunction = FunctionInfo( + packageName = SUSPENDTRANS_RUNTIME_PACKAGE, + functionName = JVM_RUN_IN_ASYNC_FUNCTION_FUNCTION_NAME, + ) + + @JvmStatic + val jvmBlockingTransformer = Transformer( + markAnnotation = jvmBlockingAnnotationInfo, + transformFunctionInfo = jvmBlockingTransformFunction, + transformReturnType = null, + transformReturnTypeGeneric = false, + originFunctionIncludeAnnotations = listOf(IncludeAnnotation(jvmSyntheticClassInfo)), + syntheticFunctionIncludeAnnotations = listOf( + IncludeAnnotation( + classInfo = jvmApi4JAnnotationClassInfo, + includeProperty = true + ) + ), + copyAnnotationsToSyntheticFunction = true, + copyAnnotationExcludes = listOf( + jvmSyntheticClassInfo, + jvmBlockingMarkAnnotationClassInfo, + jvmAsyncMarkAnnotationClassInfo, + kotlinOptInClassInfo, + ), + ) + + @JvmStatic + val jvmAsyncTransformer = Transformer( + markAnnotation = jvmAsyncAnnotationInfo, + transformFunctionInfo = jvmAsyncTransformFunction, + transformReturnType = ClassInfo("java.util.concurrent", "CompletableFuture"), + transformReturnTypeGeneric = true, + originFunctionIncludeAnnotations = listOf(IncludeAnnotation(jvmSyntheticClassInfo)), + syntheticFunctionIncludeAnnotations = listOf( + IncludeAnnotation(jvmApi4JAnnotationClassInfo, includeProperty = true) + ), + copyAnnotationsToSyntheticFunction = true, + copyAnnotationExcludes = listOf( + jvmSyntheticClassInfo, + jvmBlockingMarkAnnotationClassInfo, + jvmAsyncMarkAnnotationClassInfo, + kotlinOptInClassInfo, + ), + ) + //endregion + + //region JS Defaults + @JvmStatic + val kotlinJsExportClassInfo = ClassInfo( + packageName = KOTLIN_JS, + className = "JsExport" + ) + + @JvmStatic + val kotlinJsExportIgnoreClassInfo = ClassInfo( + packageName = KOTLIN_JS, + className = "JsExport.Ignore" + ) + + @JvmStatic + val jsApi4JsAnnotationInfo = ClassInfo( + packageName = SUSPENDTRANS_ANNOTATION_PACKAGE, + className = "Api4Js" + ) + + @JvmStatic + val jsAsyncMarkAnnotationClassInfo = ClassInfo( + packageName = SUSPENDTRANS_ANNOTATION_PACKAGE, + className = "JsPromise" + ) + + @JvmStatic + val jsAsyncAnnotationInfo = MarkAnnotation( + classInfo = jsAsyncMarkAnnotationClassInfo, + defaultSuffix = "Async" + ) + + @JvmStatic + val jsAsyncTransformFunction = FunctionInfo( + SUSPENDTRANS_RUNTIME_PACKAGE, + JS_RUN_IN_ASYNC_FUNCTION_FUNCTION_NAME, + ) + + @JvmStatic + val jsPromiseTransformer = Transformer( + markAnnotation = jsAsyncAnnotationInfo, + transformFunctionInfo = jsAsyncTransformFunction, + transformReturnType = ClassInfo(KOTLIN_JS, "Promise"), + transformReturnTypeGeneric = true, + originFunctionIncludeAnnotations = listOf(), + syntheticFunctionIncludeAnnotations = listOf( + IncludeAnnotation(jsApi4JsAnnotationInfo, includeProperty = true) + ), + copyAnnotationsToSyntheticFunction = true, + copyAnnotationExcludes = listOf( + jsAsyncMarkAnnotationClassInfo, + kotlinOptInClassInfo, + ) + ) + //endregion +} diff --git a/compiler/suspend-transform-plugin-deprecated-configuration/README.md b/compiler/suspend-transform-plugin-deprecated-configuration/README.md new file mode 100644 index 0000000..c6d37a2 --- /dev/null +++ b/compiler/suspend-transform-plugin-deprecated-configuration/README.md @@ -0,0 +1,7 @@ +# Module suspend-transform-plugin-deprecated-configuration + +此模块将原本在 `suspend-transform-plugin` 中的 +`love.forte.plugin.suspendtrans.CliOptions.kt` +和 +`love.forte.plugin.suspendtrans.SuspendTransformConfiguration.kt` +提取出来作为单独的模块,以便兼容和过渡。 diff --git a/compiler/suspend-transform-plugin-deprecated-configuration/build.gradle.kts b/compiler/suspend-transform-plugin-deprecated-configuration/build.gradle.kts new file mode 100644 index 0000000..56b2a51 --- /dev/null +++ b/compiler/suspend-transform-plugin-deprecated-configuration/build.gradle.kts @@ -0,0 +1,28 @@ +import org.jetbrains.kotlin.gradle.dsl.JvmTarget + +plugins { + kotlin("jvm") + kotlin("plugin.serialization") + id("suspend-transform.jvm-maven-publish") +} + +dependencies { + compileOnly(kotlin("compiler")) + api(libs.kotlinx.serialization.core) + api(libs.kotlinx.serialization.json) + testImplementation(kotlin("test")) +} + +kotlin { + configGradleBuildSrcFriendly() + compilerOptions { + jvmTarget.set(JvmTarget.JVM_1_8) + freeCompilerArgs.addAll("-Xjvm-default=all") + } + +} + +tasks.test { + useJUnitPlatform() +} + diff --git a/compiler/suspend-transform-plugin/src/main/kotlin/love/forte/plugin/suspendtrans/CliOptions.kt b/compiler/suspend-transform-plugin-deprecated-configuration/src/main/kotlin/love/forte/plugin/suspendtrans/CliOptions.kt similarity index 96% rename from compiler/suspend-transform-plugin/src/main/kotlin/love/forte/plugin/suspendtrans/CliOptions.kt rename to compiler/suspend-transform-plugin-deprecated-configuration/src/main/kotlin/love/forte/plugin/suspendtrans/CliOptions.kt index 03ab61e..6856426 100644 --- a/compiler/suspend-transform-plugin/src/main/kotlin/love/forte/plugin/suspendtrans/CliOptions.kt +++ b/compiler/suspend-transform-plugin-deprecated-configuration/src/main/kotlin/love/forte/plugin/suspendtrans/CliOptions.kt @@ -1,3 +1,5 @@ +@file:Suppress("DEPRECATION") + package love.forte.plugin.suspendtrans import kotlinx.serialization.builtins.ListSerializer @@ -11,6 +13,7 @@ private val defaultJson = Json { encodeDefaults = true } +@Deprecated("Use the cli module's type") object CliOptions { const val CONFIGURATION = "configuration" @@ -71,6 +74,7 @@ object CliOptions { } +@Deprecated("Use the cli module's type") private class ResolveBuilder { var outc: SuspendTransformConfiguration.() -> String = { error("no outc") } var inc: SuspendTransformConfiguration.(String) -> Unit = { error("no inc") } @@ -132,12 +136,14 @@ private fun String.option( ) } +@Deprecated("Use the cli module's type") interface ICliOption { val oName: String fun resolveToValue(configuration: SuspendTransformConfiguration): String fun resolveFromValue(configuration: SuspendTransformConfiguration, value: String) } +@Deprecated("Use the cli module's type") class SimpleCliOption( override val optionName: String, override val valueDescription: String, diff --git a/compiler/suspend-transform-plugin/src/main/kotlin/love/forte/plugin/suspendtrans/SuspendTransformConfiguration.kt b/compiler/suspend-transform-plugin-deprecated-configuration/src/main/kotlin/love/forte/plugin/suspendtrans/DeprecatedSuspendTransformConfiguration.kt similarity index 78% rename from compiler/suspend-transform-plugin/src/main/kotlin/love/forte/plugin/suspendtrans/SuspendTransformConfiguration.kt rename to compiler/suspend-transform-plugin-deprecated-configuration/src/main/kotlin/love/forte/plugin/suspendtrans/DeprecatedSuspendTransformConfiguration.kt index 9aede47..31905e6 100644 --- a/compiler/suspend-transform-plugin/src/main/kotlin/love/forte/plugin/suspendtrans/SuspendTransformConfiguration.kt +++ b/compiler/suspend-transform-plugin-deprecated-configuration/src/main/kotlin/love/forte/plugin/suspendtrans/DeprecatedSuspendTransformConfiguration.kt @@ -1,11 +1,28 @@ +@file:Suppress("DEPRECATION") + package love.forte.plugin.suspendtrans import kotlinx.serialization.Serializable -// TODO 序列化改成二进制的,比如 protobuf, -// 然后使用base64或hash进行传递,避免谜之转义 + +private const val JVM_RUN_IN_BLOCKING_FUNCTION_PACKAGE_NAME: String = "love.forte.plugin.suspendtrans.runtime" +private val JVM_RUN_IN_BLOCKING_FUNCTION_CLASS_NAME: String? = null +private const val JVM_RUN_IN_BLOCKING_FUNCTION_FUNCTION_NAME: String = "\$runInBlocking\$" + +private const val JVM_RUN_IN_ASYNC_FUNCTION_PACKAGE_NAME: String = "love.forte.plugin.suspendtrans.runtime" +private val JVM_RUN_IN_ASYNC_FUNCTION_CLASS_NAME: String? = null +private const val JVM_RUN_IN_ASYNC_FUNCTION_FUNCTION_NAME: String = "\$runInAsync\$" + +private const val JS_RUN_IN_ASYNC_FUNCTION_PACKAGE_NAME: String = "love.forte.plugin.suspendtrans.runtime" +private val JS_RUN_IN_ASYNC_FUNCTION_CLASS_NAME: String? = null +private const val JS_RUN_IN_ASYNC_FUNCTION_FUNCTION_NAME: String = "\$runInAsync\$" + @Serializable +@Deprecated( + "Use new `love.forte.plugin.suspendtrans.configuration.FunctionInfo` instead.", + ReplaceWith("FunctionInfo", "love.forte.plugin.suspendtrans.configuration.FunctionInfo") +) data class FunctionInfo( var packageName: String, @Deprecated("Top-Level function supported only") @@ -14,6 +31,10 @@ data class FunctionInfo( ) @Serializable +@Deprecated( + "Use new `love.forte.plugin.suspendtrans.configuration.ClassInfo` instead.", + ReplaceWith("ClassInfo", "love.forte.plugin.suspendtrans.configuration.ClassInfo") +) data class ClassInfo @JvmOverloads constructor( var packageName: String, var className: String, @@ -22,6 +43,10 @@ data class ClassInfo @JvmOverloads constructor( ) @Serializable +@Deprecated( + "Use new `love.forte.plugin.suspendtrans.configuration.TargetPlatform` instead.", + ReplaceWith("TargetPlatform", "love.forte.plugin.suspendtrans.configuration.TargetPlatform") +) enum class TargetPlatform { COMMON, JVM, JS, WASM, NATIVE } @@ -32,6 +57,13 @@ enum class TargetPlatform { * */ @Serializable +@Deprecated( + "Use new `love.forte.plugin.suspendtrans.configuration.Transformer` instead.", + replaceWith = ReplaceWith( + "Transformer", + "love.forte.plugin.suspendtrans.configuration.Transformer" + ) +) data class Transformer( /** 函数上的某种标记。 */ val markAnnotation: MarkAnnotation, @@ -108,6 +140,10 @@ data class Transformer( * 用于标记的注解信息. */ @Serializable +@Deprecated( + "Use new `love.forte.plugin.suspendtrans.configuration.MarkAnnotation` instead.", + ReplaceWith("MarkAnnotation", "love.forte.plugin.suspendtrans.configuration.MarkAnnotation") +) data class MarkAnnotation @JvmOverloads constructor( /** * 注解类信息 @@ -141,6 +177,10 @@ data class MarkAnnotation @JvmOverloads constructor( @Serializable +@Deprecated( + "Use new `love.forte.plugin.suspendtrans.configuration.IncludeAnnotation` instead.", + ReplaceWith("IncludeAnnotation", "love.forte.plugin.suspendtrans.configuration.IncludeAnnotation") +) data class IncludeAnnotation( val classInfo: ClassInfo, val repeatable: Boolean = false ) { @@ -152,15 +192,27 @@ data class IncludeAnnotation( var includeProperty: Boolean = false } +const val USE_NEW_EXTENSION = "Please use the `love.forte.plugin.suspendtrans.configuration.SuspendTransformConfiguration`" + + "(`suspendTransformPlugin { ... }`) instead." + /** * * @author ForteScarlet */ @Suppress("unused") @Serializable +@Deprecated( + message = USE_NEW_EXTENSION, + replaceWith = ReplaceWith( + "SuspendTransformConfiguration", + "love.forte.plugin.suspendtrans.configuration.SuspendTransformConfiguration" + ) +) open class SuspendTransformConfiguration { + @Deprecated(USE_NEW_EXTENSION) open var enabled: Boolean = true + @Deprecated(USE_NEW_EXTENSION) open var transformers: MutableMap> = mutableMapOf() /** @@ -173,23 +225,28 @@ open class SuspendTransformConfiguration { @Deprecated("Unused after *-0.11.0") open var targetMarker: ClassInfo? = targetMarkerClassInfo + @Deprecated(USE_NEW_EXTENSION) open fun clear() { transformers.clear() } + @Deprecated(USE_NEW_EXTENSION) open fun useJvmDefault() { transformers[TargetPlatform.JVM] = mutableListOf(jvmBlockingTransformer, jvmAsyncTransformer) } + @Deprecated(USE_NEW_EXTENSION) open fun useJsDefault() { transformers[TargetPlatform.JS] = mutableListOf(jsPromiseTransformer) } + @Deprecated(USE_NEW_EXTENSION) open fun useDefault() { useJvmDefault() useJsDefault() } + @Deprecated(USE_NEW_EXTENSION) open fun addTransformers(target: TargetPlatform, vararg transformers: Transformer) { this.transformers.compute(target) { _, list -> if (list != null) { @@ -200,6 +257,7 @@ open class SuspendTransformConfiguration { } } + @Deprecated(USE_NEW_EXTENSION) open fun addTransformers(target: TargetPlatform, transformers: Collection) { this.transformers.compute(target) { _, list -> if (list != null) { @@ -210,18 +268,22 @@ open class SuspendTransformConfiguration { } } + @Deprecated(USE_NEW_EXTENSION) open fun addJvmTransformers(vararg transformers: Transformer) { addTransformers(target = TargetPlatform.JVM, transformers = transformers) } + @Deprecated(USE_NEW_EXTENSION) open fun addJvmTransformers(transformers: Collection) { addTransformers(target = TargetPlatform.JVM, transformers = transformers) } + @Deprecated(USE_NEW_EXTENSION) open fun addJsTransformers(vararg transformers: Transformer) { addTransformers(target = TargetPlatform.JS, transformers = transformers) } + @Deprecated(USE_NEW_EXTENSION) open fun addJsTransformers(transformers: Collection) { addTransformers(target = TargetPlatform.JS, transformers = transformers) } @@ -230,6 +292,7 @@ open class SuspendTransformConfiguration { return "SuspendTransformConfiguration(enabled=$enabled, transformers=$transformers)" } + @Deprecated(USE_NEW_EXTENSION) companion object { val targetMarkerClassInfo = ClassInfo("love.forte.plugin.suspendtrans.annotation", "TargetMarker") @@ -329,9 +392,9 @@ open class SuspendTransformConfiguration { @JvmStatic val jsAsyncTransformFunction = FunctionInfo( - JS_RUN_IN_ASYNC_FUNCTION_PACKAGE_NAME, - JS_RUN_IN_ASYNC_FUNCTION_CLASS_NAME, - JS_RUN_IN_ASYNC_FUNCTION_FUNCTION_NAME, + love.forte.plugin.suspendtrans.JS_RUN_IN_ASYNC_FUNCTION_PACKAGE_NAME, + love.forte.plugin.suspendtrans.JS_RUN_IN_ASYNC_FUNCTION_CLASS_NAME, + love.forte.plugin.suspendtrans.JS_RUN_IN_ASYNC_FUNCTION_FUNCTION_NAME, ) @JvmStatic diff --git a/compiler/suspend-transform-plugin/build.gradle.kts b/compiler/suspend-transform-plugin/build.gradle.kts index d67ccd3..1cf4824 100644 --- a/compiler/suspend-transform-plugin/build.gradle.kts +++ b/compiler/suspend-transform-plugin/build.gradle.kts @@ -9,15 +9,12 @@ plugins { id("suspend-transform.jvm-maven-publish") } -//testWithEmbedded0() - - dependencies { compileOnly(kotlin("stdlib")) implementation(kotlin("compiler")) compileOnly(libs.kotlinx.coroutines.core) - api(libs.kotlinx.serialization.json) - // TODO 改成二进制的,比如 protobuf + api(project(":compiler:suspend-transform-plugin-deprecated-configuration")) + api(project(":compiler:suspend-transform-plugin-cli")) testImplementation("junit:junit:4.13.2") testImplementation(kotlin("stdlib")) diff --git a/compiler/suspend-transform-plugin/src/main/kotlin/love/forte/plugin/suspendtrans/SuspendTransformCommandLineProcessor.kt b/compiler/suspend-transform-plugin/src/main/kotlin/love/forte/plugin/suspendtrans/SuspendTransformCommandLineProcessor.kt index e002793..a1d9212 100644 --- a/compiler/suspend-transform-plugin/src/main/kotlin/love/forte/plugin/suspendtrans/SuspendTransformCommandLineProcessor.kt +++ b/compiler/suspend-transform-plugin/src/main/kotlin/love/forte/plugin/suspendtrans/SuspendTransformCommandLineProcessor.kt @@ -1,38 +1,46 @@ package love.forte.plugin.suspendtrans import BuildConfig +import love.forte.plugin.suspendtrans.cli.SuspendTransformCliOptions +import love.forte.plugin.suspendtrans.cli.decodeSuspendTransformConfigurationFromHex +import love.forte.plugin.suspendtrans.cli.toAbstractCliOption +import love.forte.plugin.suspendtrans.configuration.InternalSuspendTransformConfigurationApi +import love.forte.plugin.suspendtrans.configuration.SuspendTransformConfiguration +import love.forte.plugin.suspendtrans.configuration.plus import org.jetbrains.kotlin.compiler.plugin.AbstractCliOption import org.jetbrains.kotlin.compiler.plugin.CommandLineProcessor import org.jetbrains.kotlin.compiler.plugin.ExperimentalCompilerApi import org.jetbrains.kotlin.config.CompilerConfiguration import org.jetbrains.kotlin.config.CompilerConfigurationKey - @OptIn(ExperimentalCompilerApi::class) class SuspendTransformCommandLineProcessor : CommandLineProcessor { companion object { - val CONFIGURATION: CompilerConfigurationKey = - CompilerConfigurationKey.create(CliOptions.CONFIGURATION) + val CONFIGURATION_KEY: CompilerConfigurationKey = + CompilerConfigurationKey.create(SuspendTransformCliOptions.CONFIGURATION) } override val pluginId: String = BuildConfig.KOTLIN_PLUGIN_ID - override val pluginOptions: Collection = CliOptions.allOptions.map { it as SimpleCliOption } + override val pluginOptions: Collection = + listOf(SuspendTransformCliOptions.CLI_CONFIGURATION.toAbstractCliOption()) + @OptIn(InternalSuspendTransformConfigurationApi::class) override fun processOption( option: AbstractCliOption, value: String, configuration: CompilerConfiguration ) { - fun getConf(): SuspendTransformConfiguration { - return configuration[CONFIGURATION] ?: SuspendTransformConfiguration().also { - configuration.put( - CONFIGURATION, - it - ) + // The 'configuration' option + if (SuspendTransformCliOptions.CLI_CONFIGURATION.optionName == option.optionName) { + // Decode from protobuf hex value + val decodedConfiguration = decodeSuspendTransformConfigurationFromHex(value) + val currentConfig = configuration[CONFIGURATION_KEY] + if (currentConfig == null) { + configuration.put(CONFIGURATION_KEY, decodedConfiguration) + } else { + configuration.put(CONFIGURATION_KEY, currentConfig + decodedConfiguration) } } - - CliOptions.allOptionsMap[option.optionName]?.resolveFromValue(getConf(), value) } } diff --git a/compiler/suspend-transform-plugin/src/main/kotlin/love/forte/plugin/suspendtrans/SuspendTransformComponentRegistrar.kt b/compiler/suspend-transform-plugin/src/main/kotlin/love/forte/plugin/suspendtrans/SuspendTransformComponentRegistrar.kt index 7a057cd..54c6d57 100644 --- a/compiler/suspend-transform-plugin/src/main/kotlin/love/forte/plugin/suspendtrans/SuspendTransformComponentRegistrar.kt +++ b/compiler/suspend-transform-plugin/src/main/kotlin/love/forte/plugin/suspendtrans/SuspendTransformComponentRegistrar.kt @@ -1,5 +1,7 @@ package love.forte.plugin.suspendtrans +import love.forte.plugin.suspendtrans.configuration.InternalSuspendTransformConfigurationApi +import love.forte.plugin.suspendtrans.configuration.SuspendTransformConfiguration import love.forte.plugin.suspendtrans.fir.SuspendTransformFirExtensionRegistrar import love.forte.plugin.suspendtrans.ir.SuspendTransformIrGenerationExtension import love.forte.plugin.suspendtrans.symbol.SuspendTransformSyntheticResolveExtension @@ -49,10 +51,21 @@ class SuspendTransformComponentRegistrar : CompilerPluginRegistrar() { } } +// @Deprecated("Use Cli module's type") +// private fun CompilerConfiguration.resolveToSuspendTransformConfiguration(): SuspendTransformConfiguration { +// // val compilerConfiguration = this +// return get(SuspendTransformCommandLineProcessor.CONFIGURATION_KEY, SuspendTransformConfiguration()) +// // return SuspendTransformConfiguration().apply { +// // enabled = compilerConfiguration.get(SuspendTransformCommandLineProcessor.ENABLED, true) +// // } +// } +@OptIn(InternalSuspendTransformConfigurationApi::class) private fun CompilerConfiguration.resolveToSuspendTransformConfiguration(): SuspendTransformConfiguration { -// val compilerConfiguration = this - return get(SuspendTransformCommandLineProcessor.CONFIGURATION, SuspendTransformConfiguration()) + return get( + SuspendTransformCommandLineProcessor.CONFIGURATION_KEY, + SuspendTransformConfiguration(mutableMapOf()) + ) // return SuspendTransformConfiguration().apply { // enabled = compilerConfiguration.get(SuspendTransformCommandLineProcessor.ENABLED, true) // } diff --git a/compiler/suspend-transform-plugin/src/main/kotlin/love/forte/plugin/suspendtrans/SuspendTransformUserData.kt b/compiler/suspend-transform-plugin/src/main/kotlin/love/forte/plugin/suspendtrans/SuspendTransformUserData.kt index 9207100..3613442 100644 --- a/compiler/suspend-transform-plugin/src/main/kotlin/love/forte/plugin/suspendtrans/SuspendTransformUserData.kt +++ b/compiler/suspend-transform-plugin/src/main/kotlin/love/forte/plugin/suspendtrans/SuspendTransformUserData.kt @@ -1,5 +1,6 @@ package love.forte.plugin.suspendtrans +import love.forte.plugin.suspendtrans.configuration.Transformer import org.jetbrains.kotlin.descriptors.CallableDescriptor import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor import org.jetbrains.kotlin.fir.FirSession diff --git a/compiler/suspend-transform-plugin/src/main/kotlin/love/forte/plugin/suspendtrans/fir/SuspendTransformFirExtensionRegistrar.kt b/compiler/suspend-transform-plugin/src/main/kotlin/love/forte/plugin/suspendtrans/fir/SuspendTransformFirExtensionRegistrar.kt index 19ef9e1..24c0efd 100644 --- a/compiler/suspend-transform-plugin/src/main/kotlin/love/forte/plugin/suspendtrans/fir/SuspendTransformFirExtensionRegistrar.kt +++ b/compiler/suspend-transform-plugin/src/main/kotlin/love/forte/plugin/suspendtrans/fir/SuspendTransformFirExtensionRegistrar.kt @@ -1,6 +1,6 @@ package love.forte.plugin.suspendtrans.fir -import love.forte.plugin.suspendtrans.SuspendTransformConfiguration +import love.forte.plugin.suspendtrans.configuration.SuspendTransformConfiguration import org.jetbrains.kotlin.fir.extensions.FirDeclarationGenerationExtension import org.jetbrains.kotlin.fir.extensions.FirExtensionRegistrar @@ -8,7 +8,8 @@ import org.jetbrains.kotlin.fir.extensions.FirExtensionRegistrar * * @author ForteScarlet */ -class SuspendTransformFirExtensionRegistrar(private val suspendTransformConfiguration: SuspendTransformConfiguration) : FirExtensionRegistrar() { +class SuspendTransformFirExtensionRegistrar(private val suspendTransformConfiguration: SuspendTransformConfiguration) : + FirExtensionRegistrar() { override fun ExtensionRegistrarContext.configurePlugin() { FirDeclarationGenerationExtension.Factory { session -> SuspendTransformFirTransformer( diff --git a/compiler/suspend-transform-plugin/src/main/kotlin/love/forte/plugin/suspendtrans/fir/SuspendTransformFirTransformer.kt b/compiler/suspend-transform-plugin/src/main/kotlin/love/forte/plugin/suspendtrans/fir/SuspendTransformFirTransformer.kt index b44cbf7..a6b499c 100644 --- a/compiler/suspend-transform-plugin/src/main/kotlin/love/forte/plugin/suspendtrans/fir/SuspendTransformFirTransformer.kt +++ b/compiler/suspend-transform-plugin/src/main/kotlin/love/forte/plugin/suspendtrans/fir/SuspendTransformFirTransformer.kt @@ -1,8 +1,14 @@ package love.forte.plugin.suspendtrans.fir -import love.forte.plugin.suspendtrans.* +import love.forte.plugin.suspendtrans.configuration.MarkAnnotation +import love.forte.plugin.suspendtrans.configuration.SuspendTransformConfiguration +import love.forte.plugin.suspendtrans.configuration.TargetPlatform +import love.forte.plugin.suspendtrans.configuration.Transformer +import love.forte.plugin.suspendtrans.fqn import love.forte.plugin.suspendtrans.utils.* +import org.jetbrains.kotlin.KtFakeSourceElementKind import org.jetbrains.kotlin.descriptors.Modality +import org.jetbrains.kotlin.fakeElement import org.jetbrains.kotlin.fir.* import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext import org.jetbrains.kotlin.fir.analysis.checkers.context.MutableCheckerContext @@ -51,6 +57,7 @@ import org.jetbrains.kotlin.platform.isJs import org.jetbrains.kotlin.platform.isWasm import org.jetbrains.kotlin.platform.jvm.isJvm import org.jetbrains.kotlin.platform.konan.isNative +import org.jetbrains.kotlin.realElement import org.jetbrains.kotlin.utils.keysToMap import java.util.concurrent.ConcurrentHashMap @@ -74,7 +81,8 @@ class SuspendTransformFirTransformer( private val suspendTransformConfiguration: SuspendTransformConfiguration ) : FirDeclarationGenerationExtension(session) { - private val transformerFunctionSymbolMap = ConcurrentHashMap() + private val transformerFunctionSymbolMap = + ConcurrentHashMap() private lateinit var coroutineScopeSymbol: FirClassLikeSymbol<*> @@ -97,16 +105,24 @@ class SuspendTransformFirTransformer( Name.identifier("CoroutineScope") ) - coroutineScopeSymbol = session.symbolProvider.getClassLikeSymbolByClassId(classId) - ?: session.dependenciesSymbolProvider.getClassLikeSymbolByClassId(classId) - ?: error("Cannot resolve `kotlinx.coroutines.CoroutineScope` symbol.") + if (!(::coroutineScopeSymbol.isInitialized)) { + coroutineScopeSymbol = session.symbolProvider.getClassLikeSymbolByClassId(classId) + ?: session.dependenciesSymbolProvider.getClassLikeSymbolByClassId(classId) + ?: error("Cannot resolve `kotlinx.coroutines.CoroutineScope` symbol.") + } + } - private fun initTransformerFunctionSymbolMap() { + private fun initTransformerFunctionSymbolMap( + classSymbol: FirClassSymbol<*>, + memberScope: FirClassDeclaredMemberScope? + ): Map { // 尝试找到所有配置的 bridge function, 例如 `runBlocking` 等 val symbolProvider = session.symbolProvider val dependenciesSymbolProvider = session.dependenciesSymbolProvider + val map = mutableMapOf() + suspendTransformConfiguration.transformers .forEach { (_, transformerList) -> for (transformer in transformerList) { @@ -114,15 +130,6 @@ class SuspendTransformFirTransformer( val packageName = transformFunctionInfo.packageName val functionName = transformFunctionInfo.functionName - @Suppress("DEPRECATION") - val className = transformFunctionInfo.className - if (className != null) { - error( - "Not support `className` (`$className`) in transformer function info: " + - "top level function supported only." - ) - } - // TODO 校验funcs? val functionNameIdentifier = Name.identifier(functionName) @@ -141,6 +148,7 @@ class SuspendTransformFirTransformer( if (transformerFunctionSymbols.isNotEmpty()) { if (transformerFunctionSymbols.size == 1) { transformerFunctionSymbolMap[transformer] = transformerFunctionSymbols.first() + map[transformer] = transformerFunctionSymbols.first() } else { error("Found multiple transformer function symbols for transformer: $transformer") } @@ -150,15 +158,18 @@ class SuspendTransformFirTransformer( } } } + + return map } // private val cache: FirCache, FirClassDeclaredMemberScope?>, Map>?, Nothing?> = private val cache: FirCache>?, Nothing?> = - session.firCachesFactory.createCache { (symbol, scope), c -> + session.firCachesFactory.createCache { cacheKey, c -> + val (symbol, scope) = cacheKey initScopeSymbol() - initTransformerFunctionSymbolMap() + val transformerFunctionMap = initTransformerFunctionSymbolMap(symbol, scope) - createCache(symbol, scope) + createCache(symbol, scope, transformerFunctionMap) } @@ -342,9 +353,12 @@ class SuspendTransformFirTransformer( val lambdaTarget = FirFunctionTarget(null, isLambda = true) val lambda = buildAnonymousFunction { this.resolvePhase = FirResolvePhase.BODY_RESOLVE + // this.resolvePhase = FirResolvePhase.RAW_FIR this.isLambda = true this.moduleData = originFunSymbol.moduleData - this.origin = FirDeclarationOrigin.Synthetic.FakeFunction + // this.origin = FirDeclarationOrigin.Source + // this.origin = FirDeclarationOrigin.Synthetic.FakeFunction + this.origin = FirDeclarationOrigin.Plugin(SuspendTransformK2V3Key) this.returnTypeRef = originFunSymbol.resolvedReturnTypeRef this.hasExplicitParameterList = false this.status = FirResolvedDeclarationStatusImpl.DEFAULT_STATUS_FOR_SUSPEND_FUNCTION_EXPRESSION @@ -390,7 +404,6 @@ class SuspendTransformFirTransformer( source = thisReceiverParameter.source calleeReference = buildImplicitThisReference { boundSymbol = thisReceiverParameter.symbol - println("[${newFunSymbol}] thisReceiverParameter.symbol: ${thisReceiverParameter.symbol}") } } } @@ -509,14 +522,16 @@ class SuspendTransformFirTransformer( } ) operation = FirOperation.SAFE_AS - conversionTypeRef = parameterTypeNotNullable.toFirResolvedTypeRef() + conversionTypeRef = + parameterTypeNotNullable.toFirResolvedTypeRef() }, parameterFir ) } else { // coroutine not nullable // put if this is `CoroutineScope` or it is optional, otherwise throw error - var ownerIsCoroutineScopeOrParameterIsOptional = parameterSymbol.hasDefaultValue + var ownerIsCoroutineScopeOrParameterIsOptional = + parameterSymbol.hasDefaultValue for (superType in owner.getSuperTypes(session, recursive = false)) { if (superType.isCoroutineScope()) { put(thisReceiverExpression(), parameterFir) @@ -594,6 +609,8 @@ class SuspendTransformFirTransformer( val newFunTarget = FirFunctionTarget(null, isLambda = false) val newFun = buildSimpleFunctionCopy(originFunc) { + origin = FirDeclarationOrigin.Plugin(SuspendTransformK2V3Key) + source = originFunc.source?.fakeElement(KtFakeSourceElementKind.PluginGenerated) name = callableId.callableName symbol = newFunSymbol status = originFunc.status.copy( @@ -713,7 +730,7 @@ class SuspendTransformFirTransformer( val p1 = buildProperty { symbol = pSymbol name = callableId.callableName - source = original.source + source = original.source?.fakeElement(KtFakeSourceElementKind.PluginGenerated) resolvePhase = original.resolvePhase moduleData = original.moduleData origin = pKey.origin @@ -875,21 +892,28 @@ class SuspendTransformFirTransformer( } private val annotationPredicates = DeclarationPredicate.create { - var predicate: DeclarationPredicate? = null - for (value in suspendTransformConfiguration.transformers.values) { - for (transformer in value) { - val afq = transformer.markAnnotation.fqName - predicate = if (predicate == null) { - annotated(afq) - } else { - predicate or annotated(afq) - } + val annotationFqNames = suspendTransformConfiguration.transformers.values + .flatMapTo(mutableSetOf()) { transformerList -> + transformerList.map { it.markAnnotation.fqName } } - } - predicate ?: annotated() + hasAnnotated(annotationFqNames) + // var predicate: DeclarationPredicate? = null + // for (value in suspendTransformConfiguration.transformers.values) { + // for (transformer in value) { + // val afq = transformer.markAnnotation.fqName + // predicate = if (predicate == null) { + // annotated(afq) + // } else { + // predicate or annotated(afq) + // } + // } + // } + // + // predicate ?: annotated() } + /** * NB: The predict needs to be *registered* in order to parse the [@XSerializable] type * otherwise, the annotation remains unresolved @@ -900,7 +924,8 @@ class SuspendTransformFirTransformer( private fun createCache( classSymbol: FirClassSymbol<*>, - declaredScope: FirClassDeclaredMemberScope? + declaredScope: FirClassDeclaredMemberScope?, + transformerFunctionSymbolMap: Map ): Map>? { if (declaredScope == null) return null @@ -947,7 +972,6 @@ class SuspendTransformFirTransformer( // 读不到注解的参数? // 必须使用 anno.getXxxArgument(Name(argument name)), // 使用 argumentMapping.mapping 获取不到结果 -// println("RAW AnnoData: ${anno.argumentMapping.mapping}") val annoData = anno.toTransformAnnotationData(markAnnotation, functionName) val syntheticFunNameString = annoData.functionName @@ -1276,11 +1300,9 @@ class SuspendTransformFirTransformer( when (this) { is ConeDynamicType -> { - //println("Dynamic type: $this") } is ConeFlexibleType -> { - //println("Flexible type: $this") } is ConeClassLikeType -> { diff --git a/compiler/suspend-transform-plugin/src/main/kotlin/love/forte/plugin/suspendtrans/ir/SuspendTransformIrGenerationExtension.kt b/compiler/suspend-transform-plugin/src/main/kotlin/love/forte/plugin/suspendtrans/ir/SuspendTransformIrGenerationExtension.kt index afdd84b..7aa4d4e 100644 --- a/compiler/suspend-transform-plugin/src/main/kotlin/love/forte/plugin/suspendtrans/ir/SuspendTransformIrGenerationExtension.kt +++ b/compiler/suspend-transform-plugin/src/main/kotlin/love/forte/plugin/suspendtrans/ir/SuspendTransformIrGenerationExtension.kt @@ -1,7 +1,7 @@ package love.forte.plugin.suspendtrans.ir import love.forte.plugin.suspendtrans.PluginAvailability -import love.forte.plugin.suspendtrans.SuspendTransformConfiguration +import love.forte.plugin.suspendtrans.configuration.SuspendTransformConfiguration import org.jetbrains.kotlin.backend.common.extensions.IrGenerationExtension import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext import org.jetbrains.kotlin.ir.declarations.IrModuleFragment diff --git a/compiler/suspend-transform-plugin/src/main/kotlin/love/forte/plugin/suspendtrans/ir/SuspendTransformTransformer.kt b/compiler/suspend-transform-plugin/src/main/kotlin/love/forte/plugin/suspendtrans/ir/SuspendTransformTransformer.kt index 19f8a18..18dcd4a 100644 --- a/compiler/suspend-transform-plugin/src/main/kotlin/love/forte/plugin/suspendtrans/ir/SuspendTransformTransformer.kt +++ b/compiler/suspend-transform-plugin/src/main/kotlin/love/forte/plugin/suspendtrans/ir/SuspendTransformTransformer.kt @@ -1,10 +1,14 @@ package love.forte.plugin.suspendtrans.ir -import love.forte.plugin.suspendtrans.* +import love.forte.plugin.suspendtrans.SuspendTransformUserDataKey +import love.forte.plugin.suspendtrans.checkSame +import love.forte.plugin.suspendtrans.configuration.IncludeAnnotation +import love.forte.plugin.suspendtrans.configuration.SuspendTransformConfiguration import love.forte.plugin.suspendtrans.fir.SuspendTransformBridgeFunctionKey import love.forte.plugin.suspendtrans.fir.SuspendTransformGeneratedDeclarationKey import love.forte.plugin.suspendtrans.fir.SuspendTransformK2V3Key import love.forte.plugin.suspendtrans.fir.SuspendTransformPluginKey +import love.forte.plugin.suspendtrans.fqn import love.forte.plugin.suspendtrans.utils.* import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext diff --git a/compiler/suspend-transform-plugin/src/main/kotlin/love/forte/plugin/suspendtrans/symbol/AbstractSuspendTransformFunctionDescriptor.kt b/compiler/suspend-transform-plugin/src/main/kotlin/love/forte/plugin/suspendtrans/symbol/AbstractSuspendTransformFunctionDescriptor.kt index 44cff6d..60b1e79 100644 --- a/compiler/suspend-transform-plugin/src/main/kotlin/love/forte/plugin/suspendtrans/symbol/AbstractSuspendTransformFunctionDescriptor.kt +++ b/compiler/suspend-transform-plugin/src/main/kotlin/love/forte/plugin/suspendtrans/symbol/AbstractSuspendTransformFunctionDescriptor.kt @@ -2,7 +2,7 @@ package love.forte.plugin.suspendtrans.symbol import love.forte.plugin.suspendtrans.SuspendTransformUserData import love.forte.plugin.suspendtrans.SuspendTransformUserDataKey -import love.forte.plugin.suspendtrans.Transformer +import love.forte.plugin.suspendtrans.configuration.Transformer import love.forte.plugin.suspendtrans.utils.TransformAnnotationData import love.forte.plugin.suspendtrans.utils.copy import love.forte.plugin.suspendtrans.utils.findClassDescriptor diff --git a/compiler/suspend-transform-plugin/src/main/kotlin/love/forte/plugin/suspendtrans/symbol/SimpleSuspendTransformFunctionDescriptor.kt b/compiler/suspend-transform-plugin/src/main/kotlin/love/forte/plugin/suspendtrans/symbol/SimpleSuspendTransformFunctionDescriptor.kt index d9df2d9..3c6cc13 100644 --- a/compiler/suspend-transform-plugin/src/main/kotlin/love/forte/plugin/suspendtrans/symbol/SimpleSuspendTransformFunctionDescriptor.kt +++ b/compiler/suspend-transform-plugin/src/main/kotlin/love/forte/plugin/suspendtrans/symbol/SimpleSuspendTransformFunctionDescriptor.kt @@ -1,7 +1,7 @@ package love.forte.plugin.suspendtrans.symbol import love.forte.plugin.suspendtrans.SuspendTransformUserData -import love.forte.plugin.suspendtrans.Transformer +import love.forte.plugin.suspendtrans.configuration.Transformer import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor import org.jetbrains.kotlin.descriptors.annotations.Annotations diff --git a/compiler/suspend-transform-plugin/src/main/kotlin/love/forte/plugin/suspendtrans/symbol/SuspendTransformSyntheticResolveExtension.kt b/compiler/suspend-transform-plugin/src/main/kotlin/love/forte/plugin/suspendtrans/symbol/SuspendTransformSyntheticResolveExtension.kt index a08294d..7121a46 100644 --- a/compiler/suspend-transform-plugin/src/main/kotlin/love/forte/plugin/suspendtrans/symbol/SuspendTransformSyntheticResolveExtension.kt +++ b/compiler/suspend-transform-plugin/src/main/kotlin/love/forte/plugin/suspendtrans/symbol/SuspendTransformSyntheticResolveExtension.kt @@ -1,6 +1,11 @@ package love.forte.plugin.suspendtrans.symbol -import love.forte.plugin.suspendtrans.* +import love.forte.plugin.suspendtrans.PluginAvailability +import love.forte.plugin.suspendtrans.SuspendTransformUserData +import love.forte.plugin.suspendtrans.configuration.SuspendTransformConfiguration +import love.forte.plugin.suspendtrans.configuration.TargetPlatform +import love.forte.plugin.suspendtrans.configuration.Transformer +import love.forte.plugin.suspendtrans.generatedAnnotationClassId import love.forte.plugin.suspendtrans.utils.* import org.jetbrains.kotlin.backend.common.descriptors.allParameters import org.jetbrains.kotlin.descriptors.* diff --git a/compiler/suspend-transform-plugin/src/main/kotlin/love/forte/plugin/suspendtrans/utils/AnnotationDescriptorUtils.kt b/compiler/suspend-transform-plugin/src/main/kotlin/love/forte/plugin/suspendtrans/utils/AnnotationDescriptorUtils.kt index 3a1228d..ae95288 100644 --- a/compiler/suspend-transform-plugin/src/main/kotlin/love/forte/plugin/suspendtrans/utils/AnnotationDescriptorUtils.kt +++ b/compiler/suspend-transform-plugin/src/main/kotlin/love/forte/plugin/suspendtrans/utils/AnnotationDescriptorUtils.kt @@ -1,6 +1,6 @@ package love.forte.plugin.suspendtrans.utils -import love.forte.plugin.suspendtrans.Transformer +import love.forte.plugin.suspendtrans.configuration.Transformer import love.forte.plugin.suspendtrans.toJsPromiseAnnotationName import love.forte.plugin.suspendtrans.toJvmAsyncAnnotationName import love.forte.plugin.suspendtrans.toJvmBlockingAnnotationName diff --git a/compiler/suspend-transform-plugin/src/main/kotlin/love/forte/plugin/suspendtrans/utils/CopyAnnotationUtils.kt b/compiler/suspend-transform-plugin/src/main/kotlin/love/forte/plugin/suspendtrans/utils/CopyAnnotationUtils.kt index aef4652..5611cd3 100644 --- a/compiler/suspend-transform-plugin/src/main/kotlin/love/forte/plugin/suspendtrans/utils/CopyAnnotationUtils.kt +++ b/compiler/suspend-transform-plugin/src/main/kotlin/love/forte/plugin/suspendtrans/utils/CopyAnnotationUtils.kt @@ -1,6 +1,6 @@ package love.forte.plugin.suspendtrans.utils -import love.forte.plugin.suspendtrans.IncludeAnnotation +import love.forte.plugin.suspendtrans.configuration.IncludeAnnotation import org.jetbrains.kotlin.name.ClassId data class CopyAnnotationsData( diff --git a/compiler/suspend-transform-plugin/src/main/kotlin/love/forte/plugin/suspendtrans/utils/TransformUtil.kt b/compiler/suspend-transform-plugin/src/main/kotlin/love/forte/plugin/suspendtrans/utils/TransformUtil.kt index 8ee48b4..dd1b3d7 100644 --- a/compiler/suspend-transform-plugin/src/main/kotlin/love/forte/plugin/suspendtrans/utils/TransformUtil.kt +++ b/compiler/suspend-transform-plugin/src/main/kotlin/love/forte/plugin/suspendtrans/utils/TransformUtil.kt @@ -1,7 +1,7 @@ package love.forte.plugin.suspendtrans.utils -import love.forte.plugin.suspendtrans.ClassInfo -import love.forte.plugin.suspendtrans.FunctionInfo +import love.forte.plugin.suspendtrans.configuration.ClassInfo +import love.forte.plugin.suspendtrans.configuration.FunctionInfo import love.forte.plugin.suspendtrans.fqn import org.jetbrains.kotlin.name.CallableId import org.jetbrains.kotlin.name.ClassId @@ -11,6 +11,5 @@ import org.jetbrains.kotlin.name.Name fun ClassInfo.toClassId(): ClassId = ClassId(packageName.fqn, className.fqn, local) -@Suppress("DEPRECATION") fun FunctionInfo.toCallableId(): CallableId = - CallableId(packageName.fqn, className?.fqn, Name.identifier(functionName)) + CallableId(packageName.fqn, null, Name.identifier(functionName)) diff --git a/compiler/suspend-transform-plugin/src/test/love/forte/plugin/suspendtrans/runners/AbstractCodeGenTestRunner.kt b/compiler/suspend-transform-plugin/src/test/love/forte/plugin/suspendtrans/runners/AbstractCodeGenTestRunner.kt index 2f441de..3f3d5b3 100644 --- a/compiler/suspend-transform-plugin/src/test/love/forte/plugin/suspendtrans/runners/AbstractCodeGenTestRunner.kt +++ b/compiler/suspend-transform-plugin/src/test/love/forte/plugin/suspendtrans/runners/AbstractCodeGenTestRunner.kt @@ -17,7 +17,10 @@ abstract class AbstractCodeGenTestRunner : AbstractTestRunner() { override fun TestConfigurationBuilder.configureHandlers() { configureFirHandlersStep { useHandlers( - ::FirDumpHandler, ::FirCfgDumpHandler, ::FirResolvedTypesVerifier, ::FirDiagnosticsHandler, + ::FirDumpHandler, + ::FirCfgDumpHandler, + ::FirResolvedTypesVerifier, + ::FirDiagnosticsHandler, ) } diff --git a/compiler/suspend-transform-plugin/src/test/love/forte/plugin/suspendtrans/runners/AbstractTestRunner.kt b/compiler/suspend-transform-plugin/src/test/love/forte/plugin/suspendtrans/runners/AbstractTestRunner.kt index ae18f7e..d907052 100644 --- a/compiler/suspend-transform-plugin/src/test/love/forte/plugin/suspendtrans/runners/AbstractTestRunner.kt +++ b/compiler/suspend-transform-plugin/src/test/love/forte/plugin/suspendtrans/runners/AbstractTestRunner.kt @@ -42,6 +42,7 @@ abstract class AbstractTestRunner : AbstractKotlinCompilerTest() { backendKind = BackendKinds.IrBackendForK1AndK2 // this.languageVersionSettings + // languageSettings { // languageVersion = LanguageVersion.KOTLIN_2_1 // apiVersion = ApiVersion.KOTLIN_2_1 @@ -54,7 +55,6 @@ abstract class AbstractTestRunner : AbstractKotlinCompilerTest() { builder.defaultDirectives { FIR_PARSER with FirParser.LightTree - } when (targetFrontend) { diff --git a/compiler/suspend-transform-plugin/src/test/love/forte/plugin/suspendtrans/services/SuspendTransformerEnvironmentConfigurator.kt b/compiler/suspend-transform-plugin/src/test/love/forte/plugin/suspendtrans/services/SuspendTransformerEnvironmentConfigurator.kt index 8b63a10..c2bdc0a 100644 --- a/compiler/suspend-transform-plugin/src/test/love/forte/plugin/suspendtrans/services/SuspendTransformerEnvironmentConfigurator.kt +++ b/compiler/suspend-transform-plugin/src/test/love/forte/plugin/suspendtrans/services/SuspendTransformerEnvironmentConfigurator.kt @@ -1,7 +1,11 @@ package love.forte.plugin.suspendtrans.services import love.forte.plugin.suspendtrans.SuspendTransformComponentRegistrar -import love.forte.plugin.suspendtrans.SuspendTransformConfiguration +import love.forte.plugin.suspendtrans.configuration.InternalSuspendTransformConfigurationApi +import love.forte.plugin.suspendtrans.configuration.SuspendTransformConfigurations.jsPromiseTransformer +import love.forte.plugin.suspendtrans.configuration.SuspendTransformConfigurations.jvmAsyncTransformer +import love.forte.plugin.suspendtrans.configuration.SuspendTransformConfigurations.jvmBlockingTransformer +import love.forte.plugin.suspendtrans.configuration.TargetPlatform import org.jetbrains.kotlin.cli.jvm.config.addJvmClasspathRoot import org.jetbrains.kotlin.cli.jvm.config.configureJdkClasspathRoots import org.jetbrains.kotlin.compiler.plugin.CompilerPluginRegistrar @@ -19,15 +23,19 @@ import java.io.File */ class SuspendTransformerEnvironmentConfigurator(testServices: TestServices) : EnvironmentConfigurator(testServices) { - @OptIn(ExperimentalCompilerApi::class) + @OptIn(ExperimentalCompilerApi::class, InternalSuspendTransformConfigurationApi::class) override fun CompilerPluginRegistrar.ExtensionStorage.registerCompilerExtensions( module: TestModule, configuration: CompilerConfiguration ) { + val testConfiguration = love.forte.plugin.suspendtrans.configuration.SuspendTransformConfiguration( + transformers = mapOf( + TargetPlatform.JS to listOf(jsPromiseTransformer), + TargetPlatform.JVM to listOf(jvmBlockingTransformer, jvmAsyncTransformer) + ) + ) // register plugin - SuspendTransformComponentRegistrar.register(this, SuspendTransformConfiguration().apply { - useDefault() - }) + SuspendTransformComponentRegistrar.register(this, testConfiguration) } override fun configureCompilerConfiguration(configuration: CompilerConfiguration, module: TestModule) { @@ -71,7 +79,7 @@ class SuspendTransformerEnvironmentConfigurator(testServices: TestServices) : En private fun getRuntimeJarFile(clazz: Class<*>): File { // try { - return PathUtil.getResourcePathForClass(clazz) + return PathUtil.getResourcePathForClass(clazz) // } catch (e: ClassNotFoundException) { // System.err.println("Runtime jar '$clazz' not found!") //// assert(false) { "Runtime jar '$className' not found!" } diff --git a/compiler/suspend-transform-plugin/src/testData/codegen/implOverridenGeneric.asm.txt b/compiler/suspend-transform-plugin/src/testData/codegen/implOverridenGeneric.asm.txt deleted file mode 100644 index 2429b42..0000000 --- a/compiler/suspend-transform-plugin/src/testData/codegen/implOverridenGeneric.asm.txt +++ /dev/null @@ -1,449 +0,0 @@ -public abstract interface Bar : java/lang/Object, Foo { - -} - -public abstract interface Foo : java/lang/Object { - -} - -public abstract interface FooInterface1 : java/lang/Object { - public abstract java.lang.Object data(kotlin.coroutines.Continuation p0) - - public abstract java.lang.Object data2(java.lang.Object p0, kotlin.coroutines.Continuation p1) - - public abstract java.lang.Object data3(int p0, kotlin.coroutines.Continuation p1) -} - -final class FooInterface1Impl$data2Blocking$1 : kotlin/coroutines/jvm/internal/SuspendLambda, kotlin/jvm/functions/Function1 { - final java.lang.Object $value - - int label - - final FooInterface1Impl this$0 - - void (FooInterface1Impl $receiver, java.lang.Object $value, kotlin.coroutines.Continuation $completion) - - public final kotlin.coroutines.Continuation create(kotlin.coroutines.Continuation $completion) - - public final java.lang.Object invoke(kotlin.coroutines.Continuation p1) - - public java.lang.Object invoke(java.lang.Object p1) - - public final java.lang.Object invokeSuspend(java.lang.Object $result) -} - -final class FooInterface1Impl$data3Blocking$1 : kotlin/coroutines/jvm/internal/SuspendLambda, kotlin/jvm/functions/Function1 { - final int $this_data3Blocking - - int label - - final FooInterface1Impl this$0 - - void (FooInterface1Impl $receiver, int $receiver, kotlin.coroutines.Continuation $completion) - - public final kotlin.coroutines.Continuation create(kotlin.coroutines.Continuation $completion) - - public final java.lang.Object invoke(kotlin.coroutines.Continuation p1) - - public java.lang.Object invoke(java.lang.Object p1) - - public final java.lang.Object invokeSuspend(java.lang.Object $result) -} - -final class FooInterface1Impl$dataBlocking$1 : kotlin/coroutines/jvm/internal/SuspendLambda, kotlin/jvm/functions/Function1 { - int label - - final FooInterface1Impl this$0 - - void (FooInterface1Impl $receiver, kotlin.coroutines.Continuation $completion) - - public final kotlin.coroutines.Continuation create(kotlin.coroutines.Continuation $completion) - - public final java.lang.Object invoke(kotlin.coroutines.Continuation p1) - - public java.lang.Object invoke(java.lang.Object p1) - - public final java.lang.Object invokeSuspend(java.lang.Object $result) -} - -public final class FooInterface1Impl : java/lang/Object, FooInterface1 { - public void () - - public java.lang.Object data(kotlin.coroutines.Continuation $completion) - - public java.lang.Object data2(java.lang.Object value, kotlin.coroutines.Continuation $completion) - - public Bar data2Blocking(java.lang.Object value) - - public java.lang.Object data3(int $this$data3, kotlin.coroutines.Continuation $completion) - - public Bar data3Blocking(int $this$data3Blocking) - - public Bar dataBlocking() -} - -public abstract interface FooInterface2 : java/lang/Object { - public abstract java.lang.Object data(kotlin.coroutines.Continuation p0) - - public abstract java.lang.Object data2(Foo p0, kotlin.coroutines.Continuation p1) - - public abstract java.lang.Object data3(int p0, kotlin.coroutines.Continuation p1) -} - -final class FooInterface2Impl$data2Blocking$1 : kotlin/coroutines/jvm/internal/SuspendLambda, kotlin/jvm/functions/Function1 { - final Foo $value - - int label - - final FooInterface2Impl this$0 - - void (FooInterface2Impl $receiver, Foo $value, kotlin.coroutines.Continuation $completion) - - public final kotlin.coroutines.Continuation create(kotlin.coroutines.Continuation $completion) - - public final java.lang.Object invoke(kotlin.coroutines.Continuation p1) - - public java.lang.Object invoke(java.lang.Object p1) - - public final java.lang.Object invokeSuspend(java.lang.Object $result) -} - -final class FooInterface2Impl$data3Blocking$1 : kotlin/coroutines/jvm/internal/SuspendLambda, kotlin/jvm/functions/Function1 { - final int $this_data3Blocking - - int label - - final FooInterface2Impl this$0 - - void (FooInterface2Impl $receiver, int $receiver, kotlin.coroutines.Continuation $completion) - - public final kotlin.coroutines.Continuation create(kotlin.coroutines.Continuation $completion) - - public final java.lang.Object invoke(kotlin.coroutines.Continuation p1) - - public java.lang.Object invoke(java.lang.Object p1) - - public final java.lang.Object invokeSuspend(java.lang.Object $result) -} - -final class FooInterface2Impl$dataBlocking$1 : kotlin/coroutines/jvm/internal/SuspendLambda, kotlin/jvm/functions/Function1 { - int label - - final FooInterface2Impl this$0 - - void (FooInterface2Impl $receiver, kotlin.coroutines.Continuation $completion) - - public final kotlin.coroutines.Continuation create(kotlin.coroutines.Continuation $completion) - - public final java.lang.Object invoke(kotlin.coroutines.Continuation p1) - - public java.lang.Object invoke(java.lang.Object p1) - - public final java.lang.Object invokeSuspend(java.lang.Object $result) -} - -public final class FooInterface2Impl : java/lang/Object, FooInterface2 { - public void () - - public java.lang.Object data(kotlin.coroutines.Continuation $completion) - - public java.lang.Object data2(Foo value, kotlin.coroutines.Continuation $completion) - - public Foo data2Blocking(Foo value) - - public java.lang.Object data3(int $this$data3, kotlin.coroutines.Continuation $completion) - - public Foo data3Blocking(int $this$data3Blocking) - - public Foo dataBlocking() -} - -public final class FooInterface3$DefaultImpls : java/lang/Object { - public static Foo data2Blocking(FooInterface3 $this, java.lang.Object value) - - public static Foo data3Blocking(FooInterface3 $this, int $receiver) - - public static Foo dataBlocking(FooInterface3 $this) -} - -final class FooInterface3$data2Blocking$1 : kotlin/coroutines/jvm/internal/SuspendLambda, kotlin/jvm/functions/Function1 { - final java.lang.Object $value - - int label - - final FooInterface3 this$0 - - void (FooInterface3 $receiver, java.lang.Object $value, kotlin.coroutines.Continuation $completion) - - public final kotlin.coroutines.Continuation create(kotlin.coroutines.Continuation $completion) - - public final java.lang.Object invoke(kotlin.coroutines.Continuation p1) - - public java.lang.Object invoke(java.lang.Object p1) - - public final java.lang.Object invokeSuspend(java.lang.Object $result) -} - -final class FooInterface3$data3Blocking$1 : kotlin/coroutines/jvm/internal/SuspendLambda, kotlin/jvm/functions/Function1 { - final int $this_data3Blocking - - int label - - final FooInterface3 this$0 - - void (FooInterface3 $receiver, int $receiver, kotlin.coroutines.Continuation $completion) - - public final kotlin.coroutines.Continuation create(kotlin.coroutines.Continuation $completion) - - public final java.lang.Object invoke(kotlin.coroutines.Continuation p1) - - public java.lang.Object invoke(java.lang.Object p1) - - public final java.lang.Object invokeSuspend(java.lang.Object $result) -} - -final class FooInterface3$dataBlocking$1 : kotlin/coroutines/jvm/internal/SuspendLambda, kotlin/jvm/functions/Function1 { - int label - - final FooInterface3 this$0 - - void (FooInterface3 $receiver, kotlin.coroutines.Continuation $completion) - - public final kotlin.coroutines.Continuation create(kotlin.coroutines.Continuation $completion) - - public final java.lang.Object invoke(kotlin.coroutines.Continuation p1) - - public java.lang.Object invoke(java.lang.Object p1) - - public final java.lang.Object invokeSuspend(java.lang.Object $result) -} - -public abstract interface FooInterface3 : java/lang/Object { - public abstract java.lang.Object data(kotlin.coroutines.Continuation p0) - - public abstract java.lang.Object data2(java.lang.Object p0, kotlin.coroutines.Continuation p1) - - public abstract Foo data2Blocking(java.lang.Object p0) - - public abstract java.lang.Object data3(int p0, kotlin.coroutines.Continuation p1) - - public abstract Foo data3Blocking(int p0) - - public abstract Foo dataBlocking() -} - -final class FooInterface3Impl$data2Blocking$1 : kotlin/coroutines/jvm/internal/SuspendLambda, kotlin/jvm/functions/Function1 { - final java.lang.Object $value - - int label - - final FooInterface3Impl this$0 - - void (FooInterface3Impl $receiver, java.lang.Object $value, kotlin.coroutines.Continuation $completion) - - public final kotlin.coroutines.Continuation create(kotlin.coroutines.Continuation $completion) - - public final java.lang.Object invoke(kotlin.coroutines.Continuation p1) - - public java.lang.Object invoke(java.lang.Object p1) - - public final java.lang.Object invokeSuspend(java.lang.Object $result) -} - -final class FooInterface3Impl$data3Blocking$1 : kotlin/coroutines/jvm/internal/SuspendLambda, kotlin/jvm/functions/Function1 { - final int $this_data3Blocking - - int label - - final FooInterface3Impl this$0 - - void (FooInterface3Impl $receiver, int $receiver, kotlin.coroutines.Continuation $completion) - - public final kotlin.coroutines.Continuation create(kotlin.coroutines.Continuation $completion) - - public final java.lang.Object invoke(kotlin.coroutines.Continuation p1) - - public java.lang.Object invoke(java.lang.Object p1) - - public final java.lang.Object invokeSuspend(java.lang.Object $result) -} - -final class FooInterface3Impl$dataBlocking$1 : kotlin/coroutines/jvm/internal/SuspendLambda, kotlin/jvm/functions/Function1 { - int label - - final FooInterface3Impl this$0 - - void (FooInterface3Impl $receiver, kotlin.coroutines.Continuation $completion) - - public final kotlin.coroutines.Continuation create(kotlin.coroutines.Continuation $completion) - - public final java.lang.Object invoke(kotlin.coroutines.Continuation p1) - - public java.lang.Object invoke(java.lang.Object p1) - - public final java.lang.Object invokeSuspend(java.lang.Object $result) -} - -public final class FooInterface3Impl : java/lang/Object, FooInterface3 { - public void () - - public java.lang.Object data(kotlin.coroutines.Continuation $completion) - - public java.lang.Object data2(java.lang.Object value, kotlin.coroutines.Continuation $completion) - - public Bar data2Blocking(java.lang.Object value) - - public Foo data2Blocking(java.lang.Object value) - - public java.lang.Object data3(int $this$data3, kotlin.coroutines.Continuation $completion) - - public Bar data3Blocking(int $this$data3Blocking) - - public Foo data3Blocking(int $this$data3Blocking) - - public Bar dataBlocking() - - public Foo dataBlocking() -} - -public final class FooInterface4$DefaultImpls : java/lang/Object { - public static Foo data2Blocking(FooInterface4 $this, Foo value) - - public static Foo data3Blocking(FooInterface4 $this, int $receiver) - - public static Foo dataBlocking(FooInterface4 $this) -} - -final class FooInterface4$data2Blocking$1 : kotlin/coroutines/jvm/internal/SuspendLambda, kotlin/jvm/functions/Function1 { - final Foo $value - - int label - - final FooInterface4 this$0 - - void (FooInterface4 $receiver, Foo $value, kotlin.coroutines.Continuation $completion) - - public final kotlin.coroutines.Continuation create(kotlin.coroutines.Continuation $completion) - - public final java.lang.Object invoke(kotlin.coroutines.Continuation p1) - - public java.lang.Object invoke(java.lang.Object p1) - - public final java.lang.Object invokeSuspend(java.lang.Object $result) -} - -final class FooInterface4$data3Blocking$1 : kotlin/coroutines/jvm/internal/SuspendLambda, kotlin/jvm/functions/Function1 { - final int $this_data3Blocking - - int label - - final FooInterface4 this$0 - - void (FooInterface4 $receiver, int $receiver, kotlin.coroutines.Continuation $completion) - - public final kotlin.coroutines.Continuation create(kotlin.coroutines.Continuation $completion) - - public final java.lang.Object invoke(kotlin.coroutines.Continuation p1) - - public java.lang.Object invoke(java.lang.Object p1) - - public final java.lang.Object invokeSuspend(java.lang.Object $result) -} - -final class FooInterface4$dataBlocking$1 : kotlin/coroutines/jvm/internal/SuspendLambda, kotlin/jvm/functions/Function1 { - int label - - final FooInterface4 this$0 - - void (FooInterface4 $receiver, kotlin.coroutines.Continuation $completion) - - public final kotlin.coroutines.Continuation create(kotlin.coroutines.Continuation $completion) - - public final java.lang.Object invoke(kotlin.coroutines.Continuation p1) - - public java.lang.Object invoke(java.lang.Object p1) - - public final java.lang.Object invokeSuspend(java.lang.Object $result) -} - -public abstract interface FooInterface4 : java/lang/Object { - public abstract java.lang.Object data(kotlin.coroutines.Continuation p0) - - public abstract java.lang.Object data2(Foo p0, kotlin.coroutines.Continuation p1) - - public abstract Foo data2Blocking(Foo p0) - - public abstract java.lang.Object data3(int p0, kotlin.coroutines.Continuation p1) - - public abstract Foo data3Blocking(int p0) - - public abstract Foo dataBlocking() -} - -final class FooInterface4Impl$data2Blocking$1 : kotlin/coroutines/jvm/internal/SuspendLambda, kotlin/jvm/functions/Function1 { - final Foo $value - - int label - - final FooInterface4Impl this$0 - - void (FooInterface4Impl $receiver, Foo $value, kotlin.coroutines.Continuation $completion) - - public final kotlin.coroutines.Continuation create(kotlin.coroutines.Continuation $completion) - - public final java.lang.Object invoke(kotlin.coroutines.Continuation p1) - - public java.lang.Object invoke(java.lang.Object p1) - - public final java.lang.Object invokeSuspend(java.lang.Object $result) -} - -final class FooInterface4Impl$data3Blocking$1 : kotlin/coroutines/jvm/internal/SuspendLambda, kotlin/jvm/functions/Function1 { - final int $this_data3Blocking - - int label - - final FooInterface4Impl this$0 - - void (FooInterface4Impl $receiver, int $receiver, kotlin.coroutines.Continuation $completion) - - public final kotlin.coroutines.Continuation create(kotlin.coroutines.Continuation $completion) - - public final java.lang.Object invoke(kotlin.coroutines.Continuation p1) - - public java.lang.Object invoke(java.lang.Object p1) - - public final java.lang.Object invokeSuspend(java.lang.Object $result) -} - -final class FooInterface4Impl$dataBlocking$1 : kotlin/coroutines/jvm/internal/SuspendLambda, kotlin/jvm/functions/Function1 { - int label - - final FooInterface4Impl this$0 - - void (FooInterface4Impl $receiver, kotlin.coroutines.Continuation $completion) - - public final kotlin.coroutines.Continuation create(kotlin.coroutines.Continuation $completion) - - public final java.lang.Object invoke(kotlin.coroutines.Continuation p1) - - public java.lang.Object invoke(java.lang.Object p1) - - public final java.lang.Object invokeSuspend(java.lang.Object $result) -} - -public final class FooInterface4Impl : java/lang/Object, FooInterface4 { - public void () - - public java.lang.Object data(kotlin.coroutines.Continuation $completion) - - public java.lang.Object data2(Foo value, kotlin.coroutines.Continuation $completion) - - public Foo data2Blocking(Foo value) - - public java.lang.Object data3(int $this$data3, kotlin.coroutines.Continuation $completion) - - public Foo data3Blocking(int $this$data3Blocking) - - public Foo dataBlocking() -} diff --git a/compiler/suspend-transform-plugin/src/testData/codegen/implOverridenGeneric.fir.ir.txt b/compiler/suspend-transform-plugin/src/testData/codegen/implOverridenGeneric.fir.ir.txt deleted file mode 100644 index 8df2699..0000000 --- a/compiler/suspend-transform-plugin/src/testData/codegen/implOverridenGeneric.fir.ir.txt +++ /dev/null @@ -1,651 +0,0 @@ -FILE fqName: fileName:/Main.kt - CLASS CLASS name:FooInterface1Impl modality:FINAL visibility:public superTypes:[.FooInterface1.FooInterface1Impl>] - $this: VALUE_PARAMETER INSTANCE_RECEIVER name: type:.FooInterface1Impl.FooInterface1Impl> - TYPE_PARAMETER name:T index:0 variance: superTypes:[.Bar] reified:false - CONSTRUCTOR visibility:public <> () returnType:.FooInterface1Impl.FooInterface1Impl> [primary] - BLOCK_BODY - DELEGATING_CONSTRUCTOR_CALL 'public constructor () declared in kotlin.Any' - INSTANCE_INITIALIZER_CALL classDescriptor='CLASS CLASS name:FooInterface1Impl modality:FINAL visibility:public superTypes:[.FooInterface1.FooInterface1Impl>]' - 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 .FooInterface1 - $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 .FooInterface1 - $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 .FooInterface1 - $this: VALUE_PARAMETER name: type:kotlin.Any - FUN GENERATED[love.forte.plugin.suspendtrans.fir.SuspendTransformK2V3Key] name:data2Blocking visibility:public modality:OPEN ($this:.FooInterface1Impl.FooInterface1Impl>, value:A of .FooInterface1Impl.data2Blocking) returnType:T of .FooInterface1Impl - annotations: - Api4J - TYPE_PARAMETER name:A index:0 variance: superTypes:[kotlin.Any?] reified:false - $this: VALUE_PARAMETER name: type:.FooInterface1Impl.FooInterface1Impl> - VALUE_PARAMETER name:value index:0 type:A of .FooInterface1Impl.data2Blocking - BLOCK_BODY - RETURN type=kotlin.Nothing from='public open fun data2Blocking (value: A of .FooInterface1Impl.data2Blocking): T of .FooInterface1Impl declared in .FooInterface1Impl' - CALL 'public final fun $runInBlocking$ (block: kotlin.coroutines.SuspendFunction0): T of love.forte.plugin.suspendtrans.runtime.$runInBlocking$ declared in love.forte.plugin.suspendtrans.runtime' type=T of .FooInterface1Impl origin=null - : - block: FUN_EXPR type=kotlin.coroutines.SuspendFunction0.FooInterface1Impl> origin=LAMBDA - FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL <> () returnType:T of .FooInterface1Impl [suspend] - BLOCK_BODY - RETURN type=kotlin.Nothing from='local final fun (): T of .FooInterface1Impl declared in .FooInterface1Impl.data2Blocking' - CALL 'public open fun data2 (value: A of .FooInterface1Impl.data2): T of .FooInterface1Impl declared in .FooInterface1Impl' type=T of .FooInterface1Impl origin=null - : - $this: GET_VAR ': .FooInterface1Impl.FooInterface1Impl> declared in .FooInterface1Impl.data2Blocking' type=.FooInterface1Impl.FooInterface1Impl> origin=null - value: GET_VAR 'value: A of .FooInterface1Impl.data2Blocking declared in .FooInterface1Impl.data2Blocking' type=A of .FooInterface1Impl.data2Blocking origin=null - FUN GENERATED[love.forte.plugin.suspendtrans.fir.SuspendTransformK2V3Key] name:data3Blocking visibility:public modality:OPEN <> ($this:.FooInterface1Impl.FooInterface1Impl>, $receiver:kotlin.Int) returnType:T of .FooInterface1Impl - annotations: - Api4J - $this: VALUE_PARAMETER name: type:.FooInterface1Impl.FooInterface1Impl> - $receiver: VALUE_PARAMETER name: type:kotlin.Int - BLOCK_BODY - RETURN type=kotlin.Nothing from='public open fun data3Blocking (): T of .FooInterface1Impl declared in .FooInterface1Impl' - CALL 'public final fun $runInBlocking$ (block: kotlin.coroutines.SuspendFunction0): T of love.forte.plugin.suspendtrans.runtime.$runInBlocking$ declared in love.forte.plugin.suspendtrans.runtime' type=T of .FooInterface1Impl origin=null - : - block: FUN_EXPR type=kotlin.coroutines.SuspendFunction0.FooInterface1Impl> origin=LAMBDA - FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL <> () returnType:T of .FooInterface1Impl [suspend] - BLOCK_BODY - RETURN type=kotlin.Nothing from='local final fun (): T of .FooInterface1Impl declared in .FooInterface1Impl.data3Blocking' - CALL 'public open fun data3 (): T of .FooInterface1Impl declared in .FooInterface1Impl' type=T of .FooInterface1Impl origin=null - $this: GET_VAR ': .FooInterface1Impl.FooInterface1Impl> declared in .FooInterface1Impl.data3Blocking' type=.FooInterface1Impl.FooInterface1Impl> origin=null - $receiver: GET_VAR ': kotlin.Int declared in .FooInterface1Impl.data3Blocking' type=kotlin.Int origin=null - FUN GENERATED[love.forte.plugin.suspendtrans.fir.SuspendTransformK2V3Key] name:dataBlocking visibility:public modality:OPEN <> ($this:.FooInterface1Impl.FooInterface1Impl>) returnType:T of .FooInterface1Impl - annotations: - Api4J - $this: VALUE_PARAMETER name: type:.FooInterface1Impl.FooInterface1Impl> - BLOCK_BODY - RETURN type=kotlin.Nothing from='public open fun dataBlocking (): T of .FooInterface1Impl declared in .FooInterface1Impl' - CALL 'public final fun $runInBlocking$ (block: kotlin.coroutines.SuspendFunction0): T of love.forte.plugin.suspendtrans.runtime.$runInBlocking$ declared in love.forte.plugin.suspendtrans.runtime' type=T of .FooInterface1Impl origin=null - : - block: FUN_EXPR type=kotlin.coroutines.SuspendFunction0.FooInterface1Impl> origin=LAMBDA - FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL <> () returnType:T of .FooInterface1Impl [suspend] - BLOCK_BODY - RETURN type=kotlin.Nothing from='local final fun (): T of .FooInterface1Impl declared in .FooInterface1Impl.dataBlocking' - CALL 'public open fun data (): T of .FooInterface1Impl declared in .FooInterface1Impl' type=T of .FooInterface1Impl origin=null - $this: GET_VAR ': .FooInterface1Impl.FooInterface1Impl> declared in .FooInterface1Impl.dataBlocking' type=.FooInterface1Impl.FooInterface1Impl> origin=null - FUN name:data visibility:public modality:OPEN <> ($this:.FooInterface1Impl.FooInterface1Impl>) returnType:T of .FooInterface1Impl [suspend] - annotations: - JvmBlocking(baseName = , suffix = , asProperty = ) - JvmSynthetic - overridden: - public abstract fun data (): T of .FooInterface1 declared in .FooInterface1 - $this: VALUE_PARAMETER name: type:.FooInterface1Impl.FooInterface1Impl> - BLOCK_BODY - RETURN type=kotlin.Nothing from='public open fun data (): T of .FooInterface1Impl declared in .FooInterface1Impl' - CALL 'public final fun TODO (): kotlin.Nothing declared in kotlin' type=kotlin.Nothing origin=null - FUN name:data2 visibility:public modality:OPEN ($this:.FooInterface1Impl.FooInterface1Impl>, value:A of .FooInterface1Impl.data2) returnType:T of .FooInterface1Impl [suspend] - annotations: - JvmBlocking(baseName = , suffix = , asProperty = ) - JvmSynthetic - overridden: - public abstract fun data2 (value: A of .FooInterface1.data2): T of .FooInterface1 declared in .FooInterface1 - TYPE_PARAMETER name:A index:0 variance: superTypes:[kotlin.Any?] reified:false - $this: VALUE_PARAMETER name: type:.FooInterface1Impl.FooInterface1Impl> - VALUE_PARAMETER name:value index:0 type:A of .FooInterface1Impl.data2 - BLOCK_BODY - RETURN type=kotlin.Nothing from='public open fun data2 (value: A of .FooInterface1Impl.data2): T of .FooInterface1Impl declared in .FooInterface1Impl' - CALL 'public final fun TODO (): kotlin.Nothing declared in kotlin' type=kotlin.Nothing origin=null - FUN name:data3 visibility:public modality:OPEN <> ($this:.FooInterface1Impl.FooInterface1Impl>, $receiver:kotlin.Int) returnType:T of .FooInterface1Impl [suspend] - annotations: - JvmBlocking(baseName = , suffix = , asProperty = ) - JvmSynthetic - overridden: - public abstract fun data3 (): T of .FooInterface1 declared in .FooInterface1 - $this: VALUE_PARAMETER name: type:.FooInterface1Impl.FooInterface1Impl> - $receiver: VALUE_PARAMETER name: type:kotlin.Int - BLOCK_BODY - RETURN type=kotlin.Nothing from='public open fun data3 (): T of .FooInterface1Impl declared in .FooInterface1Impl' - CALL 'public final fun TODO (): kotlin.Nothing declared in kotlin' type=kotlin.Nothing origin=null - CLASS CLASS name:FooInterface2Impl modality:FINAL visibility:public superTypes:[.FooInterface2.FooInterface2Impl>] - $this: VALUE_PARAMETER INSTANCE_RECEIVER name: type:.FooInterface2Impl.FooInterface2Impl> - TYPE_PARAMETER name:T index:0 variance: superTypes:[.Foo] reified:false - CONSTRUCTOR visibility:public <> () returnType:.FooInterface2Impl.FooInterface2Impl> [primary] - BLOCK_BODY - DELEGATING_CONSTRUCTOR_CALL 'public constructor () declared in kotlin.Any' - INSTANCE_INITIALIZER_CALL classDescriptor='CLASS CLASS name:FooInterface2Impl modality:FINAL visibility:public superTypes:[.FooInterface2.FooInterface2Impl>]' - 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 .FooInterface2 - $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 .FooInterface2 - $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 .FooInterface2 - $this: VALUE_PARAMETER name: type:kotlin.Any - FUN GENERATED[love.forte.plugin.suspendtrans.fir.SuspendTransformK2V3Key] name:data2Blocking visibility:public modality:OPEN <> ($this:.FooInterface2Impl.FooInterface2Impl>, value:T of .FooInterface2Impl) returnType:T of .FooInterface2Impl - annotations: - Api4J - $this: VALUE_PARAMETER name: type:.FooInterface2Impl.FooInterface2Impl> - VALUE_PARAMETER name:value index:0 type:T of .FooInterface2Impl - BLOCK_BODY - RETURN type=kotlin.Nothing from='public open fun data2Blocking (value: T of .FooInterface2Impl): T of .FooInterface2Impl declared in .FooInterface2Impl' - CALL 'public final fun $runInBlocking$ (block: kotlin.coroutines.SuspendFunction0): T of love.forte.plugin.suspendtrans.runtime.$runInBlocking$ declared in love.forte.plugin.suspendtrans.runtime' type=T of .FooInterface2Impl origin=null - : - block: FUN_EXPR type=kotlin.coroutines.SuspendFunction0.FooInterface2Impl> origin=LAMBDA - FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL <> () returnType:T of .FooInterface2Impl [suspend] - BLOCK_BODY - RETURN type=kotlin.Nothing from='local final fun (): T of .FooInterface2Impl declared in .FooInterface2Impl.data2Blocking' - CALL 'public open fun data2 (value: T of .FooInterface2Impl): T of .FooInterface2Impl declared in .FooInterface2Impl' type=T of .FooInterface2Impl origin=null - $this: GET_VAR ': .FooInterface2Impl.FooInterface2Impl> declared in .FooInterface2Impl.data2Blocking' type=.FooInterface2Impl.FooInterface2Impl> origin=null - value: GET_VAR 'value: T of .FooInterface2Impl declared in .FooInterface2Impl.data2Blocking' type=T of .FooInterface2Impl origin=null - FUN GENERATED[love.forte.plugin.suspendtrans.fir.SuspendTransformK2V3Key] name:data3Blocking visibility:public modality:OPEN <> ($this:.FooInterface2Impl.FooInterface2Impl>, $receiver:kotlin.Int) returnType:T of .FooInterface2Impl - annotations: - Api4J - $this: VALUE_PARAMETER name: type:.FooInterface2Impl.FooInterface2Impl> - $receiver: VALUE_PARAMETER name: type:kotlin.Int - BLOCK_BODY - RETURN type=kotlin.Nothing from='public open fun data3Blocking (): T of .FooInterface2Impl declared in .FooInterface2Impl' - CALL 'public final fun $runInBlocking$ (block: kotlin.coroutines.SuspendFunction0): T of love.forte.plugin.suspendtrans.runtime.$runInBlocking$ declared in love.forte.plugin.suspendtrans.runtime' type=T of .FooInterface2Impl origin=null - : - block: FUN_EXPR type=kotlin.coroutines.SuspendFunction0.FooInterface2Impl> origin=LAMBDA - FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL <> () returnType:T of .FooInterface2Impl [suspend] - BLOCK_BODY - RETURN type=kotlin.Nothing from='local final fun (): T of .FooInterface2Impl declared in .FooInterface2Impl.data3Blocking' - CALL 'public open fun data3 (): T of .FooInterface2Impl declared in .FooInterface2Impl' type=T of .FooInterface2Impl origin=null - $this: GET_VAR ': .FooInterface2Impl.FooInterface2Impl> declared in .FooInterface2Impl.data3Blocking' type=.FooInterface2Impl.FooInterface2Impl> origin=null - $receiver: GET_VAR ': kotlin.Int declared in .FooInterface2Impl.data3Blocking' type=kotlin.Int origin=null - FUN GENERATED[love.forte.plugin.suspendtrans.fir.SuspendTransformK2V3Key] name:dataBlocking visibility:public modality:OPEN <> ($this:.FooInterface2Impl.FooInterface2Impl>) returnType:T of .FooInterface2Impl - annotations: - Api4J - $this: VALUE_PARAMETER name: type:.FooInterface2Impl.FooInterface2Impl> - BLOCK_BODY - RETURN type=kotlin.Nothing from='public open fun dataBlocking (): T of .FooInterface2Impl declared in .FooInterface2Impl' - CALL 'public final fun $runInBlocking$ (block: kotlin.coroutines.SuspendFunction0): T of love.forte.plugin.suspendtrans.runtime.$runInBlocking$ declared in love.forte.plugin.suspendtrans.runtime' type=T of .FooInterface2Impl origin=null - : - block: FUN_EXPR type=kotlin.coroutines.SuspendFunction0.FooInterface2Impl> origin=LAMBDA - FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL <> () returnType:T of .FooInterface2Impl [suspend] - BLOCK_BODY - RETURN type=kotlin.Nothing from='local final fun (): T of .FooInterface2Impl declared in .FooInterface2Impl.dataBlocking' - CALL 'public open fun data (): T of .FooInterface2Impl declared in .FooInterface2Impl' type=T of .FooInterface2Impl origin=null - $this: GET_VAR ': .FooInterface2Impl.FooInterface2Impl> declared in .FooInterface2Impl.dataBlocking' type=.FooInterface2Impl.FooInterface2Impl> origin=null - FUN name:data visibility:public modality:OPEN <> ($this:.FooInterface2Impl.FooInterface2Impl>) returnType:T of .FooInterface2Impl [suspend] - annotations: - JvmBlocking(baseName = , suffix = , asProperty = ) - JvmSynthetic - overridden: - public abstract fun data (): T of .FooInterface2 declared in .FooInterface2 - $this: VALUE_PARAMETER name: type:.FooInterface2Impl.FooInterface2Impl> - BLOCK_BODY - RETURN type=kotlin.Nothing from='public open fun data (): T of .FooInterface2Impl declared in .FooInterface2Impl' - CALL 'public final fun TODO (): kotlin.Nothing declared in kotlin' type=kotlin.Nothing origin=null - FUN name:data2 visibility:public modality:OPEN <> ($this:.FooInterface2Impl.FooInterface2Impl>, value:T of .FooInterface2Impl) returnType:T of .FooInterface2Impl [suspend] - annotations: - JvmBlocking(baseName = , suffix = , asProperty = ) - JvmSynthetic - overridden: - public abstract fun data2 (value: T of .FooInterface2): T of .FooInterface2 declared in .FooInterface2 - $this: VALUE_PARAMETER name: type:.FooInterface2Impl.FooInterface2Impl> - VALUE_PARAMETER name:value index:0 type:T of .FooInterface2Impl - BLOCK_BODY - RETURN type=kotlin.Nothing from='public open fun data2 (value: T of .FooInterface2Impl): T of .FooInterface2Impl declared in .FooInterface2Impl' - CALL 'public final fun TODO (): kotlin.Nothing declared in kotlin' type=kotlin.Nothing origin=null - FUN name:data3 visibility:public modality:OPEN <> ($this:.FooInterface2Impl.FooInterface2Impl>, $receiver:kotlin.Int) returnType:T of .FooInterface2Impl [suspend] - annotations: - JvmBlocking(baseName = , suffix = , asProperty = ) - JvmSynthetic - overridden: - public abstract fun data3 (): T of .FooInterface2 declared in .FooInterface2 - $this: VALUE_PARAMETER name: type:.FooInterface2Impl.FooInterface2Impl> - $receiver: VALUE_PARAMETER name: type:kotlin.Int - BLOCK_BODY - RETURN type=kotlin.Nothing from='public open fun data3 (): T of .FooInterface2Impl declared in .FooInterface2Impl' - CALL 'public final fun TODO (): kotlin.Nothing declared in kotlin' type=kotlin.Nothing origin=null - CLASS CLASS name:FooInterface3Impl modality:FINAL visibility:public superTypes:[.FooInterface3.FooInterface3Impl>] - $this: VALUE_PARAMETER INSTANCE_RECEIVER name: type:.FooInterface3Impl.FooInterface3Impl> - TYPE_PARAMETER name:T index:0 variance: superTypes:[.Bar] reified:false - CONSTRUCTOR visibility:public <> () returnType:.FooInterface3Impl.FooInterface3Impl> [primary] - BLOCK_BODY - DELEGATING_CONSTRUCTOR_CALL 'public constructor () declared in kotlin.Any' - INSTANCE_INITIALIZER_CALL classDescriptor='CLASS CLASS name:FooInterface3Impl modality:FINAL visibility:public superTypes:[.FooInterface3.FooInterface3Impl>]' - 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 .FooInterface3 - $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 .FooInterface3 - $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 .FooInterface3 - $this: VALUE_PARAMETER name: type:kotlin.Any - FUN GENERATED[love.forte.plugin.suspendtrans.fir.SuspendTransformK2V3Key] name:data2Blocking visibility:public modality:OPEN ($this:.FooInterface3Impl.FooInterface3Impl>, value:A of .FooInterface3Impl.data2Blocking) returnType:T of .FooInterface3Impl - annotations: - Api4J - overridden: - public open fun data2Blocking (value: A of .FooInterface3.data2Blocking): T of .FooInterface3 declared in .FooInterface3 - TYPE_PARAMETER name:A index:0 variance: superTypes:[kotlin.Any?] reified:false - $this: VALUE_PARAMETER name: type:.FooInterface3Impl.FooInterface3Impl> - VALUE_PARAMETER name:value index:0 type:A of .FooInterface3Impl.data2Blocking - BLOCK_BODY - RETURN type=kotlin.Nothing from='public open fun data2Blocking (value: A of .FooInterface3Impl.data2Blocking): T of .FooInterface3Impl declared in .FooInterface3Impl' - CALL 'public final fun $runInBlocking$ (block: kotlin.coroutines.SuspendFunction0): T of love.forte.plugin.suspendtrans.runtime.$runInBlocking$ declared in love.forte.plugin.suspendtrans.runtime' type=T of .FooInterface3Impl origin=null - : - block: FUN_EXPR type=kotlin.coroutines.SuspendFunction0.FooInterface3Impl> origin=LAMBDA - FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL <> () returnType:T of .FooInterface3Impl [suspend] - BLOCK_BODY - RETURN type=kotlin.Nothing from='local final fun (): T of .FooInterface3Impl declared in .FooInterface3Impl.data2Blocking' - CALL 'public open fun data2 (value: A of .FooInterface3Impl.data2): T of .FooInterface3Impl declared in .FooInterface3Impl' type=T of .FooInterface3Impl origin=null - : - $this: GET_VAR ': .FooInterface3Impl.FooInterface3Impl> declared in .FooInterface3Impl.data2Blocking' type=.FooInterface3Impl.FooInterface3Impl> origin=null - value: GET_VAR 'value: A of .FooInterface3Impl.data2Blocking declared in .FooInterface3Impl.data2Blocking' type=A of .FooInterface3Impl.data2Blocking origin=null - FUN GENERATED[love.forte.plugin.suspendtrans.fir.SuspendTransformK2V3Key] name:data3Blocking visibility:public modality:OPEN <> ($this:.FooInterface3Impl.FooInterface3Impl>, $receiver:kotlin.Int) returnType:T of .FooInterface3Impl - annotations: - Api4J - overridden: - public open fun data3Blocking (): T of .FooInterface3 declared in .FooInterface3 - $this: VALUE_PARAMETER name: type:.FooInterface3Impl.FooInterface3Impl> - $receiver: VALUE_PARAMETER name: type:kotlin.Int - BLOCK_BODY - RETURN type=kotlin.Nothing from='public open fun data3Blocking (): T of .FooInterface3Impl declared in .FooInterface3Impl' - CALL 'public final fun $runInBlocking$ (block: kotlin.coroutines.SuspendFunction0): T of love.forte.plugin.suspendtrans.runtime.$runInBlocking$ declared in love.forte.plugin.suspendtrans.runtime' type=T of .FooInterface3Impl origin=null - : - block: FUN_EXPR type=kotlin.coroutines.SuspendFunction0.FooInterface3Impl> origin=LAMBDA - FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL <> () returnType:T of .FooInterface3Impl [suspend] - BLOCK_BODY - RETURN type=kotlin.Nothing from='local final fun (): T of .FooInterface3Impl declared in .FooInterface3Impl.data3Blocking' - CALL 'public open fun data3 (): T of .FooInterface3Impl declared in .FooInterface3Impl' type=T of .FooInterface3Impl origin=null - $this: GET_VAR ': .FooInterface3Impl.FooInterface3Impl> declared in .FooInterface3Impl.data3Blocking' type=.FooInterface3Impl.FooInterface3Impl> origin=null - $receiver: GET_VAR ': kotlin.Int declared in .FooInterface3Impl.data3Blocking' type=kotlin.Int origin=null - FUN GENERATED[love.forte.plugin.suspendtrans.fir.SuspendTransformK2V3Key] name:dataBlocking visibility:public modality:OPEN <> ($this:.FooInterface3Impl.FooInterface3Impl>) returnType:T of .FooInterface3Impl - annotations: - Api4J - overridden: - public open fun dataBlocking (): T of .FooInterface3 declared in .FooInterface3 - $this: VALUE_PARAMETER name: type:.FooInterface3Impl.FooInterface3Impl> - BLOCK_BODY - RETURN type=kotlin.Nothing from='public open fun dataBlocking (): T of .FooInterface3Impl declared in .FooInterface3Impl' - CALL 'public final fun $runInBlocking$ (block: kotlin.coroutines.SuspendFunction0): T of love.forte.plugin.suspendtrans.runtime.$runInBlocking$ declared in love.forte.plugin.suspendtrans.runtime' type=T of .FooInterface3Impl origin=null - : - block: FUN_EXPR type=kotlin.coroutines.SuspendFunction0.FooInterface3Impl> origin=LAMBDA - FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL <> () returnType:T of .FooInterface3Impl [suspend] - BLOCK_BODY - RETURN type=kotlin.Nothing from='local final fun (): T of .FooInterface3Impl declared in .FooInterface3Impl.dataBlocking' - CALL 'public open fun data (): T of .FooInterface3Impl declared in .FooInterface3Impl' type=T of .FooInterface3Impl origin=null - $this: GET_VAR ': .FooInterface3Impl.FooInterface3Impl> declared in .FooInterface3Impl.dataBlocking' type=.FooInterface3Impl.FooInterface3Impl> origin=null - FUN name:data visibility:public modality:OPEN <> ($this:.FooInterface3Impl.FooInterface3Impl>) returnType:T of .FooInterface3Impl [suspend] - annotations: - JvmBlocking(baseName = , suffix = , asProperty = ) - JvmSynthetic - overridden: - public abstract fun data (): T of .FooInterface3 declared in .FooInterface3 - $this: VALUE_PARAMETER name: type:.FooInterface3Impl.FooInterface3Impl> - BLOCK_BODY - RETURN type=kotlin.Nothing from='public open fun data (): T of .FooInterface3Impl declared in .FooInterface3Impl' - CALL 'public final fun TODO (): kotlin.Nothing declared in kotlin' type=kotlin.Nothing origin=null - FUN name:data2 visibility:public modality:OPEN ($this:.FooInterface3Impl.FooInterface3Impl>, value:A of .FooInterface3Impl.data2) returnType:T of .FooInterface3Impl [suspend] - annotations: - JvmBlocking(baseName = , suffix = , asProperty = ) - JvmSynthetic - overridden: - public abstract fun data2 (value: A of .FooInterface3.data2): T of .FooInterface3 declared in .FooInterface3 - TYPE_PARAMETER name:A index:0 variance: superTypes:[kotlin.Any?] reified:false - $this: VALUE_PARAMETER name: type:.FooInterface3Impl.FooInterface3Impl> - VALUE_PARAMETER name:value index:0 type:A of .FooInterface3Impl.data2 - BLOCK_BODY - RETURN type=kotlin.Nothing from='public open fun data2 (value: A of .FooInterface3Impl.data2): T of .FooInterface3Impl declared in .FooInterface3Impl' - CALL 'public final fun TODO (): kotlin.Nothing declared in kotlin' type=kotlin.Nothing origin=null - FUN name:data3 visibility:public modality:OPEN <> ($this:.FooInterface3Impl.FooInterface3Impl>, $receiver:kotlin.Int) returnType:T of .FooInterface3Impl [suspend] - annotations: - JvmBlocking(baseName = , suffix = , asProperty = ) - JvmSynthetic - overridden: - public abstract fun data3 (): T of .FooInterface3 declared in .FooInterface3 - $this: VALUE_PARAMETER name: type:.FooInterface3Impl.FooInterface3Impl> - $receiver: VALUE_PARAMETER name: type:kotlin.Int - BLOCK_BODY - RETURN type=kotlin.Nothing from='public open fun data3 (): T of .FooInterface3Impl declared in .FooInterface3Impl' - CALL 'public final fun TODO (): kotlin.Nothing declared in kotlin' type=kotlin.Nothing origin=null - CLASS CLASS name:FooInterface4Impl modality:FINAL visibility:public superTypes:[.FooInterface4.FooInterface4Impl>] - $this: VALUE_PARAMETER INSTANCE_RECEIVER name: type:.FooInterface4Impl.FooInterface4Impl> - TYPE_PARAMETER name:T index:0 variance: superTypes:[.Foo] reified:false - CONSTRUCTOR visibility:public <> () returnType:.FooInterface4Impl.FooInterface4Impl> [primary] - BLOCK_BODY - DELEGATING_CONSTRUCTOR_CALL 'public constructor () declared in kotlin.Any' - INSTANCE_INITIALIZER_CALL classDescriptor='CLASS CLASS name:FooInterface4Impl modality:FINAL visibility:public superTypes:[.FooInterface4.FooInterface4Impl>]' - 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 .FooInterface4 - $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 .FooInterface4 - $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 .FooInterface4 - $this: VALUE_PARAMETER name: type:kotlin.Any - FUN GENERATED[love.forte.plugin.suspendtrans.fir.SuspendTransformK2V3Key] name:data2Blocking visibility:public modality:OPEN <> ($this:.FooInterface4Impl.FooInterface4Impl>, value:T of .FooInterface4Impl) returnType:T of .FooInterface4Impl - annotations: - Api4J - overridden: - public open fun data2Blocking (value: T of .FooInterface4): T of .FooInterface4 declared in .FooInterface4 - $this: VALUE_PARAMETER name: type:.FooInterface4Impl.FooInterface4Impl> - VALUE_PARAMETER name:value index:0 type:T of .FooInterface4Impl - BLOCK_BODY - RETURN type=kotlin.Nothing from='public open fun data2Blocking (value: T of .FooInterface4Impl): T of .FooInterface4Impl declared in .FooInterface4Impl' - CALL 'public final fun $runInBlocking$ (block: kotlin.coroutines.SuspendFunction0): T of love.forte.plugin.suspendtrans.runtime.$runInBlocking$ declared in love.forte.plugin.suspendtrans.runtime' type=T of .FooInterface4Impl origin=null - : - block: FUN_EXPR type=kotlin.coroutines.SuspendFunction0.FooInterface4Impl> origin=LAMBDA - FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL <> () returnType:T of .FooInterface4Impl [suspend] - BLOCK_BODY - RETURN type=kotlin.Nothing from='local final fun (): T of .FooInterface4Impl declared in .FooInterface4Impl.data2Blocking' - CALL 'public open fun data2 (value: T of .FooInterface4Impl): T of .FooInterface4Impl declared in .FooInterface4Impl' type=T of .FooInterface4Impl origin=null - $this: GET_VAR ': .FooInterface4Impl.FooInterface4Impl> declared in .FooInterface4Impl.data2Blocking' type=.FooInterface4Impl.FooInterface4Impl> origin=null - value: GET_VAR 'value: T of .FooInterface4Impl declared in .FooInterface4Impl.data2Blocking' type=T of .FooInterface4Impl origin=null - FUN GENERATED[love.forte.plugin.suspendtrans.fir.SuspendTransformK2V3Key] name:data3Blocking visibility:public modality:OPEN <> ($this:.FooInterface4Impl.FooInterface4Impl>, $receiver:kotlin.Int) returnType:T of .FooInterface4Impl - annotations: - Api4J - overridden: - public open fun data3Blocking (): T of .FooInterface4 declared in .FooInterface4 - $this: VALUE_PARAMETER name: type:.FooInterface4Impl.FooInterface4Impl> - $receiver: VALUE_PARAMETER name: type:kotlin.Int - BLOCK_BODY - RETURN type=kotlin.Nothing from='public open fun data3Blocking (): T of .FooInterface4Impl declared in .FooInterface4Impl' - CALL 'public final fun $runInBlocking$ (block: kotlin.coroutines.SuspendFunction0): T of love.forte.plugin.suspendtrans.runtime.$runInBlocking$ declared in love.forte.plugin.suspendtrans.runtime' type=T of .FooInterface4Impl origin=null - : - block: FUN_EXPR type=kotlin.coroutines.SuspendFunction0.FooInterface4Impl> origin=LAMBDA - FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL <> () returnType:T of .FooInterface4Impl [suspend] - BLOCK_BODY - RETURN type=kotlin.Nothing from='local final fun (): T of .FooInterface4Impl declared in .FooInterface4Impl.data3Blocking' - CALL 'public open fun data3 (): T of .FooInterface4Impl declared in .FooInterface4Impl' type=T of .FooInterface4Impl origin=null - $this: GET_VAR ': .FooInterface4Impl.FooInterface4Impl> declared in .FooInterface4Impl.data3Blocking' type=.FooInterface4Impl.FooInterface4Impl> origin=null - $receiver: GET_VAR ': kotlin.Int declared in .FooInterface4Impl.data3Blocking' type=kotlin.Int origin=null - FUN GENERATED[love.forte.plugin.suspendtrans.fir.SuspendTransformK2V3Key] name:dataBlocking visibility:public modality:OPEN <> ($this:.FooInterface4Impl.FooInterface4Impl>) returnType:T of .FooInterface4Impl - annotations: - Api4J - overridden: - public open fun dataBlocking (): T of .FooInterface4 declared in .FooInterface4 - $this: VALUE_PARAMETER name: type:.FooInterface4Impl.FooInterface4Impl> - BLOCK_BODY - RETURN type=kotlin.Nothing from='public open fun dataBlocking (): T of .FooInterface4Impl declared in .FooInterface4Impl' - CALL 'public final fun $runInBlocking$ (block: kotlin.coroutines.SuspendFunction0): T of love.forte.plugin.suspendtrans.runtime.$runInBlocking$ declared in love.forte.plugin.suspendtrans.runtime' type=T of .FooInterface4Impl origin=null - : - block: FUN_EXPR type=kotlin.coroutines.SuspendFunction0.FooInterface4Impl> origin=LAMBDA - FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL <> () returnType:T of .FooInterface4Impl [suspend] - BLOCK_BODY - RETURN type=kotlin.Nothing from='local final fun (): T of .FooInterface4Impl declared in .FooInterface4Impl.dataBlocking' - CALL 'public open fun data (): T of .FooInterface4Impl declared in .FooInterface4Impl' type=T of .FooInterface4Impl origin=null - $this: GET_VAR ': .FooInterface4Impl.FooInterface4Impl> declared in .FooInterface4Impl.dataBlocking' type=.FooInterface4Impl.FooInterface4Impl> origin=null - FUN name:data visibility:public modality:OPEN <> ($this:.FooInterface4Impl.FooInterface4Impl>) returnType:T of .FooInterface4Impl [suspend] - annotations: - JvmBlocking(baseName = , suffix = , asProperty = ) - JvmSynthetic - overridden: - public abstract fun data (): T of .FooInterface4 declared in .FooInterface4 - $this: VALUE_PARAMETER name: type:.FooInterface4Impl.FooInterface4Impl> - BLOCK_BODY - RETURN type=kotlin.Nothing from='public open fun data (): T of .FooInterface4Impl declared in .FooInterface4Impl' - CALL 'public final fun TODO (): kotlin.Nothing declared in kotlin' type=kotlin.Nothing origin=null - FUN name:data2 visibility:public modality:OPEN <> ($this:.FooInterface4Impl.FooInterface4Impl>, value:T of .FooInterface4Impl) returnType:T of .FooInterface4Impl [suspend] - annotations: - JvmBlocking(baseName = , suffix = , asProperty = ) - JvmSynthetic - overridden: - public abstract fun data2 (value: T of .FooInterface4): T of .FooInterface4 declared in .FooInterface4 - $this: VALUE_PARAMETER name: type:.FooInterface4Impl.FooInterface4Impl> - VALUE_PARAMETER name:value index:0 type:T of .FooInterface4Impl - BLOCK_BODY - RETURN type=kotlin.Nothing from='public open fun data2 (value: T of .FooInterface4Impl): T of .FooInterface4Impl declared in .FooInterface4Impl' - CALL 'public final fun TODO (): kotlin.Nothing declared in kotlin' type=kotlin.Nothing origin=null - FUN name:data3 visibility:public modality:OPEN <> ($this:.FooInterface4Impl.FooInterface4Impl>, $receiver:kotlin.Int) returnType:T of .FooInterface4Impl [suspend] - annotations: - JvmBlocking(baseName = , suffix = , asProperty = ) - JvmSynthetic - overridden: - public abstract fun data3 (): T of .FooInterface4 declared in .FooInterface4 - $this: VALUE_PARAMETER name: type:.FooInterface4Impl.FooInterface4Impl> - $receiver: VALUE_PARAMETER name: type:kotlin.Int - BLOCK_BODY - RETURN type=kotlin.Nothing from='public open fun data3 (): T of .FooInterface4Impl declared in .FooInterface4Impl' - CALL 'public final fun TODO (): kotlin.Nothing declared in kotlin' type=kotlin.Nothing origin=null - CLASS INTERFACE name:Bar modality:ABSTRACT visibility:public superTypes:[.Foo] - $this: VALUE_PARAMETER INSTANCE_RECEIVER name: type:.Bar - 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 .Foo - $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 .Foo - $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 .Foo - $this: VALUE_PARAMETER name: type:kotlin.Any - CLASS INTERFACE name:Foo modality:ABSTRACT visibility:public superTypes:[kotlin.Any] - $this: VALUE_PARAMETER INSTANCE_RECEIVER name: type:.Foo - 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 - CLASS INTERFACE name:FooInterface1 modality:ABSTRACT visibility:public superTypes:[kotlin.Any] - $this: VALUE_PARAMETER INSTANCE_RECEIVER name: type:.FooInterface1.FooInterface1> - TYPE_PARAMETER name:T index:0 variance: superTypes:[.Foo] reified:false - 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 name:data visibility:public modality:ABSTRACT <> ($this:.FooInterface1.FooInterface1>) returnType:T of .FooInterface1 [suspend] - $this: VALUE_PARAMETER name: type:.FooInterface1.FooInterface1> - FUN name:data2 visibility:public modality:ABSTRACT ($this:.FooInterface1.FooInterface1>, value:A of .FooInterface1.data2) returnType:T of .FooInterface1 [suspend] - TYPE_PARAMETER name:A index:0 variance: superTypes:[kotlin.Any?] reified:false - $this: VALUE_PARAMETER name: type:.FooInterface1.FooInterface1> - VALUE_PARAMETER name:value index:0 type:A of .FooInterface1.data2 - FUN name:data3 visibility:public modality:ABSTRACT <> ($this:.FooInterface1.FooInterface1>, $receiver:kotlin.Int) returnType:T of .FooInterface1 [suspend] - $this: VALUE_PARAMETER name: type:.FooInterface1.FooInterface1> - $receiver: VALUE_PARAMETER name: type:kotlin.Int - CLASS INTERFACE name:FooInterface2 modality:ABSTRACT visibility:public superTypes:[kotlin.Any] - $this: VALUE_PARAMETER INSTANCE_RECEIVER name: type:.FooInterface2.FooInterface2> - TYPE_PARAMETER name:T index:0 variance: superTypes:[.Foo] reified:false - 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 name:data visibility:public modality:ABSTRACT <> ($this:.FooInterface2.FooInterface2>) returnType:T of .FooInterface2 [suspend] - $this: VALUE_PARAMETER name: type:.FooInterface2.FooInterface2> - FUN name:data2 visibility:public modality:ABSTRACT <> ($this:.FooInterface2.FooInterface2>, value:T of .FooInterface2) returnType:T of .FooInterface2 [suspend] - $this: VALUE_PARAMETER name: type:.FooInterface2.FooInterface2> - VALUE_PARAMETER name:value index:0 type:T of .FooInterface2 - FUN name:data3 visibility:public modality:ABSTRACT <> ($this:.FooInterface2.FooInterface2>, $receiver:kotlin.Int) returnType:T of .FooInterface2 [suspend] - $this: VALUE_PARAMETER name: type:.FooInterface2.FooInterface2> - $receiver: VALUE_PARAMETER name: type:kotlin.Int - CLASS INTERFACE name:FooInterface3 modality:ABSTRACT visibility:public superTypes:[kotlin.Any] - $this: VALUE_PARAMETER INSTANCE_RECEIVER name: type:.FooInterface3.FooInterface3> - TYPE_PARAMETER name:T index:0 variance: superTypes:[.Foo] reified:false - 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[love.forte.plugin.suspendtrans.fir.SuspendTransformK2V3Key] name:data2Blocking visibility:public modality:OPEN ($this:.FooInterface3.FooInterface3>, value:A of .FooInterface3.data2Blocking) returnType:T of .FooInterface3 - annotations: - Api4J - TYPE_PARAMETER name:A index:0 variance: superTypes:[kotlin.Any?] reified:false - $this: VALUE_PARAMETER name: type:.FooInterface3.FooInterface3> - VALUE_PARAMETER name:value index:0 type:A of .FooInterface3.data2Blocking - BLOCK_BODY - RETURN type=kotlin.Nothing from='public open fun data2Blocking (value: A of .FooInterface3.data2Blocking): T of .FooInterface3 declared in .FooInterface3' - CALL 'public final fun $runInBlocking$ (block: kotlin.coroutines.SuspendFunction0): T of love.forte.plugin.suspendtrans.runtime.$runInBlocking$ declared in love.forte.plugin.suspendtrans.runtime' type=T of .FooInterface3 origin=null - : - block: FUN_EXPR type=kotlin.coroutines.SuspendFunction0.FooInterface3> origin=LAMBDA - FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL <> () returnType:T of .FooInterface3 [suspend] - BLOCK_BODY - RETURN type=kotlin.Nothing from='local final fun (): T of .FooInterface3 declared in .FooInterface3.data2Blocking' - CALL 'public abstract fun data2 (value: A of .FooInterface3.data2): T of .FooInterface3 declared in .FooInterface3' type=T of .FooInterface3 origin=null - : - $this: GET_VAR ': .FooInterface3.FooInterface3> declared in .FooInterface3.data2Blocking' type=.FooInterface3.FooInterface3> origin=null - value: GET_VAR 'value: A of .FooInterface3.data2Blocking declared in .FooInterface3.data2Blocking' type=A of .FooInterface3.data2Blocking origin=null - FUN GENERATED[love.forte.plugin.suspendtrans.fir.SuspendTransformK2V3Key] name:data3Blocking visibility:public modality:OPEN <> ($this:.FooInterface3.FooInterface3>, $receiver:kotlin.Int) returnType:T of .FooInterface3 - annotations: - Api4J - $this: VALUE_PARAMETER name: type:.FooInterface3.FooInterface3> - $receiver: VALUE_PARAMETER name: type:kotlin.Int - BLOCK_BODY - RETURN type=kotlin.Nothing from='public open fun data3Blocking (): T of .FooInterface3 declared in .FooInterface3' - CALL 'public final fun $runInBlocking$ (block: kotlin.coroutines.SuspendFunction0): T of love.forte.plugin.suspendtrans.runtime.$runInBlocking$ declared in love.forte.plugin.suspendtrans.runtime' type=T of .FooInterface3 origin=null - : - block: FUN_EXPR type=kotlin.coroutines.SuspendFunction0.FooInterface3> origin=LAMBDA - FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL <> () returnType:T of .FooInterface3 [suspend] - BLOCK_BODY - RETURN type=kotlin.Nothing from='local final fun (): T of .FooInterface3 declared in .FooInterface3.data3Blocking' - CALL 'public abstract fun data3 (): T of .FooInterface3 declared in .FooInterface3' type=T of .FooInterface3 origin=null - $this: GET_VAR ': .FooInterface3.FooInterface3> declared in .FooInterface3.data3Blocking' type=.FooInterface3.FooInterface3> origin=null - $receiver: GET_VAR ': kotlin.Int declared in .FooInterface3.data3Blocking' type=kotlin.Int origin=null - FUN GENERATED[love.forte.plugin.suspendtrans.fir.SuspendTransformK2V3Key] name:dataBlocking visibility:public modality:OPEN <> ($this:.FooInterface3.FooInterface3>) returnType:T of .FooInterface3 - annotations: - Api4J - $this: VALUE_PARAMETER name: type:.FooInterface3.FooInterface3> - BLOCK_BODY - RETURN type=kotlin.Nothing from='public open fun dataBlocking (): T of .FooInterface3 declared in .FooInterface3' - CALL 'public final fun $runInBlocking$ (block: kotlin.coroutines.SuspendFunction0): T of love.forte.plugin.suspendtrans.runtime.$runInBlocking$ declared in love.forte.plugin.suspendtrans.runtime' type=T of .FooInterface3 origin=null - : - block: FUN_EXPR type=kotlin.coroutines.SuspendFunction0.FooInterface3> origin=LAMBDA - FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL <> () returnType:T of .FooInterface3 [suspend] - BLOCK_BODY - RETURN type=kotlin.Nothing from='local final fun (): T of .FooInterface3 declared in .FooInterface3.dataBlocking' - CALL 'public abstract fun data (): T of .FooInterface3 declared in .FooInterface3' type=T of .FooInterface3 origin=null - $this: GET_VAR ': .FooInterface3.FooInterface3> declared in .FooInterface3.dataBlocking' type=.FooInterface3.FooInterface3> origin=null - FUN name:data visibility:public modality:ABSTRACT <> ($this:.FooInterface3.FooInterface3>) returnType:T of .FooInterface3 [suspend] - annotations: - JvmBlocking(baseName = , suffix = , asProperty = ) - JvmSynthetic - $this: VALUE_PARAMETER name: type:.FooInterface3.FooInterface3> - FUN name:data2 visibility:public modality:ABSTRACT ($this:.FooInterface3.FooInterface3>, value:A of .FooInterface3.data2) returnType:T of .FooInterface3 [suspend] - annotations: - JvmBlocking(baseName = , suffix = , asProperty = ) - JvmSynthetic - TYPE_PARAMETER name:A index:0 variance: superTypes:[kotlin.Any?] reified:false - $this: VALUE_PARAMETER name: type:.FooInterface3.FooInterface3> - VALUE_PARAMETER name:value index:0 type:A of .FooInterface3.data2 - FUN name:data3 visibility:public modality:ABSTRACT <> ($this:.FooInterface3.FooInterface3>, $receiver:kotlin.Int) returnType:T of .FooInterface3 [suspend] - annotations: - JvmBlocking(baseName = , suffix = , asProperty = ) - JvmSynthetic - $this: VALUE_PARAMETER name: type:.FooInterface3.FooInterface3> - $receiver: VALUE_PARAMETER name: type:kotlin.Int - CLASS INTERFACE name:FooInterface4 modality:ABSTRACT visibility:public superTypes:[kotlin.Any] - $this: VALUE_PARAMETER INSTANCE_RECEIVER name: type:.FooInterface4.FooInterface4> - TYPE_PARAMETER name:T index:0 variance: superTypes:[.Foo] reified:false - 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[love.forte.plugin.suspendtrans.fir.SuspendTransformK2V3Key] name:data2Blocking visibility:public modality:OPEN <> ($this:.FooInterface4.FooInterface4>, value:T of .FooInterface4) returnType:T of .FooInterface4 - annotations: - Api4J - $this: VALUE_PARAMETER name: type:.FooInterface4.FooInterface4> - VALUE_PARAMETER name:value index:0 type:T of .FooInterface4 - BLOCK_BODY - RETURN type=kotlin.Nothing from='public open fun data2Blocking (value: T of .FooInterface4): T of .FooInterface4 declared in .FooInterface4' - CALL 'public final fun $runInBlocking$ (block: kotlin.coroutines.SuspendFunction0): T of love.forte.plugin.suspendtrans.runtime.$runInBlocking$ declared in love.forte.plugin.suspendtrans.runtime' type=T of .FooInterface4 origin=null - : - block: FUN_EXPR type=kotlin.coroutines.SuspendFunction0.FooInterface4> origin=LAMBDA - FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL <> () returnType:T of .FooInterface4 [suspend] - BLOCK_BODY - RETURN type=kotlin.Nothing from='local final fun (): T of .FooInterface4 declared in .FooInterface4.data2Blocking' - CALL 'public abstract fun data2 (value: T of .FooInterface4): T of .FooInterface4 declared in .FooInterface4' type=T of .FooInterface4 origin=null - $this: GET_VAR ': .FooInterface4.FooInterface4> declared in .FooInterface4.data2Blocking' type=.FooInterface4.FooInterface4> origin=null - value: GET_VAR 'value: T of .FooInterface4 declared in .FooInterface4.data2Blocking' type=T of .FooInterface4 origin=null - FUN GENERATED[love.forte.plugin.suspendtrans.fir.SuspendTransformK2V3Key] name:data3Blocking visibility:public modality:OPEN <> ($this:.FooInterface4.FooInterface4>, $receiver:kotlin.Int) returnType:T of .FooInterface4 - annotations: - Api4J - $this: VALUE_PARAMETER name: type:.FooInterface4.FooInterface4> - $receiver: VALUE_PARAMETER name: type:kotlin.Int - BLOCK_BODY - RETURN type=kotlin.Nothing from='public open fun data3Blocking (): T of .FooInterface4 declared in .FooInterface4' - CALL 'public final fun $runInBlocking$ (block: kotlin.coroutines.SuspendFunction0): T of love.forte.plugin.suspendtrans.runtime.$runInBlocking$ declared in love.forte.plugin.suspendtrans.runtime' type=T of .FooInterface4 origin=null - : - block: FUN_EXPR type=kotlin.coroutines.SuspendFunction0.FooInterface4> origin=LAMBDA - FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL <> () returnType:T of .FooInterface4 [suspend] - BLOCK_BODY - RETURN type=kotlin.Nothing from='local final fun (): T of .FooInterface4 declared in .FooInterface4.data3Blocking' - CALL 'public abstract fun data3 (): T of .FooInterface4 declared in .FooInterface4' type=T of .FooInterface4 origin=null - $this: GET_VAR ': .FooInterface4.FooInterface4> declared in .FooInterface4.data3Blocking' type=.FooInterface4.FooInterface4> origin=null - $receiver: GET_VAR ': kotlin.Int declared in .FooInterface4.data3Blocking' type=kotlin.Int origin=null - FUN GENERATED[love.forte.plugin.suspendtrans.fir.SuspendTransformK2V3Key] name:dataBlocking visibility:public modality:OPEN <> ($this:.FooInterface4.FooInterface4>) returnType:T of .FooInterface4 - annotations: - Api4J - $this: VALUE_PARAMETER name: type:.FooInterface4.FooInterface4> - BLOCK_BODY - RETURN type=kotlin.Nothing from='public open fun dataBlocking (): T of .FooInterface4 declared in .FooInterface4' - CALL 'public final fun $runInBlocking$ (block: kotlin.coroutines.SuspendFunction0): T of love.forte.plugin.suspendtrans.runtime.$runInBlocking$ declared in love.forte.plugin.suspendtrans.runtime' type=T of .FooInterface4 origin=null - : - block: FUN_EXPR type=kotlin.coroutines.SuspendFunction0.FooInterface4> origin=LAMBDA - FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL <> () returnType:T of .FooInterface4 [suspend] - BLOCK_BODY - RETURN type=kotlin.Nothing from='local final fun (): T of .FooInterface4 declared in .FooInterface4.dataBlocking' - CALL 'public abstract fun data (): T of .FooInterface4 declared in .FooInterface4' type=T of .FooInterface4 origin=null - $this: GET_VAR ': .FooInterface4.FooInterface4> declared in .FooInterface4.dataBlocking' type=.FooInterface4.FooInterface4> origin=null - FUN name:data visibility:public modality:ABSTRACT <> ($this:.FooInterface4.FooInterface4>) returnType:T of .FooInterface4 [suspend] - annotations: - JvmBlocking(baseName = , suffix = , asProperty = ) - JvmSynthetic - $this: VALUE_PARAMETER name: type:.FooInterface4.FooInterface4> - FUN name:data2 visibility:public modality:ABSTRACT <> ($this:.FooInterface4.FooInterface4>, value:T of .FooInterface4) returnType:T of .FooInterface4 [suspend] - annotations: - JvmBlocking(baseName = , suffix = , asProperty = ) - JvmSynthetic - $this: VALUE_PARAMETER name: type:.FooInterface4.FooInterface4> - VALUE_PARAMETER name:value index:0 type:T of .FooInterface4 - FUN name:data3 visibility:public modality:ABSTRACT <> ($this:.FooInterface4.FooInterface4>, $receiver:kotlin.Int) returnType:T of .FooInterface4 [suspend] - annotations: - JvmBlocking(baseName = , suffix = , asProperty = ) - JvmSynthetic - $this: VALUE_PARAMETER name: type:.FooInterface4.FooInterface4> - $receiver: VALUE_PARAMETER name: type:kotlin.Int diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index d011c27..6982b43 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -13,7 +13,9 @@ kotlinx-coroutines-jdk8 = { group = "org.jetbrains.kotlinx", name = "kotlinx-cor kotlinx-coroutines-test = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-test", version.ref = "kotlinx-coroutines" } # kotlinx-serialization +kotlinx-serialization-core = { group = "org.jetbrains.kotlinx", name = "kotlinx-serialization-core", version.ref = "kotlinx-serialization" } kotlinx-serialization-json = { group = "org.jetbrains.kotlinx", name = "kotlinx-serialization-json", version.ref = "kotlinx-serialization" } +kotlinx-serialization-protobuf = { group = "org.jetbrains.kotlinx", name = "kotlinx-serialization-protobuf", version.ref = "kotlinx-serialization" } # google auto-service diff --git a/plugins/ide/suspend-transform-plugin-idea/src/main/resources/META-INF/plugin.xml b/plugins/ide/suspend-transform-plugin-idea/src/main/resources/META-INF/plugin.xml index 39a345a..da17a17 100644 --- a/plugins/ide/suspend-transform-plugin-idea/src/main/resources/META-INF/plugin.xml +++ b/plugins/ide/suspend-transform-plugin-idea/src/main/resources/META-INF/plugin.xml @@ -44,4 +44,4 @@ - \ No newline at end of file + diff --git a/plugins/suspend-transform-plugin-gradle/build.gradle.kts b/plugins/suspend-transform-plugin-gradle/build.gradle.kts index 2efccde..dbad3c8 100644 --- a/plugins/suspend-transform-plugin-gradle/build.gradle.kts +++ b/plugins/suspend-transform-plugin-gradle/build.gradle.kts @@ -3,6 +3,7 @@ import love.forte.gradle.common.publication.configure.configPublishMaven import love.forte.gradle.common.publication.configure.publishingExtension import love.forte.gradle.common.publication.configure.setupPom import org.jetbrains.kotlin.gradle.dsl.JvmTarget +import org.jetbrains.kotlin.gradle.dsl.KotlinVersion import org.jetbrains.kotlin.gradle.tasks.KotlinCompile import utils.isMainPublishable @@ -29,8 +30,17 @@ dependencies { compileOnly(gradleApi()) compileOnly(kotlin("gradle-plugin")) compileOnly(kotlin("gradle-plugin-api")) - api(project(":compiler:suspend-transform-plugin")) + // compileOnly(project(":compiler:suspend-transform-plugin")) + api(project(":compiler:suspend-transform-plugin-cli")) + api(project(":compiler:suspend-transform-plugin-configuration")) + api(project(":compiler:suspend-transform-plugin-deprecated-configuration")) +} +kotlin { + configGradleBuildSrcFriendly() + compilerOptions { + freeCompilerArgs.addAll("-Xjvm-default=all") + } } buildConfig { @@ -63,7 +73,6 @@ buildConfig { //if (!isAutomatedGradlePluginPublishing()) { if (isMainPublishable()) { - @Suppress("UnstableApiUsage") gradlePlugin { website = "https://github.com/ForteScarlet/kotlin-suspend-transform-compiler-plugin" vcsUrl = "https://github.com/ForteScarlet/kotlin-suspend-transform-compiler-plugin.git" diff --git a/plugins/suspend-transform-plugin-gradle/src/main/kotlin/love/forte/plugin/suspendtrans/gradle/SuspendTransformGradleExtension.kt b/plugins/suspend-transform-plugin-gradle/src/main/kotlin/love/forte/plugin/suspendtrans/gradle/SuspendTransformGradleExtension.kt index 363d639..3cd9832 100644 --- a/plugins/suspend-transform-plugin-gradle/src/main/kotlin/love/forte/plugin/suspendtrans/gradle/SuspendTransformGradleExtension.kt +++ b/plugins/suspend-transform-plugin-gradle/src/main/kotlin/love/forte/plugin/suspendtrans/gradle/SuspendTransformGradleExtension.kt @@ -1,41 +1,61 @@ package love.forte.plugin.suspendtrans.gradle -import love.forte.plugin.suspendtrans.SuspendTransformConfiguration - +const val USE_NEW_EXTENSION = "Use the new extension " + + "`love.forte.plugin.suspendtrans.gradle.SuspendTransformPluginExtension` " + + "(`suspendTransformPlugin { ... }`)" /** * * @author ForteScarlet */ -open class SuspendTransformGradleExtension : SuspendTransformConfiguration() { +@Suppress("DEPRECATION") +@Deprecated( + message = USE_NEW_EXTENSION, + replaceWith = ReplaceWith( + "SuspendTransformPluginExtension", + "love.forte.plugin.suspendtrans.gradle.SuspendTransformPluginExtension" + ) +) +open class SuspendTransformGradleExtension : love.forte.plugin.suspendtrans.SuspendTransformConfiguration() { + @Deprecated("Please use the " + + "`love.forte.plugin.suspendtrans.configuration.SuspendTransformConfiguration` " + + "(`suspendTransformPlugin { ... }`) instead.") + override var enabled: Boolean = true /** * 是否增加 `love.forte.plugin.suspend-transform:suspend-transform-annotation` 的运行时。 */ + @Deprecated(USE_NEW_EXTENSION) open var includeAnnotation: Boolean = true + @Deprecated(USE_NEW_EXTENSION) open var annotationDependencyVersion: String = SuspendTransPluginConstants.ANNOTATION_VERSION /** * 当 [includeAnnotation] 为 true 时,配置runtime环境的依赖方式。默认为 `compileOnly` (在JVM中) 。 */ + @Deprecated(USE_NEW_EXTENSION) open var annotationConfigurationName: String = "compileOnly" /** * 是否增加 `love.forte.plugin.suspend-transform:suspend-transform-runtime` 的运行时。 */ + @Deprecated(USE_NEW_EXTENSION) open var includeRuntime: Boolean = true + @Deprecated(USE_NEW_EXTENSION) open var runtimeDependencyVersion: String = SuspendTransPluginConstants.RUNTIME_VERSION /** * 当 [includeRuntime] 为 true 时,配置runtime环境的依赖方式。默认为 `implementation` (在JVM中)。 */ + @Deprecated(USE_NEW_EXTENSION) open var runtimeConfigurationName: String = "implementation" /** * 将runtime环境作为 `api` 的方式进行配置(在JVM中)。 */ + @Deprecated(USE_NEW_EXTENSION) open fun runtimeAsApi() { runtimeConfigurationName = "api" } diff --git a/plugins/suspend-transform-plugin-gradle/src/main/kotlin/love/forte/plugin/suspendtrans/gradle/SuspendTransformGradlePlugin.kt b/plugins/suspend-transform-plugin-gradle/src/main/kotlin/love/forte/plugin/suspendtrans/gradle/SuspendTransformGradlePlugin.kt index e5b7ec5..d0efe29 100644 --- a/plugins/suspend-transform-plugin-gradle/src/main/kotlin/love/forte/plugin/suspendtrans/gradle/SuspendTransformGradlePlugin.kt +++ b/plugins/suspend-transform-plugin-gradle/src/main/kotlin/love/forte/plugin/suspendtrans/gradle/SuspendTransformGradlePlugin.kt @@ -1,20 +1,53 @@ package love.forte.plugin.suspendtrans.gradle -import love.forte.plugin.suspendtrans.CliOptions +import love.forte.plugin.suspendtrans.cli.SuspendTransformCliOptions +import love.forte.plugin.suspendtrans.cli.encodeToHex +import love.forte.plugin.suspendtrans.configuration.* import love.forte.plugin.suspendtrans.gradle.DependencyConfigurationName.* import org.gradle.api.Project import org.gradle.api.provider.Provider import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension import org.jetbrains.kotlin.gradle.plugin.* +@Suppress("DEPRECATION") +private typealias DeprecatedClassInfo = love.forte.plugin.suspendtrans.ClassInfo +@Suppress("DEPRECATION") +private typealias DeprecatedFunctionInfo = love.forte.plugin.suspendtrans.FunctionInfo +@Suppress("DEPRECATION") +private typealias DeprecatedIncludeAnnotation = love.forte.plugin.suspendtrans.IncludeAnnotation +@Suppress("DEPRECATION") +private typealias DeprecatedMarkAnnotation = love.forte.plugin.suspendtrans.MarkAnnotation +@Suppress("DEPRECATION") +private typealias DeprecatedSuspendTransformConfiguration = love.forte.plugin.suspendtrans.SuspendTransformConfiguration +@Suppress("DEPRECATION") +private typealias DeprecatedTargetPlatform = love.forte.plugin.suspendtrans.TargetPlatform +@Suppress("DEPRECATION") +private typealias DeprecatedTransformer = love.forte.plugin.suspendtrans.Transformer /** * * @author ForteScarlet */ open class SuspendTransformGradlePlugin : KotlinCompilerPluginSupportPlugin { + companion object { + const val EXTENSION_NAME = "suspendTransform" + const val PLUGIN_EXTENSION_NAME = "suspendTransformPlugin" + } + override fun apply(target: Project) { - target.extensions.create("suspendTransform", SuspendTransformGradleExtension::class.java) + @Suppress("DEPRECATION") + target.extensions.create( + EXTENSION_NAME, + SuspendTransformGradleExtension::class.java + ) + + val createdExtensions = target.extensions.create( + PLUGIN_EXTENSION_NAME, + SuspendTransformPluginExtension::class.java, + ) + + createdExtensions.defaults(target.objects, target.providers) + target.configureDependencies() } @@ -22,7 +55,9 @@ open class SuspendTransformGradlePlugin : KotlinCompilerPluginSupportPlugin { val project = kotlinCompilation.target.project val isApplicable = project.plugins.hasPlugin(SuspendTransformGradlePlugin::class.java) - && project.configOrNull?.enabled != false + && project.configOrNull?.enabled?.get() != false + + project.logger.debug("Is suspend transform plugin applicable for {}: {}", kotlinCompilation, isApplicable) return isApplicable } @@ -41,74 +76,258 @@ open class SuspendTransformGradlePlugin : KotlinCompilerPluginSupportPlugin { override fun applyToCompilation(kotlinCompilation: KotlinCompilation<*>): Provider> { val target = kotlinCompilation.target val project = target.project - val extension = project.extensions.getByType(SuspendTransformGradleExtension::class.java) - - -// val dependencies = project.dependencies -// dependencies.add( -// "compileOnly", -// "${SuspendTransPluginConstants.ANNOTATION_GROUP}:${SuspendTransPluginConstants.ANNOTATION_NAME}:${SuspendTransPluginConstants.ANNOTATION_VERSION}" -// ) -// if (extension.includeRuntime) { -// dependencies.add( -// extension.runtimeConfigurationName, -// "${SuspendTransPluginConstants.RUNTIME_GROUP}:${SuspendTransPluginConstants.RUNTIME_NAME}:${SuspendTransPluginConstants.RUNTIME_VERSION}" -// ) -// } - - return project.provider { - extension.toSubpluginOptions() - } + + project.logger.debug("Apply suspend transform plugin to compilation {}, target: {}", kotlinCompilation, target) + + val extension = resolveExtension(project) + return extension.toSubpluginOptionsProvider(target, project) } + private fun resolveExtension(project: Project): SuspendTransformPluginExtension { + val extension = project.extensions.getByType(SuspendTransformPluginExtension::class.java) + + @Suppress("DEPRECATION") val oldExtension = + project.extensions.getByType(SuspendTransformGradleExtension::class.java) + @Suppress("DEPRECATION") + if (oldExtension.enabled && oldExtension.transformers.isNotEmpty()) { + val dontShowWarn = + project.providers.gradleProperty("love.forte.plugin.suspend-transform.suppressDeprecatedExtensionWarn") + .orNull.toBoolean() + + val msg = "WARN: The `love.forte.plugin.suspendtrans.gradle.SuspendTransformGradleExtension` " + + "(`suspendTransform { ... }`) is deprecated, \n" + + "please use `love.forte.plugin.suspendtrans.gradle.SuspendTransformPluginExtension` " + + "(`suspendTransformPlugin { ... }`) instead. \n" + + "The SuspendTransformGradleExtension property " + + "will currently be aggregated with `SuspendTransformPluginExtension`, " + + "but it will soon be deprecated completely. \n" + + "Add 'love.forte.plugin.suspend-transform.suppressDeprecatedExtensionWarn=true' " + + "to gradle.properties to suppress this warning." + + if (!dontShowWarn) { + project.logger.warn(msg) + } + + oldExtension.mergeTo(extension) + } + + return extension + } } +@Suppress("DEPRECATION", "DEPRECATION_ERROR", "TYPEALIAS_EXPANSION_DEPRECATION") +private fun SuspendTransformGradleExtension.mergeTo(extension: SuspendTransformPluginExtension) { + if (this.enabled) { + extension.enabled.convention(true) + } + if (this.includeAnnotation) { + extension.includeAnnotation.convention(true) + } -private fun SuspendTransformGradleExtension.toSubpluginOptions(): List { - return CliOptions.allOptions.map { - SubpluginOption(it.oName, it.resolveToValue(this)) + // Annotation + val deprecatedAnnotationVersion = this.annotationDependencyVersion + // Not the default value + if (deprecatedAnnotationVersion != SuspendTransPluginConstants.ANNOTATION_VERSION) { + extension.annotationDependency { + version.convention(deprecatedAnnotationVersion) + } + } + val deprecatedAnnotationConfigurationName = this.annotationConfigurationName + if (deprecatedAnnotationConfigurationName != "compileOnly") { + extension.annotationDependency { + configurationName.convention(deprecatedAnnotationConfigurationName) + } + } + + if (this.includeRuntime) { + extension.includeRuntime.convention(true) } + // Runtime + val deprecatedRuntimeVersion = this.runtimeDependencyVersion + if (deprecatedRuntimeVersion != SuspendTransPluginConstants.RUNTIME_VERSION) { + extension.runtimeDependency { + version.convention(deprecatedRuntimeVersion) + } + } + val deprecatedRuntimeConfigurationName = this.runtimeConfigurationName + if (deprecatedRuntimeConfigurationName != "implementation") { + extension.runtimeDependency { + configurationName.convention(deprecatedRuntimeConfigurationName) + } + } + + // Transformers + if (this.transformers.isNotEmpty()) { + extension.transformers { transformerContainer -> + for ((deprecatedTarget, deprecatedTransformers) in this.transformers) { + val target = deprecatedTarget.toTarget() + deprecatedTransformers.forEach { deprecatedTransformer -> + when (deprecatedTransformer) { + DeprecatedSuspendTransformConfiguration.jvmBlockingTransformer -> { + transformerContainer.add(target, SuspendTransformConfigurations.jvmBlockingTransformer) + } + + DeprecatedSuspendTransformConfiguration.jvmAsyncTransformer -> { + transformerContainer.add(target, SuspendTransformConfigurations.jvmAsyncTransformer) + } + + DeprecatedSuspendTransformConfiguration.jsPromiseTransformer -> { + transformerContainer.add(target, SuspendTransformConfigurations.jsPromiseTransformer) + } + + else -> transformerContainer.add(target, deprecatedTransformer.toTransformer()) + } + } + } + } + } +} + +@Suppress("DEPRECATION", "TYPEALIAS_EXPANSION_DEPRECATION", "KotlinRedundantDiagnosticSuppress") +private fun DeprecatedTargetPlatform.toTarget(): TargetPlatform { + return when (this) { + DeprecatedTargetPlatform.COMMON -> TargetPlatform.COMMON + DeprecatedTargetPlatform.JVM -> TargetPlatform.JVM + DeprecatedTargetPlatform.JS -> TargetPlatform.JS + DeprecatedTargetPlatform.WASM -> TargetPlatform.WASM + DeprecatedTargetPlatform.NATIVE -> TargetPlatform.NATIVE + } +} + +@OptIn(InternalSuspendTransformConfigurationApi::class) +@Suppress("TYPEALIAS_EXPANSION_DEPRECATION") +private fun DeprecatedTransformer.toTransformer(): Transformer { + return Transformer( + markAnnotation = this.markAnnotation.toMarkAnnotation(), + transformFunctionInfo = this.transformFunctionInfo.toFunctionInfo(), + transformReturnType = this.transformReturnType?.toClassInfo(), + transformReturnTypeGeneric = this.transformReturnTypeGeneric, + originFunctionIncludeAnnotations = this.originFunctionIncludeAnnotations.map { it.toIncludeAnnotation() }, + syntheticFunctionIncludeAnnotations = this.syntheticFunctionIncludeAnnotations.map { it.toIncludeAnnotation() }, + copyAnnotationsToSyntheticFunction = this.copyAnnotationsToSyntheticFunction, + copyAnnotationExcludes = this.copyAnnotationExcludes.map { it.toClassInfo() }, + copyAnnotationsToSyntheticProperty = this.copyAnnotationsToSyntheticProperty + ) +} + +@OptIn(InternalSuspendTransformConfigurationApi::class) +@Suppress("TYPEALIAS_EXPANSION_DEPRECATION") +private fun DeprecatedMarkAnnotation.toMarkAnnotation(): MarkAnnotation { + return MarkAnnotation( + classInfo = this.classInfo.toClassInfo(), + baseNameProperty = this.baseNameProperty, + suffixProperty = this.suffixProperty, + asPropertyProperty = this.asPropertyProperty, + defaultSuffix = this.defaultSuffix, + defaultAsProperty = this.defaultAsProperty + ) +} + +@OptIn(InternalSuspendTransformConfigurationApi::class) +@Suppress("TYPEALIAS_EXPANSION_DEPRECATION") +private fun DeprecatedFunctionInfo.toFunctionInfo(): FunctionInfo { + return FunctionInfo( + packageName = this.packageName, + functionName = this.functionName + ) +} + +@OptIn(InternalSuspendTransformConfigurationApi::class) +@Suppress("TYPEALIAS_EXPANSION_DEPRECATION") +private fun DeprecatedClassInfo.toClassInfo(): ClassInfo { + return ClassInfo( + packageName = this.packageName, + className = this.className, + local = this.local, + nullable = this.nullable + ) +} + +@OptIn(InternalSuspendTransformConfigurationApi::class) +@Suppress("TYPEALIAS_EXPANSION_DEPRECATION") +private fun DeprecatedIncludeAnnotation.toIncludeAnnotation(): IncludeAnnotation { + return IncludeAnnotation( + classInfo = this.classInfo.toClassInfo(), + repeatable = this.repeatable, + includeProperty = this.includeProperty + ) } +private fun SuspendTransformPluginExtension.toSubpluginOptionsProvider( + target: KotlinTarget, + project: Project +): Provider> { + return enabled + .flatMap { isEnabled -> + if (!isEnabled) { + project.logger.debug("The suspend transform is disabled for {}.", target) + return@flatMap project.provider { emptyList() } + } + + val configurationProvider = toConfigurationProvider(project.objects) + + configurationProvider.map { configuration -> + val transformers = configuration.transformers + if (transformers.isEmpty()) { + project.logger.debug("The suspend transform is enabled but transformers are empty for {}.", target) + return@map emptyList() + } + + val cliConfig = SuspendTransformCliOptions.CLI_CONFIGURATION + listOf(SubpluginOption(cliConfig.optionName, configuration.encodeToHex())) + } + } + +} private fun Project.configureDependencies() { - fun Project.include(platform: Platform, conf: SuspendTransformGradleExtension) { - if (!conf.enabled) { + fun Project.include(platform: Platform, conf: SuspendTransformPluginExtension) { + if (!conf.enabled.get()) { logger.info( - "The `SuspendTransformGradleExtension.enable` in project {} for platform {} is `false`, skip config.", + "The `SuspendTransformPluginExtension.enable` in project {} for platform {} is `false`, skip config.", this, platform ) return } - if (conf.includeAnnotation) { + if (conf.includeAnnotation.get()) { + // val notation = getDependencyNotation( val notation = getDependencyNotation( SuspendTransPluginConstants.ANNOTATION_GROUP, SuspendTransPluginConstants.ANNOTATION_NAME, platform, - conf.annotationDependencyVersion + conf.annotationDependency.flatMap { it.version } ) - if (platform == Platform.JVM) { - dependencies.add(conf.annotationConfigurationName, notation) - } else { - // JS, native 似乎不支持 compileOnly - dependencies.add("implementation", notation) + + var configName = conf.annotationDependency.get().configurationName.get() + if (configName == "compileOnly" && platform != Platform.JVM) { + configName = "implementation" } + + dependencies.add(configName, notation) dependencies.add("testImplementation", notation) } - if (conf.includeRuntime) { + + if (conf.includeRuntime.get()) { val notation = getDependencyNotation( SuspendTransPluginConstants.RUNTIME_GROUP, SuspendTransPluginConstants.RUNTIME_NAME, platform, - conf.runtimeDependencyVersion + conf.runtimeDependency.flatMap { it.version } ) - dependencies.add(conf.runtimeConfigurationName, notation) + var configName = conf.runtimeDependency.get().configurationName.get() + if (configName == "compileOnly" && platform != Platform.JVM) { + // JS, native 似乎不支持 compileOnly,因此如果不是JVM,更换为 implementation + configName = "implementation" + } + + dependencies.add(configName, notation) dependencies.add("testImplementation", notation) } } + withPluginWhenEvaluatedConf("kotlin") { conf -> include(Platform.JVM, conf) } @@ -139,7 +358,7 @@ fun Project.withPluginWhenEvaluated(plugin: String, fn: Project.() -> Unit) { fun Project.withPluginWhenEvaluatedConf( plugin: String, - fn: Project.(conf: SuspendTransformGradleExtension) -> Unit + fn: Project.(conf: SuspendTransformPluginExtension) -> Unit ) { withPluginWhenEvaluated(plugin) { fn(config) @@ -150,8 +369,8 @@ private enum class DependencyConfigurationName { API, IMPLEMENTATION, COMPILE_ONLY } -fun Project.configureMultiplatformDependency(conf: SuspendTransformGradleExtension) { - if (!conf.enabled) { +fun Project.configureMultiplatformDependency(conf: SuspendTransformPluginExtension) { + if (!conf.enabled.get()) { logger.info( "The `SuspendTransformGradleExtension.enable` in project {} for multiplatform is `false`, skip config.", this, @@ -159,6 +378,9 @@ fun Project.configureMultiplatformDependency(conf: SuspendTransformGradleExtensi return } + val sourceSetsByCompilation = sourceSetsByCompilation() + project.logger.info("Suspend transform sourceSetsByCompilation: $sourceSetsByCompilation") + // 时间久远,已经忘记为什么要做这个判断了,也忘记这段是在哪儿参考来的了💀 if (rootProject.getBooleanProperty("kotlin.mpp.enableGranularSourceSetsMetadata")) { val multiplatformExtensions = project.extensions.getByType(KotlinMultiplatformExtension::class.java) @@ -168,23 +390,23 @@ fun Project.configureMultiplatformDependency(conf: SuspendTransformGradleExtensi val commonTestSourceSets = multiplatformExtensions.sourceSets.getByName(KotlinSourceSet.COMMON_TEST_SOURCE_SET_NAME) - if (conf.includeAnnotation) { + if (conf.includeAnnotation.get()) { val notation = getDependencyNotation( SuspendTransPluginConstants.ANNOTATION_GROUP, SuspendTransPluginConstants.ANNOTATION_NAME, Platform.MULTIPLATFORM, - conf.annotationDependencyVersion + conf.annotationDependency.flatMap { it.version } ) dependencies.add(commonMainSourceSets.compileOnlyConfigurationName, notation) dependencies.add(commonTestSourceSets.implementationConfigurationName, notation) } - if (conf.includeRuntime) { + if (conf.includeRuntime.get()) { val notation = getDependencyNotation( SuspendTransPluginConstants.RUNTIME_GROUP, SuspendTransPluginConstants.RUNTIME_NAME, Platform.MULTIPLATFORM, - conf.annotationDependencyVersion + conf.runtimeDependency.flatMap { it.version } ) dependencies.add(commonMainSourceSets.implementationConfigurationName, notation) dependencies.add(commonTestSourceSets.implementationConfigurationName, notation) @@ -192,30 +414,30 @@ fun Project.configureMultiplatformDependency(conf: SuspendTransformGradleExtensi // For each source set that is only used in Native compilations, add an implementation dependency so that it // gets published and is properly consumed as a transitive dependency: - sourceSetsByCompilation().forEach { (sourceSet, compilations) -> + sourceSetsByCompilation.forEach { (sourceSet, compilations) -> val isSharedSourceSet = compilations.all { it.platformType == KotlinPlatformType.common || it.platformType == KotlinPlatformType.native || it.platformType == KotlinPlatformType.js || it.platformType == KotlinPlatformType.wasm } if (isSharedSourceSet) { - if (conf.includeAnnotation) { + if (conf.includeAnnotation.get()) { val notation = getDependencyNotation( SuspendTransPluginConstants.ANNOTATION_GROUP, SuspendTransPluginConstants.ANNOTATION_NAME, Platform.MULTIPLATFORM, - conf.annotationDependencyVersion + conf.annotationDependency.flatMap { it.version } ) val configuration = sourceSet.implementationConfigurationName dependencies.add(configuration, notation) } - if (conf.includeRuntime) { + if (conf.includeRuntime.get()) { val notation = getDependencyNotation( SuspendTransPluginConstants.RUNTIME_GROUP, SuspendTransPluginConstants.RUNTIME_NAME, Platform.MULTIPLATFORM, - conf.annotationDependencyVersion + conf.runtimeDependency.flatMap { it.version } ) val configuration = sourceSet.implementationConfigurationName dependencies.add(configuration, notation) @@ -223,7 +445,7 @@ fun Project.configureMultiplatformDependency(conf: SuspendTransformGradleExtensi } } } else { - sourceSetsByCompilation().forEach { (sourceSet, compilations) -> + sourceSetsByCompilation.forEach { (sourceSet, compilations) -> val platformTypes = compilations.map { it.platformType }.toSet() logger.info( "Configure sourceSet [{}]. compilations: {}, platformTypes: {}", @@ -257,7 +479,7 @@ fun Project.configureMultiplatformDependency(conf: SuspendTransformGradleExtensi } } - if (conf.includeAnnotation) { + if (conf.includeAnnotation.get()) { val configurationName = when { // impl dependency for native (there is no transformation) platform == Platform.NATIVE -> IMPLEMENTATION // sourceSet.implementationConfigurationName @@ -272,7 +494,7 @@ fun Project.configureMultiplatformDependency(conf: SuspendTransformGradleExtensi SuspendTransPluginConstants.ANNOTATION_GROUP, SuspendTransPluginConstants.ANNOTATION_NAME, platform, - conf.annotationDependencyVersion + conf.annotationDependency.flatMap { it.version } ) sourceSet.dependencies { @@ -300,14 +522,14 @@ fun Project.configureMultiplatformDependency(conf: SuspendTransformGradleExtensi ) } - if (conf.includeRuntime) { + if (conf.includeRuntime.get()) { // val configurationName = sourceSet.implementationConfigurationName val notation = getDependencyNotation( SuspendTransPluginConstants.RUNTIME_GROUP, SuspendTransPluginConstants.RUNTIME_NAME, platform, - conf.runtimeDependencyVersion + conf.runtimeDependency.flatMap { it.version } ) sourceSet.dependencies { implementation(notation) @@ -353,11 +575,11 @@ private fun String.compilationNameToType(): CompilationType? = when (this) { else -> null } -private val Project.config: SuspendTransformGradleExtension - get() = configOrNull ?: SuspendTransformGradleExtension() +private val Project.config: SuspendTransformPluginExtension + get() = configOrNull ?: objects.newInstance(SuspendTransformPluginExtension::class.java) -private val Project.configOrNull: SuspendTransformGradleExtension? - get() = extensions.findByType(SuspendTransformGradleExtension::class.java) +private val Project.configOrNull: SuspendTransformPluginExtension? + get() = extensions.findByType(SuspendTransformPluginExtension::class.java) private enum class Platform(val suffix: String) { JVM("-jvm"), JS("-js"), NATIVE(""), MULTIPLATFORM("") @@ -366,5 +588,13 @@ private enum class Platform(val suffix: String) { private fun getDependencyNotation(group: String, name: String, platform: Platform, version: String): String = "$group:$name${platform.suffix}:$version" +private fun getDependencyNotation( + group: String, + name: String, + platform: Platform, + version: Provider +): Provider = + version.map { versionValue -> getDependencyNotation(group, name, platform, versionValue) } + private fun Project.getBooleanProperty(name: String) = rootProject.findProperty(name)?.toString()?.toBooleanStrict() ?: false diff --git a/plugins/suspend-transform-plugin-gradle/src/main/kotlin/love/forte/plugin/suspendtrans/gradle/SuspendTransformPluginExtension.kt b/plugins/suspend-transform-plugin-gradle/src/main/kotlin/love/forte/plugin/suspendtrans/gradle/SuspendTransformPluginExtension.kt new file mode 100644 index 0000000..1e4ab91 --- /dev/null +++ b/plugins/suspend-transform-plugin-gradle/src/main/kotlin/love/forte/plugin/suspendtrans/gradle/SuspendTransformPluginExtension.kt @@ -0,0 +1,920 @@ +package love.forte.plugin.suspendtrans.gradle + +import love.forte.plugin.suspendtrans.configuration.* +import love.forte.plugin.suspendtrans.configuration.SuspendTransformConfigurations.jsPromiseTransformer +import love.forte.plugin.suspendtrans.configuration.SuspendTransformConfigurations.jvmAsyncTransformer +import love.forte.plugin.suspendtrans.configuration.SuspendTransformConfigurations.jvmBlockingTransformer +import org.gradle.api.Action +import org.gradle.api.DomainObjectSet +import org.gradle.api.model.ObjectFactory +import org.gradle.api.provider.ListProperty +import org.gradle.api.provider.Property +import org.gradle.api.provider.Provider +import org.gradle.api.provider.ProviderFactory +import java.util.* +import javax.inject.Inject + +/** + * @since 0.12.0 + */ +@DslMarker +annotation class SuspendTransformPluginExtensionSpecDslMarker + +/** + * @since 0.12.0 + */ +@SuspendTransformPluginExtensionSpecDslMarker +interface SuspendTransformPluginExtensionSpec + +/** + * @since 0.12.0 + */ +@SuspendTransformPluginExtensionSpecDslMarker +interface SuspendTransformPluginExtensionClassInfoSpec : SuspendTransformPluginExtensionSpec { + fun classInfo(action: Action) + fun classInfo(action: ClassInfoSpec.() -> Unit) +} + +/** + * @since 0.12.0 + */ +@Suppress("unused") +interface SuspendTransformPluginExtensionSpecFactory { + fun createClassInfo(action: Action): ClassInfoSpec + fun createClassInfo(action: ClassInfoSpec.() -> Unit): ClassInfoSpec = + createClassInfo(Action(action)) + + fun createClassInfo(): ClassInfoSpec = + createClassInfo { } + + fun createMarkAnnotation(action: Action): MarkAnnotationSpec + fun createMarkAnnotation(action: MarkAnnotationSpec.() -> Unit): MarkAnnotationSpec = + createMarkAnnotation(Action(action)) + + fun createMarkAnnotation(): MarkAnnotationSpec = + createMarkAnnotation { } + + fun createFunctionInfo(action: Action): FunctionInfoSpec + fun createFunctionInfo(action: FunctionInfoSpec.() -> Unit): FunctionInfoSpec = + createFunctionInfo(Action(action)) + + fun createFunctionInfo(): FunctionInfoSpec = + createFunctionInfo { } + + fun createIncludeAnnotation(action: Action): IncludeAnnotationSpec + fun createIncludeAnnotation(action: IncludeAnnotationSpec.() -> Unit): IncludeAnnotationSpec = + createIncludeAnnotation(Action(action)) + + fun createIncludeAnnotation(): IncludeAnnotationSpec = + createIncludeAnnotation { } + + fun createRuntimeDependency(action: Action): RuntimeDependencySpec + fun createRuntimeDependency(action: RuntimeDependencySpec.() -> Unit): RuntimeDependencySpec = + createRuntimeDependency(Action(action)) + + fun createRuntimeDependency(): RuntimeDependencySpec = + createRuntimeDependency { } + + fun createAnnotationDependency(action: Action): AnnotationDependencySpec + fun createAnnotationDependency(action: AnnotationDependencySpec.() -> Unit): AnnotationDependencySpec = + createAnnotationDependency(Action(action)) + + fun createAnnotationDependency(): AnnotationDependencySpec = + createAnnotationDependency { } + + fun createTransformFunctionInfo(action: Action): FunctionInfoSpec + fun createTransformFunctionInfo(action: FunctionInfoSpec.() -> Unit): FunctionInfoSpec = + createTransformFunctionInfo(Action(action)) + + fun createTransformFunctionInfo(): FunctionInfoSpec = + createTransformFunctionInfo { } + + fun createTransformer(action: Action): TransformerSpec + fun createTransformer(action: TransformerSpec.() -> Unit): TransformerSpec = + createTransformer(Action(action)) + + fun createTransformer(): TransformerSpec = + createTransformer { } +} + +/** + * @since 0.12.0 + */ +interface SuspendTransformPluginExtensionSpecFactoryAware { + val factory: SuspendTransformPluginExtensionSpecFactory +} + +private class SuspendTransformPluginExtensionSpecFactoryImpl( + private val objects: ObjectFactory, +) : SuspendTransformPluginExtensionSpecFactory { + override fun createClassInfo(action: Action): ClassInfoSpec { + return objects.newInstance().also(action::execute) + } + + override fun createAnnotationDependency(action: Action): AnnotationDependencySpec { + return objects.newInstance().also(action::execute) + } + + override fun createMarkAnnotation(action: Action): MarkAnnotationSpec { + return objects.newInstance().also(action::execute) + } + + override fun createFunctionInfo(action: Action): FunctionInfoSpec { + return objects.newInstance().also(action::execute) + } + + override fun createIncludeAnnotation(action: Action): IncludeAnnotationSpec { + return objects.newInstance().also(action::execute) + } + + override fun createRuntimeDependency(action: Action): RuntimeDependencySpec { + return objects.newInstance().also(action::execute) + } + + override fun createTransformFunctionInfo(action: Action): FunctionInfoSpec { + return objects.newInstance().also(action::execute) + } + + override fun createTransformer(action: Action): TransformerSpec { + return objects.newInstance().also(action::execute) + } +} + +/** + * @since 0.12.0 + */ +@Suppress("unused") +abstract class TransformersContainer +@Inject constructor( + private val objects: ObjectFactory +) : SuspendTransformPluginExtensionSpec, + SuspendTransformPluginExtensionSpecFactoryAware { + override val factory: SuspendTransformPluginExtensionSpecFactory = + SuspendTransformPluginExtensionSpecFactoryImpl(objects) + + // mutableMapOf() + internal val containers: MutableMap> = + EnumMap(TargetPlatform::class.java) + // TODO Maybe ... + // containers: NamedDomainObjectContainer = + // objects.domainObjectContainer(TransformerSpecContainer::class.java) { name -> + // objects.newInstance(TransformerSpecContainer::class.java, name) + // } + // abstract class TransformerSpecContainer @Inject constructor(name: String) { + // val targetPlatform: TargetPlatform = TargetPlatform.valueOf(name) + // abstract val transformerSet: DomainObjectSet + // } + + + private fun getTransformersInternal(platform: TargetPlatform): ListProperty { + // return containers.maybeCreate(platform.name).transformerSet + return containers.computeIfAbsent(platform) { objects.listProperty(TransformerSpec::class.java) } + } + + /** + * Create a [TransformerSpec] but not add. + */ + fun createTransformer(action: Action): TransformerSpec { + return objects.newInstance().also(action::execute) + } + + /** + * Create a [TransformerSpec] but not add. + */ + fun createTransformer(action: TransformerSpec.() -> Unit): TransformerSpec { + return factory.createTransformer(action) + } + + fun add(platform: TargetPlatform, action: Action) { + val transformerSpecs = getTransformersInternal(platform) + transformerSpecs.add(createTransformer(action)) + } + + fun add(platform: TargetPlatform, action: TransformerSpec.() -> Unit) { + val transformerSpecs = getTransformersInternal(platform) + transformerSpecs.add(createTransformer(action)) + } + + fun add(platform: TargetPlatform, transformer: TransformerSpec) { + val transformerSpecs = getTransformersInternal(platform) + transformerSpecs.add(transformer) + } + + fun add(platform: TargetPlatform, transformer: Provider) { + val transformerSpecs = getTransformersInternal(platform) + transformerSpecs.add(transformer) + } + + fun add(platform: TargetPlatform, transformer: Transformer) { + add(platform) { + from(transformer) + } + } + + fun addJvm(transformer: TransformerSpec) = add(TargetPlatform.JVM, transformer) + fun addJvm(transformer: Transformer) = addJvm { from(transformer) } + fun addJvm(transformer: Provider) = add(TargetPlatform.JVM, transformer) + fun addJvm(action: Action) = add(TargetPlatform.JVM, action) + fun addJvm(action: TransformerSpec.() -> Unit) = add(TargetPlatform.JVM, action) + + fun addJs(transformer: TransformerSpec) = add(TargetPlatform.JS, transformer) + fun addJs(transformer: Transformer) = addJs { from(transformer) } + fun addJs(transformer: Provider) = add(TargetPlatform.JS, transformer) + fun addJs(action: Action) = add(TargetPlatform.JS, action) + fun addJs(action: TransformerSpec.() -> Unit) = add(TargetPlatform.JS, action) + + fun addNative(transformer: TransformerSpec) = add(TargetPlatform.NATIVE, transformer) + fun addNative(transformer: Transformer) = addNative { from(transformer) } + fun addNative(transformer: Provider) = add(TargetPlatform.NATIVE, transformer) + fun addNative(action: Action) = add(TargetPlatform.NATIVE, action) + fun addNative(action: TransformerSpec.() -> Unit) = add(TargetPlatform.NATIVE, action) + + fun addWasm(transformer: TransformerSpec) = add(TargetPlatform.WASM, transformer) + fun addWasm(transformer: Transformer) = addWasm { from(transformer) } + fun addWasm(transformer: Provider) = add(TargetPlatform.WASM, transformer) + fun addWasm(action: Action) = add(TargetPlatform.WASM, action) + fun addWasm(action: TransformerSpec.() -> Unit) = add(TargetPlatform.WASM, action) + + fun addCommon(transformer: TransformerSpec) = add(TargetPlatform.COMMON, transformer) + fun addCommon(transformer: Transformer) = addCommon { from(transformer) } + fun addCommon(transformer: Provider) = add(TargetPlatform.COMMON, transformer) + fun addCommon(action: TransformerSpec.() -> Unit) = add(TargetPlatform.COMMON, action) + + + // JVM defaults + fun addJvmBlocking() { + addJvm(jvmBlockingTransformer) + } + + fun addJvmBlocking(action: Action) { + addJvm { + from(jvmBlockingTransformer) + action.execute(this) + } + } + + fun addJvmBlocking(action: TransformerSpec.() -> Unit) { + addJvm { + from(jvmBlockingTransformer) + action() + } + } + + fun addJvmAsync() { + addJvm(jvmAsyncTransformer) + } + + fun addJvmAsync(action: Action) { + addJvm { + from(jvmAsyncTransformer) + action.execute(this) + } + } + + fun addJvmAsync(action: TransformerSpec.() -> Unit) { + addJvm { + from(jvmAsyncTransformer) + action() + } + } + + // JS defaults + + /** + * Add [jsPromiseTransformer] + */ + fun addJsPromise() { + addJs(jsPromiseTransformer) + } + + /** + * Add a js transformer based on [jsPromiseTransformer] + */ + fun addJsPromise(action: TransformerSpec.() -> Unit) { + addJs { + from(jsPromiseTransformer) + action() + } + } + + fun useJvmDefault() { + addJvmBlocking() + addJvmAsync() + } + + fun useJsDefault() { + addJsPromise() + } + + fun useDefault() { + useJvmDefault() + useJsDefault() + } +} + +/** + * @since 0.12.0 + */ +@Suppress("unused") +abstract class SuspendTransformPluginExtension +@Inject constructor(objects: ObjectFactory) : SuspendTransformPluginExtensionSpec { + /** + * Enabled plugin. + * + * Default is `true`. + */ + abstract val enabled: Property + + val transformers: TransformersContainer = objects.newInstance() + + fun transformers(action: Action) { + action.execute(transformers) + } + + fun transformers(action: TransformersContainer.() -> Unit) { + action(transformers) + } + + /** + * Include the `love.forte.plugin.suspend-transform:suspend-transform-annotation`. + * Default is `true`. + */ + abstract val includeAnnotation: Property + + /** + * Include the `love.forte.plugin.suspend-transform:suspend-transform-runtime`. + * Default is `true`. + */ + abstract val includeRuntime: Property + + /** + * Default is `compileOnly` with [SuspendTransPluginConstants.ANNOTATION_VERSION] + */ + abstract val annotationDependency: Property + + fun annotationDependency(action: Action) { + annotationDependency.set(annotationDependency.get().also(action::execute)) + } + + fun annotationDependency(action: AnnotationDependencySpec.() -> Unit) { + annotationDependency.set(annotationDependency.get().also(action)) + } + + /** + * Default is `implementation` with [SuspendTransPluginConstants.RUNTIME_VERSION] + */ + abstract val runtimeDependency: Property + + fun runtimeDependency(action: Action) { + runtimeDependency.set(runtimeDependency.get().also(action::execute)) + } + + fun runtimeDependency(action: RuntimeDependencySpec.() -> Unit) { + runtimeDependency.set(runtimeDependency.get().also(action)) + } + + fun runtimeAsApi() { + runtimeDependency.get().configurationName.set("api") + } +} + +internal data class TransformerEntry( + val targetPlatform: TargetPlatform, + val transformers: List +) + +@OptIn(InternalSuspendTransformConfigurationApi::class) +internal fun SuspendTransformPluginExtension.toConfigurationProvider(objects: ObjectFactory): Provider { + val combines = objects.listProperty(TransformerEntry::class.java) + for ((targetPlatform, transformerListProperty) in transformers.containers) { + combines.addAll( + transformerListProperty.map { list -> + if (list.isEmpty()) { + // Type mismatch: inferred type is TransformerEntry? but TransformerEntry was expected + // if return null with `combines.add` + emptyList() + } else { + listOf( + TransformerEntry(targetPlatform, list.map { it.toTransformer() }) + ) + } + } + ) + } + + return combines.map { entries -> + val transformersMap: Map> = entries.associateBy( + keySelector = { it.targetPlatform }, + valueTransform = { it.transformers } + ) + + // 此处 `Map` 可能为 空,但是 `List` 不会有空的。 + // 后续在使用的时候只需要判断一下 transformers 本身是不是空即可。 + SuspendTransformConfiguration( + transformers = transformersMap + ) + } + +} + +/** + * @since 0.12.0 + */ +sealed interface DependencySpec : SuspendTransformPluginExtensionSpec { + val version: Property + val configurationName: Property +} + +/** + * @since 0.12.0 + */ +interface AnnotationDependencySpec : DependencySpec { + /** + * Default is `compileOnly`. + */ + override val configurationName: Property + + /** + * Default is [SuspendTransPluginConstants.ANNOTATION_VERSION] + */ + override val version: Property +} + +/** + * @since 0.12.0 + */ +interface RuntimeDependencySpec : DependencySpec { + /** + * Default is `implementation`. + */ + override val configurationName: Property + + /** + * Default is [SuspendTransPluginConstants.RUNTIME_VERSION] + */ + override val version: Property +} + +internal fun SuspendTransformPluginExtension.defaults( + objects: ObjectFactory, + providers: ProviderFactory +) { + enabled.convention(true) + includeAnnotation.convention(true) + includeRuntime.convention(true) + annotationDependency.convention(providers.provider { + objects.newInstance(AnnotationDependencySpec::class.java).apply { + version.convention(SuspendTransPluginConstants.ANNOTATION_VERSION) + configurationName.convention("compileOnly") + } + }) + runtimeDependency.convention(providers.provider { + objects.newInstance(RuntimeDependencySpec::class.java).apply { + version.convention(SuspendTransPluginConstants.RUNTIME_VERSION) + configurationName.convention("implementation") + } + }) +} + +/** + * @since 0.12.0 + */ +@Suppress("unused") +abstract class TransformerSpec +@Inject constructor(private val objects: ObjectFactory) : SuspendTransformPluginExtensionSpec { + /** + * @see Transformer.markAnnotation + */ + abstract val markAnnotation: Property + + fun markAnnotation(action: Action) { + val old = markAnnotation.getOrElse(objects.newInstance()) + markAnnotation.set(old.also(action::execute)) + } + + fun markAnnotation(action: MarkAnnotationSpec.() -> Unit) { + val old = markAnnotation.getOrElse(objects.newInstance()) + markAnnotation.set(old.also(action)) + } + + /** + * 用于转化的函数信息。 + * + * 这个函数的实际格式必须为 + * + * ```kotlin + * fun (block: suspend () -> T[, scope: CoroutineScope = ...]): T { + * // ... + * } + * ``` + * + * 其中,此异步函数可以有第二个参数,此参数格式必须为 [kotlinx.coroutines.CoroutineScope]。 + * 如果存在此参数,当转化函数所处类型自身实现了 [kotlinx.coroutines.CoroutineScope] 时,将会将其自身作为参数填入,类似于: + * + * ```kotlin + * class Bar : CoroutineScope { + * @Xxx + * suspend fun foo(): Foo + * + * @Api4J fun fooXxx(): CompletableFuture = transform(block = { foo() }, scope = this) + * } + */ + @Suppress("KDocUnresolvedReference") + abstract val transformFunctionInfo: Property + + fun transformFunctionInfo(action: Action) { + transformFunctionInfo.set( + transformFunctionInfo.getOrElse( + objects.newInstance() + ).also(action::execute) + ) + } + + fun transformFunctionInfo(action: FunctionInfoSpec.() -> Unit) { + transformFunctionInfo.set( + transformFunctionInfo.getOrElse( + objects.newInstance() + ).also(action) + ) + } + + /** + * 转化后的返回值类型, 为null时代表与原函数一致。 + * + * Will be used when [transformReturnTypeGeneric] is `true`. + */ + abstract val transformReturnType: Property + + fun transformReturnType(action: Action) { + transformReturnType.set( + transformReturnType.getOrElse( + objects.newInstance() + ).also(action::execute) + ) + } + + fun transformReturnType(action: ClassInfoSpec.() -> Unit) { + transformReturnType.set( + transformReturnType.getOrElse( + objects.newInstance() + ).also(action) + ) + } + + /** + * 转化后的返回值类型中,是否存在需要与原本返回值类型一致的泛型。 + * 这里指的是返回值类型中嵌套的范型,例如 `CompletableFuture` 中的 `T`。 + * 如果是直接返回 `T`,则不需要设置为 `true`。 + * + * Default value is `false`. + */ + val transformReturnTypeGeneric: Property = + objects.property(Boolean::class.java).convention(false) + + fun transformReturnTypeGeneric() { + transformReturnTypeGeneric.set(true) + } + + /** + * 函数生成后,需要在原函数上追加的注解信息。 + * + * 例如追加个 `@kotlin.jvm.JvmSynthetic` 之类的。 + */ + abstract val originFunctionIncludeAnnotations: DomainObjectSet + + private fun newIncludeAnnotationSpec(): IncludeAnnotationSpec = + objects.newInstance() + + fun createIncludeAnnotation(action: Action): IncludeAnnotationSpec { + return newIncludeAnnotationSpec().also(action::execute) + } + + fun createIncludeAnnotation(action: IncludeAnnotationSpec.() -> Unit): IncludeAnnotationSpec { + return newIncludeAnnotationSpec().also(action) + } + + fun addOriginFunctionIncludeAnnotation(action: Action) { + originFunctionIncludeAnnotations.add( + newIncludeAnnotationSpec().also(action::execute) + ) + } + + fun addOriginFunctionIncludeAnnotation(action: IncludeAnnotationSpec.() -> Unit) { + originFunctionIncludeAnnotations.add( + newIncludeAnnotationSpec().also(action) + ) + } + + abstract val syntheticFunctionIncludeAnnotations: DomainObjectSet + + fun addSyntheticFunctionIncludeAnnotation(action: Action) { + syntheticFunctionIncludeAnnotations.add(createIncludeAnnotation(action)) + } + + fun addSyntheticFunctionIncludeAnnotation(action: IncludeAnnotationSpec.() -> Unit) { + syntheticFunctionIncludeAnnotations.add(createIncludeAnnotation(action)) + } + + /** + * 是否复制源函数上的注解到新的函数上。 + * 如果生成的是属性类型,则表示是否复制到 `getter` 上。 + * + * Default value is `false`. + */ + val copyAnnotationsToSyntheticFunction: Property = + objects.property(Boolean::class.java).convention(false) + + fun copyAnnotationsToSyntheticFunction() { + copyAnnotationsToSyntheticFunction.set(true) + } + + /** + * 复制原函数上注解时需要排除掉的注解。 + */ + abstract val copyAnnotationExcludes: DomainObjectSet + + /** + * Add a [ClassInfoSpec] into [copyAnnotationExcludes] + */ + fun addCopyAnnotationExclude(action: Action) { + copyAnnotationExcludes.add(createCopyAnnotationExclude(action)) + } + + /** + * Add a [ClassInfoSpec] into [copyAnnotationExcludes] + */ + fun addCopyAnnotationExclude(action: ClassInfoSpec.() -> Unit) { + copyAnnotationExcludes.add(createCopyAnnotationExclude(action)) + } + + /** + * Create a [ClassInfoSpec] but does not add. + */ + fun createCopyAnnotationExclude(action: Action): ClassInfoSpec { + return objects.newInstance().also(action::execute) + } + + /** + * Create a [ClassInfoSpec] but does not add. + */ + fun createCopyAnnotationExclude(action: ClassInfoSpec.() -> Unit): ClassInfoSpec { + return objects.newInstance().also(action) + } + + /** + * 如果是生成属性的话,是否复制源函数上的注解到新的属性上 + * + * @since 0.9.0 + */ + val copyAnnotationsToSyntheticProperty: Property = + objects.property(Boolean::class.java).convention(false) + + fun copyAnnotationsToSyntheticProperty() { + copyAnnotationsToSyntheticProperty.set(true) + } + + /** + * Configures the current specification using a [Transformer]. + * + * @param transformer see [Transformer] or the constants in [SuspendTransformConfigurations], + * e.g. [SuspendTransformConfigurations.jvmBlockingTransformer]. + */ + fun from(transformer: Transformer) { + markAnnotation { from(transformer.markAnnotation) } + transformFunctionInfo { from(transformer.transformFunctionInfo) } + transformer.transformReturnType?.also { transformReturnType -> + transformReturnType { from(transformReturnType) } + } + transformReturnTypeGeneric.set(transformer.transformReturnTypeGeneric) + for (originFunctionIncludeAnnotation in transformer.originFunctionIncludeAnnotations) { + addOriginFunctionIncludeAnnotation { + from(originFunctionIncludeAnnotation) + } + } + + for (syntheticFunctionIncludeAnnotation in transformer.syntheticFunctionIncludeAnnotations) { + addSyntheticFunctionIncludeAnnotation { + from(syntheticFunctionIncludeAnnotation) + } + } + + copyAnnotationsToSyntheticFunction.set(transformer.copyAnnotationsToSyntheticFunction) + + for (copyAnnotationExclude in transformer.copyAnnotationExcludes) { + addCopyAnnotationExclude { + from(copyAnnotationExclude) + } + } + + copyAnnotationsToSyntheticProperty.set(transformer.copyAnnotationsToSyntheticProperty) + } +} + +/** + * @see MarkAnnotation + */ +/** + * @since 0.12.0 + */ +@Suppress("unused") +abstract class MarkAnnotationSpec +@Inject constructor(private val objects: ObjectFactory) : + SuspendTransformPluginExtensionSpec, + SuspendTransformPluginExtensionClassInfoSpec { + /** + * The mark annotation's class info. + */ + abstract val classInfo: Property + + override fun classInfo(action: Action) { + classInfo.set(classInfo.getOrElse(objects.newInstance()).also(action::execute)) + } + + override fun classInfo(action: ClassInfoSpec.() -> Unit) { + classInfo.set(classInfo.getOrElse(objects.newInstance()).also(action)) + } + + /** + * 用于标记生成函数需要使用的基础函数名的注解属性名。 + * + * Default value is `"baseName"` + */ + val baseNameProperty: Property = + objects.property(String::class.java).convention("baseName") + + /** + * 用于标记生成函数需要使用的基础函数名之后的后缀的注解属性名。 + * + * Default value is `"suffix"` + */ + val suffixProperty: Property = + objects.property(String::class.java).convention("suffix") + + /** + * 用于标记生成函数是否需要转化为 property 类型的注解属性名。 + * + * Default value is `"asProperty"` + */ + val asPropertyProperty: Property = + objects.property(String::class.java).convention("asProperty") + + /** + * 当 [suffixProperty] 不存在时使用的默认后缀 + * + * Default value is `""` + */ + val defaultSuffix: Property = + objects.property(String::class.java).convention("") + + /** + * 当 [asPropertyProperty] 不存在时使用的默认值 + */ + val defaultAsProperty: Property = + objects.property(Boolean::class.java).convention(false) + + fun from(markAnnotation: MarkAnnotation) { + classInfo { + from(markAnnotation.classInfo) + } + baseNameProperty.set(markAnnotation.baseNameProperty) + suffixProperty.set(markAnnotation.suffixProperty) + asPropertyProperty.set(markAnnotation.asPropertyProperty) + defaultSuffix.set(markAnnotation.defaultSuffix) + defaultAsProperty.set(markAnnotation.defaultAsProperty) + } +} + +/** + * @see ClassInfo + */ +/** + * @since 0.12.0 + */ +interface ClassInfoSpec : SuspendTransformPluginExtensionSpec { + val packageName: Property + val className: Property + + /** + * Default value is `false` + */ + val local: Property + + /** + * Default value is `false` + */ + val nullable: Property + + fun from(classInfo: ClassInfo) { + packageName.set(classInfo.packageName) + className.set(classInfo.className) + local.set(classInfo.local) + nullable.set(classInfo.nullable) + } +} + +/** + * @since 0.12.0 + */ +interface FunctionInfoSpec : SuspendTransformPluginExtensionSpec { + val packageName: Property + val functionName: Property + + fun from(functionInfo: FunctionInfo) { + packageName.set(functionInfo.packageName) + functionName.set(functionInfo.functionName) + } +} + +/** + * @since 0.12.0 + */ +@Suppress("unused") +abstract class IncludeAnnotationSpec +@Inject constructor(private val objects: ObjectFactory) : + SuspendTransformPluginExtensionSpec, + SuspendTransformPluginExtensionClassInfoSpec { + abstract val classInfo: Property + + override fun classInfo(action: Action) { + classInfo.set(classInfo.getOrElse(objects.newInstance()).also(action::execute)) + } + + override fun classInfo(action: ClassInfoSpec.() -> Unit) { + classInfo.set(classInfo.getOrElse(objects.newInstance()).also(action)) + } + + /** + * Default value is `false` + */ + abstract val repeatable: Property + + /** + * Default value is `false` + */ + abstract val includeProperty: Property + + fun from(includeAnnotation: IncludeAnnotation) { + classInfo { + from(includeAnnotation.classInfo) + } + repeatable.set(includeAnnotation.repeatable) + includeProperty.set(includeAnnotation.includeProperty) + } +} + +@OptIn(InternalSuspendTransformConfigurationApi::class) +internal fun TransformerSpec.toTransformer(): Transformer { + return Transformer( + markAnnotation = markAnnotation.get().toMarkAnnotation(), + transformFunctionInfo = transformFunctionInfo.get().toFunctionInfo(), + transformReturnType = transformReturnType.orNull?.toClassInfo(), + transformReturnTypeGeneric = transformReturnTypeGeneric.getOrElse(false), + originFunctionIncludeAnnotations = originFunctionIncludeAnnotations.map { it.toIncludeAnnotation() }.toList(), + syntheticFunctionIncludeAnnotations = syntheticFunctionIncludeAnnotations.map { it.toIncludeAnnotation() } + .toList(), + copyAnnotationsToSyntheticFunction = copyAnnotationsToSyntheticFunction.getOrElse(false), + copyAnnotationExcludes = copyAnnotationExcludes.map { it.toClassInfo() }.toList(), + copyAnnotationsToSyntheticProperty = copyAnnotationsToSyntheticProperty.get() + ) +} + +@OptIn(InternalSuspendTransformConfigurationApi::class) +internal fun MarkAnnotationSpec.toMarkAnnotation(): MarkAnnotation { + return MarkAnnotation( + classInfo = classInfo.get().toClassInfo(), + baseNameProperty = baseNameProperty.get(), + suffixProperty = suffixProperty.get(), + asPropertyProperty = asPropertyProperty.get(), + defaultSuffix = defaultSuffix.get(), + defaultAsProperty = defaultAsProperty.get() + ) +} + +@OptIn(InternalSuspendTransformConfigurationApi::class) +internal fun ClassInfoSpec.toClassInfo(): ClassInfo { + return ClassInfo( + packageName = packageName.get(), + className = className.get(), + local = local.getOrElse(false), + nullable = nullable.getOrElse(false) + ) +} + +@OptIn(InternalSuspendTransformConfigurationApi::class) +internal fun FunctionInfoSpec.toFunctionInfo(): FunctionInfo { + return FunctionInfo( + packageName = packageName.get(), + functionName = functionName.get() + ) +} + +@OptIn(InternalSuspendTransformConfigurationApi::class) +internal fun IncludeAnnotationSpec.toIncludeAnnotation(): IncludeAnnotation { + return IncludeAnnotation( + classInfo = classInfo.get().toClassInfo(), + repeatable = repeatable.getOrElse(false), + includeProperty = includeProperty.getOrElse(false) + ) +} + +private inline fun ObjectFactory.newInstance(): T = newInstance(T::class.java) diff --git a/settings.gradle.kts b/settings.gradle.kts index 619a39c..0e3c35b 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,6 +1,5 @@ rootProject.name = "kotlin-suspend-transform-compiler-plugin" -// compose for test enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS") pluginManagement { repositories { @@ -8,18 +7,24 @@ pluginManagement { google() gradlePluginPortal() mavenCentral() + mavenLocal() } } -@Suppress("UnstableApiUsage") + dependencyResolutionManagement { + @Suppress("UnstableApiUsage") repositories { google() mavenCentral() maven("https://maven.pkg.jetbrains.space/public/p/compose/dev") + // mavenLocal() } } include(":compiler:suspend-transform-plugin") +include(":compiler:suspend-transform-plugin-cli") +include(":compiler:suspend-transform-plugin-deprecated-configuration") +include(":compiler:suspend-transform-plugin-configuration") include(":compiler:suspend-transform-plugin-embeddable") include(":runtime:suspend-transform-annotation") diff --git a/tests/build.gradle.kts b/tests/build.gradle.kts new file mode 100644 index 0000000..98948c1 --- /dev/null +++ b/tests/build.gradle.kts @@ -0,0 +1,3 @@ +plugins { + id("love.forte.plugin.suspend-transform") version "2.1.20-0.12.0" apply false +} diff --git a/tests/test-js/build.gradle.kts b/tests/test-js/build.gradle.kts index a5cbd9b..60fb60a 100644 --- a/tests/test-js/build.gradle.kts +++ b/tests/test-js/build.gradle.kts @@ -1,22 +1,9 @@ -import love.forte.plugin.suspendtrans.ClassInfo -import love.forte.plugin.suspendtrans.SuspendTransformConfiguration -import love.forte.plugin.suspendtrans.TargetPlatform -import love.forte.plugin.suspendtrans.gradle.SuspendTransformGradleExtension +import love.forte.plugin.suspendtrans.configuration.SuspendTransformConfigurations.kotlinJsExportIgnoreClassInfo import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi plugins { kotlin("multiplatform") -} - - -buildscript { - this@buildscript.repositories { - mavenLocal() - mavenCentral() - } - dependencies { - classpath("love.forte.plugin.suspend-transform:suspend-transform-plugin-gradle:2.1.0-0.11.1") - } + id("love.forte.plugin.suspend-transform") } repositories { @@ -64,16 +51,46 @@ kotlin { } } -extensions.getByType().apply { +// suspendTransformPlugin { +// includeRuntime = false +// includeAnnotation = false +// transformers { +// addJsPromise { +// addCopyAnnotationExclude { +// from(kotlinJsExportIgnoreClassInfo) +// } +// } +// } +// } + +suspendTransformPlugin { includeRuntime = false includeAnnotation = false + transformers { + addJsPromise { + addOriginFunctionIncludeAnnotation { + classInfo { + from(kotlinJsExportIgnoreClassInfo) + } + } - transformers[TargetPlatform.JS] = mutableListOf( - SuspendTransformConfiguration.jsPromiseTransformer.copy( - copyAnnotationExcludes = listOf( - ClassInfo("kotlin.js", "JsExport.Ignore") - ) - ) - ) - + addCopyAnnotationExclude { + from(kotlinJsExportIgnoreClassInfo) + } + } + } } + +// extensions.getByType().apply { +// includeRuntime = false +// includeAnnotation = false +// +// transformers[TargetPlatform.JS] = mutableListOf( +// SuspendTransformConfiguration.jsPromiseTransformer.copy( +// copyAnnotationExcludes = listOf( +// ClassInfo("kotlin.js", "JsExport.Ignore") +// ) +// ) +// ) +// +// } diff --git a/tests/test-jvm/build.gradle.kts b/tests/test-jvm/build.gradle.kts index 979f8b1..743e100 100644 --- a/tests/test-jvm/build.gradle.kts +++ b/tests/test-jvm/build.gradle.kts @@ -1,32 +1,19 @@ -import love.forte.plugin.suspendtrans.ClassInfo -import love.forte.plugin.suspendtrans.SuspendTransformConfiguration.Companion.jvmAsyncTransformer -import love.forte.plugin.suspendtrans.SuspendTransformConfiguration.Companion.jvmBlockingTransformer -import love.forte.plugin.suspendtrans.TargetPlatform -import love.forte.plugin.suspendtrans.gradle.SuspendTransformGradleExtension +import org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_11 plugins { `java-library` kotlin("jvm") -// id("love.forte.plugin.suspend-transform") + id("love.forte.plugin.suspend-transform") // id("suspend-transform.jvm-maven-publish") // id(project(":suspend-transform-plugin-gradle")) } - -buildscript { - this@buildscript.repositories { - mavenLocal() - mavenCentral() - } - dependencies { - classpath("love.forte.plugin.suspend-transform:suspend-transform-plugin-gradle:2.1.0-0.11.1") - } -} - kotlin { + jvmToolchain(11) compilerOptions { + jvmTarget = JVM_11 + javaParameters = true freeCompilerArgs.add("-Xjvm-default=all") - } } @@ -34,7 +21,7 @@ repositories { mavenLocal() } -apply(plugin = "love.forte.plugin.suspend-transform") +// apply(plugin = "love.forte.plugin.suspend-transform") dependencies { api(kotlin("stdlib")) @@ -45,29 +32,32 @@ dependencies { api(libs.kotlinx.coroutines.core) } -extensions.getByType().apply { - includeRuntime = false - includeAnnotation = false -// useJvmDefault() - transformers[TargetPlatform.JVM] = mutableListOf( - // Add `kotlin.OptIn` to copyAnnotationExcludes - jvmBlockingTransformer.copy( - copyAnnotationExcludes = buildList { - addAll(jvmBlockingTransformer.copyAnnotationExcludes) - add(ClassInfo("kotlin", "OptIn")) - } - ), +// @Suppress("DEPRECATION") +// suspendTransform { +// enabled = true +// includeAnnotation = false +// includeRuntime = false +// useDefault() +// } - // Add `kotlin.OptIn` to copyAnnotationExcludes - jvmAsyncTransformer.copy( - copyAnnotationExcludes = buildList { - addAll(jvmAsyncTransformer.copyAnnotationExcludes) - add(ClassInfo("kotlin", "OptIn")) - } - ) - ) +suspendTransformPlugin { + includeAnnotation = false + includeRuntime = false + transformers { + useDefault() + } } +/* +> val blockingBaseName: String = "", +> val blockingSuffix: String = "Blocking", +> val blockingAsProperty: Boolean = false, +> +> val asyncBaseName: String = "", +> val asyncSuffix: String = "Async", +> val asyncAsProperty: Boolean = false + */ + tasks.withType { useJUnitPlatform() } diff --git a/tests/test-jvm/src/test/kotlin/SuspendTransformTests.kt b/tests/test-jvm/src/test/kotlin/SuspendTransformTests.kt index 6df947e..e7f3a05 100644 --- a/tests/test-jvm/src/test/kotlin/SuspendTransformTests.kt +++ b/tests/test-jvm/src/test/kotlin/SuspendTransformTests.kt @@ -25,7 +25,9 @@ import love.forte.plugin.suspendtrans.annotation.JvmBlocking import java.lang.reflect.Modifier import java.util.concurrent.CompletableFuture import kotlin.reflect.KTypeParameter +import kotlin.reflect.full.functions import kotlin.reflect.full.memberProperties +import kotlin.reflect.jvm.javaMethod import kotlin.test.* @@ -69,6 +71,14 @@ class STPTrans1Impl : STPTrans1 { */ class SuspendTransformTests { + @Test + fun javaMethodResolve() { + val run1Blocking = STTrans1::class.functions.find { it.name == "run1Blocking" } + assertNotNull(run1Blocking) + println(run1Blocking) + println(run1Blocking.javaMethod) + } + @Test fun `interface suspend trans function test`() { with(STTrans1::class.java) { diff --git a/tests/test-kmp/build.gradle.kts b/tests/test-kmp/build.gradle.kts index 5ddee77..b04e501 100644 --- a/tests/test-kmp/build.gradle.kts +++ b/tests/test-kmp/build.gradle.kts @@ -1,22 +1,6 @@ -import love.forte.plugin.suspendtrans.ClassInfo -import love.forte.plugin.suspendtrans.SuspendTransformConfiguration.Companion.jvmAsyncTransformer -import love.forte.plugin.suspendtrans.SuspendTransformConfiguration.Companion.jvmBlockingTransformer -import love.forte.plugin.suspendtrans.TargetPlatform -import love.forte.plugin.suspendtrans.gradle.SuspendTransformGradleExtension - plugins { kotlin("multiplatform") -} - - -buildscript { - this@buildscript.repositories { - mavenLocal() - mavenCentral() - } - dependencies { - classpath("love.forte.plugin.suspend-transform:suspend-transform-plugin-gradle:2.1.0-0.11.1") - } + id("love.forte.plugin.suspend-transform") } kotlin { @@ -33,9 +17,24 @@ repositories { apply(plugin = "love.forte.plugin.suspend-transform") kotlin { + + jvmToolchain(11) jvm() js { nodejs() + + useEsModules() + generateTypeScriptDefinitions() + binaries.executable() + + compilerOptions { + target = "es2015" + useEsClasses = true + freeCompilerArgs.addAll( + // https://kotlinlang.org/docs/whatsnew20.html#per-file-compilation-for-kotlin-js-projects + "-Xir-per-file", + ) + } } sourceSets { @@ -45,32 +44,57 @@ kotlin { implementation(project(":runtime:suspend-transform-runtime")) implementation(libs.kotlinx.coroutines.core) } + + commonTest.dependencies { + implementation(kotlin("test")) + implementation(libs.kotlinx.coroutines.test) + } } } -extensions.getByType().apply { +tasks.withType { + options.encoding = "UTF-8" + sourceCompatibility = "11" + targetCompatibility = "11" + + // see https://kotlinlang.org/docs/gradle-configure-project.html#configure-with-java-modules-jpms-enabled + // if (moduleName != null) { + // options.compilerArgumentProviders.add( + // CommandLineArgumentProvider { + // // Provide compiled Kotlin classes to javac – needed for Java/Kotlin mixed sources to work + // // listOf("--patch-module", "$moduleName=${sourceSets["main"].output.asPath}") + // val sourceSet = sourceSets.findByName("main") ?: sourceSets.findByName("jvmMain") + // if (sourceSet != null) { + // listOf("--patch-module", "$moduleName=${sourceSet.output.asPath}") + // } else { + // emptyList() + // } + // // listOf("--patch-module", "$moduleName=${sourceSets["main"].output.asPath}") + // } + // ) + // } +} + +suspendTransformPlugin { includeRuntime = false includeAnnotation = false -// useJvmDefault() - transformers[TargetPlatform.JVM] = mutableListOf( - // Add `kotlin.OptIn` to copyAnnotationExcludes - jvmBlockingTransformer.copy( - copyAnnotationExcludes = buildList { - addAll(jvmBlockingTransformer.copyAnnotationExcludes) - add(ClassInfo("kotlin", "OptIn")) - } - ), +} - // Add `kotlin.OptIn` to copyAnnotationExcludes - jvmAsyncTransformer.copy( - copyAnnotationExcludes = buildList { - addAll(jvmAsyncTransformer.copyAnnotationExcludes) - add(ClassInfo("kotlin", "OptIn")) - } +@Suppress("DEPRECATION") +suspendTransform { + includeRuntime = false + includeAnnotation = false + useJvmDefault() + addJsTransformers( + love.forte.plugin.suspendtrans.SuspendTransformConfiguration.jsPromiseTransformer.copy( + copyAnnotationExcludes = listOf( + love.forte.plugin.suspendtrans.ClassInfo("kotlin.js", "JsExport.Ignore") + ) ) ) } + tasks.withType { useJUnitPlatform() } diff --git a/tests/test-kmp/src/commonMain/kotlin/example/MyClass.kt b/tests/test-kmp/src/commonMain/kotlin/example/MyClass.kt index 1c20a34..28f03a9 100644 --- a/tests/test-kmp/src/commonMain/kotlin/example/MyClass.kt +++ b/tests/test-kmp/src/commonMain/kotlin/example/MyClass.kt @@ -1,10 +1,28 @@ package example +import kotlinx.coroutines.delay +import love.forte.plugin.suspendtrans.annotation.JsPromise +import love.forte.plugin.suspendtrans.annotation.JvmAsync import love.forte.plugin.suspendtrans.annotation.JvmBlocking +import kotlin.js.ExperimentalJsExport +import kotlin.js.JsExport expect class MoneyValue +@OptIn(ExperimentalJsExport::class) +@JsExport class MyClass { @JvmBlocking + @JvmAsync + @JsPromise + @JsExport.Ignore suspend fun errorReproduction(amount: MoneyValue) = println(amount) + + @JvmBlocking + @JvmAsync + @JsExport.Ignore + suspend fun accept(): Int { + delay(1) + return 1 + } } diff --git a/tests/test-kmp/src/commonMain/kotlin/example/MyInterface.kt b/tests/test-kmp/src/commonMain/kotlin/example/MyInterface.kt new file mode 100644 index 0000000..2d9f5ae --- /dev/null +++ b/tests/test-kmp/src/commonMain/kotlin/example/MyInterface.kt @@ -0,0 +1,26 @@ +package example + +import love.forte.plugin.suspendtrans.annotation.JsPromise +import love.forte.plugin.suspendtrans.annotation.JvmAsync +import love.forte.plugin.suspendtrans.annotation.JvmBlocking +import kotlin.js.ExperimentalJsExport +import kotlin.js.JsExport + +/** + * + * @author ForteScarlet + */ +@OptIn(ExperimentalJsExport::class) +@JsExport +interface MyInterface { + @JvmBlocking + @JvmAsync + @JsPromise + @JsExport.Ignore + suspend fun delete() + @JvmBlocking + @JvmAsync + @JsPromise(baseName = "delete2") + @JsExport.Ignore + suspend fun delete(vararg value: String) +} \ No newline at end of file diff --git a/tests/test-kmp/src/jsMain/kotlin/example/MyClass.js.kt b/tests/test-kmp/src/jsMain/kotlin/example/MyClass.js.kt index 13f4705..9c41c23 100644 --- a/tests/test-kmp/src/jsMain/kotlin/example/MyClass.js.kt +++ b/tests/test-kmp/src/jsMain/kotlin/example/MyClass.js.kt @@ -1,3 +1,5 @@ package example -actual class MoneyValue +// actual class MoneyValue + +actual typealias MoneyValue = Double diff --git a/tests/test-kmp/src/jvmTest/kotlin/MyClassReflectTests.kt b/tests/test-kmp/src/jvmTest/kotlin/MyClassReflectTests.kt new file mode 100644 index 0000000..7fe8de7 --- /dev/null +++ b/tests/test-kmp/src/jvmTest/kotlin/MyClassReflectTests.kt @@ -0,0 +1,26 @@ +import example.MyClass +import example.MyInterface +import kotlin.reflect.full.functions +import kotlin.reflect.jvm.javaMethod +import kotlin.test.Test +import kotlin.test.assertNotNull + +/** + * + * @author ForteScarlet + */ +class MyClassReflectTests { + + @Test + fun testMyClassReflect() { + val acceptBlocking = MyClass::class.functions.find { it.name == "acceptBlocking" } + assertNotNull(acceptBlocking) + println(acceptBlocking) + println(acceptBlocking.javaMethod) + + val deleteBlocking = MyInterface::class.functions.find { it.name == "deleteBlocking" } + assertNotNull(deleteBlocking) + println(deleteBlocking) + println(deleteBlocking.javaMethod) + } +} \ No newline at end of file