Skip to content

Add Kotlin 2.0+ support for Gradle and IR compiler plugin (#435) - #487

Open
kareemessam09 wants to merge 3 commits into
touchlab:mainfrom
kareemessam09:feat/kotlin-2-compiler-plugin
Open

Add Kotlin 2.0+ support for Gradle and IR compiler plugin (#435)#487
kareemessam09 wants to merge 3 commits into
touchlab:mainfrom
kareemessam09:feat/kotlin-2-compiler-plugin

Conversation

@kareemessam09

Copy link
Copy Markdown

Fixes #435
Context: #424 (comment) (cc @samhill303)

Summary

Restores and modernizes the Kermit Gradle plugin and IR compiler plugin for Kotlin 2.0+ (K2) support. In Kermit 1.x, the plugin was used to strip log statements at compile-time, but was disabled during the 2.0 migration due to Kotlin compiler internal changes.

Implementation notes

  • CompilerPluginRegistrar Migration: Replaced deprecated ComponentRegistrar with CompilerPluginRegistrar with supportsK2 = true and pluginId. Extensions are now registered via ExtensionStorage.
  • IR API Updates: Switched from deprecated referenceClass(FqName) to ClassId, and migrated isSubtypeOfClass to org.jetbrains.kotlin.ir.util.isSubtypeOfClass. Added @OptIn(UnsafeDuringIrConstructionAPI::class, DeprecatedForRemovalCompilerApi::class) to handle IR receiver inspection safely.
  • Removed Native Subplugin: Deleted the obsolete kermit-ir-plugin-native module and removed getPluginArtifactForNative() from KermitGradlePlugin, as Kotlin 2.0+ unifies native IR compiler plugins via standard JVM jar artifacts.
  • Service Loader Descriptors: Replaced kapt and auto-service with direct META-INF/services descriptor files for CompilerPluginRegistrar and CommandLineProcessor.
  • Testing Modernization: Updated test framework to dev.zacsweers.kctfork:core:0.12.1 (aligned with the project's Kotlin 2.3 toolchain). Un-ignored and updated all compiler tests, including an active runtime execution test that verifies stripped log lambdas produce zero invocations/side-effects.
  • Zero Impact on Library Code: Existing library modules (kermit, kermit-core, kermit-test, samples) are completely untouched.

Testing

  • Built the project and ran its test suite locally
  • Added or updated tests covering this change
  • Verified by hand

Commands run locally:

  • ./gradlew :kermit-ir-plugin:test (5/5 tests passed, including runtime bytecode execution test)
  • ./gradlew :kermit-gradle-plugin:test (3/3 unit tests passed)
  • ./gradlew :kermit:jvmTest :kermit-core:jvmTest (existing modules pass with zero regressions)
  • ./gradlew :kermit-ir-plugin:ktlintCheck :kermit-gradle-plugin:ktlintCheck (0 lint violations)

Platforms verified

  • Verified: Linux (linux_x64), JVM targets, and Kotlin IR compiler plugin transformations.
  • Skipped: Apple native targets (macos, ios, watchos, tvos) were not built locally due to running on a Linux host without Apple SDKs.

User-facing impact

  • User-facing change

Users on Kotlin 2.0+ can once again apply id("co.touchlab.kermit") in Gradle and configure kermit { stripBelow = StripSeverity.<Level> } to strip log statements at compile time.

Documentation

  • No documentation changes needed
    (Note: Happy to add a documentation page restoring the "Kermit Chisel" guide in website/docs/ if requested).

Migrate kermit-ir-plugin to Kotlin 2.0+ CompilerPluginRegistrar with supportsK2 enabled.
- Replace ComponentRegistrar with CompilerPluginRegistrar
- Register IR extension via ExtensionStorage and use ClassId and org.jetbrains.kotlin.ir.util.isSubtypeOfClass
- Drop obsolete kermit-ir-plugin-native module (unneeded in Kotlin 2.0+)
- Remove getPluginArtifactForNative from KermitGradlePlugin
- Replace kapt and auto-service with direct META-INF/services declarations
- Modernize test suite with kctfork and add runtime execution verification test
- Add KermitGradlePluginTest unit tests and ensure ktlint passes
@faogustavo
faogustavo requested review from faogustavo and a balanced review from Copilot September 8, 2026 14:07
@faogustavo

Copy link
Copy Markdown
Contributor

Thanks for the contribution. I'll try to take some time to review it this week.

Added Copilot for an initial round

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Kotlin 2.0 compatibility is unverified, and a supported non-embeddable Native configuration no longer receives the compiler plugin.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

Restores Kermit’s Gradle and IR compiler plugins for modern Kotlin/K2 toolchains.

Changes:

  • Migrates compiler registration and IR APIs to K2-compatible interfaces.
  • Removes the legacy Native-specific plugin artifact.
  • Restores publishing and expands compiler/plugin tests.
File summaries
File Description
settings.gradle.kts Re-enables plugin modules.
plugin/kermit-ir-plugin/src/test/kotlin/co/touchlab/kermit/irplugin/KermitStripperIrPluginTest.kt Restores compiler and runtime tests.
plugin/kermit-ir-plugin/src/test/kotlin/co/touchlab/kermit/irplugin/Helper.kt Updates the test logger fixture.
plugin/kermit-ir-plugin/src/main/resources/META-INF/services/org.jetbrains.kotlin.compiler.plugin.CompilerPluginRegistrar Registers the compiler registrar.
plugin/kermit-ir-plugin/src/main/resources/META-INF/services/org.jetbrains.kotlin.compiler.plugin.CommandLineProcessor Registers option processing.
plugin/kermit-ir-plugin/src/main/kotlin/co/touchlab/kermit/irplugin/KermitIrGenerationExtension.kt Simplifies IR transformation setup.
plugin/kermit-ir-plugin/src/main/kotlin/co/touchlab/kermit/irplugin/KermitCompilerPluginRegistrar.kt Migrates registration to K2 APIs.
plugin/kermit-ir-plugin/src/main/kotlin/co/touchlab/kermit/irplugin/KermitCommandLineProcessor.kt Updates compiler API opt-in.
plugin/kermit-ir-plugin/src/main/kotlin/co/touchlab/kermit/irplugin/KermitChiselTransformer.kt Modernizes IR lookup and transformation.
plugin/kermit-ir-plugin/build.gradle.kts Updates testing and publishing.
plugin/kermit-ir-plugin-native/gradle.properties Removes Native artifact metadata.
plugin/kermit-ir-plugin-native/build.gradle.kts Removes the legacy Native module.
plugin/kermit-ir-plugin-native/.gitignore Removes obsolete module configuration.
plugin/kermit-gradle-plugin/src/test/kotlin/co/touchlab/kermit/gradle/KermitGradlePluginTest.kt Adds Gradle plugin unit tests.
plugin/kermit-gradle-plugin/src/main/kotlin/co/touchlab/kermit/gradle/StripSeverity.kt Applies formatting updates.
plugin/kermit-gradle-plugin/src/main/kotlin/co/touchlab/kermit/gradle/KermitGradlePlugin.kt Uses the unified compiler artifact.
plugin/kermit-gradle-plugin/build.gradle.kts Adds tests and publishing configuration.
gradle/libs.versions.toml Adds compiler-testing and publishing aliases.
build.gradle.kts Enables publishing and API exclusions.
Review details
  • Files reviewed: 18/19 changed files
  • Comments generated: 2
  • Review effort level: Balanced

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

override fun applyToCompilation(
kotlinCompilation: KotlinCompilation<*>
): Provider<List<SubpluginOption>> {
override fun applyToCompilation(kotlinCompilation: KotlinCompilation<*>): Provider<List<SubpluginOption>> {
testImplementation(kotlin("test-junit"))
testImplementation("org.jetbrains.kotlin:kotlin-compiler-embeddable")
testImplementation("com.github.tschuchortdev:kotlin-compile-testing:1.4.8")
testImplementation("dev.zacsweers.kctfork:core:0.12.1")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you please use the item from the version catalog?

@kareemessam09

Copy link
Copy Markdown
Author

Hi @faogustavo, thanks for taking a look! Looking forward to your review whenever you have time this week.

In the meantime, I looked into the points raised by Copilot's automated review:

  1. Kotlin 2.0. Compatibility & pluginId:*

    • I tested the published plugin end-to-end against consumer projects across Kotlin 2.0.0, 2.0.21, 2.1.0, 2.2.0, and 2.3.21. All versions compile cleanly and properly strip log statements and lambdas at runtime.
    • While abstract val pluginId was introduced in Kotlin 2.3.0, implementing it in KermitCompilerPluginRegistrar provides clean forward/backward compatibility: on Kotlin 2.0–2.2 runtimes, the compiler ignores the extra getter method, while on Kotlin 2.3+ it fulfills the required abstract property.
  2. Native getPluginArtifactForNative():

    • In Kotlin 2.0+, kotlin.native.useEmbeddableCompilerJar=true is enabled by default, unifying Native compiler plugins with JVM via getPluginArtifact().
    • JetBrains has officially deprecated getPluginArtifactForNative() in KGP and scheduled its removal in Kotlin 2.4 in favor of this unified embeddable plugin artifact.
  3. Expanded Test Suite (Commit bc070b4):

    • Added runtime bytecode stripping tests for Logger.withTag(...) chaining, Logger subclasses (class CustomLogger : Logger()), and Throwable overloads.
    • Added unit tests for KermitCommandLineProcessor (ARG_STRIP_BELOW configuration and argument validation).
    • Added unit tests for KermitGradlePlugin compilation options mapping.

@kareemessam09
kareemessam09 requested a balanced review from Copilot September 8, 2026 16:35

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@faogustavo faogustavo left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you also update any of the samples to include an example of plugin usage?

Comment on lines +282 to +287
@OptIn(ExperimentalCompilerApi::class)
fun compile(sourceFiles: List<SourceFile>, stripBelow: String = "None"): JvmCompilationResult = KotlinCompilation().apply {
sources = sourceFiles
compilerPluginRegistrars = listOf(KermitCompilerPluginRegistrar(stripBelow))
inheritClassPath = true
}.compile()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The tests seem to only run a JVM compilation. Is there a way to also test a kotlin native compilation?

testImplementation(kotlin("test-junit"))
testImplementation("org.jetbrains.kotlin:kotlin-compiler-embeddable")
testImplementation("com.github.tschuchortdev:kotlin-compile-testing:1.4.8")
testImplementation("dev.zacsweers.kctfork:core:0.12.1")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you please use the item from the version catalog?

@kareemessam09

Copy link
Copy Markdown
Author

Hi @faogustavo, thanks for the review! I've addressed the feedback in the last commit:

  1. Version Catalog:
    Updated plugin/kermit-ir-plugin/build.gradle.kts to reference libs.kctfork and libs.kotlin.compiler.embeddable from libs.versions.toml.

  2. Sample Plugin Usage:
    Updated samples/sample-production to demonstrate plugin usage and log stripping:

    • Configured co.touchlab.kermit in root build.gradle.kts.
    • Applied id("co.touchlab.kermit") in shared/build.gradle.kts with stripBelow = StripSeverity.Info.
    • Updated samples/sample-production/README.md with documentation on configuring the plugin and severity thresholds.
  3. Kotlin/Native Compilation Testing:

    • The unit tests in KermitStripperIrPluginTest use dev.zacsweers.kctfork (Kotlin Compile Testing), which compiles in-memory via K2JVMCompiler. This allows fast in-process testing of the IR tree transformations and reflective execution to verify runtime behavior.
    • Because KermitChiselTransformer is an IrGenerationExtension operating purely on the unified K2 IR frontend before backend code generation, the AST stripping transformation is identical across all targets (JVM, Native, JS, Wasm). kctfork does not support invoking konanc directly because Kotlin/Native requires the host Konan toolchain (LLVM, platform sysroots, linker).
    • To verify the Kotlin/Native pipeline end-to-end with the plugin applied, updating samples/sample-production (which targets iOS: iosX64, iosArm64, iosSimulatorArm64) ensures that every CI run (./ci-test-samples.sh after publishToMavenLocal) compiles the native targets with the Kermit compiler plugin registered and active.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Gradle plugin not published for Kotlin 2.0

3 participants