diff --git a/.github/workflows/release-kotlin-preview.yaml b/.github/workflows/release-kotlin-preview.yaml index f103e943..7234aa30 100644 --- a/.github/workflows/release-kotlin-preview.yaml +++ b/.github/workflows/release-kotlin-preview.yaml @@ -4,6 +4,8 @@ on: tags: - 'v[0-9]+.[0-9]+.[0-9]+-kotlin-[0-9]+.[0-9]+.[0-9]+-Beta' - 'v[0-9]+.[0-9]+.[0-9]+-ALPHA-[0-9]+-kotlin-[0-9]+.[0-9]+.[0-9]+-Beta' + - 'v[0-9]+.[0-9]+.[0-9]+-kotlin-[0-9]+.[0-9]+.[0-9]+-Beta[0-9]+' + - 'v[0-9]+.[0-9]+.[0-9]+-ALPHA-[0-9]+-kotlin-[0-9]+.[0-9]+.[0-9]+-Beta[0-9]+' - 'v[0-9]+.[0-9]+.[0-9]+-kotlin-[0-9]+.[0-9]+.[0-9]+-RC' - 'v[0-9]+.[0-9]+.[0-9]+-ALPHA-[0-9]+-kotlin-[0-9]+.[0-9]+.[0-9]+-RC' - 'v[0-9]+.[0-9]+.[0-9]+-kotlin-[0-9]+.[0-9]+.[0-9]+-RC[0-9]+' @@ -33,3 +35,10 @@ jobs: SIGNING_SECRET_KEY: ${{ secrets.SIGNING_SECRET_KEY }} OSSRH_USERNAME: ${{ secrets.OSSRH_USERNAME }} OSSRH_PASSWORD: ${{ secrets.OSSRH_PASSWORD }} + - name: Publish IDEA plugin + run: ./gradlew publishPlugin + env: + IDEA_CERTIFICATE_CHAIN: ${{ secrets.IDEA_CERTIFICATE_CHAIN }} + IDEA_PRIVATE_KEY: ${{ secrets.IDEA_PRIVATE_KEY }} + IDEA_PRIVATE_KEY_PASSWORD: ${{ secrets.IDEA_PRIVATE_KEY_PASSWORD }} + IDEA_PUBLISH_TOKEN: ${{ secrets.IDEA_PUBLISH_TOKEN }} diff --git a/.github/workflows/release-kotlin.yaml b/.github/workflows/release-kotlin.yaml index fd62bee6..89f830f3 100644 --- a/.github/workflows/release-kotlin.yaml +++ b/.github/workflows/release-kotlin.yaml @@ -39,10 +39,10 @@ jobs: SIGNING_SECRET_KEY: ${{ secrets.SIGNING_SECRET_KEY }} GRADLE_PUBLISH_KEY: ${{ secrets.GRADLE_PUBLISH_KEY }} GRADLE_PUBLISH_SECRET: ${{ secrets.GRADLE_PUBLISH_SECRET }} -# - name: Publish IDEA plugin -# run: ./gradlew publishPlugin -# env: -# IDEA_CERTIFICATE_CHAIN: ${{ secrets.IDEA_CERTIFICATE_CHAIN }} -# IDEA_PRIVATE_KEY: ${{ secrets.IDEA_PRIVATE_KEY }} -# IDEA_PRIVATE_KEY_PASSWORD: ${{ secrets.IDEA_PRIVATE_KEY_PASSWORD }} -# IDEA_PUBLISH_TOKEN: ${{ secrets.IDEA_PUBLISH_TOKEN }} + - name: Publish IDEA plugin + run: ./gradlew publishPlugin + env: + IDEA_CERTIFICATE_CHAIN: ${{ secrets.IDEA_CERTIFICATE_CHAIN }} + IDEA_PRIVATE_KEY: ${{ secrets.IDEA_PRIVATE_KEY }} + IDEA_PRIVATE_KEY_PASSWORD: ${{ secrets.IDEA_PRIVATE_KEY_PASSWORD }} + IDEA_PUBLISH_TOKEN: ${{ secrets.IDEA_PUBLISH_TOKEN }} diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml index fdf8d994..e805548a 100644 --- a/.idea/kotlinc.xml +++ b/.idea/kotlinc.xml @@ -1,6 +1,6 @@ - \ No newline at end of file diff --git a/KMPNativeCoroutinesAsync.podspec b/KMPNativeCoroutinesAsync.podspec index 94d0645f..60b137c1 100644 --- a/KMPNativeCoroutinesAsync.podspec +++ b/KMPNativeCoroutinesAsync.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'KMPNativeCoroutinesAsync' - s.version = '1.0.0-ALPHA-17' + s.version = '1.0.0-ALPHA-21' s.summary = 'Swift library for Kotlin Coroutines with Swift Async/Await' s.homepage = 'https://github.com/rickclephas/KMP-NativeCoroutines' diff --git a/KMPNativeCoroutinesCombine.podspec b/KMPNativeCoroutinesCombine.podspec index 92a46ecd..f07052de 100644 --- a/KMPNativeCoroutinesCombine.podspec +++ b/KMPNativeCoroutinesCombine.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'KMPNativeCoroutinesCombine' - s.version = '1.0.0-ALPHA-17' + s.version = '1.0.0-ALPHA-21' s.summary = 'Swift library for Kotlin Coroutines with Combine' s.homepage = 'https://github.com/rickclephas/KMP-NativeCoroutines' diff --git a/KMPNativeCoroutinesCore.podspec b/KMPNativeCoroutinesCore.podspec index 4001a93d..aa71bceb 100644 --- a/KMPNativeCoroutinesCore.podspec +++ b/KMPNativeCoroutinesCore.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'KMPNativeCoroutinesCore' - s.version = '1.0.0-ALPHA-17' + s.version = '1.0.0-ALPHA-21' s.summary = 'Swift library for Kotlin Coroutines' s.homepage = 'https://github.com/rickclephas/KMP-NativeCoroutines' diff --git a/KMPNativeCoroutinesRxSwift.podspec b/KMPNativeCoroutinesRxSwift.podspec index 2092d787..694e73ef 100644 --- a/KMPNativeCoroutinesRxSwift.podspec +++ b/KMPNativeCoroutinesRxSwift.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'KMPNativeCoroutinesRxSwift' - s.version = '1.0.0-ALPHA-17' + s.version = '1.0.0-ALPHA-21' s.summary = 'Swift library for Kotlin Coroutines with RxSwift' s.homepage = 'https://github.com/rickclephas/KMP-NativeCoroutines' diff --git a/MIGRATING_TO_V1.md b/MIGRATING_TO_V1.md index 5a0dc4f2..66c93b69 100644 --- a/MIGRATING_TO_V1.md +++ b/MIGRATING_TO_V1.md @@ -2,7 +2,8 @@ The 1.0 release will bring some improvements that require some changes in your code 😅. -> **Note**: make sure to use the same library versions for your Kotlin and Swift code! +> [!NOTE] +> Make sure to use the same library versions for your Kotlin and Swift code! ## KSP @@ -26,7 +27,8 @@ To tell the plugin what declarations should be refined for ObjC/Swift you'll nee suspend fun getRandomLetters(): String = "" ``` -> **Note**: error messages and IDE support are currently limited. +> [!NOTE] +> Error messages and IDE support are currently limited. > Please track [#81](https://github.com/rickclephas/KMP-NativeCoroutines/issues/81) and > [#82](https://github.com/rickclephas/KMP-NativeCoroutines/issues/82) for improved error messages. @@ -62,7 +64,8 @@ The value and replay cache property names also drop the `Native` suffix: + let replayCache = clock.timeReplayCache ``` -> **Note**: you can now customize the value and replay cache suffixes, +> [!NOTE] +> You can now customize the value and replay cache suffixes, > or if desired completely remove those properties from the generated code. > Checkout the [README](README.md#name-suffix) for more info. diff --git a/README.md b/README.md index 17c1c8ba..88fba41b 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,7 @@ A library to use Kotlin Coroutines from Swift code in KMP apps. +> [!IMPORTANT] > Looking to upgrade from the 0.x releases? Checkout the [migration steps](MIGRATING_TO_V1.md). ## Why this library? @@ -12,7 +13,8 @@ The most important limitation is cancellation support. Kotlin suspend functions are exposed to Swift as functions with a completion handler. This allows you to easily use them from your Swift code, but it doesn't support cancellation. -> **Note**: while Swift 5.5 brings async functions to Swift, it doesn't solve this issue. +> [!NOTE] +> While Swift 5.5 brings async functions to Swift, it doesn't solve this issue. > For interoperability with ObjC all functions with a completion handler can be called like an async function. > This means starting with Swift 5.5 your Kotlin suspend functions will look like Swift async functions. > But that's just syntactic sugar, so there's still no cancellation support. @@ -24,19 +26,21 @@ This library solves both of these limitations 😄. ## Compatibility -The latest version of the library uses Kotlin version `1.9.0`. +The latest version of the library uses Kotlin version `1.9.20`. Compatibility versions for older and/or preview Kotlin versions are also available: -| Version | Version suffix | Kotlin | KSP | Coroutines | -|----------------|--------------------|:---------:|:----------:|:----------:| -| **_latest_** | **_no suffix_** | **1.9.0** | **1.0.12** | **1.7.3** | -| 1.0.0-ALPHA-13 | _no suffix_ | 1.9.0 | 1.0.11 | 1.7.2 | -| 1.0.0-ALPHA-12 | _no suffix_ | 1.8.22 | 1.0.11 | 1.7.2 | -| 1.0.0-ALPHA-10 | _no suffix_ | 1.8.21 | 1.0.11 | 1.7.1 | -| 1.0.0-ALPHA-8 | _no suffix_ | 1.8.21 | 1.0.11 | 1.6.4 | -| 1.0.0-ALPHA-7 | _no suffix_ | 1.8.20 | 1.0.10 | 1.6.4 | -| 1.0.0-ALPHA-5 | _no suffix_ | 1.8.10 | 1.0.9 | 1.6.4 | -| 1.0.0-ALPHA-4 | _no suffix_ | 1.8.0 | 1.0.8 | 1.6.4 | +| Version | Version suffix | Kotlin | KSP | Coroutines | +|----------------|---------------------|:-----------:|:----------:|:----------:| +| _latest_ | -kotlin-2.0.0-Beta1 | 2.0.0-Beta1 | 1.0.14 | 1.7.3 | +| **_latest_** | **_no suffix_** | **1.9.20** | **1.0.14** | **1.7.3** | +| 1.0.0-ALPHA-19 | _no suffix_ | 1.9.20 | 1.0.13 | 1.7.3 | +| 1.0.0-ALPHA-18 | _no suffix_ | 1.9.10 | 1.0.13 | 1.7.3 | +| 1.0.0-ALPHA-17 | _no suffix_ | 1.9.0 | 1.0.12 | 1.7.3 | +| 1.0.0-ALPHA-13 | _no suffix_ | 1.9.0 | 1.0.11 | 1.7.2 | +| 1.0.0-ALPHA-12 | _no suffix_ | 1.8.22 | 1.0.11 | 1.7.2 | +| 1.0.0-ALPHA-10 | _no suffix_ | 1.8.21 | 1.0.11 | 1.7.1 | +| 1.0.0-ALPHA-8 | _no suffix_ | 1.8.21 | 1.0.11 | 1.6.4 | +| 1.0.0-ALPHA-7 | _no suffix_ | 1.8.20 | 1.0.10 | 1.6.4 | You can choose from a couple of Swift implementations. Depending on the implementation you can support as low as iOS 9, macOS 10.9, tvOS 9 and watchOS 3: @@ -60,8 +64,8 @@ Make sure to always use the same versions for all the libraries! For Kotlin just add the plugin to your `build.gradle.kts`: ```kotlin plugins { - id("com.google.devtools.ksp") version "1.9.0-1.0.12" - id("com.rickclephas.kmp.nativecoroutines") version "1.0.0-ALPHA-17" + id("com.google.devtools.ksp") version "1.9.20-1.0.14" + id("com.rickclephas.kmp.nativecoroutines") version "1.0.0-ALPHA-21" } ``` and make sure to opt in to the experimental `@ObjCName` annotation: @@ -77,28 +81,44 @@ The Swift implementations are available via the Swift Package Manager. Just add it to your `Package.swift` file: ```swift dependencies: [ - .package(url: "https://github.com/rickclephas/KMP-NativeCoroutines.git", from: "1.0.0-ALPHA-17") + .package(url: "https://github.com/rickclephas/KMP-NativeCoroutines.git", exact: "1.0.0-ALPHA-21") +], +targets: [ + .target( + name: "MyTargetName", + dependencies: [ + // Swift Concurrency implementation + .product(name: "KMPNativeCoroutinesAsync", package: "KMP-NativeCoroutines"), + // Combine implementation + .product(name: "KMPNativeCoroutinesCombine", package: "KMP-NativeCoroutines"), + // RxSwift implementation + .product(name: "KMPNativeCoroutinesRxSwift", package: "KMP-NativeCoroutines") + ] + ) ] ``` Or add it in Xcode by going to `File` > `Add Packages...` and providing the URL: `https://github.com/rickclephas/KMP-NativeCoroutines.git`. -> **Note**: the version for the Swift package should not contain the Kotlin version suffix +> [!NOTE] +> The version for the Swift package should not contain the Kotlin version suffix > (e.g. `-new-mm` or `-kotlin-1.6.0`). -> **Note**: if you only need a single implementation you can also use the SPM specific versions with suffixes +> [!NOTE] +> If you only need a single implementation you can also use the SPM specific versions with suffixes > `-spm-async`, `-spm-combine` and `-spm-rxswift`. ### Swift (CocoaPods) If you use CocoaPods add one or more of the following libraries to your `Podfile`: ```ruby -pod 'KMPNativeCoroutinesAsync', '1.0.0-ALPHA-17' # Swift Concurrency implementation -pod 'KMPNativeCoroutinesCombine', '1.0.0-ALPHA-17' # Combine implementation -pod 'KMPNativeCoroutinesRxSwift', '1.0.0-ALPHA-17' # RxSwift implementation +pod 'KMPNativeCoroutinesAsync', '1.0.0-ALPHA-21' # Swift Concurrency implementation +pod 'KMPNativeCoroutinesCombine', '1.0.0-ALPHA-21' # Combine implementation +pod 'KMPNativeCoroutinesRxSwift', '1.0.0-ALPHA-21' # RxSwift implementation ``` -> **Note**: the version for CocoaPods should not contain the Kotlin version suffix (e.g. `-new-mm` or `-kotlin-1.6.0`). +> [!NOTE] +> The version for CocoaPods should not contain the Kotlin version suffix (e.g. `-new-mm` or `-kotlin-1.6.0`). ### IntelliJ / Android Studio @@ -317,7 +337,8 @@ handle.cancel() The Combine implementation provides a couple functions to get an `AnyPublisher` for your Coroutines code. -> **Note**: these functions create deferred `AnyPublisher`s. +> [!NOTE] +> These functions create deferred `AnyPublisher`s. > Meaning every subscription will trigger the collection of the `Flow` or execution of the suspend function. #### Publisher @@ -369,7 +390,8 @@ cancellable.cancel() The RxSwift implementation provides a couple functions to get an `Observable` or `Single` for your Coroutines code. -> **Note**: these functions create deferred `Observable`s and `Single`s. +> [!NOTE] +> These functions create deferred `Observable`s and `Single`s. > Meaning every subscription will trigger the collection of the `Flow` or execution of the suspend function. #### Observable @@ -464,14 +486,16 @@ class Clock { } ``` -> **Note**: your custom coroutine scope must be either `internal` or `public`. +> [!NOTE] +> Your custom coroutine scope must be either `internal` or `public`. If you don't provide a `CoroutineScope` the default scope will be used which is defined as: ```kotlin internal val defaultCoroutineScope = CoroutineScope(SupervisorJob() + Dispatchers.Default) ``` -> **Note**: KMP-NativeCoroutines has built-in support for [KMM-ViewModel](https://github.com/rickclephas/KMM-ViewModel). +> [!NOTE] +> KMP-NativeCoroutines has built-in support for [KMM-ViewModel](https://github.com/rickclephas/KMM-ViewModel). > Coroutines inside your `KMMViewModel` will (by default) use the `CoroutineScope` from the `ViewModelScope`. ### Ignoring declarations @@ -494,7 +518,8 @@ If for some reason you would like to further refine your Kotlin declarations in These will tell the plugin to add the [`ShouldRefineInSwift`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.native/-should-refine-in-swift/) annotation to the generated properties/function. -> **Note**: this currently requires a module-wide opt-in to `kotlin.experimental.ExperimentalObjCRefinement`. +> [!NOTE] +> This currently requires a module-wide opt-in to `kotlin.experimental.ExperimentalObjCRefinement`. You could for example refine your `Flow` property to an `AnyPublisher` property: ```kotlin diff --git a/build.gradle.kts b/build.gradle.kts index 5e357436..fa300ea4 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -12,7 +12,7 @@ buildscript { allprojects { group = "com.rickclephas.kmp" - version = "1.0.0-ALPHA-17" + version = "1.0.0-ALPHA-21" repositories { mavenCentral() diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 346fbe07..7d56b1cc 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,7 +1,7 @@ [versions] -kotlin = "1.9.0" +kotlin = "1.9.20" kotlinx-coroutines = "1.7.3" -ksp = "1.9.0-1.0.12" +ksp = "1.9.20-1.0.14" kotlinpoet = "1.14.2" junit = "5.9.1" @@ -20,7 +20,7 @@ kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test", version.ref = "kotl kotlin-reflect = { module = "org.jetbrains.kotlin:kotlin-reflect", version.ref = "kotlin" } kotlin-compiler-internalTestFramework = { module = "org.jetbrains.kotlin:kotlin-compiler-internal-test-framework", version.ref = "kotlin" } kotlinx-coroutines-test = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-test", version.ref = "kotlinx-coroutines" } -kotlinCompileTesting-ksp = { module = "com.github.tschuchortdev:kotlin-compile-testing-ksp", version = "1.5.0" } +kotlinCompileTesting-ksp = { module = "dev.zacsweers.kctfork:ksp", version = "0.3.2" } junit = { module = "junit:junit", version = "4.13.2" } junit-bom = { module = "org.junit:junit-bom", version.ref = "junit" } junit-jupiter = { module = "org.junit.jupiter:junit-jupiter" } diff --git a/kmp-nativecoroutines-compiler/build.gradle.kts b/kmp-nativecoroutines-compiler/build.gradle.kts index 63363de8..da62412f 100644 --- a/kmp-nativecoroutines-compiler/build.gradle.kts +++ b/kmp-nativecoroutines-compiler/build.gradle.kts @@ -1,3 +1,5 @@ +import org.jetbrains.kotlin.gradle.utils.NativeCompilerDownloader + plugins { alias(libs.plugins.kotlin.jvm) `kmp-nativecoroutines-publish` @@ -38,12 +40,17 @@ tasks.compileKotlin.configure { } tasks.test { + systemProperty("kotlin.internal.native.test.nativeHome", NativeCompilerDownloader(project).compilerDirectory.absolutePath) inputs.dir("src/testData") useJUnitPlatform() } +val deleteGeneratedTests by tasks.registering(Delete::class) { + delete("src/test/generated") +} + val generateTests by tasks.registering(JavaExec::class) { - doFirst { delete("src/test/generated") } + dependsOn(deleteGeneratedTests) classpath = sourceSets.test.get().runtimeClasspath mainClass.set("com.rickclephas.kmp.nativecoroutines.compiler.GenerateTestsKt") } diff --git a/kmp-nativecoroutines-compiler/src/main/kotlin/com/rickclephas/kmp/nativecoroutines/compiler/KmpNativeCoroutinesCompilerPluginRegistrar.kt b/kmp-nativecoroutines-compiler/src/main/kotlin/com/rickclephas/kmp/nativecoroutines/compiler/KmpNativeCoroutinesCompilerPluginRegistrar.kt index 147669da..16489596 100644 --- a/kmp-nativecoroutines-compiler/src/main/kotlin/com/rickclephas/kmp/nativecoroutines/compiler/KmpNativeCoroutinesCompilerPluginRegistrar.kt +++ b/kmp-nativecoroutines-compiler/src/main/kotlin/com/rickclephas/kmp/nativecoroutines/compiler/KmpNativeCoroutinesCompilerPluginRegistrar.kt @@ -1,17 +1,20 @@ package com.rickclephas.kmp.nativecoroutines.compiler -import com.rickclephas.kmp.nativecoroutines.compiler.extensions.KmpNativeCoroutinesStorageComponentContainerContributor +import com.rickclephas.kmp.nativecoroutines.compiler.classic.extensions.KmpNativeCoroutinesStorageComponentContainerContributor +import com.rickclephas.kmp.nativecoroutines.compiler.fir.extensions.KmpNativeCoroutinesFirExtensionRegistrar import org.jetbrains.kotlin.compiler.plugin.CompilerPluginRegistrar import org.jetbrains.kotlin.compiler.plugin.ExperimentalCompilerApi import org.jetbrains.kotlin.config.CompilerConfiguration import org.jetbrains.kotlin.extensions.StorageComponentContainerContributor +import org.jetbrains.kotlin.fir.extensions.FirExtensionRegistrarAdapter @OptIn(ExperimentalCompilerApi::class) public class KmpNativeCoroutinesCompilerPluginRegistrar: CompilerPluginRegistrar() { - override val supportsK2: Boolean = false // TODO: Add K2 support + override val supportsK2: Boolean = true override fun ExtensionStorage.registerExtensions(configuration: CompilerConfiguration) { + FirExtensionRegistrarAdapter.registerExtension(KmpNativeCoroutinesFirExtensionRegistrar(configuration)) StorageComponentContainerContributor.registerExtension( KmpNativeCoroutinesStorageComponentContainerContributor(configuration) ) diff --git a/kmp-nativecoroutines-compiler/src/main/kotlin/com/rickclephas/kmp/nativecoroutines/compiler/classic/diagnostics/DefaultErrorMessages.kt b/kmp-nativecoroutines-compiler/src/main/kotlin/com/rickclephas/kmp/nativecoroutines/compiler/classic/diagnostics/DefaultErrorMessages.kt new file mode 100644 index 00000000..96cfb0d5 --- /dev/null +++ b/kmp-nativecoroutines-compiler/src/main/kotlin/com/rickclephas/kmp/nativecoroutines/compiler/classic/diagnostics/DefaultErrorMessages.kt @@ -0,0 +1,66 @@ +package com.rickclephas.kmp.nativecoroutines.compiler.classic.diagnostics + +import com.rickclephas.kmp.nativecoroutines.compiler.classic.diagnostics.KmpNativeCoroutinesErrors.CONFLICT_COROUTINES +import com.rickclephas.kmp.nativecoroutines.compiler.classic.diagnostics.KmpNativeCoroutinesErrors.EXPOSED_FLOW_TYPE +import com.rickclephas.kmp.nativecoroutines.compiler.classic.diagnostics.KmpNativeCoroutinesErrors.EXPOSED_SUSPEND_FUNCTION +import com.rickclephas.kmp.nativecoroutines.compiler.classic.diagnostics.KmpNativeCoroutinesErrors.EXPOSED_FLOW_TYPE_ERROR +import com.rickclephas.kmp.nativecoroutines.compiler.classic.diagnostics.KmpNativeCoroutinesErrors.EXPOSED_STATE_FLOW_PROPERTY +import com.rickclephas.kmp.nativecoroutines.compiler.classic.diagnostics.KmpNativeCoroutinesErrors.EXPOSED_STATE_FLOW_PROPERTY_ERROR +import com.rickclephas.kmp.nativecoroutines.compiler.classic.diagnostics.KmpNativeCoroutinesErrors.EXPOSED_SUSPEND_FUNCTION_ERROR +import com.rickclephas.kmp.nativecoroutines.compiler.classic.diagnostics.KmpNativeCoroutinesErrors.IGNORED_COROUTINES +import com.rickclephas.kmp.nativecoroutines.compiler.classic.diagnostics.KmpNativeCoroutinesErrors.IGNORED_COROUTINES_REFINED +import com.rickclephas.kmp.nativecoroutines.compiler.classic.diagnostics.KmpNativeCoroutinesErrors.IGNORED_COROUTINES_REFINED_STATE +import com.rickclephas.kmp.nativecoroutines.compiler.classic.diagnostics.KmpNativeCoroutinesErrors.IGNORED_COROUTINES_STATE +import com.rickclephas.kmp.nativecoroutines.compiler.classic.diagnostics.KmpNativeCoroutinesErrors.INVALID_COROUTINES +import com.rickclephas.kmp.nativecoroutines.compiler.classic.diagnostics.KmpNativeCoroutinesErrors.INVALID_COROUTINES_IGNORE +import com.rickclephas.kmp.nativecoroutines.compiler.classic.diagnostics.KmpNativeCoroutinesErrors.INVALID_COROUTINES_REFINED +import com.rickclephas.kmp.nativecoroutines.compiler.classic.diagnostics.KmpNativeCoroutinesErrors.INVALID_COROUTINES_REFINED_STATE +import com.rickclephas.kmp.nativecoroutines.compiler.classic.diagnostics.KmpNativeCoroutinesErrors.INVALID_COROUTINES_STATE +import com.rickclephas.kmp.nativecoroutines.compiler.classic.diagnostics.KmpNativeCoroutinesErrors.INVALID_COROUTINE_SCOPE +import com.rickclephas.kmp.nativecoroutines.compiler.classic.diagnostics.KmpNativeCoroutinesErrors.REDUNDANT_OVERRIDE_COROUTINES +import com.rickclephas.kmp.nativecoroutines.compiler.classic.diagnostics.KmpNativeCoroutinesErrors.REDUNDANT_OVERRIDE_COROUTINES_IGNORE +import com.rickclephas.kmp.nativecoroutines.compiler.classic.diagnostics.KmpNativeCoroutinesErrors.REDUNDANT_OVERRIDE_COROUTINES_REFINED +import com.rickclephas.kmp.nativecoroutines.compiler.classic.diagnostics.KmpNativeCoroutinesErrors.REDUNDANT_OVERRIDE_COROUTINES_REFINED_STATE +import com.rickclephas.kmp.nativecoroutines.compiler.classic.diagnostics.KmpNativeCoroutinesErrors.REDUNDANT_OVERRIDE_COROUTINES_STATE +import com.rickclephas.kmp.nativecoroutines.compiler.classic.diagnostics.KmpNativeCoroutinesErrors.REDUNDANT_PRIVATE_COROUTINES +import com.rickclephas.kmp.nativecoroutines.compiler.classic.diagnostics.KmpNativeCoroutinesErrors.REDUNDANT_PRIVATE_COROUTINES_IGNORE +import com.rickclephas.kmp.nativecoroutines.compiler.classic.diagnostics.KmpNativeCoroutinesErrors.REDUNDANT_PRIVATE_COROUTINES_REFINED +import com.rickclephas.kmp.nativecoroutines.compiler.classic.diagnostics.KmpNativeCoroutinesErrors.REDUNDANT_PRIVATE_COROUTINES_REFINED_STATE +import com.rickclephas.kmp.nativecoroutines.compiler.classic.diagnostics.KmpNativeCoroutinesErrors.REDUNDANT_PRIVATE_COROUTINES_STATE +import com.rickclephas.kmp.nativecoroutines.compiler.classic.diagnostics.KmpNativeCoroutinesErrors.UNSUPPORTED_CLASS_EXTENSION_PROPERTY +import org.jetbrains.kotlin.diagnostics.rendering.DefaultErrorMessages +import org.jetbrains.kotlin.diagnostics.rendering.DiagnosticFactoryToRendererMap + +@Suppress("DuplicatedCode") +internal object DefaultErrorMessages : DefaultErrorMessages.Extension { + override fun getMap(): DiagnosticFactoryToRendererMap = DiagnosticFactoryToRendererMap("KmpNativeCoroutines").apply { + put(CONFLICT_COROUTINES, "NativeCoroutines, NativeCoroutinesRefined, NativeCoroutinesRefinedState and NativeCoroutinesState can't be combined") + put(EXPOSED_FLOW_TYPE, "Flow type is exposed to ObjC") + put(EXPOSED_FLOW_TYPE_ERROR, "Flow type is exposed to ObjC") + put(EXPOSED_STATE_FLOW_PROPERTY, "StateFlow property is exposed to ObjC") + put(EXPOSED_STATE_FLOW_PROPERTY_ERROR, "StateFlow property is exposed to ObjC") + put(EXPOSED_SUSPEND_FUNCTION, "suspend function is exposed to ObjC") + put(EXPOSED_SUSPEND_FUNCTION_ERROR, "suspend function is exposed to ObjC") + put(IGNORED_COROUTINES, "NativeCoroutinesIgnore overrides NativeCoroutines") + put(IGNORED_COROUTINES_REFINED, "NativeCoroutinesIgnore overrides NativeCoroutinesRefined") + put(IGNORED_COROUTINES_REFINED_STATE, "NativeCoroutinesIgnore overrides NativeCoroutinesRefinedState") + put(IGNORED_COROUTINES_STATE, "NativeCoroutinesIgnore overrides NativeCoroutinesState") + put(INVALID_COROUTINES, "NativeCoroutines is only supported on suspend-functions and Flow declarations") + put(INVALID_COROUTINES_IGNORE, "NativeCoroutinesIgnore is only supported on suspend-functions and Flow declarations") + put(INVALID_COROUTINES_REFINED, "NativeCoroutinesRefined is only supported on suspend-functions and Flow declarations") + put(INVALID_COROUTINES_REFINED_STATE, "NativeCoroutinesRefinedState is only supported on StateFlow properties") + put(INVALID_COROUTINES_STATE, "NativeCoroutinesState is only supported on StateFlow properties") + put(INVALID_COROUTINE_SCOPE, "NativeCoroutineScope is only supported on CoroutineScope properties") + put(REDUNDANT_OVERRIDE_COROUTINES, "NativeCoroutines should be applied to overridden declaration instead") + put(REDUNDANT_OVERRIDE_COROUTINES_IGNORE, "NativeCoroutinesIgnore isn't supported on overridden declarations") + put(REDUNDANT_OVERRIDE_COROUTINES_REFINED, "NativeCoroutinesRefined should be applied to overridden declaration instead") + put(REDUNDANT_OVERRIDE_COROUTINES_REFINED_STATE, "NativeCoroutinesRefinedState should be applied to overridden declaration instead") + put(REDUNDANT_OVERRIDE_COROUTINES_STATE, "NativeCoroutinesState should be applied to overridden declaration instead") + put(REDUNDANT_PRIVATE_COROUTINES, "NativeCoroutines is only supported on public declarations") + put(REDUNDANT_PRIVATE_COROUTINES_IGNORE, "NativeCoroutinesIgnore is only supported on public declarations") + put(REDUNDANT_PRIVATE_COROUTINES_REFINED, "NativeCoroutinesRefined is only supported on public declarations") + put(REDUNDANT_PRIVATE_COROUTINES_REFINED_STATE, "NativeCoroutinesRefinedState is only supported on public declarations") + put(REDUNDANT_PRIVATE_COROUTINES_STATE, "NativeCoroutinesState is only supported on public declarations") + put(UNSUPPORTED_CLASS_EXTENSION_PROPERTY, "Class extension properties aren't supported") + } +} diff --git a/kmp-nativecoroutines-compiler/src/main/kotlin/com/rickclephas/kmp/nativecoroutines/compiler/classic/diagnostics/KmpNativeCoroutinesChecker.kt b/kmp-nativecoroutines-compiler/src/main/kotlin/com/rickclephas/kmp/nativecoroutines/compiler/classic/diagnostics/KmpNativeCoroutinesChecker.kt new file mode 100644 index 00000000..c342dd75 --- /dev/null +++ b/kmp-nativecoroutines-compiler/src/main/kotlin/com/rickclephas/kmp/nativecoroutines/compiler/classic/diagnostics/KmpNativeCoroutinesChecker.kt @@ -0,0 +1,175 @@ +package com.rickclephas.kmp.nativecoroutines.compiler.classic.diagnostics + +import com.rickclephas.kmp.nativecoroutines.compiler.config.ExposedSeverity +import com.rickclephas.kmp.nativecoroutines.compiler.classic.diagnostics.KmpNativeCoroutinesErrors.CONFLICT_COROUTINES +import com.rickclephas.kmp.nativecoroutines.compiler.classic.diagnostics.KmpNativeCoroutinesErrors.EXPOSED_FLOW_TYPE +import com.rickclephas.kmp.nativecoroutines.compiler.classic.diagnostics.KmpNativeCoroutinesErrors.EXPOSED_FLOW_TYPE_ERROR +import com.rickclephas.kmp.nativecoroutines.compiler.classic.diagnostics.KmpNativeCoroutinesErrors.EXPOSED_SUSPEND_FUNCTION +import com.rickclephas.kmp.nativecoroutines.compiler.classic.diagnostics.KmpNativeCoroutinesErrors.EXPOSED_SUSPEND_FUNCTION_ERROR +import com.rickclephas.kmp.nativecoroutines.compiler.classic.diagnostics.KmpNativeCoroutinesErrors.IGNORED_COROUTINES +import com.rickclephas.kmp.nativecoroutines.compiler.classic.diagnostics.KmpNativeCoroutinesErrors.IGNORED_COROUTINES_STATE +import com.rickclephas.kmp.nativecoroutines.compiler.classic.diagnostics.KmpNativeCoroutinesErrors.INVALID_COROUTINES +import com.rickclephas.kmp.nativecoroutines.compiler.classic.diagnostics.KmpNativeCoroutinesErrors.INVALID_COROUTINES_IGNORE +import com.rickclephas.kmp.nativecoroutines.compiler.classic.diagnostics.KmpNativeCoroutinesErrors.INVALID_COROUTINE_SCOPE +import com.rickclephas.kmp.nativecoroutines.compiler.classic.diagnostics.KmpNativeCoroutinesErrors.INVALID_COROUTINES_STATE +import com.rickclephas.kmp.nativecoroutines.compiler.classic.diagnostics.KmpNativeCoroutinesErrors.REDUNDANT_OVERRIDE_COROUTINES +import com.rickclephas.kmp.nativecoroutines.compiler.classic.diagnostics.KmpNativeCoroutinesErrors.REDUNDANT_OVERRIDE_COROUTINES_IGNORE +import com.rickclephas.kmp.nativecoroutines.compiler.classic.diagnostics.KmpNativeCoroutinesErrors.REDUNDANT_OVERRIDE_COROUTINES_STATE +import com.rickclephas.kmp.nativecoroutines.compiler.classic.diagnostics.KmpNativeCoroutinesErrors.REDUNDANT_PRIVATE_COROUTINES +import com.rickclephas.kmp.nativecoroutines.compiler.classic.diagnostics.KmpNativeCoroutinesErrors.REDUNDANT_PRIVATE_COROUTINES_IGNORE +import com.rickclephas.kmp.nativecoroutines.compiler.classic.diagnostics.KmpNativeCoroutinesErrors.REDUNDANT_PRIVATE_COROUTINES_STATE +import com.rickclephas.kmp.nativecoroutines.compiler.classic.diagnostics.KmpNativeCoroutinesErrors.EXPOSED_STATE_FLOW_PROPERTY +import com.rickclephas.kmp.nativecoroutines.compiler.classic.diagnostics.KmpNativeCoroutinesErrors.EXPOSED_STATE_FLOW_PROPERTY_ERROR +import com.rickclephas.kmp.nativecoroutines.compiler.classic.diagnostics.KmpNativeCoroutinesErrors.IGNORED_COROUTINES_REFINED +import com.rickclephas.kmp.nativecoroutines.compiler.classic.diagnostics.KmpNativeCoroutinesErrors.IGNORED_COROUTINES_REFINED_STATE +import com.rickclephas.kmp.nativecoroutines.compiler.classic.diagnostics.KmpNativeCoroutinesErrors.INVALID_COROUTINES_REFINED +import com.rickclephas.kmp.nativecoroutines.compiler.classic.diagnostics.KmpNativeCoroutinesErrors.INVALID_COROUTINES_REFINED_STATE +import com.rickclephas.kmp.nativecoroutines.compiler.classic.diagnostics.KmpNativeCoroutinesErrors.REDUNDANT_OVERRIDE_COROUTINES_REFINED +import com.rickclephas.kmp.nativecoroutines.compiler.classic.diagnostics.KmpNativeCoroutinesErrors.REDUNDANT_OVERRIDE_COROUTINES_REFINED_STATE +import com.rickclephas.kmp.nativecoroutines.compiler.classic.diagnostics.KmpNativeCoroutinesErrors.REDUNDANT_PRIVATE_COROUTINES_REFINED +import com.rickclephas.kmp.nativecoroutines.compiler.classic.diagnostics.KmpNativeCoroutinesErrors.REDUNDANT_PRIVATE_COROUTINES_REFINED_STATE +import com.rickclephas.kmp.nativecoroutines.compiler.classic.diagnostics.KmpNativeCoroutinesErrors.UNSUPPORTED_CLASS_EXTENSION_PROPERTY +import com.rickclephas.kmp.nativecoroutines.compiler.classic.utils.NativeCoroutinesAnnotations +import com.rickclephas.kmp.nativecoroutines.compiler.classic.utils.coroutinesReturnType +import com.rickclephas.kmp.nativecoroutines.compiler.utils.CoroutinesReturnType +import org.jetbrains.kotlin.descriptors.CallableDescriptor +import org.jetbrains.kotlin.descriptors.DeclarationDescriptor +import org.jetbrains.kotlin.descriptors.FunctionDescriptor +import org.jetbrains.kotlin.descriptors.PropertyDescriptor +import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor +import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor +import org.jetbrains.kotlin.diagnostics.DiagnosticFactory0 +import org.jetbrains.kotlin.psi.KtDeclaration +import org.jetbrains.kotlin.psi.KtElement +import org.jetbrains.kotlin.resolve.BindingTrace +import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils.getSourceFromAnnotation +import org.jetbrains.kotlin.resolve.checkers.DeclarationChecker +import org.jetbrains.kotlin.resolve.checkers.DeclarationCheckerContext +import org.jetbrains.kotlin.resolve.descriptorUtil.isEffectivelyPublicApi +import org.jetbrains.kotlin.resolve.descriptorUtil.isExtension + +public class KmpNativeCoroutinesChecker( + exposedSeverity: ExposedSeverity +): DeclarationChecker { + + private val exposedSuspendFunction = when (exposedSeverity) { + ExposedSeverity.NONE -> null + ExposedSeverity.WARNING -> EXPOSED_SUSPEND_FUNCTION + ExposedSeverity.ERROR -> EXPOSED_SUSPEND_FUNCTION_ERROR + } + + private val exposedFlowType = when (exposedSeverity) { + ExposedSeverity.NONE -> null + ExposedSeverity.WARNING -> EXPOSED_FLOW_TYPE + ExposedSeverity.ERROR -> EXPOSED_FLOW_TYPE_ERROR + } + + private val exposedStateFlowProperty = when (exposedSeverity) { + ExposedSeverity.NONE -> null + ExposedSeverity.WARNING -> EXPOSED_STATE_FLOW_PROPERTY + ExposedSeverity.ERROR -> EXPOSED_STATE_FLOW_PROPERTY_ERROR + } + + override fun check( + declaration: KtDeclaration, + descriptor: DeclarationDescriptor, + context: DeclarationCheckerContext + ) { + if (descriptor !is CallableDescriptor) return + if (descriptor !is SimpleFunctionDescriptor && descriptor !is PropertyDescriptor) return + val annotations = NativeCoroutinesAnnotations(descriptor) + val isPublic = descriptor.isEffectivelyPublicApi + val isOverride = descriptor.overriddenDescriptors.isNotEmpty() + val isSuspend = descriptor is FunctionDescriptor && descriptor.isSuspend + val returnType = descriptor.coroutinesReturnType + + //region CONFLICT_COROUTINES + val coroutinesAnnotations = listOf( + annotations.nativeCoroutines, + annotations.nativeCoroutinesRefined, + annotations.nativeCoroutinesRefinedState, + annotations.nativeCoroutinesState, + ) + val annotationCount = coroutinesAnnotations.count { it != null } + if (annotationCount > 1) { + coroutinesAnnotations.forEach { + context.trace.report(CONFLICT_COROUTINES, it, declaration) + } + } + //endregion + + //region EXPOSED_* + if (isPublic && !isOverride && annotationCount == 0 && annotations.nativeCoroutinesIgnore == null) { + if (isSuspend) { + exposedSuspendFunction?.on(declaration)?.let(context.trace::report) + } + if (returnType is CoroutinesReturnType.Flow) { + val diagnosticFactory = when { + descriptor !is PropertyDescriptor -> exposedFlowType + returnType != CoroutinesReturnType.Flow.State -> exposedFlowType + else -> exposedStateFlowProperty + } + diagnosticFactory?.on(declaration)?.let(context.trace::report) + } + } + //endregion + + //region IGNORED_* + if (annotations.nativeCoroutinesIgnore != null) { + context.trace.report(IGNORED_COROUTINES, annotations.nativeCoroutines, declaration) + context.trace.report(IGNORED_COROUTINES_REFINED, annotations.nativeCoroutinesRefined, declaration) + context.trace.report(IGNORED_COROUTINES_REFINED_STATE, annotations.nativeCoroutinesRefinedState, declaration) + context.trace.report(IGNORED_COROUTINES_STATE, annotations.nativeCoroutinesState, declaration) + } + //endregion + + //region INVALID_* + if (descriptor !is PropertyDescriptor || returnType != CoroutinesReturnType.CoroutineScope) { + context.trace.report(INVALID_COROUTINE_SCOPE, annotations.nativeCoroutineScope, declaration) + } + if (!isSuspend && returnType !is CoroutinesReturnType.Flow) { + context.trace.report(INVALID_COROUTINES, annotations.nativeCoroutines, declaration) + context.trace.report(INVALID_COROUTINES_IGNORE, annotations.nativeCoroutinesIgnore, declaration) + context.trace.report(INVALID_COROUTINES_REFINED, annotations.nativeCoroutinesRefined, declaration) + } + if (descriptor !is PropertyDescriptor || returnType !is CoroutinesReturnType.Flow.State) { + context.trace.report(INVALID_COROUTINES_REFINED_STATE, annotations.nativeCoroutinesRefinedState, declaration) + context.trace.report(INVALID_COROUTINES_STATE, annotations.nativeCoroutinesState, declaration) + } + //endregion + + //region REDUNDANT_* + if (isOverride) { + context.trace.report(REDUNDANT_OVERRIDE_COROUTINES, annotations.nativeCoroutines, declaration) + context.trace.report(REDUNDANT_OVERRIDE_COROUTINES_IGNORE, annotations.nativeCoroutinesIgnore, declaration) + context.trace.report(REDUNDANT_OVERRIDE_COROUTINES_REFINED, annotations.nativeCoroutinesRefined, declaration) + context.trace.report(REDUNDANT_OVERRIDE_COROUTINES_REFINED_STATE, annotations.nativeCoroutinesRefinedState, declaration) + context.trace.report(REDUNDANT_OVERRIDE_COROUTINES_STATE, annotations.nativeCoroutinesState, declaration) + } + if (!isPublic) { + context.trace.report(REDUNDANT_PRIVATE_COROUTINES, annotations.nativeCoroutines, declaration) + context.trace.report(REDUNDANT_PRIVATE_COROUTINES_IGNORE, annotations.nativeCoroutinesIgnore, declaration) + context.trace.report(REDUNDANT_PRIVATE_COROUTINES_REFINED, annotations.nativeCoroutinesRefined, declaration) + context.trace.report(REDUNDANT_PRIVATE_COROUTINES_REFINED_STATE, annotations.nativeCoroutinesRefinedState, declaration) + context.trace.report(REDUNDANT_PRIVATE_COROUTINES_STATE, annotations.nativeCoroutinesState, declaration) + } + //endregion + + //region UNSUPPORTED_* + if (descriptor is PropertyDescriptor && descriptor.dispatchReceiverParameter != null && descriptor.isExtension) { + coroutinesAnnotations.forEach { + context.trace.report(UNSUPPORTED_CLASS_EXTENSION_PROPERTY, it, declaration) + } + } + //endregion + } + + private fun BindingTrace.report( + diagnosticFactory: DiagnosticFactory0, + annotationDescriptor: AnnotationDescriptor?, + declaration: KtDeclaration + ) { + if (annotationDescriptor == null) return + report(diagnosticFactory.on(getSourceFromAnnotation(annotationDescriptor) ?: declaration)) + } +} diff --git a/kmp-nativecoroutines-compiler/src/main/kotlin/com/rickclephas/kmp/nativecoroutines/compiler/diagnostics/KmpNativeCoroutinesErrors.kt b/kmp-nativecoroutines-compiler/src/main/kotlin/com/rickclephas/kmp/nativecoroutines/compiler/classic/diagnostics/KmpNativeCoroutinesErrors.kt similarity index 71% rename from kmp-nativecoroutines-compiler/src/main/kotlin/com/rickclephas/kmp/nativecoroutines/compiler/diagnostics/KmpNativeCoroutinesErrors.kt rename to kmp-nativecoroutines-compiler/src/main/kotlin/com/rickclephas/kmp/nativecoroutines/compiler/classic/diagnostics/KmpNativeCoroutinesErrors.kt index 4e90648b..683b8997 100644 --- a/kmp-nativecoroutines-compiler/src/main/kotlin/com/rickclephas/kmp/nativecoroutines/compiler/diagnostics/KmpNativeCoroutinesErrors.kt +++ b/kmp-nativecoroutines-compiler/src/main/kotlin/com/rickclephas/kmp/nativecoroutines/compiler/classic/diagnostics/KmpNativeCoroutinesErrors.kt @@ -1,26 +1,27 @@ -package com.rickclephas.kmp.nativecoroutines.compiler.diagnostics +package com.rickclephas.kmp.nativecoroutines.compiler.classic.diagnostics -import com.intellij.psi.PsiElement import org.jetbrains.kotlin.diagnostics.DiagnosticFactory0 import org.jetbrains.kotlin.diagnostics.Errors +import org.jetbrains.kotlin.diagnostics.PositioningStrategies import org.jetbrains.kotlin.diagnostics.Severity +import org.jetbrains.kotlin.psi.KtDeclaration import org.jetbrains.kotlin.psi.KtElement public object KmpNativeCoroutinesErrors { @JvmField public val CONFLICT_COROUTINES: DiagnosticFactory0 = DiagnosticFactory0.create(Severity.ERROR) @JvmField - public val EXPOSED_FLOW_TYPE: DiagnosticFactory0 = DiagnosticFactory0.create(Severity.WARNING) + public val EXPOSED_FLOW_TYPE: DiagnosticFactory0 = DiagnosticFactory0.create(Severity.WARNING, PositioningStrategies.DECLARATION_RETURN_TYPE) @JvmField - public val EXPOSED_FLOW_TYPE_ERROR: DiagnosticFactory0 = DiagnosticFactory0.create(Severity.ERROR) + public val EXPOSED_FLOW_TYPE_ERROR: DiagnosticFactory0 = DiagnosticFactory0.create(Severity.ERROR, PositioningStrategies.DECLARATION_RETURN_TYPE) @JvmField - public val EXPOSED_STATE_FLOW_PROPERTY: DiagnosticFactory0 = DiagnosticFactory0.create(Severity.WARNING) + public val EXPOSED_STATE_FLOW_PROPERTY: DiagnosticFactory0 = DiagnosticFactory0.create(Severity.WARNING, PositioningStrategies.DECLARATION_RETURN_TYPE) @JvmField - public val EXPOSED_STATE_FLOW_PROPERTY_ERROR: DiagnosticFactory0 = DiagnosticFactory0.create(Severity.ERROR) + public val EXPOSED_STATE_FLOW_PROPERTY_ERROR: DiagnosticFactory0 = DiagnosticFactory0.create(Severity.ERROR, PositioningStrategies.DECLARATION_RETURN_TYPE) @JvmField - public val EXPOSED_SUSPEND_FUNCTION: DiagnosticFactory0 = DiagnosticFactory0.create(Severity.WARNING) + public val EXPOSED_SUSPEND_FUNCTION: DiagnosticFactory0 = DiagnosticFactory0.create(Severity.WARNING, PositioningStrategies.SUSPEND_MODIFIER) @JvmField - public val EXPOSED_SUSPEND_FUNCTION_ERROR: DiagnosticFactory0 = DiagnosticFactory0.create(Severity.ERROR) + public val EXPOSED_SUSPEND_FUNCTION_ERROR: DiagnosticFactory0 = DiagnosticFactory0.create(Severity.ERROR, PositioningStrategies.SUSPEND_MODIFIER) @JvmField public val IGNORED_COROUTINES: DiagnosticFactory0 = DiagnosticFactory0.create(Severity.ERROR) @JvmField @@ -60,7 +61,9 @@ public object KmpNativeCoroutinesErrors { @JvmField public val REDUNDANT_PRIVATE_COROUTINES_REFINED_STATE: DiagnosticFactory0 = DiagnosticFactory0.create(Severity.ERROR) @JvmField - public val REDUNDANT_PRIVATE_COROUTINES_STATE: DiagnosticFactory0 = DiagnosticFactory0.create(Severity.ERROR) + public val REDUNDANT_PRIVATE_COROUTINES_STATE: DiagnosticFactory0 = DiagnosticFactory0.create(Severity.ERROR) + @JvmField + public val UNSUPPORTED_CLASS_EXTENSION_PROPERTY: DiagnosticFactory0 = DiagnosticFactory0.create(Severity.ERROR) init { Errors.Initializer.initializeFactoryNamesAndDefaultErrorMessages(KmpNativeCoroutinesErrors::class.java, DefaultErrorMessages) diff --git a/kmp-nativecoroutines-compiler/src/main/kotlin/com/rickclephas/kmp/nativecoroutines/compiler/extensions/KmpNativeCoroutinesStorageComponentContainerContributor.kt b/kmp-nativecoroutines-compiler/src/main/kotlin/com/rickclephas/kmp/nativecoroutines/compiler/classic/extensions/KmpNativeCoroutinesStorageComponentContainerContributor.kt similarity index 84% rename from kmp-nativecoroutines-compiler/src/main/kotlin/com/rickclephas/kmp/nativecoroutines/compiler/extensions/KmpNativeCoroutinesStorageComponentContainerContributor.kt rename to kmp-nativecoroutines-compiler/src/main/kotlin/com/rickclephas/kmp/nativecoroutines/compiler/classic/extensions/KmpNativeCoroutinesStorageComponentContainerContributor.kt index 86b96bbf..56d87bfc 100644 --- a/kmp-nativecoroutines-compiler/src/main/kotlin/com/rickclephas/kmp/nativecoroutines/compiler/extensions/KmpNativeCoroutinesStorageComponentContainerContributor.kt +++ b/kmp-nativecoroutines-compiler/src/main/kotlin/com/rickclephas/kmp/nativecoroutines/compiler/classic/extensions/KmpNativeCoroutinesStorageComponentContainerContributor.kt @@ -1,8 +1,8 @@ -package com.rickclephas.kmp.nativecoroutines.compiler.extensions +package com.rickclephas.kmp.nativecoroutines.compiler.classic.extensions import com.rickclephas.kmp.nativecoroutines.compiler.config.EXPOSED_SEVERITY import com.rickclephas.kmp.nativecoroutines.compiler.config.get -import com.rickclephas.kmp.nativecoroutines.compiler.diagnostics.KmpNativeCoroutinesChecker +import com.rickclephas.kmp.nativecoroutines.compiler.classic.diagnostics.KmpNativeCoroutinesChecker import org.jetbrains.kotlin.config.CompilerConfiguration import org.jetbrains.kotlin.container.StorageComponentContainer import org.jetbrains.kotlin.container.useInstance diff --git a/kmp-nativecoroutines-compiler/src/main/kotlin/com/rickclephas/kmp/nativecoroutines/compiler/classic/utils/CoroutinesReturnType.kt b/kmp-nativecoroutines-compiler/src/main/kotlin/com/rickclephas/kmp/nativecoroutines/compiler/classic/utils/CoroutinesReturnType.kt new file mode 100644 index 00000000..05909f42 --- /dev/null +++ b/kmp-nativecoroutines-compiler/src/main/kotlin/com/rickclephas/kmp/nativecoroutines/compiler/classic/utils/CoroutinesReturnType.kt @@ -0,0 +1,32 @@ +package com.rickclephas.kmp.nativecoroutines.compiler.classic.utils + +import com.rickclephas.kmp.nativecoroutines.compiler.utils.CoroutinesClassIds +import com.rickclephas.kmp.nativecoroutines.compiler.utils.CoroutinesReturnType +import org.jetbrains.kotlin.descriptors.CallableDescriptor +import org.jetbrains.kotlin.descriptors.ModuleDescriptor +import org.jetbrains.kotlin.descriptors.findClassifierAcrossModuleDependencies +import org.jetbrains.kotlin.name.ClassId +import org.jetbrains.kotlin.resolve.calls.inference.returnTypeOrNothing +import org.jetbrains.kotlin.resolve.descriptorUtil.module +import org.jetbrains.kotlin.types.TypeConstructor +import org.jetbrains.kotlin.types.typeUtil.supertypes + +internal val CallableDescriptor.coroutinesReturnType: CoroutinesReturnType? get() { + val returnType = returnTypeOrNothing + val stateFlowConstructor = module.findTypeConstructor(CoroutinesClassIds.stateFlow) + if (returnType.constructor == stateFlowConstructor) return CoroutinesReturnType.Flow.State + val flowConstructor = module.findTypeConstructor(CoroutinesClassIds.flow) + if (returnType.constructor == flowConstructor) return CoroutinesReturnType.Flow.Generic + val coroutineScopeConstructor = module.findTypeConstructor(CoroutinesClassIds.coroutineScope) + if (returnType.constructor == coroutineScopeConstructor) return CoroutinesReturnType.CoroutineScope + returnType.supertypes().forEach { + if (it.constructor == stateFlowConstructor) return CoroutinesReturnType.Flow.State + if (it.constructor == flowConstructor) return CoroutinesReturnType.Flow.Generic + if (it.constructor == coroutineScopeConstructor) return CoroutinesReturnType.CoroutineScope + } + return null +} + +private fun ModuleDescriptor.findTypeConstructor(classId: ClassId): TypeConstructor = + findClassifierAcrossModuleDependencies(classId)?.typeConstructor + ?: throw NoSuchElementException("Couldn't find ${classId.relativeClassName} constructor") diff --git a/kmp-nativecoroutines-compiler/src/main/kotlin/com/rickclephas/kmp/nativecoroutines/compiler/utils/NativeCoroutinesAnnotations.kt b/kmp-nativecoroutines-compiler/src/main/kotlin/com/rickclephas/kmp/nativecoroutines/compiler/classic/utils/NativeCoroutinesAnnotations.kt similarity index 96% rename from kmp-nativecoroutines-compiler/src/main/kotlin/com/rickclephas/kmp/nativecoroutines/compiler/utils/NativeCoroutinesAnnotations.kt rename to kmp-nativecoroutines-compiler/src/main/kotlin/com/rickclephas/kmp/nativecoroutines/compiler/classic/utils/NativeCoroutinesAnnotations.kt index 308cae4e..a006aa16 100644 --- a/kmp-nativecoroutines-compiler/src/main/kotlin/com/rickclephas/kmp/nativecoroutines/compiler/utils/NativeCoroutinesAnnotations.kt +++ b/kmp-nativecoroutines-compiler/src/main/kotlin/com/rickclephas/kmp/nativecoroutines/compiler/classic/utils/NativeCoroutinesAnnotations.kt @@ -1,4 +1,4 @@ -package com.rickclephas.kmp.nativecoroutines.compiler.utils +package com.rickclephas.kmp.nativecoroutines.compiler.classic.utils import com.rickclephas.kmp.nativecoroutines.compiler.utils.NativeCoroutinesFqNames as FqNames import org.jetbrains.kotlin.descriptors.CallableDescriptor diff --git a/kmp-nativecoroutines-compiler/src/main/kotlin/com/rickclephas/kmp/nativecoroutines/compiler/diagnostics/DefaultErrorMessages.kt b/kmp-nativecoroutines-compiler/src/main/kotlin/com/rickclephas/kmp/nativecoroutines/compiler/diagnostics/DefaultErrorMessages.kt deleted file mode 100644 index 7c102431..00000000 --- a/kmp-nativecoroutines-compiler/src/main/kotlin/com/rickclephas/kmp/nativecoroutines/compiler/diagnostics/DefaultErrorMessages.kt +++ /dev/null @@ -1,63 +0,0 @@ -package com.rickclephas.kmp.nativecoroutines.compiler.diagnostics - -import com.rickclephas.kmp.nativecoroutines.compiler.diagnostics.KmpNativeCoroutinesErrors.CONFLICT_COROUTINES -import com.rickclephas.kmp.nativecoroutines.compiler.diagnostics.KmpNativeCoroutinesErrors.EXPOSED_FLOW_TYPE -import com.rickclephas.kmp.nativecoroutines.compiler.diagnostics.KmpNativeCoroutinesErrors.EXPOSED_SUSPEND_FUNCTION -import com.rickclephas.kmp.nativecoroutines.compiler.diagnostics.KmpNativeCoroutinesErrors.EXPOSED_FLOW_TYPE_ERROR -import com.rickclephas.kmp.nativecoroutines.compiler.diagnostics.KmpNativeCoroutinesErrors.EXPOSED_STATE_FLOW_PROPERTY -import com.rickclephas.kmp.nativecoroutines.compiler.diagnostics.KmpNativeCoroutinesErrors.EXPOSED_STATE_FLOW_PROPERTY_ERROR -import com.rickclephas.kmp.nativecoroutines.compiler.diagnostics.KmpNativeCoroutinesErrors.EXPOSED_SUSPEND_FUNCTION_ERROR -import com.rickclephas.kmp.nativecoroutines.compiler.diagnostics.KmpNativeCoroutinesErrors.IGNORED_COROUTINES -import com.rickclephas.kmp.nativecoroutines.compiler.diagnostics.KmpNativeCoroutinesErrors.IGNORED_COROUTINES_REFINED -import com.rickclephas.kmp.nativecoroutines.compiler.diagnostics.KmpNativeCoroutinesErrors.IGNORED_COROUTINES_REFINED_STATE -import com.rickclephas.kmp.nativecoroutines.compiler.diagnostics.KmpNativeCoroutinesErrors.IGNORED_COROUTINES_STATE -import com.rickclephas.kmp.nativecoroutines.compiler.diagnostics.KmpNativeCoroutinesErrors.INVALID_COROUTINES -import com.rickclephas.kmp.nativecoroutines.compiler.diagnostics.KmpNativeCoroutinesErrors.INVALID_COROUTINES_IGNORE -import com.rickclephas.kmp.nativecoroutines.compiler.diagnostics.KmpNativeCoroutinesErrors.INVALID_COROUTINES_REFINED -import com.rickclephas.kmp.nativecoroutines.compiler.diagnostics.KmpNativeCoroutinesErrors.INVALID_COROUTINES_REFINED_STATE -import com.rickclephas.kmp.nativecoroutines.compiler.diagnostics.KmpNativeCoroutinesErrors.INVALID_COROUTINES_STATE -import com.rickclephas.kmp.nativecoroutines.compiler.diagnostics.KmpNativeCoroutinesErrors.INVALID_COROUTINE_SCOPE -import com.rickclephas.kmp.nativecoroutines.compiler.diagnostics.KmpNativeCoroutinesErrors.REDUNDANT_OVERRIDE_COROUTINES -import com.rickclephas.kmp.nativecoroutines.compiler.diagnostics.KmpNativeCoroutinesErrors.REDUNDANT_OVERRIDE_COROUTINES_IGNORE -import com.rickclephas.kmp.nativecoroutines.compiler.diagnostics.KmpNativeCoroutinesErrors.REDUNDANT_OVERRIDE_COROUTINES_REFINED -import com.rickclephas.kmp.nativecoroutines.compiler.diagnostics.KmpNativeCoroutinesErrors.REDUNDANT_OVERRIDE_COROUTINES_REFINED_STATE -import com.rickclephas.kmp.nativecoroutines.compiler.diagnostics.KmpNativeCoroutinesErrors.REDUNDANT_OVERRIDE_COROUTINES_STATE -import com.rickclephas.kmp.nativecoroutines.compiler.diagnostics.KmpNativeCoroutinesErrors.REDUNDANT_PRIVATE_COROUTINES -import com.rickclephas.kmp.nativecoroutines.compiler.diagnostics.KmpNativeCoroutinesErrors.REDUNDANT_PRIVATE_COROUTINES_IGNORE -import com.rickclephas.kmp.nativecoroutines.compiler.diagnostics.KmpNativeCoroutinesErrors.REDUNDANT_PRIVATE_COROUTINES_REFINED -import com.rickclephas.kmp.nativecoroutines.compiler.diagnostics.KmpNativeCoroutinesErrors.REDUNDANT_PRIVATE_COROUTINES_REFINED_STATE -import com.rickclephas.kmp.nativecoroutines.compiler.diagnostics.KmpNativeCoroutinesErrors.REDUNDANT_PRIVATE_COROUTINES_STATE -import org.jetbrains.kotlin.diagnostics.rendering.DefaultErrorMessages -import org.jetbrains.kotlin.diagnostics.rendering.DiagnosticFactoryToRendererMap - -internal object DefaultErrorMessages : DefaultErrorMessages.Extension { - override fun getMap(): DiagnosticFactoryToRendererMap = DiagnosticFactoryToRendererMap("KmpNativeCoroutines").apply { - put(CONFLICT_COROUTINES, "NativeCoroutines, NativeCoroutinesRefined, NativeCoroutinesRefinedState and NativeCoroutinesState can't be combined") - put(EXPOSED_FLOW_TYPE, "Flow type is exposed to ObjC") - put(EXPOSED_FLOW_TYPE_ERROR, "Flow type is exposed to ObjC") - put(EXPOSED_STATE_FLOW_PROPERTY, "StateFlow property is exposed to ObjC") - put(EXPOSED_STATE_FLOW_PROPERTY_ERROR, "StateFlow property is exposed to ObjC") - put(EXPOSED_SUSPEND_FUNCTION, "suspend function is exposed to ObjC") - put(EXPOSED_SUSPEND_FUNCTION_ERROR, "suspend function is exposed to ObjC") - put(IGNORED_COROUTINES, "NativeCoroutinesIgnore overrides NativeCoroutines") - put(IGNORED_COROUTINES_REFINED, "NativeCoroutinesIgnore overrides NativeCoroutinesRefined") - put(IGNORED_COROUTINES_REFINED_STATE, "NativeCoroutinesIgnore overrides NativeCoroutinesRefinedState") - put(IGNORED_COROUTINES_STATE, "NativeCoroutinesIgnore overrides NativeCoroutinesState") - put(INVALID_COROUTINES, "NativeCoroutines is only supported on suspend-functions and Flow declarations") - put(INVALID_COROUTINES_IGNORE, "NativeCoroutinesIgnore is only supported on suspend-functions and Flow declarations") - put(INVALID_COROUTINES_REFINED, "NativeCoroutinesRefined is only supported on suspend-functions and Flow declarations") - put(INVALID_COROUTINES_REFINED_STATE, "NativeCoroutinesRefinedState is only supported on StateFlow properties") - put(INVALID_COROUTINES_STATE, "NativeCoroutinesState is only supported on StateFlow properties") - put(INVALID_COROUTINE_SCOPE, "NativeCoroutineScope is only supported on CoroutineScope properties") - put(REDUNDANT_OVERRIDE_COROUTINES, "NativeCoroutines should be applied to overridden declaration instead") - put(REDUNDANT_OVERRIDE_COROUTINES_IGNORE, "NativeCoroutinesIgnore isn't supported on overridden declarations") - put(REDUNDANT_OVERRIDE_COROUTINES_REFINED, "NativeCoroutinesRefined should be applied to overridden declaration instead") - put(REDUNDANT_OVERRIDE_COROUTINES_REFINED_STATE, "NativeCoroutinesRefinedState should be applied to overridden declaration instead") - put(REDUNDANT_OVERRIDE_COROUTINES_STATE, "NativeCoroutinesState should be applied to overridden declaration instead") - put(REDUNDANT_PRIVATE_COROUTINES, "NativeCoroutines is only supported on public declarations") - put(REDUNDANT_PRIVATE_COROUTINES_IGNORE, "NativeCoroutinesIgnore is only supported on public declarations") - put(REDUNDANT_PRIVATE_COROUTINES_REFINED, "NativeCoroutinesRefined is only supported on public declarations") - put(REDUNDANT_PRIVATE_COROUTINES_REFINED_STATE, "NativeCoroutinesRefinedState is only supported on public declarations") - put(REDUNDANT_PRIVATE_COROUTINES_STATE, "NativeCoroutinesState is only supported on public declarations") - } -} diff --git a/kmp-nativecoroutines-compiler/src/main/kotlin/com/rickclephas/kmp/nativecoroutines/compiler/diagnostics/KmpNativeCoroutinesChecker.kt b/kmp-nativecoroutines-compiler/src/main/kotlin/com/rickclephas/kmp/nativecoroutines/compiler/diagnostics/KmpNativeCoroutinesChecker.kt deleted file mode 100644 index 77e7b4c7..00000000 --- a/kmp-nativecoroutines-compiler/src/main/kotlin/com/rickclephas/kmp/nativecoroutines/compiler/diagnostics/KmpNativeCoroutinesChecker.kt +++ /dev/null @@ -1,163 +0,0 @@ -package com.rickclephas.kmp.nativecoroutines.compiler.diagnostics - -import com.intellij.psi.PsiElement -import com.rickclephas.kmp.nativecoroutines.compiler.config.ExposedSeverity -import com.rickclephas.kmp.nativecoroutines.compiler.diagnostics.KmpNativeCoroutinesErrors.CONFLICT_COROUTINES -import com.rickclephas.kmp.nativecoroutines.compiler.diagnostics.KmpNativeCoroutinesErrors.EXPOSED_FLOW_TYPE -import com.rickclephas.kmp.nativecoroutines.compiler.diagnostics.KmpNativeCoroutinesErrors.EXPOSED_FLOW_TYPE_ERROR -import com.rickclephas.kmp.nativecoroutines.compiler.diagnostics.KmpNativeCoroutinesErrors.EXPOSED_SUSPEND_FUNCTION -import com.rickclephas.kmp.nativecoroutines.compiler.diagnostics.KmpNativeCoroutinesErrors.EXPOSED_SUSPEND_FUNCTION_ERROR -import com.rickclephas.kmp.nativecoroutines.compiler.diagnostics.KmpNativeCoroutinesErrors.IGNORED_COROUTINES -import com.rickclephas.kmp.nativecoroutines.compiler.diagnostics.KmpNativeCoroutinesErrors.IGNORED_COROUTINES_STATE -import com.rickclephas.kmp.nativecoroutines.compiler.diagnostics.KmpNativeCoroutinesErrors.INVALID_COROUTINES -import com.rickclephas.kmp.nativecoroutines.compiler.diagnostics.KmpNativeCoroutinesErrors.INVALID_COROUTINES_IGNORE -import com.rickclephas.kmp.nativecoroutines.compiler.diagnostics.KmpNativeCoroutinesErrors.INVALID_COROUTINE_SCOPE -import com.rickclephas.kmp.nativecoroutines.compiler.diagnostics.KmpNativeCoroutinesErrors.INVALID_COROUTINES_STATE -import com.rickclephas.kmp.nativecoroutines.compiler.diagnostics.KmpNativeCoroutinesErrors.REDUNDANT_OVERRIDE_COROUTINES -import com.rickclephas.kmp.nativecoroutines.compiler.diagnostics.KmpNativeCoroutinesErrors.REDUNDANT_OVERRIDE_COROUTINES_IGNORE -import com.rickclephas.kmp.nativecoroutines.compiler.diagnostics.KmpNativeCoroutinesErrors.REDUNDANT_OVERRIDE_COROUTINES_STATE -import com.rickclephas.kmp.nativecoroutines.compiler.diagnostics.KmpNativeCoroutinesErrors.REDUNDANT_PRIVATE_COROUTINES -import com.rickclephas.kmp.nativecoroutines.compiler.diagnostics.KmpNativeCoroutinesErrors.REDUNDANT_PRIVATE_COROUTINES_IGNORE -import com.rickclephas.kmp.nativecoroutines.compiler.diagnostics.KmpNativeCoroutinesErrors.REDUNDANT_PRIVATE_COROUTINES_STATE -import com.rickclephas.kmp.nativecoroutines.compiler.diagnostics.KmpNativeCoroutinesErrors.EXPOSED_STATE_FLOW_PROPERTY -import com.rickclephas.kmp.nativecoroutines.compiler.diagnostics.KmpNativeCoroutinesErrors.EXPOSED_STATE_FLOW_PROPERTY_ERROR -import com.rickclephas.kmp.nativecoroutines.compiler.diagnostics.KmpNativeCoroutinesErrors.IGNORED_COROUTINES_REFINED -import com.rickclephas.kmp.nativecoroutines.compiler.diagnostics.KmpNativeCoroutinesErrors.IGNORED_COROUTINES_REFINED_STATE -import com.rickclephas.kmp.nativecoroutines.compiler.diagnostics.KmpNativeCoroutinesErrors.INVALID_COROUTINES_REFINED -import com.rickclephas.kmp.nativecoroutines.compiler.diagnostics.KmpNativeCoroutinesErrors.INVALID_COROUTINES_REFINED_STATE -import com.rickclephas.kmp.nativecoroutines.compiler.diagnostics.KmpNativeCoroutinesErrors.REDUNDANT_OVERRIDE_COROUTINES_REFINED -import com.rickclephas.kmp.nativecoroutines.compiler.diagnostics.KmpNativeCoroutinesErrors.REDUNDANT_OVERRIDE_COROUTINES_REFINED_STATE -import com.rickclephas.kmp.nativecoroutines.compiler.diagnostics.KmpNativeCoroutinesErrors.REDUNDANT_PRIVATE_COROUTINES_REFINED -import com.rickclephas.kmp.nativecoroutines.compiler.diagnostics.KmpNativeCoroutinesErrors.REDUNDANT_PRIVATE_COROUTINES_REFINED_STATE -import com.rickclephas.kmp.nativecoroutines.compiler.utils.NativeCoroutinesAnnotations -import com.rickclephas.kmp.nativecoroutines.compiler.utils.CoroutinesReturnType -import com.rickclephas.kmp.nativecoroutines.compiler.utils.coroutinesReturnType -import org.jetbrains.kotlin.descriptors.CallableDescriptor -import org.jetbrains.kotlin.descriptors.DeclarationDescriptor -import org.jetbrains.kotlin.descriptors.FunctionDescriptor -import org.jetbrains.kotlin.descriptors.PropertyDescriptor -import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor -import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor -import org.jetbrains.kotlin.diagnostics.DiagnosticFactory0 -import org.jetbrains.kotlin.lexer.KtTokens -import org.jetbrains.kotlin.psi.KtCallableDeclaration -import org.jetbrains.kotlin.psi.KtDeclaration -import org.jetbrains.kotlin.psi.KtElement -import org.jetbrains.kotlin.resolve.BindingTrace -import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils.getSourceFromAnnotation -import org.jetbrains.kotlin.resolve.checkers.DeclarationChecker -import org.jetbrains.kotlin.resolve.checkers.DeclarationCheckerContext -import org.jetbrains.kotlin.resolve.descriptorUtil.isEffectivelyPublicApi - -public class KmpNativeCoroutinesChecker( - private val exposedSeverity: ExposedSeverity -): DeclarationChecker { - - override fun check( - declaration: KtDeclaration, - descriptor: DeclarationDescriptor, - context: DeclarationCheckerContext - ) { - if (descriptor !is CallableDescriptor) return - if (descriptor !is SimpleFunctionDescriptor && descriptor !is PropertyDescriptor) return - val annotations = NativeCoroutinesAnnotations(descriptor) - val isPublic = descriptor.isEffectivelyPublicApi - val isOverride = descriptor.overriddenDescriptors.isNotEmpty() - val isSuspend = descriptor is FunctionDescriptor && descriptor.isSuspend - val returnType = descriptor.coroutinesReturnType - - var annotationCount = 0 - if (annotations.nativeCoroutines != null) annotationCount++ - if (annotations.nativeCoroutinesRefined != null) annotationCount++ - if (annotations.nativeCoroutinesRefinedState != null) annotationCount++ - if (annotations.nativeCoroutinesState != null) annotationCount++ - if (annotationCount > 1) { - context.trace.report(CONFLICT_COROUTINES, annotations.nativeCoroutines, declaration) - context.trace.report(CONFLICT_COROUTINES, annotations.nativeCoroutinesRefined, declaration) - context.trace.report(CONFLICT_COROUTINES, annotations.nativeCoroutinesRefinedState, declaration) - context.trace.report(CONFLICT_COROUTINES, annotations.nativeCoroutinesState, declaration) - } - - val exposedSuspendFunction: DiagnosticFactory0? - val exposedFlowType: DiagnosticFactory0? - val exposedStateFlowProperty: DiagnosticFactory0? - when (exposedSeverity) { - ExposedSeverity.NONE -> { - exposedSuspendFunction = null - exposedFlowType = null - exposedStateFlowProperty = null - } - ExposedSeverity.WARNING -> { - exposedSuspendFunction = EXPOSED_SUSPEND_FUNCTION - exposedFlowType = EXPOSED_FLOW_TYPE - exposedStateFlowProperty = EXPOSED_STATE_FLOW_PROPERTY - } - ExposedSeverity.ERROR -> { - exposedSuspendFunction = EXPOSED_SUSPEND_FUNCTION_ERROR - exposedFlowType = EXPOSED_FLOW_TYPE_ERROR - exposedStateFlowProperty = EXPOSED_STATE_FLOW_PROPERTY_ERROR - } - } - if (isPublic && !isOverride && annotationCount == 0 && annotations.nativeCoroutinesIgnore == null) { - if (isSuspend) { - val element = declaration.modifierList?.getModifier(KtTokens.SUSPEND_KEYWORD) ?: declaration - exposedSuspendFunction?.on(element)?.let(context.trace::report) - } - if (returnType is CoroutinesReturnType.Flow) { - val diagnosticFactory = when { - descriptor !is PropertyDescriptor -> exposedFlowType - returnType != CoroutinesReturnType.Flow.State -> exposedFlowType - else -> exposedStateFlowProperty - } - val element = (declaration as? KtCallableDeclaration)?.let { - it.typeReference ?: it.nameIdentifier - } ?: declaration - diagnosticFactory?.on(element)?.let(context.trace::report) - } - } - - if (annotations.nativeCoroutinesIgnore != null) { - context.trace.report(IGNORED_COROUTINES, annotations.nativeCoroutines, declaration) - context.trace.report(IGNORED_COROUTINES_REFINED, annotations.nativeCoroutinesRefined, declaration) - context.trace.report(IGNORED_COROUTINES_REFINED_STATE, annotations.nativeCoroutinesRefinedState, declaration) - context.trace.report(IGNORED_COROUTINES_STATE, annotations.nativeCoroutinesState, declaration) - } - - if (descriptor !is PropertyDescriptor || returnType != CoroutinesReturnType.CoroutineScope) { - context.trace.report(INVALID_COROUTINE_SCOPE, annotations.nativeCoroutineScope, declaration) - } - if (!isSuspend && returnType !is CoroutinesReturnType.Flow) { - context.trace.report(INVALID_COROUTINES, annotations.nativeCoroutines, declaration) - context.trace.report(INVALID_COROUTINES_IGNORE, annotations.nativeCoroutinesIgnore, declaration) - context.trace.report(INVALID_COROUTINES_REFINED, annotations.nativeCoroutinesRefined, declaration) - } - if (descriptor !is PropertyDescriptor || returnType !is CoroutinesReturnType.Flow.State) { - context.trace.report(INVALID_COROUTINES_REFINED_STATE, annotations.nativeCoroutinesRefinedState, declaration) - context.trace.report(INVALID_COROUTINES_STATE, annotations.nativeCoroutinesState, declaration) - } - - if (isOverride) { - context.trace.report(REDUNDANT_OVERRIDE_COROUTINES, annotations.nativeCoroutines, declaration) - context.trace.report(REDUNDANT_OVERRIDE_COROUTINES_IGNORE, annotations.nativeCoroutinesIgnore, declaration) - context.trace.report(REDUNDANT_OVERRIDE_COROUTINES_REFINED, annotations.nativeCoroutinesRefined, declaration) - context.trace.report(REDUNDANT_OVERRIDE_COROUTINES_REFINED_STATE, annotations.nativeCoroutinesRefinedState, declaration) - context.trace.report(REDUNDANT_OVERRIDE_COROUTINES_STATE, annotations.nativeCoroutinesState, declaration) - } - if (!isPublic) { - context.trace.report(REDUNDANT_PRIVATE_COROUTINES, annotations.nativeCoroutines, declaration) - context.trace.report(REDUNDANT_PRIVATE_COROUTINES_IGNORE, annotations.nativeCoroutinesIgnore, declaration) - context.trace.report(REDUNDANT_PRIVATE_COROUTINES_REFINED, annotations.nativeCoroutinesRefined, declaration) - context.trace.report(REDUNDANT_PRIVATE_COROUTINES_REFINED_STATE, annotations.nativeCoroutinesRefinedState, declaration) - context.trace.report(REDUNDANT_PRIVATE_COROUTINES_STATE, annotations.nativeCoroutinesState, declaration) - } - } - - private fun BindingTrace.report( - diagnosticFactory: DiagnosticFactory0, - annotationDescriptor: AnnotationDescriptor?, - declaration: KtDeclaration - ) { - if (annotationDescriptor == null) return - report(diagnosticFactory.on(getSourceFromAnnotation(annotationDescriptor) ?: declaration)) - } -} diff --git a/kmp-nativecoroutines-compiler/src/main/kotlin/com/rickclephas/kmp/nativecoroutines/compiler/fir/diagnostics/FirDefaultErrorMessages.kt b/kmp-nativecoroutines-compiler/src/main/kotlin/com/rickclephas/kmp/nativecoroutines/compiler/fir/diagnostics/FirDefaultErrorMessages.kt new file mode 100644 index 00000000..8dc8139f --- /dev/null +++ b/kmp-nativecoroutines-compiler/src/main/kotlin/com/rickclephas/kmp/nativecoroutines/compiler/fir/diagnostics/FirDefaultErrorMessages.kt @@ -0,0 +1,66 @@ +package com.rickclephas.kmp.nativecoroutines.compiler.fir.diagnostics + +import com.rickclephas.kmp.nativecoroutines.compiler.fir.diagnostics.FirKmpNativeCoroutinesErrors.CONFLICT_COROUTINES +import com.rickclephas.kmp.nativecoroutines.compiler.fir.diagnostics.FirKmpNativeCoroutinesErrors.EXPOSED_FLOW_TYPE +import com.rickclephas.kmp.nativecoroutines.compiler.fir.diagnostics.FirKmpNativeCoroutinesErrors.EXPOSED_FLOW_TYPE_ERROR +import com.rickclephas.kmp.nativecoroutines.compiler.fir.diagnostics.FirKmpNativeCoroutinesErrors.EXPOSED_STATE_FLOW_PROPERTY +import com.rickclephas.kmp.nativecoroutines.compiler.fir.diagnostics.FirKmpNativeCoroutinesErrors.EXPOSED_STATE_FLOW_PROPERTY_ERROR +import com.rickclephas.kmp.nativecoroutines.compiler.fir.diagnostics.FirKmpNativeCoroutinesErrors.EXPOSED_SUSPEND_FUNCTION +import com.rickclephas.kmp.nativecoroutines.compiler.fir.diagnostics.FirKmpNativeCoroutinesErrors.EXPOSED_SUSPEND_FUNCTION_ERROR +import com.rickclephas.kmp.nativecoroutines.compiler.fir.diagnostics.FirKmpNativeCoroutinesErrors.IGNORED_COROUTINES +import com.rickclephas.kmp.nativecoroutines.compiler.fir.diagnostics.FirKmpNativeCoroutinesErrors.IGNORED_COROUTINES_REFINED +import com.rickclephas.kmp.nativecoroutines.compiler.fir.diagnostics.FirKmpNativeCoroutinesErrors.IGNORED_COROUTINES_REFINED_STATE +import com.rickclephas.kmp.nativecoroutines.compiler.fir.diagnostics.FirKmpNativeCoroutinesErrors.IGNORED_COROUTINES_STATE +import com.rickclephas.kmp.nativecoroutines.compiler.fir.diagnostics.FirKmpNativeCoroutinesErrors.INVALID_COROUTINES +import com.rickclephas.kmp.nativecoroutines.compiler.fir.diagnostics.FirKmpNativeCoroutinesErrors.INVALID_COROUTINES_IGNORE +import com.rickclephas.kmp.nativecoroutines.compiler.fir.diagnostics.FirKmpNativeCoroutinesErrors.INVALID_COROUTINES_REFINED +import com.rickclephas.kmp.nativecoroutines.compiler.fir.diagnostics.FirKmpNativeCoroutinesErrors.INVALID_COROUTINES_REFINED_STATE +import com.rickclephas.kmp.nativecoroutines.compiler.fir.diagnostics.FirKmpNativeCoroutinesErrors.INVALID_COROUTINES_STATE +import com.rickclephas.kmp.nativecoroutines.compiler.fir.diagnostics.FirKmpNativeCoroutinesErrors.INVALID_COROUTINE_SCOPE +import com.rickclephas.kmp.nativecoroutines.compiler.fir.diagnostics.FirKmpNativeCoroutinesErrors.REDUNDANT_OVERRIDE_COROUTINES +import com.rickclephas.kmp.nativecoroutines.compiler.fir.diagnostics.FirKmpNativeCoroutinesErrors.REDUNDANT_OVERRIDE_COROUTINES_IGNORE +import com.rickclephas.kmp.nativecoroutines.compiler.fir.diagnostics.FirKmpNativeCoroutinesErrors.REDUNDANT_OVERRIDE_COROUTINES_REFINED +import com.rickclephas.kmp.nativecoroutines.compiler.fir.diagnostics.FirKmpNativeCoroutinesErrors.REDUNDANT_OVERRIDE_COROUTINES_REFINED_STATE +import com.rickclephas.kmp.nativecoroutines.compiler.fir.diagnostics.FirKmpNativeCoroutinesErrors.REDUNDANT_OVERRIDE_COROUTINES_STATE +import com.rickclephas.kmp.nativecoroutines.compiler.fir.diagnostics.FirKmpNativeCoroutinesErrors.REDUNDANT_PRIVATE_COROUTINES +import com.rickclephas.kmp.nativecoroutines.compiler.fir.diagnostics.FirKmpNativeCoroutinesErrors.REDUNDANT_PRIVATE_COROUTINES_IGNORE +import com.rickclephas.kmp.nativecoroutines.compiler.fir.diagnostics.FirKmpNativeCoroutinesErrors.REDUNDANT_PRIVATE_COROUTINES_REFINED +import com.rickclephas.kmp.nativecoroutines.compiler.fir.diagnostics.FirKmpNativeCoroutinesErrors.REDUNDANT_PRIVATE_COROUTINES_REFINED_STATE +import com.rickclephas.kmp.nativecoroutines.compiler.fir.diagnostics.FirKmpNativeCoroutinesErrors.REDUNDANT_PRIVATE_COROUTINES_STATE +import com.rickclephas.kmp.nativecoroutines.compiler.fir.diagnostics.FirKmpNativeCoroutinesErrors.UNSUPPORTED_CLASS_EXTENSION_PROPERTY +import org.jetbrains.kotlin.diagnostics.KtDiagnosticFactoryToRendererMap +import org.jetbrains.kotlin.diagnostics.rendering.BaseDiagnosticRendererFactory + +@Suppress("DuplicatedCode") +internal object FirDefaultErrorMessages: BaseDiagnosticRendererFactory() { + override val MAP: KtDiagnosticFactoryToRendererMap = KtDiagnosticFactoryToRendererMap("KmpNativeCoroutines").apply { + put(CONFLICT_COROUTINES, "NativeCoroutines, NativeCoroutinesRefined, NativeCoroutinesRefinedState and NativeCoroutinesState can't be combined") + put(EXPOSED_FLOW_TYPE, "Flow type is exposed to ObjC") + put(EXPOSED_FLOW_TYPE_ERROR, "Flow type is exposed to ObjC") + put(EXPOSED_STATE_FLOW_PROPERTY, "StateFlow property is exposed to ObjC") + put(EXPOSED_STATE_FLOW_PROPERTY_ERROR, "StateFlow property is exposed to ObjC") + put(EXPOSED_SUSPEND_FUNCTION, "suspend function is exposed to ObjC") + put(EXPOSED_SUSPEND_FUNCTION_ERROR, "suspend function is exposed to ObjC") + put(IGNORED_COROUTINES, "NativeCoroutinesIgnore overrides NativeCoroutines") + put(IGNORED_COROUTINES_REFINED, "NativeCoroutinesIgnore overrides NativeCoroutinesRefined") + put(IGNORED_COROUTINES_REFINED_STATE, "NativeCoroutinesIgnore overrides NativeCoroutinesRefinedState") + put(IGNORED_COROUTINES_STATE, "NativeCoroutinesIgnore overrides NativeCoroutinesState") + put(INVALID_COROUTINES, "NativeCoroutines is only supported on suspend-functions and Flow declarations") + put(INVALID_COROUTINES_IGNORE, "NativeCoroutinesIgnore is only supported on suspend-functions and Flow declarations") + put(INVALID_COROUTINES_REFINED, "NativeCoroutinesRefined is only supported on suspend-functions and Flow declarations") + put(INVALID_COROUTINES_REFINED_STATE, "NativeCoroutinesRefinedState is only supported on StateFlow properties") + put(INVALID_COROUTINES_STATE, "NativeCoroutinesState is only supported on StateFlow properties") + put(INVALID_COROUTINE_SCOPE, "NativeCoroutineScope is only supported on CoroutineScope properties") + put(REDUNDANT_OVERRIDE_COROUTINES, "NativeCoroutines should be applied to overridden declaration instead") + put(REDUNDANT_OVERRIDE_COROUTINES_IGNORE, "NativeCoroutinesIgnore isn't supported on overridden declarations") + put(REDUNDANT_OVERRIDE_COROUTINES_REFINED, "NativeCoroutinesRefined should be applied to overridden declaration instead") + put(REDUNDANT_OVERRIDE_COROUTINES_REFINED_STATE, "NativeCoroutinesRefinedState should be applied to overridden declaration instead") + put(REDUNDANT_OVERRIDE_COROUTINES_STATE, "NativeCoroutinesState should be applied to overridden declaration instead") + put(REDUNDANT_PRIVATE_COROUTINES, "NativeCoroutines is only supported on public declarations") + put(REDUNDANT_PRIVATE_COROUTINES_IGNORE, "NativeCoroutinesIgnore is only supported on public declarations") + put(REDUNDANT_PRIVATE_COROUTINES_REFINED, "NativeCoroutinesRefined is only supported on public declarations") + put(REDUNDANT_PRIVATE_COROUTINES_REFINED_STATE, "NativeCoroutinesRefinedState is only supported on public declarations") + put(REDUNDANT_PRIVATE_COROUTINES_STATE, "NativeCoroutinesState is only supported on public declarations") + put(UNSUPPORTED_CLASS_EXTENSION_PROPERTY, "Class extension properties aren't supported") + } +} diff --git a/kmp-nativecoroutines-compiler/src/main/kotlin/com/rickclephas/kmp/nativecoroutines/compiler/fir/diagnostics/FirKmpNativeCoroutinesDeclarationChecker.kt b/kmp-nativecoroutines-compiler/src/main/kotlin/com/rickclephas/kmp/nativecoroutines/compiler/fir/diagnostics/FirKmpNativeCoroutinesDeclarationChecker.kt new file mode 100644 index 00000000..90cda341 --- /dev/null +++ b/kmp-nativecoroutines-compiler/src/main/kotlin/com/rickclephas/kmp/nativecoroutines/compiler/fir/diagnostics/FirKmpNativeCoroutinesDeclarationChecker.kt @@ -0,0 +1,166 @@ +package com.rickclephas.kmp.nativecoroutines.compiler.fir.diagnostics + +import com.rickclephas.kmp.nativecoroutines.compiler.config.ExposedSeverity +import com.rickclephas.kmp.nativecoroutines.compiler.fir.diagnostics.FirKmpNativeCoroutinesErrors.CONFLICT_COROUTINES +import com.rickclephas.kmp.nativecoroutines.compiler.fir.diagnostics.FirKmpNativeCoroutinesErrors.EXPOSED_FLOW_TYPE +import com.rickclephas.kmp.nativecoroutines.compiler.fir.diagnostics.FirKmpNativeCoroutinesErrors.EXPOSED_FLOW_TYPE_ERROR +import com.rickclephas.kmp.nativecoroutines.compiler.fir.diagnostics.FirKmpNativeCoroutinesErrors.EXPOSED_STATE_FLOW_PROPERTY +import com.rickclephas.kmp.nativecoroutines.compiler.fir.diagnostics.FirKmpNativeCoroutinesErrors.EXPOSED_STATE_FLOW_PROPERTY_ERROR +import com.rickclephas.kmp.nativecoroutines.compiler.fir.diagnostics.FirKmpNativeCoroutinesErrors.EXPOSED_SUSPEND_FUNCTION +import com.rickclephas.kmp.nativecoroutines.compiler.fir.diagnostics.FirKmpNativeCoroutinesErrors.EXPOSED_SUSPEND_FUNCTION_ERROR +import com.rickclephas.kmp.nativecoroutines.compiler.fir.diagnostics.FirKmpNativeCoroutinesErrors.IGNORED_COROUTINES +import com.rickclephas.kmp.nativecoroutines.compiler.fir.diagnostics.FirKmpNativeCoroutinesErrors.IGNORED_COROUTINES_REFINED +import com.rickclephas.kmp.nativecoroutines.compiler.fir.diagnostics.FirKmpNativeCoroutinesErrors.IGNORED_COROUTINES_REFINED_STATE +import com.rickclephas.kmp.nativecoroutines.compiler.fir.diagnostics.FirKmpNativeCoroutinesErrors.IGNORED_COROUTINES_STATE +import com.rickclephas.kmp.nativecoroutines.compiler.fir.diagnostics.FirKmpNativeCoroutinesErrors.INVALID_COROUTINES +import com.rickclephas.kmp.nativecoroutines.compiler.fir.diagnostics.FirKmpNativeCoroutinesErrors.INVALID_COROUTINES_IGNORE +import com.rickclephas.kmp.nativecoroutines.compiler.fir.diagnostics.FirKmpNativeCoroutinesErrors.INVALID_COROUTINES_REFINED +import com.rickclephas.kmp.nativecoroutines.compiler.fir.diagnostics.FirKmpNativeCoroutinesErrors.INVALID_COROUTINES_REFINED_STATE +import com.rickclephas.kmp.nativecoroutines.compiler.fir.diagnostics.FirKmpNativeCoroutinesErrors.INVALID_COROUTINES_STATE +import com.rickclephas.kmp.nativecoroutines.compiler.fir.diagnostics.FirKmpNativeCoroutinesErrors.INVALID_COROUTINE_SCOPE +import com.rickclephas.kmp.nativecoroutines.compiler.fir.diagnostics.FirKmpNativeCoroutinesErrors.REDUNDANT_OVERRIDE_COROUTINES +import com.rickclephas.kmp.nativecoroutines.compiler.fir.diagnostics.FirKmpNativeCoroutinesErrors.REDUNDANT_OVERRIDE_COROUTINES_IGNORE +import com.rickclephas.kmp.nativecoroutines.compiler.fir.diagnostics.FirKmpNativeCoroutinesErrors.REDUNDANT_OVERRIDE_COROUTINES_REFINED +import com.rickclephas.kmp.nativecoroutines.compiler.fir.diagnostics.FirKmpNativeCoroutinesErrors.REDUNDANT_OVERRIDE_COROUTINES_REFINED_STATE +import com.rickclephas.kmp.nativecoroutines.compiler.fir.diagnostics.FirKmpNativeCoroutinesErrors.REDUNDANT_OVERRIDE_COROUTINES_STATE +import com.rickclephas.kmp.nativecoroutines.compiler.fir.diagnostics.FirKmpNativeCoroutinesErrors.REDUNDANT_PRIVATE_COROUTINES +import com.rickclephas.kmp.nativecoroutines.compiler.fir.diagnostics.FirKmpNativeCoroutinesErrors.REDUNDANT_PRIVATE_COROUTINES_IGNORE +import com.rickclephas.kmp.nativecoroutines.compiler.fir.diagnostics.FirKmpNativeCoroutinesErrors.REDUNDANT_PRIVATE_COROUTINES_REFINED +import com.rickclephas.kmp.nativecoroutines.compiler.fir.diagnostics.FirKmpNativeCoroutinesErrors.REDUNDANT_PRIVATE_COROUTINES_REFINED_STATE +import com.rickclephas.kmp.nativecoroutines.compiler.fir.diagnostics.FirKmpNativeCoroutinesErrors.REDUNDANT_PRIVATE_COROUTINES_STATE +import com.rickclephas.kmp.nativecoroutines.compiler.fir.diagnostics.FirKmpNativeCoroutinesErrors.UNSUPPORTED_CLASS_EXTENSION_PROPERTY +import com.rickclephas.kmp.nativecoroutines.compiler.fir.utils.NativeCoroutinesAnnotations +import com.rickclephas.kmp.nativecoroutines.compiler.fir.utils.getCoroutinesReturnType +import com.rickclephas.kmp.nativecoroutines.compiler.utils.CoroutinesReturnType +import org.jetbrains.kotlin.AbstractKtSourceElement +import org.jetbrains.kotlin.diagnostics.DiagnosticReporter +import org.jetbrains.kotlin.diagnostics.KtDiagnosticFactory0 +import org.jetbrains.kotlin.diagnostics.reportOn +import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext +import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirCallableDeclarationChecker +import org.jetbrains.kotlin.fir.declarations.FirCallableDeclaration +import org.jetbrains.kotlin.fir.declarations.FirProperty +import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction +import org.jetbrains.kotlin.fir.declarations.utils.effectiveVisibility +import org.jetbrains.kotlin.fir.declarations.utils.isExtension +import org.jetbrains.kotlin.fir.declarations.utils.isOverride +import org.jetbrains.kotlin.fir.declarations.utils.isSuspend +import org.jetbrains.kotlin.fir.expressions.FirAnnotation + +internal class FirKmpNativeCoroutinesDeclarationChecker( + exposedSeverity: ExposedSeverity +): FirCallableDeclarationChecker() { + + private val exposedSuspendFunction = when (exposedSeverity) { + ExposedSeverity.NONE -> null + ExposedSeverity.WARNING -> EXPOSED_SUSPEND_FUNCTION + ExposedSeverity.ERROR -> EXPOSED_SUSPEND_FUNCTION_ERROR + } + + private val exposedFlowType = when (exposedSeverity) { + ExposedSeverity.NONE -> null + ExposedSeverity.WARNING -> EXPOSED_FLOW_TYPE + ExposedSeverity.ERROR -> EXPOSED_FLOW_TYPE_ERROR + } + + private val exposedStateFlowProperty = when (exposedSeverity) { + ExposedSeverity.NONE -> null + ExposedSeverity.WARNING -> EXPOSED_STATE_FLOW_PROPERTY + ExposedSeverity.ERROR -> EXPOSED_STATE_FLOW_PROPERTY_ERROR + } + + override fun check(declaration: FirCallableDeclaration, context: CheckerContext, reporter: DiagnosticReporter) { + if (declaration !is FirSimpleFunction && declaration !is FirProperty) return + + fun KtDiagnosticFactory0.reportOn(annotation: FirAnnotation?) { + if (annotation == null) return + reporter.reportOn(annotation.source, this, context) + } + + fun KtDiagnosticFactory0?.reportOn(source: AbstractKtSourceElement?) { + if (this == null) return + reporter.reportOn(source, this, context) + } + + val annotations = NativeCoroutinesAnnotations(declaration, context.session) + val isPublic = declaration.effectiveVisibility.publicApi + val isOverride = declaration.isOverride + val isSuspend = declaration.isSuspend + val returnType = declaration.getCoroutinesReturnType(context.session) + + //region CONFLICT_COROUTINES + val coroutinesAnnotations = listOf( + annotations.nativeCoroutines, + annotations.nativeCoroutinesRefined, + annotations.nativeCoroutinesRefinedState, + annotations.nativeCoroutinesState, + ) + val annotationCount = coroutinesAnnotations.count { it != null } + if (annotationCount > 1) { + coroutinesAnnotations.forEach { CONFLICT_COROUTINES.reportOn(it) } + } + //endregion + + //region EXPOSED_* + if (isPublic && !isOverride && annotationCount == 0 && annotations.nativeCoroutinesIgnore == null) { + if (isSuspend) { + exposedSuspendFunction.reportOn(declaration.source) + } + if (returnType is CoroutinesReturnType.Flow) { + val diagnosticFactory = when { + declaration is FirProperty && returnType == CoroutinesReturnType.Flow.State -> exposedStateFlowProperty + else -> exposedFlowType + } + diagnosticFactory.reportOn(declaration.source) + } + } + //endregion + + //region IGNORED_* + if (annotations.nativeCoroutinesIgnore != null) { + IGNORED_COROUTINES.reportOn(annotations.nativeCoroutines) + IGNORED_COROUTINES_REFINED.reportOn(annotations.nativeCoroutinesRefined) + IGNORED_COROUTINES_REFINED_STATE.reportOn(annotations.nativeCoroutinesRefinedState) + IGNORED_COROUTINES_STATE.reportOn(annotations.nativeCoroutinesState) + } + //endregion + + //region INVALID_* + if (declaration !is FirProperty || returnType != CoroutinesReturnType.CoroutineScope) { + INVALID_COROUTINE_SCOPE.reportOn(annotations.nativeCoroutineScope) + } + if (!isSuspend && returnType !is CoroutinesReturnType.Flow) { + INVALID_COROUTINES.reportOn(annotations.nativeCoroutines) + INVALID_COROUTINES_IGNORE.reportOn(annotations.nativeCoroutinesIgnore) + INVALID_COROUTINES_REFINED.reportOn(annotations.nativeCoroutinesRefined) + } + if (declaration !is FirProperty || returnType !is CoroutinesReturnType.Flow.State) { + INVALID_COROUTINES_REFINED_STATE.reportOn(annotations.nativeCoroutinesRefinedState) + INVALID_COROUTINES_STATE.reportOn(annotations.nativeCoroutinesState) + } + //endregion + + //region REDUNDANT_* + if (isOverride) { + REDUNDANT_OVERRIDE_COROUTINES.reportOn(annotations.nativeCoroutines) + REDUNDANT_OVERRIDE_COROUTINES_IGNORE.reportOn(annotations.nativeCoroutinesIgnore) + REDUNDANT_OVERRIDE_COROUTINES_REFINED.reportOn(annotations.nativeCoroutinesRefined) + REDUNDANT_OVERRIDE_COROUTINES_REFINED_STATE.reportOn(annotations.nativeCoroutinesRefinedState) + REDUNDANT_OVERRIDE_COROUTINES_STATE.reportOn(annotations.nativeCoroutinesState) + } + if (!isPublic) { + REDUNDANT_PRIVATE_COROUTINES.reportOn(annotations.nativeCoroutines) + REDUNDANT_PRIVATE_COROUTINES_IGNORE.reportOn(annotations.nativeCoroutinesIgnore) + REDUNDANT_PRIVATE_COROUTINES_REFINED.reportOn(annotations.nativeCoroutinesRefined) + REDUNDANT_PRIVATE_COROUTINES_REFINED_STATE.reportOn(annotations.nativeCoroutinesRefinedState) + REDUNDANT_PRIVATE_COROUTINES_STATE.reportOn(annotations.nativeCoroutinesState) + } + //endregion + + //region UNSUPPORTED_* + if (declaration is FirProperty && declaration.dispatchReceiverType != null && declaration.isExtension) { + coroutinesAnnotations.forEach { UNSUPPORTED_CLASS_EXTENSION_PROPERTY.reportOn(it) } + } + //endregion + } +} diff --git a/kmp-nativecoroutines-compiler/src/main/kotlin/com/rickclephas/kmp/nativecoroutines/compiler/fir/diagnostics/FirKmpNativeCoroutinesErrors.kt b/kmp-nativecoroutines-compiler/src/main/kotlin/com/rickclephas/kmp/nativecoroutines/compiler/fir/diagnostics/FirKmpNativeCoroutinesErrors.kt new file mode 100644 index 00000000..0766b3e7 --- /dev/null +++ b/kmp-nativecoroutines-compiler/src/main/kotlin/com/rickclephas/kmp/nativecoroutines/compiler/fir/diagnostics/FirKmpNativeCoroutinesErrors.kt @@ -0,0 +1,43 @@ +package com.rickclephas.kmp.nativecoroutines.compiler.fir.diagnostics + +import org.jetbrains.kotlin.diagnostics.KtDiagnosticFactory0 +import org.jetbrains.kotlin.diagnostics.SourceElementPositioningStrategies +import org.jetbrains.kotlin.diagnostics.error0 +import org.jetbrains.kotlin.diagnostics.rendering.RootDiagnosticRendererFactory +import org.jetbrains.kotlin.diagnostics.warning0 +import org.jetbrains.kotlin.psi.KtElement + +public object FirKmpNativeCoroutinesErrors { + public val CONFLICT_COROUTINES: KtDiagnosticFactory0 by error0() + public val EXPOSED_FLOW_TYPE: KtDiagnosticFactory0 by warning0(SourceElementPositioningStrategies.DECLARATION_RETURN_TYPE) + public val EXPOSED_FLOW_TYPE_ERROR: KtDiagnosticFactory0 by error0(SourceElementPositioningStrategies.DECLARATION_RETURN_TYPE) + public val EXPOSED_STATE_FLOW_PROPERTY: KtDiagnosticFactory0 by warning0(SourceElementPositioningStrategies.DECLARATION_RETURN_TYPE) + public val EXPOSED_STATE_FLOW_PROPERTY_ERROR: KtDiagnosticFactory0 by error0(SourceElementPositioningStrategies.DECLARATION_RETURN_TYPE) + public val EXPOSED_SUSPEND_FUNCTION: KtDiagnosticFactory0 by warning0(SourceElementPositioningStrategies.SUSPEND_MODIFIER) + public val EXPOSED_SUSPEND_FUNCTION_ERROR: KtDiagnosticFactory0 by error0(SourceElementPositioningStrategies.SUSPEND_MODIFIER) + public val IGNORED_COROUTINES: KtDiagnosticFactory0 by error0() + public val IGNORED_COROUTINES_REFINED: KtDiagnosticFactory0 by error0() + public val IGNORED_COROUTINES_REFINED_STATE: KtDiagnosticFactory0 by error0() + public val IGNORED_COROUTINES_STATE: KtDiagnosticFactory0 by error0() + public val INVALID_COROUTINES: KtDiagnosticFactory0 by error0() + public val INVALID_COROUTINES_IGNORE: KtDiagnosticFactory0 by error0() + public val INVALID_COROUTINES_REFINED: KtDiagnosticFactory0 by error0() + public val INVALID_COROUTINES_REFINED_STATE: KtDiagnosticFactory0 by error0() + public val INVALID_COROUTINES_STATE: KtDiagnosticFactory0 by error0() + public val INVALID_COROUTINE_SCOPE: KtDiagnosticFactory0 by error0() + public val REDUNDANT_OVERRIDE_COROUTINES: KtDiagnosticFactory0 by warning0() + public val REDUNDANT_OVERRIDE_COROUTINES_IGNORE: KtDiagnosticFactory0 by error0() + public val REDUNDANT_OVERRIDE_COROUTINES_REFINED: KtDiagnosticFactory0 by warning0() + public val REDUNDANT_OVERRIDE_COROUTINES_REFINED_STATE: KtDiagnosticFactory0 by warning0() + public val REDUNDANT_OVERRIDE_COROUTINES_STATE: KtDiagnosticFactory0 by warning0() + public val REDUNDANT_PRIVATE_COROUTINES: KtDiagnosticFactory0 by error0() + public val REDUNDANT_PRIVATE_COROUTINES_IGNORE: KtDiagnosticFactory0 by error0() + public val REDUNDANT_PRIVATE_COROUTINES_REFINED: KtDiagnosticFactory0 by error0() + public val REDUNDANT_PRIVATE_COROUTINES_REFINED_STATE: KtDiagnosticFactory0 by error0() + public val REDUNDANT_PRIVATE_COROUTINES_STATE: KtDiagnosticFactory0 by error0() + public val UNSUPPORTED_CLASS_EXTENSION_PROPERTY: KtDiagnosticFactory0 by error0() + + init { + RootDiagnosticRendererFactory.registerFactory(FirDefaultErrorMessages) + } +} diff --git a/kmp-nativecoroutines-compiler/src/main/kotlin/com/rickclephas/kmp/nativecoroutines/compiler/fir/extensions/KmpNativeCoroutinesFirAdditionalCheckersExtension.kt b/kmp-nativecoroutines-compiler/src/main/kotlin/com/rickclephas/kmp/nativecoroutines/compiler/fir/extensions/KmpNativeCoroutinesFirAdditionalCheckersExtension.kt new file mode 100644 index 00000000..e2258a52 --- /dev/null +++ b/kmp-nativecoroutines-compiler/src/main/kotlin/com/rickclephas/kmp/nativecoroutines/compiler/fir/extensions/KmpNativeCoroutinesFirAdditionalCheckersExtension.kt @@ -0,0 +1,17 @@ +package com.rickclephas.kmp.nativecoroutines.compiler.fir.extensions + +import com.rickclephas.kmp.nativecoroutines.compiler.config.ExposedSeverity +import com.rickclephas.kmp.nativecoroutines.compiler.fir.diagnostics.FirKmpNativeCoroutinesDeclarationChecker +import org.jetbrains.kotlin.fir.FirSession +import org.jetbrains.kotlin.fir.analysis.checkers.declaration.DeclarationCheckers +import org.jetbrains.kotlin.fir.analysis.extensions.FirAdditionalCheckersExtension + +internal class KmpNativeCoroutinesFirAdditionalCheckersExtension( + session: FirSession, + exposedSeverity: ExposedSeverity +): FirAdditionalCheckersExtension(session) { + + override val declarationCheckers: DeclarationCheckers = object : DeclarationCheckers() { + override val callableDeclarationCheckers = setOf(FirKmpNativeCoroutinesDeclarationChecker(exposedSeverity)) + } +} diff --git a/kmp-nativecoroutines-compiler/src/main/kotlin/com/rickclephas/kmp/nativecoroutines/compiler/fir/extensions/KmpNativeCoroutinesFirExtensionRegistrar.kt b/kmp-nativecoroutines-compiler/src/main/kotlin/com/rickclephas/kmp/nativecoroutines/compiler/fir/extensions/KmpNativeCoroutinesFirExtensionRegistrar.kt new file mode 100644 index 00000000..21022a96 --- /dev/null +++ b/kmp-nativecoroutines-compiler/src/main/kotlin/com/rickclephas/kmp/nativecoroutines/compiler/fir/extensions/KmpNativeCoroutinesFirExtensionRegistrar.kt @@ -0,0 +1,14 @@ +package com.rickclephas.kmp.nativecoroutines.compiler.fir.extensions + +import com.rickclephas.kmp.nativecoroutines.compiler.config.EXPOSED_SEVERITY +import com.rickclephas.kmp.nativecoroutines.compiler.config.get +import org.jetbrains.kotlin.config.CompilerConfiguration +import org.jetbrains.kotlin.fir.extensions.FirExtensionRegistrar + +internal class KmpNativeCoroutinesFirExtensionRegistrar( + private val configuration: CompilerConfiguration +): FirExtensionRegistrar() { + override fun ExtensionRegistrarContext.configurePlugin() { + +::KmpNativeCoroutinesFirAdditionalCheckersExtension.bind(configuration[EXPOSED_SEVERITY]) + } +} diff --git a/kmp-nativecoroutines-compiler/src/main/kotlin/com/rickclephas/kmp/nativecoroutines/compiler/fir/utils/CoroutinesReturnType.kt b/kmp-nativecoroutines-compiler/src/main/kotlin/com/rickclephas/kmp/nativecoroutines/compiler/fir/utils/CoroutinesReturnType.kt new file mode 100644 index 00000000..1a2ef6fe --- /dev/null +++ b/kmp-nativecoroutines-compiler/src/main/kotlin/com/rickclephas/kmp/nativecoroutines/compiler/fir/utils/CoroutinesReturnType.kt @@ -0,0 +1,23 @@ +package com.rickclephas.kmp.nativecoroutines.compiler.fir.utils + +import com.rickclephas.kmp.nativecoroutines.compiler.utils.CoroutinesClassIds +import com.rickclephas.kmp.nativecoroutines.compiler.utils.CoroutinesReturnType +import org.jetbrains.kotlin.fir.FirSession +import org.jetbrains.kotlin.fir.analysis.checkers.toClassLikeSymbol +import org.jetbrains.kotlin.fir.declarations.FirCallableDeclaration +import org.jetbrains.kotlin.fir.declarations.fullyExpandedClass +import org.jetbrains.kotlin.fir.resolve.isSubclassOf +import org.jetbrains.kotlin.fir.types.toLookupTag + +internal fun FirCallableDeclaration.getCoroutinesReturnType(session: FirSession): CoroutinesReturnType? { + val symbol = returnTypeRef.toClassLikeSymbol(session)?.fullyExpandedClass(session) ?: return null + return coroutinesReturnTypes.firstNotNullOfOrNull { (lookupTag, returnType) -> + returnType.takeIf { symbol.isSubclassOf(lookupTag, session, isStrict = false, lookupInterfaces = true) } + } +} + +private val coroutinesReturnTypes = mapOf( + CoroutinesClassIds.stateFlow.toLookupTag() to CoroutinesReturnType.Flow.State, + CoroutinesClassIds.flow.toLookupTag() to CoroutinesReturnType.Flow.Generic, + CoroutinesClassIds.coroutineScope.toLookupTag() to CoroutinesReturnType.CoroutineScope, +) diff --git a/kmp-nativecoroutines-compiler/src/main/kotlin/com/rickclephas/kmp/nativecoroutines/compiler/fir/utils/NativeCoroutinesAnnotations.kt b/kmp-nativecoroutines-compiler/src/main/kotlin/com/rickclephas/kmp/nativecoroutines/compiler/fir/utils/NativeCoroutinesAnnotations.kt new file mode 100644 index 00000000..f35628a3 --- /dev/null +++ b/kmp-nativecoroutines-compiler/src/main/kotlin/com/rickclephas/kmp/nativecoroutines/compiler/fir/utils/NativeCoroutinesAnnotations.kt @@ -0,0 +1,18 @@ +package com.rickclephas.kmp.nativecoroutines.compiler.fir.utils + +import com.rickclephas.kmp.nativecoroutines.compiler.utils.NativeCoroutinesClassIds as ClassIds +import org.jetbrains.kotlin.fir.FirSession +import org.jetbrains.kotlin.fir.declarations.FirCallableDeclaration +import org.jetbrains.kotlin.fir.declarations.getAnnotationByClassId + +internal class NativeCoroutinesAnnotations( + declaration: FirCallableDeclaration, + session: FirSession +) { + val nativeCoroutines = declaration.getAnnotationByClassId(ClassIds.nativeCoroutines, session) + val nativeCoroutineScope = declaration.getAnnotationByClassId(ClassIds.nativeCoroutineScope, session) + val nativeCoroutinesIgnore = declaration.getAnnotationByClassId(ClassIds.nativeCoroutinesIgnore, session) + val nativeCoroutinesRefined = declaration.getAnnotationByClassId(ClassIds.nativeCoroutinesRefined, session) + val nativeCoroutinesRefinedState = declaration.getAnnotationByClassId(ClassIds.nativeCoroutinesRefinedState, session) + val nativeCoroutinesState = declaration.getAnnotationByClassId(ClassIds.nativeCoroutinesState, session) +} diff --git a/kmp-nativecoroutines-compiler/src/main/kotlin/com/rickclephas/kmp/nativecoroutines/compiler/utils/CoroutineScope.kt b/kmp-nativecoroutines-compiler/src/main/kotlin/com/rickclephas/kmp/nativecoroutines/compiler/utils/CoroutineScope.kt deleted file mode 100644 index 38ef2986..00000000 --- a/kmp-nativecoroutines-compiler/src/main/kotlin/com/rickclephas/kmp/nativecoroutines/compiler/utils/CoroutineScope.kt +++ /dev/null @@ -1,14 +0,0 @@ -package com.rickclephas.kmp.nativecoroutines.compiler.utils - -import org.jetbrains.kotlin.descriptors.ModuleDescriptor -import org.jetbrains.kotlin.descriptors.findClassifierAcrossModuleDependencies -import org.jetbrains.kotlin.name.ClassId -import org.jetbrains.kotlin.name.FqName -import org.jetbrains.kotlin.types.TypeConstructor - -private val coroutineScopeFqName = FqName("kotlinx.coroutines.CoroutineScope") -private val coroutineScopeClassId = ClassId.topLevel(coroutineScopeFqName) - -internal fun ModuleDescriptor.findCoroutineScopeConstructor(): TypeConstructor = - findClassifierAcrossModuleDependencies(coroutineScopeClassId)?.typeConstructor - ?: throw NoSuchElementException("Couldn't find CoroutineScope constructor") diff --git a/kmp-nativecoroutines-compiler/src/main/kotlin/com/rickclephas/kmp/nativecoroutines/compiler/utils/CoroutinesClassIds.kt b/kmp-nativecoroutines-compiler/src/main/kotlin/com/rickclephas/kmp/nativecoroutines/compiler/utils/CoroutinesClassIds.kt new file mode 100644 index 00000000..fe3c1b5f --- /dev/null +++ b/kmp-nativecoroutines-compiler/src/main/kotlin/com/rickclephas/kmp/nativecoroutines/compiler/utils/CoroutinesClassIds.kt @@ -0,0 +1,10 @@ +package com.rickclephas.kmp.nativecoroutines.compiler.utils + +import com.rickclephas.kmp.nativecoroutines.compiler.utils.CoroutinesFqNames as FqNames +import org.jetbrains.kotlin.name.ClassId + +internal object CoroutinesClassIds { + val coroutineScope: ClassId = ClassId.topLevel(FqNames.coroutineScope) + val flow: ClassId = ClassId.topLevel(FqNames.flow) + val stateFlow: ClassId = ClassId.topLevel(FqNames.stateFlow) +} diff --git a/kmp-nativecoroutines-compiler/src/main/kotlin/com/rickclephas/kmp/nativecoroutines/compiler/utils/CoroutinesFqNames.kt b/kmp-nativecoroutines-compiler/src/main/kotlin/com/rickclephas/kmp/nativecoroutines/compiler/utils/CoroutinesFqNames.kt new file mode 100644 index 00000000..374f47a5 --- /dev/null +++ b/kmp-nativecoroutines-compiler/src/main/kotlin/com/rickclephas/kmp/nativecoroutines/compiler/utils/CoroutinesFqNames.kt @@ -0,0 +1,9 @@ +package com.rickclephas.kmp.nativecoroutines.compiler.utils + +import org.jetbrains.kotlin.name.FqName + +internal object CoroutinesFqNames { + val coroutineScope: FqName = FqName("kotlinx.coroutines.CoroutineScope") + val flow: FqName = FqName("kotlinx.coroutines.flow.Flow") + val stateFlow: FqName = FqName("kotlinx.coroutines.flow.StateFlow") +} diff --git a/kmp-nativecoroutines-compiler/src/main/kotlin/com/rickclephas/kmp/nativecoroutines/compiler/utils/CoroutinesReturnType.kt b/kmp-nativecoroutines-compiler/src/main/kotlin/com/rickclephas/kmp/nativecoroutines/compiler/utils/CoroutinesReturnType.kt index 05385b4c..08cf4806 100644 --- a/kmp-nativecoroutines-compiler/src/main/kotlin/com/rickclephas/kmp/nativecoroutines/compiler/utils/CoroutinesReturnType.kt +++ b/kmp-nativecoroutines-compiler/src/main/kotlin/com/rickclephas/kmp/nativecoroutines/compiler/utils/CoroutinesReturnType.kt @@ -1,10 +1,5 @@ package com.rickclephas.kmp.nativecoroutines.compiler.utils -import org.jetbrains.kotlin.descriptors.CallableDescriptor -import org.jetbrains.kotlin.resolve.calls.inference.returnTypeOrNothing -import org.jetbrains.kotlin.resolve.descriptorUtil.module -import org.jetbrains.kotlin.types.typeUtil.supertypes - internal sealed class CoroutinesReturnType private constructor() { data object CoroutineScope: CoroutinesReturnType() sealed class Flow private constructor(): CoroutinesReturnType() { @@ -12,19 +7,3 @@ internal sealed class CoroutinesReturnType private constructor() { data object State: Flow() } } - -internal val CallableDescriptor.coroutinesReturnType: CoroutinesReturnType? get() { - val returnType = returnTypeOrNothing - val stateFlowConstructor = module.findStateFlowConstructor() - if (returnType.constructor == stateFlowConstructor) return CoroutinesReturnType.Flow.State - val flowConstructor = module.findFlowConstructor() - if (returnType.constructor == flowConstructor) return CoroutinesReturnType.Flow.Generic - val coroutineScopeConstructor = module.findCoroutineScopeConstructor() - if (returnType.constructor == coroutineScopeConstructor) return CoroutinesReturnType.CoroutineScope - returnType.supertypes().forEach { - if (it.constructor == stateFlowConstructor) return CoroutinesReturnType.Flow.State - if (it.constructor == flowConstructor) return CoroutinesReturnType.Flow.Generic - if (it.constructor == coroutineScopeConstructor) return CoroutinesReturnType.CoroutineScope - } - return null -} diff --git a/kmp-nativecoroutines-compiler/src/main/kotlin/com/rickclephas/kmp/nativecoroutines/compiler/utils/Flow.kt b/kmp-nativecoroutines-compiler/src/main/kotlin/com/rickclephas/kmp/nativecoroutines/compiler/utils/Flow.kt deleted file mode 100644 index 3f5050b5..00000000 --- a/kmp-nativecoroutines-compiler/src/main/kotlin/com/rickclephas/kmp/nativecoroutines/compiler/utils/Flow.kt +++ /dev/null @@ -1,22 +0,0 @@ -package com.rickclephas.kmp.nativecoroutines.compiler.utils - -import org.jetbrains.kotlin.descriptors.ModuleDescriptor -import org.jetbrains.kotlin.descriptors.findClassifierAcrossModuleDependencies -import org.jetbrains.kotlin.name.ClassId -import org.jetbrains.kotlin.name.FqName -import org.jetbrains.kotlin.types.TypeConstructor - -private val flowFqName = FqName("kotlinx.coroutines.flow.Flow") -private val flowClassId = ClassId.topLevel(flowFqName) - -internal fun ModuleDescriptor.findFlowConstructor(): TypeConstructor = - findClassifierAcrossModuleDependencies(flowClassId)?.typeConstructor - ?: throw NoSuchElementException("Couldn't find Flow constructor") - - -private val stateFlowFqName = FqName("kotlinx.coroutines.flow.StateFlow") -private val stateFlowClassId = ClassId.topLevel(stateFlowFqName) - -internal fun ModuleDescriptor.findStateFlowConstructor(): TypeConstructor = - findClassifierAcrossModuleDependencies(stateFlowClassId)?.typeConstructor - ?: throw NoSuchElementException("Couldn't find StateFlow constructor") diff --git a/kmp-nativecoroutines-compiler/src/main/kotlin/com/rickclephas/kmp/nativecoroutines/compiler/utils/NativeCoroutinesClassIds.kt b/kmp-nativecoroutines-compiler/src/main/kotlin/com/rickclephas/kmp/nativecoroutines/compiler/utils/NativeCoroutinesClassIds.kt new file mode 100644 index 00000000..df80b15e --- /dev/null +++ b/kmp-nativecoroutines-compiler/src/main/kotlin/com/rickclephas/kmp/nativecoroutines/compiler/utils/NativeCoroutinesClassIds.kt @@ -0,0 +1,13 @@ +package com.rickclephas.kmp.nativecoroutines.compiler.utils + +import com.rickclephas.kmp.nativecoroutines.compiler.utils.NativeCoroutinesFqNames as FqNames +import org.jetbrains.kotlin.name.ClassId + +public object NativeCoroutinesClassIds { + public val nativeCoroutines: ClassId = ClassId.topLevel(FqNames.nativeCoroutines) + public val nativeCoroutineScope: ClassId = ClassId.topLevel(FqNames.nativeCoroutineScope) + public val nativeCoroutinesIgnore: ClassId = ClassId.topLevel(FqNames.nativeCoroutinesIgnore) + public val nativeCoroutinesRefined: ClassId = ClassId.topLevel(FqNames.nativeCoroutinesRefined) + public val nativeCoroutinesRefinedState: ClassId = ClassId.topLevel(FqNames.nativeCoroutinesRefinedState) + public val nativeCoroutinesState: ClassId = ClassId.topLevel(FqNames.nativeCoroutinesState) +} diff --git a/kmp-nativecoroutines-compiler/src/test/generated/com/rickclephas/kmp/nativecoroutines/compiler/runners/ClassicDiagnosticsTestGenerated.java b/kmp-nativecoroutines-compiler/src/test/generated/com/rickclephas/kmp/nativecoroutines/compiler/runners/ClassicDiagnosticsTestGenerated.java new file mode 100644 index 00000000..b0fcb95c --- /dev/null +++ b/kmp-nativecoroutines-compiler/src/test/generated/com/rickclephas/kmp/nativecoroutines/compiler/runners/ClassicDiagnosticsTestGenerated.java @@ -0,0 +1,77 @@ + + +package com.rickclephas.kmp.nativecoroutines.compiler.runners; + +import com.intellij.testFramework.TestDataPath; +import org.jetbrains.kotlin.test.util.KtTestUtil; +import org.jetbrains.kotlin.test.TestMetadata; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +import java.io.File; +import java.util.regex.Pattern; + +/** This class is generated by {@link com.rickclephas.kmp.nativecoroutines.compiler.GenerateTestsKt}. DO NOT MODIFY MANUALLY */ +@SuppressWarnings("all") +@TestMetadata("src/testData/diagnostics") +@TestDataPath("$PROJECT_ROOT") +public class ClassicDiagnosticsTestGenerated extends AbstractClassicDiagnosticsTest { + @Test + public void testAllFilesPresentInDiagnostics() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("src/testData/diagnostics"), Pattern.compile("^(.+)\\.kt$"), null, true); + } + + @Test + @TestMetadata("conflict.kt") + public void testConflict() throws Exception { + runTest("src/testData/diagnostics/conflict.kt"); + } + + @Test + @TestMetadata("exposedAnnotated.kt") + public void testExposedAnnotated() throws Exception { + runTest("src/testData/diagnostics/exposedAnnotated.kt"); + } + + @Test + @TestMetadata("exposedError.kt") + public void testExposedError() throws Exception { + runTest("src/testData/diagnostics/exposedError.kt"); + } + + @Test + @TestMetadata("exposedNone.kt") + public void testExposedNone() throws Exception { + runTest("src/testData/diagnostics/exposedNone.kt"); + } + + @Test + @TestMetadata("exposedWarning.kt") + public void testExposedWarning() throws Exception { + runTest("src/testData/diagnostics/exposedWarning.kt"); + } + + @Test + @TestMetadata("ignored.kt") + public void testIgnored() throws Exception { + runTest("src/testData/diagnostics/ignored.kt"); + } + + @Test + @TestMetadata("invalid.kt") + public void testInvalid() throws Exception { + runTest("src/testData/diagnostics/invalid.kt"); + } + + @Test + @TestMetadata("redundant.kt") + public void testRedundant() throws Exception { + runTest("src/testData/diagnostics/redundant.kt"); + } + + @Test + @TestMetadata("unsupported.kt") + public void testUnsupported() throws Exception { + runTest("src/testData/diagnostics/unsupported.kt"); + } +} diff --git a/kmp-nativecoroutines-compiler/src/test/generated/com/rickclephas/kmp/nativecoroutines/compiler/runners/FirLightTreeDiagnosticsTestGenerated.java b/kmp-nativecoroutines-compiler/src/test/generated/com/rickclephas/kmp/nativecoroutines/compiler/runners/FirLightTreeDiagnosticsTestGenerated.java new file mode 100644 index 00000000..bf59d892 --- /dev/null +++ b/kmp-nativecoroutines-compiler/src/test/generated/com/rickclephas/kmp/nativecoroutines/compiler/runners/FirLightTreeDiagnosticsTestGenerated.java @@ -0,0 +1,77 @@ + + +package com.rickclephas.kmp.nativecoroutines.compiler.runners; + +import com.intellij.testFramework.TestDataPath; +import org.jetbrains.kotlin.test.util.KtTestUtil; +import org.jetbrains.kotlin.test.TestMetadata; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +import java.io.File; +import java.util.regex.Pattern; + +/** This class is generated by {@link com.rickclephas.kmp.nativecoroutines.compiler.GenerateTestsKt}. DO NOT MODIFY MANUALLY */ +@SuppressWarnings("all") +@TestMetadata("src/testData/diagnostics") +@TestDataPath("$PROJECT_ROOT") +public class FirLightTreeDiagnosticsTestGenerated extends AbstractFirLightTreeDiagnosticsTest { + @Test + public void testAllFilesPresentInDiagnostics() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("src/testData/diagnostics"), Pattern.compile("^(.+)\\.kt$"), null, true); + } + + @Test + @TestMetadata("conflict.kt") + public void testConflict() throws Exception { + runTest("src/testData/diagnostics/conflict.kt"); + } + + @Test + @TestMetadata("exposedAnnotated.kt") + public void testExposedAnnotated() throws Exception { + runTest("src/testData/diagnostics/exposedAnnotated.kt"); + } + + @Test + @TestMetadata("exposedError.kt") + public void testExposedError() throws Exception { + runTest("src/testData/diagnostics/exposedError.kt"); + } + + @Test + @TestMetadata("exposedNone.kt") + public void testExposedNone() throws Exception { + runTest("src/testData/diagnostics/exposedNone.kt"); + } + + @Test + @TestMetadata("exposedWarning.kt") + public void testExposedWarning() throws Exception { + runTest("src/testData/diagnostics/exposedWarning.kt"); + } + + @Test + @TestMetadata("ignored.kt") + public void testIgnored() throws Exception { + runTest("src/testData/diagnostics/ignored.kt"); + } + + @Test + @TestMetadata("invalid.kt") + public void testInvalid() throws Exception { + runTest("src/testData/diagnostics/invalid.kt"); + } + + @Test + @TestMetadata("redundant.kt") + public void testRedundant() throws Exception { + runTest("src/testData/diagnostics/redundant.kt"); + } + + @Test + @TestMetadata("unsupported.kt") + public void testUnsupported() throws Exception { + runTest("src/testData/diagnostics/unsupported.kt"); + } +} diff --git a/kmp-nativecoroutines-compiler/src/test/generated/com/rickclephas/kmp/nativecoroutines/compiler/runners/DiagnosticsTestGenerated.java b/kmp-nativecoroutines-compiler/src/test/generated/com/rickclephas/kmp/nativecoroutines/compiler/runners/FirPsiDiagnosticsTestGenerated.java similarity index 89% rename from kmp-nativecoroutines-compiler/src/test/generated/com/rickclephas/kmp/nativecoroutines/compiler/runners/DiagnosticsTestGenerated.java rename to kmp-nativecoroutines-compiler/src/test/generated/com/rickclephas/kmp/nativecoroutines/compiler/runners/FirPsiDiagnosticsTestGenerated.java index dd9298ee..8e789f92 100644 --- a/kmp-nativecoroutines-compiler/src/test/generated/com/rickclephas/kmp/nativecoroutines/compiler/runners/DiagnosticsTestGenerated.java +++ b/kmp-nativecoroutines-compiler/src/test/generated/com/rickclephas/kmp/nativecoroutines/compiler/runners/FirPsiDiagnosticsTestGenerated.java @@ -15,7 +15,7 @@ @SuppressWarnings("all") @TestMetadata("src/testData/diagnostics") @TestDataPath("$PROJECT_ROOT") -public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { +public class FirPsiDiagnosticsTestGenerated extends AbstractFirPsiDiagnosticsTest { @Test public void testAllFilesPresentInDiagnostics() throws Exception { KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("src/testData/diagnostics"), Pattern.compile("^(.+)\\.kt$"), null, true); @@ -68,4 +68,10 @@ public void testInvalid() throws Exception { public void testRedundant() throws Exception { runTest("src/testData/diagnostics/redundant.kt"); } + + @Test + @TestMetadata("unsupported.kt") + public void testUnsupported() throws Exception { + runTest("src/testData/diagnostics/unsupported.kt"); + } } diff --git a/kmp-nativecoroutines-compiler/src/test/kotlin/com/rickclephas/kmp/nativecoroutines/compiler/GenerateTests.kt b/kmp-nativecoroutines-compiler/src/test/kotlin/com/rickclephas/kmp/nativecoroutines/compiler/GenerateTests.kt index 8c712acc..27b05b03 100644 --- a/kmp-nativecoroutines-compiler/src/test/kotlin/com/rickclephas/kmp/nativecoroutines/compiler/GenerateTests.kt +++ b/kmp-nativecoroutines-compiler/src/test/kotlin/com/rickclephas/kmp/nativecoroutines/compiler/GenerateTests.kt @@ -1,12 +1,20 @@ package com.rickclephas.kmp.nativecoroutines.compiler -import com.rickclephas.kmp.nativecoroutines.compiler.runners.AbstractDiagnosticsTest +import com.rickclephas.kmp.nativecoroutines.compiler.runners.AbstractClassicDiagnosticsTest +import com.rickclephas.kmp.nativecoroutines.compiler.runners.AbstractFirLightTreeDiagnosticsTest +import com.rickclephas.kmp.nativecoroutines.compiler.runners.AbstractFirPsiDiagnosticsTest import org.jetbrains.kotlin.generators.generateTestGroupSuiteWithJUnit5 fun main() { generateTestGroupSuiteWithJUnit5 { testGroup(testDataRoot = "src/testData", testsRoot = "src/test/generated") { - testClass { + testClass { + model("diagnostics") + } + testClass { + model("diagnostics") + } + testClass { model("diagnostics") } } diff --git a/kmp-nativecoroutines-compiler/src/test/kotlin/com/rickclephas/kmp/nativecoroutines/compiler/runners/AbstractBaseDiagnosticsTest.kt b/kmp-nativecoroutines-compiler/src/test/kotlin/com/rickclephas/kmp/nativecoroutines/compiler/runners/AbstractBaseDiagnosticsTest.kt new file mode 100644 index 00000000..4d906c20 --- /dev/null +++ b/kmp-nativecoroutines-compiler/src/test/kotlin/com/rickclephas/kmp/nativecoroutines/compiler/runners/AbstractBaseDiagnosticsTest.kt @@ -0,0 +1,32 @@ +package com.rickclephas.kmp.nativecoroutines.compiler.runners + +import org.jetbrains.kotlin.platform.konan.NativePlatforms +import org.jetbrains.kotlin.test.Constructor +import org.jetbrains.kotlin.test.builders.TestConfigurationBuilder +import org.jetbrains.kotlin.test.directives.ConfigurationDirectives +import org.jetbrains.kotlin.test.frontend.classic.handlers.OldNewInferenceMetaInfoProcessor +import org.jetbrains.kotlin.test.model.* +import org.jetbrains.kotlin.test.services.configuration.CommonEnvironmentConfigurator +import org.jetbrains.kotlin.test.services.configuration.NativeEnvironmentConfigurator + +abstract class AbstractBaseDiagnosticsTest>: AbstractKmpNativeCoroutinesTest() { + abstract val targetFrontend: FrontendKind + abstract val frontend: Constructor> + abstract fun TestConfigurationBuilder.handlersSetup() + + final override fun TestConfigurationBuilder.configuration() { + globalDefaults { + frontend = targetFrontend + targetPlatform = NativePlatforms.unspecifiedNativePlatform + dependencyKind = DependencyKind.Source + } + defaultDirectives { + +ConfigurationDirectives.WITH_STDLIB + } + enableMetaInfoHandler() + useConfigurators(::CommonEnvironmentConfigurator, ::NativeEnvironmentConfigurator) + useMetaInfoProcessors(::OldNewInferenceMetaInfoProcessor) + facadeStep(frontend) + handlersSetup() + } +} diff --git a/kmp-nativecoroutines-compiler/src/test/kotlin/com/rickclephas/kmp/nativecoroutines/compiler/runners/AbstractClassicDiagnosticsTest.kt b/kmp-nativecoroutines-compiler/src/test/kotlin/com/rickclephas/kmp/nativecoroutines/compiler/runners/AbstractClassicDiagnosticsTest.kt new file mode 100644 index 00000000..8337a803 --- /dev/null +++ b/kmp-nativecoroutines-compiler/src/test/kotlin/com/rickclephas/kmp/nativecoroutines/compiler/runners/AbstractClassicDiagnosticsTest.kt @@ -0,0 +1,19 @@ +package com.rickclephas.kmp.nativecoroutines.compiler.runners + +import org.jetbrains.kotlin.test.Constructor +import org.jetbrains.kotlin.test.builders.TestConfigurationBuilder +import org.jetbrains.kotlin.test.builders.classicFrontendHandlersStep +import org.jetbrains.kotlin.test.frontend.classic.ClassicFrontendFacade +import org.jetbrains.kotlin.test.frontend.classic.ClassicFrontendOutputArtifact +import org.jetbrains.kotlin.test.frontend.classic.handlers.ClassicDiagnosticsHandler +import org.jetbrains.kotlin.test.model.* + +abstract class AbstractClassicDiagnosticsTest: AbstractBaseDiagnosticsTest() { + final override val targetFrontend: FrontendKind + get() = FrontendKinds.ClassicFrontend + final override val frontend: Constructor> + get() = ::ClassicFrontendFacade + final override fun TestConfigurationBuilder.handlersSetup() = classicFrontendHandlersStep { + useHandlers(::ClassicDiagnosticsHandler) + } +} diff --git a/kmp-nativecoroutines-compiler/src/test/kotlin/com/rickclephas/kmp/nativecoroutines/compiler/runners/AbstractDiagnosticsTest.kt b/kmp-nativecoroutines-compiler/src/test/kotlin/com/rickclephas/kmp/nativecoroutines/compiler/runners/AbstractDiagnosticsTest.kt deleted file mode 100644 index 00e62184..00000000 --- a/kmp-nativecoroutines-compiler/src/test/kotlin/com/rickclephas/kmp/nativecoroutines/compiler/runners/AbstractDiagnosticsTest.kt +++ /dev/null @@ -1,29 +0,0 @@ -package com.rickclephas.kmp.nativecoroutines.compiler.runners - -import org.jetbrains.kotlin.platform.konan.NativePlatforms -import org.jetbrains.kotlin.test.builders.TestConfigurationBuilder -import org.jetbrains.kotlin.test.builders.classicFrontendHandlersStep -import org.jetbrains.kotlin.test.frontend.classic.ClassicFrontendFacade -import org.jetbrains.kotlin.test.frontend.classic.handlers.ClassicDiagnosticsHandler -import org.jetbrains.kotlin.test.frontend.classic.handlers.OldNewInferenceMetaInfoProcessor -import org.jetbrains.kotlin.test.model.DependencyKind -import org.jetbrains.kotlin.test.model.FrontendKinds -import org.jetbrains.kotlin.test.services.configuration.CommonEnvironmentConfigurator - -abstract class AbstractDiagnosticsTest: AbstractKmpNativeCoroutinesTest() { - - override fun TestConfigurationBuilder.configuration() { - globalDefaults { - frontend = FrontendKinds.ClassicFrontend - targetPlatform = NativePlatforms.unspecifiedNativePlatform - dependencyKind = DependencyKind.Source - } - enableMetaInfoHandler() - useConfigurators(::CommonEnvironmentConfigurator) - useMetaInfoProcessors(::OldNewInferenceMetaInfoProcessor) - facadeStep(::ClassicFrontendFacade) - classicFrontendHandlersStep { - useHandlers(::ClassicDiagnosticsHandler) - } - } -} diff --git a/kmp-nativecoroutines-compiler/src/test/kotlin/com/rickclephas/kmp/nativecoroutines/compiler/runners/AbstractFirDiagnosticsTest.kt b/kmp-nativecoroutines-compiler/src/test/kotlin/com/rickclephas/kmp/nativecoroutines/compiler/runners/AbstractFirDiagnosticsTest.kt new file mode 100644 index 00000000..6013ff1e --- /dev/null +++ b/kmp-nativecoroutines-compiler/src/test/kotlin/com/rickclephas/kmp/nativecoroutines/compiler/runners/AbstractFirDiagnosticsTest.kt @@ -0,0 +1,40 @@ +package com.rickclephas.kmp.nativecoroutines.compiler.runners + +import org.jetbrains.kotlin.test.Constructor +import org.jetbrains.kotlin.test.FirParser +import org.jetbrains.kotlin.test.builders.TestConfigurationBuilder +import org.jetbrains.kotlin.test.builders.firHandlersStep +import org.jetbrains.kotlin.test.directives.configureFirParser +import org.jetbrains.kotlin.test.frontend.fir.FirFrontendFacade +import org.jetbrains.kotlin.test.frontend.fir.FirOutputArtifact +import org.jetbrains.kotlin.test.frontend.fir.handlers.FirDiagnosticsHandler +import org.jetbrains.kotlin.test.frontend.fir.handlers.FirResolvedTypesVerifier +import org.jetbrains.kotlin.test.model.* +import org.jetbrains.kotlin.test.runners.configurationForClassicAndFirTestsAlongside +import org.jetbrains.kotlin.test.runners.enableLazyResolvePhaseChecking + +abstract class AbstractFirBaseDiagnosticsTest( + private val parser: FirParser +): AbstractBaseDiagnosticsTest() { + final override val targetFrontend: FrontendKind + get() = FrontendKinds.FIR + final override val frontend: Constructor> + get() = ::FirFrontendFacade + final override fun TestConfigurationBuilder.handlersSetup() = firHandlersStep { + useHandlers(::FirDiagnosticsHandler, ::FirResolvedTypesVerifier) + } + + override fun configure(builder: TestConfigurationBuilder) { + super.configure(builder) + with(builder) { + configureFirParser(parser) + enableLazyResolvePhaseChecking() + forTestsMatching("testData/diagnostics/*") { + configurationForClassicAndFirTestsAlongside() + } + } + } +} + +abstract class AbstractFirPsiDiagnosticsTest: AbstractFirBaseDiagnosticsTest(FirParser.Psi) +abstract class AbstractFirLightTreeDiagnosticsTest: AbstractFirBaseDiagnosticsTest(FirParser.LightTree) diff --git a/kmp-nativecoroutines-compiler/src/testData/diagnostics/conflict.kt b/kmp-nativecoroutines-compiler/src/testData/diagnostics/conflict.kt index 7944639d..d68d8511 100644 --- a/kmp-nativecoroutines-compiler/src/testData/diagnostics/conflict.kt +++ b/kmp-nativecoroutines-compiler/src/testData/diagnostics/conflict.kt @@ -1,3 +1,5 @@ +// FIR_IDENTICAL + import com.rickclephas.kmp.nativecoroutines.NativeCoroutines import com.rickclephas.kmp.nativecoroutines.NativeCoroutinesRefined import com.rickclephas.kmp.nativecoroutines.NativeCoroutinesRefinedState diff --git a/kmp-nativecoroutines-compiler/src/testData/diagnostics/exposedAnnotated.kt b/kmp-nativecoroutines-compiler/src/testData/diagnostics/exposedAnnotated.kt index 4a5eba6f..d589efb7 100644 --- a/kmp-nativecoroutines-compiler/src/testData/diagnostics/exposedAnnotated.kt +++ b/kmp-nativecoroutines-compiler/src/testData/diagnostics/exposedAnnotated.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL // EXPOSED_SEVERITY: WARNING // FILE: customFlow.kt diff --git a/kmp-nativecoroutines-compiler/src/testData/diagnostics/exposedError.kt b/kmp-nativecoroutines-compiler/src/testData/diagnostics/exposedError.kt index 24b6916d..048e3eca 100644 --- a/kmp-nativecoroutines-compiler/src/testData/diagnostics/exposedError.kt +++ b/kmp-nativecoroutines-compiler/src/testData/diagnostics/exposedError.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL // EXPOSED_SEVERITY: ERROR // FILE: customFlows.kt diff --git a/kmp-nativecoroutines-compiler/src/testData/diagnostics/exposedNone.kt b/kmp-nativecoroutines-compiler/src/testData/diagnostics/exposedNone.kt index 276f0fbb..6951a7f1 100644 --- a/kmp-nativecoroutines-compiler/src/testData/diagnostics/exposedNone.kt +++ b/kmp-nativecoroutines-compiler/src/testData/diagnostics/exposedNone.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL // EXPOSED_SEVERITY: NONE // FILE: customFlows.kt diff --git a/kmp-nativecoroutines-compiler/src/testData/diagnostics/exposedWarning.kt b/kmp-nativecoroutines-compiler/src/testData/diagnostics/exposedWarning.kt index f287a88a..297eace6 100644 --- a/kmp-nativecoroutines-compiler/src/testData/diagnostics/exposedWarning.kt +++ b/kmp-nativecoroutines-compiler/src/testData/diagnostics/exposedWarning.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL // EXPOSED_SEVERITY: WARNING // FILE: customFlows.kt diff --git a/kmp-nativecoroutines-compiler/src/testData/diagnostics/ignored.kt b/kmp-nativecoroutines-compiler/src/testData/diagnostics/ignored.kt index 6c4983d6..f60d2dca 100644 --- a/kmp-nativecoroutines-compiler/src/testData/diagnostics/ignored.kt +++ b/kmp-nativecoroutines-compiler/src/testData/diagnostics/ignored.kt @@ -1,3 +1,5 @@ +// FIR_IDENTICAL + import com.rickclephas.kmp.nativecoroutines.NativeCoroutines import com.rickclephas.kmp.nativecoroutines.NativeCoroutinesIgnore import com.rickclephas.kmp.nativecoroutines.NativeCoroutinesRefined diff --git a/kmp-nativecoroutines-compiler/src/testData/diagnostics/invalid.kt b/kmp-nativecoroutines-compiler/src/testData/diagnostics/invalid.kt index 95cea7e0..fc6edc81 100644 --- a/kmp-nativecoroutines-compiler/src/testData/diagnostics/invalid.kt +++ b/kmp-nativecoroutines-compiler/src/testData/diagnostics/invalid.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL // FILE: customStateFlow.kt import kotlinx.coroutines.flow.StateFlow diff --git a/kmp-nativecoroutines-compiler/src/testData/diagnostics/redundant.kt b/kmp-nativecoroutines-compiler/src/testData/diagnostics/redundant.kt index 5c8aad6a..c865cb2d 100644 --- a/kmp-nativecoroutines-compiler/src/testData/diagnostics/redundant.kt +++ b/kmp-nativecoroutines-compiler/src/testData/diagnostics/redundant.kt @@ -1,3 +1,5 @@ +// FIR_IDENTICAL + import com.rickclephas.kmp.nativecoroutines.NativeCoroutines import com.rickclephas.kmp.nativecoroutines.NativeCoroutinesIgnore import com.rickclephas.kmp.nativecoroutines.NativeCoroutinesRefined diff --git a/kmp-nativecoroutines-compiler/src/testData/diagnostics/unsupported.kt b/kmp-nativecoroutines-compiler/src/testData/diagnostics/unsupported.kt new file mode 100644 index 00000000..f041b9df --- /dev/null +++ b/kmp-nativecoroutines-compiler/src/testData/diagnostics/unsupported.kt @@ -0,0 +1,26 @@ +// FIR_IDENTICAL + +import com.rickclephas.kmp.nativecoroutines.NativeCoroutines +import com.rickclephas.kmp.nativecoroutines.NativeCoroutinesIgnore +import com.rickclephas.kmp.nativecoroutines.NativeCoroutinesRefined +import com.rickclephas.kmp.nativecoroutines.NativeCoroutinesRefinedState +import com.rickclephas.kmp.nativecoroutines.NativeCoroutinesState +import kotlinx.coroutines.flow.StateFlow + +class TestClass { + + @NativeCoroutines + val Int.extensionPropertyA: StateFlow get() = throw Throwable() + + @NativeCoroutinesIgnore + val Int.extensionPropertyE: StateFlow get() = throw Throwable() + + @NativeCoroutinesRefined + val Int.extensionPropertyB: StateFlow get() = throw Throwable() + + @NativeCoroutinesRefinedState + val Int.extensionPropertyC: StateFlow get() = throw Throwable() + + @NativeCoroutinesState + val Int.extensionPropertyD: StateFlow get() = throw Throwable() +} diff --git a/kmp-nativecoroutines-core/build.gradle.kts b/kmp-nativecoroutines-core/build.gradle.kts index 5d5654e6..923a32e5 100644 --- a/kmp-nativecoroutines-core/build.gradle.kts +++ b/kmp-nativecoroutines-core/build.gradle.kts @@ -1,3 +1,5 @@ +import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi + plugins { alias(libs.plugins.kotlin.multiplatform) `kmp-nativecoroutines-publish` @@ -7,19 +9,28 @@ kotlin { explicitApi() jvmToolchain(11) - val macosX64 = macosX64() - val macosArm64 = macosArm64() - val iosArm64 = iosArm64() - val iosX64 = iosX64() - val iosSimulatorArm64 = iosSimulatorArm64() - val watchosArm32 = watchosArm32() - val watchosArm64 = watchosArm64() - val watchosX64 = watchosX64() - val watchosSimulatorArm64 = watchosSimulatorArm64() - val watchosDeviceArm64 = watchosDeviceArm64() - val tvosArm64 = tvosArm64() - val tvosX64 = tvosX64() - val tvosSimulatorArm64 = tvosSimulatorArm64() + @OptIn(ExperimentalKotlinGradlePluginApi::class) + applyDefaultHierarchyTemplate { + common { + group("nativeCoroutines") { + group("apple") + } + } + } + + macosX64() + macosArm64() + iosArm64() + iosX64() + iosSimulatorArm64() + watchosArm32() + watchosArm64() + watchosX64() + watchosSimulatorArm64() + watchosDeviceArm64() + tvosArm64() + tvosX64() + tvosSimulatorArm64() jvm() js { browser() @@ -28,42 +39,26 @@ kotlin { linuxArm64() linuxX64() mingwX64() + + targets.all { + compilations.all { + compilerOptions.configure { + freeCompilerArgs.add("-Xexpect-actual-classes") + } + } + } + sourceSets { - val commonMain by getting { + commonMain { dependencies { api(libs.kotlinx.coroutines.core) } } - val commonTest by getting { + commonTest { dependencies { implementation(libs.kotlin.test) implementation(libs.kotlinx.coroutines.test) } } - val nativeCoroutinesMain by creating { - dependsOn(commonMain) - } - val nativeCoroutinesTest by creating { - dependsOn(commonTest) - } - val appleMain by creating { - dependsOn(nativeCoroutinesMain) - } - val appleTest by creating { - dependsOn(nativeCoroutinesTest) - } - listOf( - macosX64, macosArm64, - iosArm64, iosX64, iosSimulatorArm64, - watchosArm32, watchosArm64, watchosX64, watchosSimulatorArm64, watchosDeviceArm64, - tvosArm64, tvosX64, tvosSimulatorArm64 - ).forEach { - getByName("${it.targetName}Main") { - dependsOn(appleMain) - } - getByName("${it.targetName}Test") { - dependsOn(appleTest) - } - } } } diff --git a/kmp-nativecoroutines-idea-plugin/build.gradle.kts b/kmp-nativecoroutines-idea-plugin/build.gradle.kts index b56c18e1..699f106a 100644 --- a/kmp-nativecoroutines-idea-plugin/build.gradle.kts +++ b/kmp-nativecoroutines-idea-plugin/build.gradle.kts @@ -39,6 +39,9 @@ tasks { publishPlugin { token = System.getenv("IDEA_PUBLISH_TOKEN") + if ((version as String).contains("-kotlin-")) { + channels = listOf("eap") + } } runIde { diff --git a/kmp-nativecoroutines-idea-plugin/src/main/kotlin/com/rickclephas/kmp/nativecoroutines/idea/compiler/extensions/KmpNativeCoroutinesStorageComponentContainerContributor.kt b/kmp-nativecoroutines-idea-plugin/src/main/kotlin/com/rickclephas/kmp/nativecoroutines/idea/compiler/extensions/KmpNativeCoroutinesStorageComponentContainerContributor.kt index 5bf917ea..c98f2db3 100644 --- a/kmp-nativecoroutines-idea-plugin/src/main/kotlin/com/rickclephas/kmp/nativecoroutines/idea/compiler/extensions/KmpNativeCoroutinesStorageComponentContainerContributor.kt +++ b/kmp-nativecoroutines-idea-plugin/src/main/kotlin/com/rickclephas/kmp/nativecoroutines/idea/compiler/extensions/KmpNativeCoroutinesStorageComponentContainerContributor.kt @@ -2,7 +2,7 @@ package com.rickclephas.kmp.nativecoroutines.idea.compiler.extensions import com.rickclephas.kmp.nativecoroutines.compiler.config.ConfigOption import com.rickclephas.kmp.nativecoroutines.compiler.config.EXPOSED_SEVERITY -import com.rickclephas.kmp.nativecoroutines.compiler.diagnostics.KmpNativeCoroutinesChecker +import com.rickclephas.kmp.nativecoroutines.compiler.classic.diagnostics.KmpNativeCoroutinesChecker import org.jetbrains.kotlin.analyzer.moduleInfo import org.jetbrains.kotlin.container.StorageComponentContainer import org.jetbrains.kotlin.container.useInstance diff --git a/kmp-nativecoroutines-idea-plugin/src/main/kotlin/com/rickclephas/kmp/nativecoroutines/idea/quickfixes/AddAnnotationFixFactory.kt b/kmp-nativecoroutines-idea-plugin/src/main/kotlin/com/rickclephas/kmp/nativecoroutines/idea/quickfixes/AddAnnotationFixFactory.kt index b16baecc..679a47e6 100644 --- a/kmp-nativecoroutines-idea-plugin/src/main/kotlin/com/rickclephas/kmp/nativecoroutines/idea/quickfixes/AddAnnotationFixFactory.kt +++ b/kmp-nativecoroutines-idea-plugin/src/main/kotlin/com/rickclephas/kmp/nativecoroutines/idea/quickfixes/AddAnnotationFixFactory.kt @@ -3,7 +3,6 @@ package com.rickclephas.kmp.nativecoroutines.idea.quickfixes import com.intellij.codeInsight.intention.HighPriorityAction import com.intellij.codeInsight.intention.IntentionAction import com.intellij.codeInsight.intention.LowPriorityAction -import com.intellij.psi.PsiElement import com.intellij.psi.util.findParentOfType import com.rickclephas.kmp.nativecoroutines.compiler.utils.NativeCoroutinesFqNames import org.jetbrains.kotlin.diagnostics.Diagnostic @@ -13,17 +12,18 @@ import org.jetbrains.kotlin.idea.quickfix.KotlinIntentionActionsFactory import org.jetbrains.kotlin.idea.quickfix.QuickFixes import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.psi.KtCallableDeclaration +import org.jetbrains.kotlin.psi.KtDeclaration import org.jetbrains.kotlin.psi.KtModifierListOwner internal class AddAnnotationFixFactory( - private val diagnosticFactories: List>, + private val diagnosticFactories: List>, private val preferredFqName: FqName, private val alternativeFqName: FqName? ): KotlinIntentionActionsFactory() { internal companion object { fun QuickFixes.registerAddAnnotationFix( - diagnosticFactories: List>, + diagnosticFactories: List>, preferredFqName: FqName, alternativeFqName: FqName? = null ) { diff --git a/kmp-nativecoroutines-idea-plugin/src/main/kotlin/com/rickclephas/kmp/nativecoroutines/idea/quickfixes/KmpNativeCoroutinesQuickFixContributor.kt b/kmp-nativecoroutines-idea-plugin/src/main/kotlin/com/rickclephas/kmp/nativecoroutines/idea/quickfixes/KmpNativeCoroutinesQuickFixContributor.kt index 9678b5b3..a94ad397 100644 --- a/kmp-nativecoroutines-idea-plugin/src/main/kotlin/com/rickclephas/kmp/nativecoroutines/idea/quickfixes/KmpNativeCoroutinesQuickFixContributor.kt +++ b/kmp-nativecoroutines-idea-plugin/src/main/kotlin/com/rickclephas/kmp/nativecoroutines/idea/quickfixes/KmpNativeCoroutinesQuickFixContributor.kt @@ -1,32 +1,32 @@ package com.rickclephas.kmp.nativecoroutines.idea.quickfixes -import com.rickclephas.kmp.nativecoroutines.compiler.diagnostics.KmpNativeCoroutinesErrors.CONFLICT_COROUTINES -import com.rickclephas.kmp.nativecoroutines.compiler.diagnostics.KmpNativeCoroutinesErrors.EXPOSED_FLOW_TYPE -import com.rickclephas.kmp.nativecoroutines.compiler.diagnostics.KmpNativeCoroutinesErrors.EXPOSED_FLOW_TYPE_ERROR -import com.rickclephas.kmp.nativecoroutines.compiler.diagnostics.KmpNativeCoroutinesErrors.EXPOSED_STATE_FLOW_PROPERTY -import com.rickclephas.kmp.nativecoroutines.compiler.diagnostics.KmpNativeCoroutinesErrors.EXPOSED_STATE_FLOW_PROPERTY_ERROR -import com.rickclephas.kmp.nativecoroutines.compiler.diagnostics.KmpNativeCoroutinesErrors.EXPOSED_SUSPEND_FUNCTION -import com.rickclephas.kmp.nativecoroutines.compiler.diagnostics.KmpNativeCoroutinesErrors.EXPOSED_SUSPEND_FUNCTION_ERROR -import com.rickclephas.kmp.nativecoroutines.compiler.diagnostics.KmpNativeCoroutinesErrors.IGNORED_COROUTINES -import com.rickclephas.kmp.nativecoroutines.compiler.diagnostics.KmpNativeCoroutinesErrors.IGNORED_COROUTINES_REFINED -import com.rickclephas.kmp.nativecoroutines.compiler.diagnostics.KmpNativeCoroutinesErrors.IGNORED_COROUTINES_REFINED_STATE -import com.rickclephas.kmp.nativecoroutines.compiler.diagnostics.KmpNativeCoroutinesErrors.IGNORED_COROUTINES_STATE -import com.rickclephas.kmp.nativecoroutines.compiler.diagnostics.KmpNativeCoroutinesErrors.INVALID_COROUTINES -import com.rickclephas.kmp.nativecoroutines.compiler.diagnostics.KmpNativeCoroutinesErrors.INVALID_COROUTINES_IGNORE -import com.rickclephas.kmp.nativecoroutines.compiler.diagnostics.KmpNativeCoroutinesErrors.INVALID_COROUTINES_REFINED -import com.rickclephas.kmp.nativecoroutines.compiler.diagnostics.KmpNativeCoroutinesErrors.INVALID_COROUTINES_REFINED_STATE -import com.rickclephas.kmp.nativecoroutines.compiler.diagnostics.KmpNativeCoroutinesErrors.INVALID_COROUTINES_STATE -import com.rickclephas.kmp.nativecoroutines.compiler.diagnostics.KmpNativeCoroutinesErrors.INVALID_COROUTINE_SCOPE -import com.rickclephas.kmp.nativecoroutines.compiler.diagnostics.KmpNativeCoroutinesErrors.REDUNDANT_OVERRIDE_COROUTINES -import com.rickclephas.kmp.nativecoroutines.compiler.diagnostics.KmpNativeCoroutinesErrors.REDUNDANT_OVERRIDE_COROUTINES_IGNORE -import com.rickclephas.kmp.nativecoroutines.compiler.diagnostics.KmpNativeCoroutinesErrors.REDUNDANT_OVERRIDE_COROUTINES_REFINED -import com.rickclephas.kmp.nativecoroutines.compiler.diagnostics.KmpNativeCoroutinesErrors.REDUNDANT_OVERRIDE_COROUTINES_REFINED_STATE -import com.rickclephas.kmp.nativecoroutines.compiler.diagnostics.KmpNativeCoroutinesErrors.REDUNDANT_OVERRIDE_COROUTINES_STATE -import com.rickclephas.kmp.nativecoroutines.compiler.diagnostics.KmpNativeCoroutinesErrors.REDUNDANT_PRIVATE_COROUTINES -import com.rickclephas.kmp.nativecoroutines.compiler.diagnostics.KmpNativeCoroutinesErrors.REDUNDANT_PRIVATE_COROUTINES_IGNORE -import com.rickclephas.kmp.nativecoroutines.compiler.diagnostics.KmpNativeCoroutinesErrors.REDUNDANT_PRIVATE_COROUTINES_REFINED -import com.rickclephas.kmp.nativecoroutines.compiler.diagnostics.KmpNativeCoroutinesErrors.REDUNDANT_PRIVATE_COROUTINES_REFINED_STATE -import com.rickclephas.kmp.nativecoroutines.compiler.diagnostics.KmpNativeCoroutinesErrors.REDUNDANT_PRIVATE_COROUTINES_STATE +import com.rickclephas.kmp.nativecoroutines.compiler.classic.diagnostics.KmpNativeCoroutinesErrors.CONFLICT_COROUTINES +import com.rickclephas.kmp.nativecoroutines.compiler.classic.diagnostics.KmpNativeCoroutinesErrors.EXPOSED_FLOW_TYPE +import com.rickclephas.kmp.nativecoroutines.compiler.classic.diagnostics.KmpNativeCoroutinesErrors.EXPOSED_FLOW_TYPE_ERROR +import com.rickclephas.kmp.nativecoroutines.compiler.classic.diagnostics.KmpNativeCoroutinesErrors.EXPOSED_STATE_FLOW_PROPERTY +import com.rickclephas.kmp.nativecoroutines.compiler.classic.diagnostics.KmpNativeCoroutinesErrors.EXPOSED_STATE_FLOW_PROPERTY_ERROR +import com.rickclephas.kmp.nativecoroutines.compiler.classic.diagnostics.KmpNativeCoroutinesErrors.EXPOSED_SUSPEND_FUNCTION +import com.rickclephas.kmp.nativecoroutines.compiler.classic.diagnostics.KmpNativeCoroutinesErrors.EXPOSED_SUSPEND_FUNCTION_ERROR +import com.rickclephas.kmp.nativecoroutines.compiler.classic.diagnostics.KmpNativeCoroutinesErrors.IGNORED_COROUTINES +import com.rickclephas.kmp.nativecoroutines.compiler.classic.diagnostics.KmpNativeCoroutinesErrors.IGNORED_COROUTINES_REFINED +import com.rickclephas.kmp.nativecoroutines.compiler.classic.diagnostics.KmpNativeCoroutinesErrors.IGNORED_COROUTINES_REFINED_STATE +import com.rickclephas.kmp.nativecoroutines.compiler.classic.diagnostics.KmpNativeCoroutinesErrors.IGNORED_COROUTINES_STATE +import com.rickclephas.kmp.nativecoroutines.compiler.classic.diagnostics.KmpNativeCoroutinesErrors.INVALID_COROUTINES +import com.rickclephas.kmp.nativecoroutines.compiler.classic.diagnostics.KmpNativeCoroutinesErrors.INVALID_COROUTINES_IGNORE +import com.rickclephas.kmp.nativecoroutines.compiler.classic.diagnostics.KmpNativeCoroutinesErrors.INVALID_COROUTINES_REFINED +import com.rickclephas.kmp.nativecoroutines.compiler.classic.diagnostics.KmpNativeCoroutinesErrors.INVALID_COROUTINES_REFINED_STATE +import com.rickclephas.kmp.nativecoroutines.compiler.classic.diagnostics.KmpNativeCoroutinesErrors.INVALID_COROUTINES_STATE +import com.rickclephas.kmp.nativecoroutines.compiler.classic.diagnostics.KmpNativeCoroutinesErrors.INVALID_COROUTINE_SCOPE +import com.rickclephas.kmp.nativecoroutines.compiler.classic.diagnostics.KmpNativeCoroutinesErrors.REDUNDANT_OVERRIDE_COROUTINES +import com.rickclephas.kmp.nativecoroutines.compiler.classic.diagnostics.KmpNativeCoroutinesErrors.REDUNDANT_OVERRIDE_COROUTINES_IGNORE +import com.rickclephas.kmp.nativecoroutines.compiler.classic.diagnostics.KmpNativeCoroutinesErrors.REDUNDANT_OVERRIDE_COROUTINES_REFINED +import com.rickclephas.kmp.nativecoroutines.compiler.classic.diagnostics.KmpNativeCoroutinesErrors.REDUNDANT_OVERRIDE_COROUTINES_REFINED_STATE +import com.rickclephas.kmp.nativecoroutines.compiler.classic.diagnostics.KmpNativeCoroutinesErrors.REDUNDANT_OVERRIDE_COROUTINES_STATE +import com.rickclephas.kmp.nativecoroutines.compiler.classic.diagnostics.KmpNativeCoroutinesErrors.REDUNDANT_PRIVATE_COROUTINES +import com.rickclephas.kmp.nativecoroutines.compiler.classic.diagnostics.KmpNativeCoroutinesErrors.REDUNDANT_PRIVATE_COROUTINES_IGNORE +import com.rickclephas.kmp.nativecoroutines.compiler.classic.diagnostics.KmpNativeCoroutinesErrors.REDUNDANT_PRIVATE_COROUTINES_REFINED +import com.rickclephas.kmp.nativecoroutines.compiler.classic.diagnostics.KmpNativeCoroutinesErrors.REDUNDANT_PRIVATE_COROUTINES_REFINED_STATE +import com.rickclephas.kmp.nativecoroutines.compiler.classic.diagnostics.KmpNativeCoroutinesErrors.REDUNDANT_PRIVATE_COROUTINES_STATE import com.rickclephas.kmp.nativecoroutines.idea.quickfixes.AddAnnotationFixFactory.Companion.registerAddAnnotationFix import com.rickclephas.kmp.nativecoroutines.idea.quickfixes.RemoveAnnotationFixFactory.Companion.registerRemoveAnnotationFix import com.rickclephas.kmp.nativecoroutines.compiler.utils.NativeCoroutinesFqNames as FqNames diff --git a/kmp-nativecoroutines-ksp/src/main/kotlin/com/rickclephas/kmp/nativecoroutines/ksp/NativeCoroutinesPropertySpecs.kt b/kmp-nativecoroutines-ksp/src/main/kotlin/com/rickclephas/kmp/nativecoroutines/ksp/NativeCoroutinesPropertySpecs.kt index 86d19783..44961483 100644 --- a/kmp-nativecoroutines-ksp/src/main/kotlin/com/rickclephas/kmp/nativecoroutines/ksp/NativeCoroutinesPropertySpecs.kt +++ b/kmp-nativecoroutines-ksp/src/main/kotlin/com/rickclephas/kmp/nativecoroutines/ksp/NativeCoroutinesPropertySpecs.kt @@ -14,27 +14,27 @@ internal fun KSPropertyDeclaration.toNativeCoroutinesPropertySpecs( ): List? { val typeParameterResolver = getTypeParameterResolver() val type = type.getReturnType(typeParameterResolver) ?: return null - if (type !is ReturnType.Flow) error("Only Flow properties are supported") + if (type !is ReturnType.Flow) return emptyList() // Only Flow properties are supported return buildList { val flowSuffix = if (asState) options.stateFlowSuffix else options.suffix if (flowSuffix != null) - add(toNativeCoroutinesPropertySpec(scopeProperty, flowSuffix, !asState, typeParameterResolver, type, shouldRefine)) + toPropertySpec(scopeProperty, flowSuffix, !asState, typeParameterResolver, type, shouldRefine)?.let(::add) val valueSuffix = if (asState) options.stateSuffix else options.flowValueSuffix if (type is ReturnType.Flow.State && valueSuffix != null) - add(toNativeCoroutinesValuePropertySpec(valueSuffix, asState, typeParameterResolver, type, shouldRefine)) + toValuePropertySpec(valueSuffix, asState, typeParameterResolver, type, shouldRefine)?.let(::add) if (type is ReturnType.Flow.Shared && options.flowReplayCacheSuffix != null) - add(toNativeCoroutinesReplayCachePropertySpec(options.flowReplayCacheSuffix, typeParameterResolver, type, shouldRefine)) + toReplayCachePropertySpec(options.flowReplayCacheSuffix, typeParameterResolver, type, shouldRefine)?.let(::add) } } -private fun KSPropertyDeclaration.toNativeCoroutinesPropertySpec( +private fun KSPropertyDeclaration.toPropertySpec( scopeProperty: CoroutineScopeProvider.ScopeProperty, nameSuffix: String, setObjCName: Boolean, typeParameterResolver: TypeParameterResolver, type: ReturnType.Flow, shouldRefine: Boolean -): PropertySpec { +): PropertySpec? { var typeName: TypeName = nativeFlowClassName.parameterizedBy(type.valueType).copy(nullable = type.nullable) typeName = typeName.copy(annotations = type.typeReference.annotations.toAnnotationSpecs()) val simpleName = simpleName.asString() @@ -44,18 +44,18 @@ private fun KSPropertyDeclaration.toNativeCoroutinesPropertySpec( codeArgs.add(asNativeFlowMemberName) scopeProperty.codeArg.let(codeArgs::addAll) addCode("return $code${if(type.nullable) "?." else "."}%M(${scopeProperty.code})", *codeArgs.toTypedArray()) - }).apply { + })?.apply { scopeProperty.containingFile?.let(::addOriginatingKSFile) - }.build() + }?.build() } -private fun KSPropertyDeclaration.toNativeCoroutinesValuePropertySpec( +private fun KSPropertyDeclaration.toValuePropertySpec( nameSuffix: String, setObjCName: Boolean, typeParameterResolver: TypeParameterResolver, type: ReturnType.Flow.State, shouldRefine: Boolean -): PropertySpec { +): PropertySpec? { var typeName = type.valueType.copy(annotations = type.typeReference.annotations.toAnnotationSpecs()) if (type.nullable) typeName = typeName.copy(nullable = true) val simpleName = simpleName.asString() @@ -68,22 +68,22 @@ private fun KSPropertyDeclaration.toNativeCoroutinesValuePropertySpec( else -> { code, codeArgs -> addCode("$code${if(type.nullable) "?." else "."}value = value", *codeArgs.toTypedArray()) } - }).build() + })?.build() } -private fun KSPropertyDeclaration.toNativeCoroutinesReplayCachePropertySpec( +private fun KSPropertyDeclaration.toReplayCachePropertySpec( nameSuffix: String, typeParameterResolver: TypeParameterResolver, type: ReturnType.Flow.Shared, shouldRefine: Boolean -): PropertySpec { +): PropertySpec? { var typeName: TypeName = LIST.parameterizedBy(type.valueType).copy(nullable = type.nullable) typeName = typeName.copy(annotations = type.typeReference.annotations.toAnnotationSpecs()) val simpleName = simpleName.asString() val name = "$simpleName$nameSuffix" return createPropertySpec(typeParameterResolver, name, null, typeName, shouldRefine, { code, codeArgs -> addCode("return $code${if(type.nullable) "?." else "."}replayCache", *codeArgs.toTypedArray()) - }).build() + })?.build() } private fun KSPropertyDeclaration.createPropertySpec( @@ -94,7 +94,7 @@ private fun KSPropertyDeclaration.createPropertySpec( shouldRefine: Boolean, addGetterCode: FunSpec.Builder.(code: String, codeArgs: MutableList) -> Unit, addSetterCode: (FunSpec.Builder.(code: String, codeArgs: MutableList) -> Unit)? = null -): PropertySpec.Builder { +): PropertySpec.Builder? { val classDeclaration = parentDeclaration as? KSClassDeclaration val builder = PropertySpec.builder(name, typeName) @@ -119,7 +119,7 @@ private fun KSPropertyDeclaration.createPropertySpec( val extensionReceiver = extensionReceiver if (classDeclaration != null) { builder.receiver(classDeclaration.toTypeName(typeParameterResolver)) - if (extensionReceiver != null) error("Class extension properties aren't supported") + if (extensionReceiver != null) return null // Class extension properties aren't supported } else if (extensionReceiver != null) { builder.receiver(extensionReceiver.toTypeName(typeParameterResolver)) } diff --git a/kmp-nativecoroutines-ksp/src/test/kotlin/com/rickclephas/kmp/nativecoroutines/ksp/CompilationTests.kt b/kmp-nativecoroutines-ksp/src/test/kotlin/com/rickclephas/kmp/nativecoroutines/ksp/CompilationTests.kt index 5b7e8a98..aec86c48 100644 --- a/kmp-nativecoroutines-ksp/src/test/kotlin/com/rickclephas/kmp/nativecoroutines/ksp/CompilationTests.kt +++ b/kmp-nativecoroutines-ksp/src/test/kotlin/com/rickclephas/kmp/nativecoroutines/ksp/CompilationTests.kt @@ -2,6 +2,7 @@ package com.rickclephas.kmp.nativecoroutines.ksp import com.tschuchort.compiletesting.* import org.intellij.lang.annotations.Language +import org.jetbrains.kotlin.compiler.plugin.ExperimentalCompilerApi import org.junit.Rule import org.junit.rules.TemporaryFolder import java.lang.Integer.max @@ -11,6 +12,7 @@ open class CompilationTests { @Rule @JvmField val temporaryFolder: TemporaryFolder = TemporaryFolder() + @OptIn(ExperimentalCompilerApi::class) protected fun runKspTest( @Language("kotlin") inputContent: String, @Language("kotlin") outputContent: String, @@ -34,6 +36,7 @@ open class CompilationTests { } } +@OptIn(ExperimentalCompilerApi::class) private fun KotlinCompilation.assertKspSourceFile(path: String, @Language("kotlin") contents: String) { val file = kspSourcesDir.resolve("kotlin/$path") assert(file.exists()) { "KSP source file <$path> doesn't exist." } @@ -45,8 +48,9 @@ private fun KotlinCompilation.assertKspSourceFile(path: String, @Language("kotli } } +@OptIn(ExperimentalCompilerApi::class) private fun KotlinCompilation.assertCompile( exitCode: KotlinCompilation.ExitCode = KotlinCompilation.ExitCode.OK -): KotlinCompilation.Result = compile().also { +): CompilationResult = compile().also { assertEquals(exitCode, it.exitCode) } diff --git a/sample/shared/build.gradle.kts b/sample/shared/build.gradle.kts index 8e59d9a3..00c44b06 100644 --- a/sample/shared/build.gradle.kts +++ b/sample/shared/build.gradle.kts @@ -27,22 +27,16 @@ kotlin { all { languageSettings.optIn("kotlin.experimental.ExperimentalObjCName") } - val commonMain by getting { + commonMain { dependencies { implementation(libs.kotlinx.serialization.json) } } - val commonTest by getting { + commonTest { dependencies { implementation(libs.kotlin.test) } } - val appleMain by creating { - dependsOn(commonMain) - } - val appleTest by creating { - dependsOn(commonTest) - } listOf( macosX64, macosArm64, iosArm64, iosX64, iosSimulatorArm64, @@ -52,12 +46,6 @@ kotlin { it.binaries.framework { baseName = "NativeCoroutinesSampleShared" } - getByName("${it.targetName}Main") { - dependsOn(appleMain) - } - getByName("${it.targetName}Test") { - dependsOn(appleTest) - } } } }