Hello, I am trying the new K2/FIR Compiler plugin ...
# compiler
g
Hello, I am trying the new K2/FIR Compiler plugin API on Kotlin
1.8.20-dev-649
and I'm getting a
NoClassDefFoundError: com/intellij/psi/PsiElement
error. Thanks in advance 🙏
When running IntelliJ CE (K2 Plugin) and K2 enabled in a JVM project, I am getting the following error:
Copy code
java.lang.NoClassDefFoundError: com/intellij/psi/PsiElement
	at dev.conguard.compiler.fir.errors.FirConguardErrors.<clinit>(FirConguardErrors.kt:19)
	at dev.conguard.compiler.fir.checkers.OneClassPerFileChecker.check(OneClassPerFileChecker.kt:23)
	at dev.conguard.compiler.fir.checkers.OneClassPerFileChecker.check(OneClassPerFileChecker.kt:12)
	at org.jetbrains.kotlin.fir.analysis.collectors.components.DeclarationCheckersDiagnosticComponent.check(DeclarationCheckersDiagnosticComponent.kt:89)
	at org.jetbrains.kotlin.fir.analysis.collectors.components.DeclarationCheckersDiagnosticComponent.visitFile(DeclarationCheckersDiagnosticComponent.kt:25)
	at org.jetbrains.kotlin.fir.analysis.collectors.components.DeclarationCheckersDiagnosticComponent.visitFile(DeclarationCheckersDiagnosticComponent.kt:17)
	at org.jetbrains.kotlin.fir.declarations.FirFile.accept(FirFile.kt:38)
	at org.jetbrains.kotlin.fir.analysis.collectors.CheckerRunningDiagnosticCollectorVisitor.checkElement(CheckerRunningDiagnosticCollectorVisitor.kt:21)
	at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.access$checkElement(AbstractDiagnosticCollectorVisitor.kt:21)
	at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitFile(AbstractDiagnosticCollectorVisitor.kt:637)
	at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitFile(AbstractDiagnosticCollectorVisitor.kt:21)
	at org.jetbrains.kotlin.fir.declarations.FirFile.accept(FirFile.kt:38)
	at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollector.collectDiagnostics(AbstractDiagnosticCollector.kt:31)
	at org.jetbrains.kotlin.fir.pipeline.AnalyseKt.runCheckers(analyse.kt:24)
	at org.jetbrains.kotlin.cli.jvm.compiler.FirKotlinToJvmBytecodeCompiler.runFrontend(FirKotlinToJvmBytecodeCompiler.kt:314)
	at org.jetbrains.kotlin.cli.jvm.compiler.FirKotlinToJvmBytecodeCompiler.compileModule(FirKotlinToJvmBytecodeCompiler.kt:176)
	at org.jetbrains.kotlin.cli.jvm.compiler.FirKotlinToJvmBytecodeCompiler.compileModulesUsingFrontendIR(FirKotlinToJvmBytecodeCompiler.kt:142)
	at org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler.compileModules$cli(KotlinToJVMBytecodeCompiler.kt:81)
	at org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler.compileModules$cli$default(KotlinToJVMBytecodeCompiler.kt:49)
	at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:168)
	at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:53)
	at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:101)
	at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:47)
	at org.jetbrains.kotlin.cli.common.CLITool.exec(CLITool.kt:101)
	at org.jetbrains.kotlin.incremental.IncrementalJvmCompilerRunner.runCompiler(IncrementalJvmCompilerRunner.kt:491)
	at org.jetbrains.kotlin.incremental.IncrementalJvmCompilerRunner.runCompiler(IncrementalJvmCompilerRunner.kt:131)
	at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.doCompile(IncrementalCompilerRunner.kt:422)
	at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compileImpl(IncrementalCompilerRunner.kt:358)
	at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compileNonIncrementally(IncrementalCompilerRunner.kt:240)
	at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compile(IncrementalCompilerRunner.kt:96)
	at org.jetbrains.kotlin.daemon.CompileServiceImplBase.execIncrementalCompiler(CompileServiceImpl.kt:625)
	at org.jetbrains.kotlin.daemon.CompileServiceImplBase.access$execIncrementalCompiler(CompileServiceImpl.kt:101)
	at org.jetbrains.kotlin.daemon.CompileServiceImpl.compile(CompileServiceImpl.kt:1746)
	at jdk.internal.reflect.GeneratedMethodAccessor103.invoke(Unknown Source)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
	at java.rmi/sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:359)
	at java.rmi/sun.rmi.transport.Transport$1.run(Transport.java:200)
	at java.rmi/sun.rmi.transport.Transport$1.run(Transport.java:197)
	at java.base/java.security.AccessController.doPrivileged(Native Method)
	at java.rmi/sun.rmi.transport.Transport.serviceCall(Transport.java:196)
	at java.rmi/sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:562)
	at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:796)
	at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$0(TCPTransport.java:677)
	at java.base/java.security.AccessController.doPrivileged(Native Method)
	at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:676)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
	at java.base/java.lang.Thread.run(Thread.java:829)
