The Gradle plugin currently adds Burst runtime dependency to testImplementation, androidTestImplementation, and commonTest configurations but applies the compiler plugin to all compilations.
This usually isn't an issue as the compiler plugin early returns when there's no @Burst annotation.
However since now Burst has FIR checkers that also run in the IDE, incompatibility issue with Studio's bundled Kotlin version can surface in main sourceset (where Burst doesn't care about) too, preventing diagnostics from other FIR checkers meant for the main sourceset to work in IDE.
Here's an example where Burst's FunctionParameterChecker crashes in Studio due to FirSimpleFunction being renamed to FirNamedFunction in Kotlin 2.3.20 while Studio still bundles an older version of Kotlin.
|
override fun check(declaration: FirNamedFunction) { |
IDE log:
2026-03-31 00:30:40,613 [278490937] SEVERE - #o.j.k.a.l.l.a.f.d.LLFirDiagnosticVisitor$Companion - Android Studio Panda 4 | 2025.3.4 Canary 2 Build #AI-253.32098.37.2534.15100028
2026-03-31 00:30:40,613 [278490937] SEVERE - #o.j.k.a.l.l.a.f.d.LLFirDiagnosticVisitor$Companion - JDK: 21.0.10; VM: OpenJDK 64-Bit Server VM; Vendor: JetBrains s.r.o.
2026-03-31 00:30:40,613 [278490937] SEVERE - #o.j.k.a.l.l.a.f.d.LLFirDiagnosticVisitor$Companion - OS: Mac OS X
2026-03-31 00:30:40,613 [278490937] SEVERE - #o.j.k.a.l.l.a.f.d.LLFirDiagnosticVisitor$Companion - The diagnostic collector has been interrupted by an exception. The result may be incomplete
java.lang.NoClassDefFoundError: org/jetbrains/kotlin/fir/declarations/FirNamedFunction
at app.cash.burst.kotlin.diagnostic.FunctionParameterChecker.check(ArgumentChecker.kt:63)
at org.jetbrains.kotlin.fir.analysis.checkers.declaration.DeclarationCheckersDiagnosticComponent.visitSimpleFunction(DeclarationCheckersDiagnosticComponent.kt:189)
at org.jetbrains.kotlin.fir.analysis.checkers.declaration.DeclarationCheckersDiagnosticComponent.visitSimpleFunction(DeclarationCheckersDiagnosticComponent.kt:25)
at org.jetbrains.kotlin.fir.declarations.FirSimpleFunction.accept(FirSimpleFunction.kt:51)
at org.jetbrains.kotlin.analysis.low.level.api.fir.diagnostics.LLFirDiagnosticVisitor.checkElement(LLFirDiagnosticVisitor.kt:44)
at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.access$checkElement(AbstractDiagnosticCollectorVisitor.kt:37)
at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitSimpleFunction(AbstractDiagnosticCollectorVisitor.kt:808)
at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitSimpleFunction(AbstractDiagnosticCollectorVisitor.kt:37)
at org.jetbrains.kotlin.fir.declarations.FirSimpleFunction.accept(FirSimpleFunction.kt:51)
at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollector.collectDiagnostics(AbstractDiagnosticCollector.kt:36)
at org.jetbrains.kotlin.analysis.low.level.api.fir.diagnostics.FileStructureElementDiagnosticsCollectorKt.collectForStructureElement(FileStructureElementDiagnosticsCollector.kt:25)
at org.jetbrains.kotlin.analysis.low.level.api.fir.diagnostics.FileStructureElementDiagnosticRetriever.retrieve(FileStructureElementDiagnosticRetriever.kt:48)
at org.jetbrains.kotlin.analysis.low.level.api.fir.diagnostics.FileStructureElementDiagnostics.diagnosticByDefaultCheckers_delegate$lambda$0(FileStructureElementDiagnostics.kt:15)
at kotlin.SynchronizedLazyImpl.getValue(LazyJVM.kt:86)
at org.jetbrains.kotlin.analysis.low.level.api.fir.diagnostics.FileStructureElementDiagnostics.getDiagnosticByDefaultCheckers(FileStructureElementDiagnostics.kt:14)
at org.jetbrains.kotlin.analysis.low.level.api.fir.diagnostics.FileStructureElementDiagnostics.diagnosticsFor(FileStructureElementDiagnostics.kt:29)
at org.jetbrains.kotlin.analysis.low.level.api.fir.diagnostics.DiagnosticsCollector.getDiagnosticsFor(DiagnosticsCollector.kt:20)
at org.jetbrains.kotlin.analysis.low.level.api.fir.state.LLSourceDiagnosticProvider.getDiagnostics(LLDiagnosticProvider.kt:49)
at org.jetbrains.kotlin.analysis.low.level.api.fir.api.LLResolutionFacade.getDiagnostics$low_level_api_fir(LLResolutionFacade.kt:119)
at org.jetbrains.kotlin.analysis.low.level.api.fir.api.LowLevelFirApiFacadeKt.getDiagnostics(LowLevelFirApiFacade.kt:82)
at org.jetbrains.kotlin.analysis.api.fir.components.KaFirDiagnosticProvider.diagnostics(KaFirDiagnosticProvider.kt:25)
at org.jetbrains.kotlin.analysis.api.impl.base.KaBaseSession.diagnostics(KaBaseSession.kt)
at org.jetbrains.kotlin.idea.highlighting.visitor.KotlinDiagnosticHighlightVisitor$triggerCollectingDiagnostics$1.invokeSuspend$lambda$0(KotlinDiagnosticHighlightVisitor.kt:176)
at com.intellij.openapi.application.rw.InternalReadAction.insideReadAction(InternalReadAction.kt:111)
at com.intellij.openapi.application.rw.InternalReadAction.tryReadCancellable$lambda$0(InternalReadAction.kt:101)
at com.intellij.openapi.application.rw.CancellableReadActionKt.cancellableReadActionInternal$lambda$0$0$0(cancellableReadAction.kt:32)
at com.intellij.platform.locking.impl.NestedLocksThreadingSupport.tryRunReadAction(NestedLocksThreadingSupport.kt:901)
at com.intellij.openapi.application.impl.ApplicationImpl.tryRunReadAction(ApplicationImpl.java:1237)
at com.intellij.openapi.application.rw.CancellableReadActionKt.cancellableReadActionInternal$lambda$0$0(cancellableReadAction.kt:30)
at com.intellij.openapi.progress.util.ProgressIndicatorUtilService.runActionAndCancelBeforeWrite(ProgressIndicatorUtilService.java:73)
at com.intellij.openapi.progress.util.ProgressIndicatorUtils.runActionAndCancelBeforeWrite(ProgressIndicatorUtils.java:152)
at com.intellij.openapi.application.rw.CancellableReadActionKt.cancellableReadActionInternal$lambda$0(cancellableReadAction.kt:28)
at com.intellij.concurrency.ThreadContext.installThreadContext(threadContext.kt:305)
at com.intellij.concurrency.ThreadContext.installThreadContext$default(threadContext.kt:303)
at com.intellij.openapi.application.rw.CancellableReadActionKt.cancellableReadActionInternal(cancellableReadAction.kt:24)
at com.intellij.openapi.application.rw.InternalReadAction.tryReadCancellable(InternalReadAction.kt:100)
at com.intellij.openapi.application.rw.InternalReadAction.tryReadAction(InternalReadAction.kt:86)
at com.intellij.openapi.application.rw.InternalReadAction.readLoop(InternalReadAction.kt:73)
at com.intellij.openapi.application.rw.InternalReadAction.access$readLoop(InternalReadAction.kt:15)
at com.intellij.openapi.application.rw.InternalReadAction$runReadAction$6.invokeSuspend(InternalReadAction.kt:52)
at com.intellij.openapi.application.rw.InternalReadAction$runReadAction$6.invoke(InternalReadAction.kt)
at com.intellij.openapi.application.rw.InternalReadAction$runReadAction$6.invoke(InternalReadAction.kt)
at kotlinx.coroutines.intrinsics.UndispatchedKt.startUndispatchedOrReturn(Undispatched.kt:44)
at kotlinx.coroutines.BuildersKt__Builders_commonKt.withContext(Builders.common.kt:166)
at kotlinx.coroutines.BuildersKt.withContext(Unknown Source)
at com.intellij.openapi.application.rw.InternalReadAction.runReadAction(InternalReadAction.kt:50)
at com.intellij.openapi.application.rw.PlatformReadWriteActionSupport.executeReadAction(PlatformReadWriteActionSupport.kt:66)
at com.intellij.openapi.application.ReadWriteActionSupport.executeReadAction$default(ReadWriteActionSupport.kt:15)
at com.intellij.openapi.application.CoroutinesKt.constrainedReadAction(coroutines.kt:60)
at com.intellij.openapi.application.CoroutinesKt.readAction(coroutines.kt:27)
at org.jetbrains.kotlin.idea.highlighting.visitor.KotlinDiagnosticHighlightVisitor$triggerCollectingDiagnostics$1.invokeSuspend(KotlinDiagnosticHighlightVisitor.kt:172)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:34)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:100)
at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:610)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runDefaultDispatcherTask(CoroutineScheduler.kt:1194)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:906)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:775)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:762)
Caused by: java.lang.ClassNotFoundException: org.jetbrains.kotlin.fir.declarations.FirNamedFunction
I understand that dealing with IDE compatibility is painful (Metro deals with these issues with its compiler-compat), but I think it doesn't hurt if Burst only applies its compiler plugin to the test compilations so at least any such compatibility issues won't affect non-test code in IDE.
Happy to send a PR if you're ok with this.
The Gradle plugin currently adds Burst runtime dependency to
testImplementation,androidTestImplementation, andcommonTestconfigurations but applies the compiler plugin to all compilations.This usually isn't an issue as the compiler plugin early returns when there's no
@Burstannotation.However since now Burst has FIR checkers that also run in the IDE, incompatibility issue with Studio's bundled Kotlin version can surface in main sourceset (where Burst doesn't care about) too, preventing diagnostics from other FIR checkers meant for the main sourceset to work in IDE.
Here's an example where Burst's
FunctionParameterCheckercrashes in Studio due toFirSimpleFunctionbeing renamed toFirNamedFunctionin Kotlin 2.3.20 while Studio still bundles an older version of Kotlin.burst/burst-kotlin-plugin/src/main/kotlin/app/cash/burst/kotlin/diagnostic/ArgumentChecker.kt
Line 65 in f26c174
IDE log:
I understand that dealing with IDE compatibility is painful (Metro deals with these issues with its
compiler-compat), but I think it doesn't hurt if Burst only applies its compiler plugin to the test compilations so at least any such compatibility issues won't affect non-test code in IDE.Happy to send a PR if you're ok with this.