Caused by: java.lang.ClassNotFoundException: com.intellij.psi.PsiElement
	at java.base/java.net.URLClassLoader.findClass(URLClassLoader.java:476)
	at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:589)
	at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:522)
	... 49 more
Which comes from the following checker:
Copy code
class OneClassPerFileChecker(private val conventions: Conventions) : FirFileChecker() {

    @OptIn(InternalDiagnosticFactoryMethod::class)
    override fun check(declaration: FirFile, context: CheckerContext, reporter: DiagnosticReporter) {
        if (conventions.oneClassPerFile) {
            val fileName = declaration.name.substringBefore(".kt")
            declaration.declarations.forEach { subDeclaration: FirDeclaration ->
                if (subDeclaration is FirRegularClass) {
                    if (subDeclaration.name.toString() != fileName) {
                        subDeclaration.source?.let { source ->
                            reporter.report(
                                ONE_CLASS_PER_FILE.on(
                                    source,
                                    AbstractSourceElementPositioningStrategy.DEFAULT
                                ), context
                            )
                        }
                    }
                }
            }
        }
    }
}
d
There is an inconsistency in building compiler plugins caused by shading. Shading is a process when all dependency classes which are bundled in
kotlin-compiler.jar
are renamed from
foo.bar.Baz
to
org.jetbrains.kotlin.foo.bar.Baz
to avoid potential dependency conflicts. So there is two versions of compiler:
kotlin-compiler
with unshaded dependencies and
kotlin-compiler-embeddable
with shaded dependencies And the problem is that in different environments different compilers are used: • unshaded is used in Kotlin IDE plugin and test framework • shaded compiler is used for building projects using gradle
So to fix this issue you need to build two versions of your plugin with different dependencies (one for IDE and testing, and one for regular build) Unfortunately this is ugly and not trivial We plan to provide acceptable solution for it with K2 release (I hope for that)
BTW consider
reporter.reportOn
function for reporting diagnostics
Copy code
reporter.reportOn(subDeclaration.source, ONE_CLASS_PER_FILE, context)
g
Thanks for the explanation! Any existing compiler plugin already doing this so I could follow its example?
d
I don't know actually
g
Looks like devs need some kind of jetifier mechanism for publishing
I just used
kotlin-compiler-embeddable
instead of
kotlin-compiler
and I don't see yet any IDE error showing up but at least on building I see it:
Copy code
e: file:///home/galex/github/conguard/sample/jvm-app/src/main/java/org/example/SameName.kt:6:1 Each class should reside in its own File by the same name
Errors were stored into /home/galex/github/conguard/sample/.gradle/build_errors/errors-1665400118796.log
And indeed the test framework doesn't work anymore, well it works but the tests don't compile anymore
d
I don't see yet any IDE error showing up
In which IDE do you test? One build from
intellij-community/master
?
g
Yes, ran in Configuration
IDEA (K2 Kotlin)
d
Hm. And how do you connect plugin to test project? Via gradle or via compiler options in IDEA UI?
g