Skip to content

Commit 26310be

Browse files
committed
Use K2Compiler via JvmFirPipeline to support Kotlin v2
1 parent 16ada97 commit 26310be

14 files changed

Lines changed: 499 additions & 336 deletions

rewrite-kotlin/build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ plugins {
77
kotlin("jvm") version "2.2.21"
88
}
99

10-
val kotlinVersion = "1.9.25"
10+
val kotlinVersion = "2.2.21"
1111

1212
dependencies {
1313
compileOnly(project(":rewrite-core"))

rewrite-kotlin/src/main/java/org/openrewrite/kotlin/KotlinParser.java

Lines changed: 107 additions & 198 deletions
Large diffs are not rendered by default.

rewrite-kotlin/src/main/java/org/openrewrite/kotlin/internal/KotlinTreeParserVisitor.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3905,6 +3905,7 @@ private Space prefixAndInfix(@Nullable PsiElement element, @Nullable Set<PsiElem
39053905
}
39063906

39073907
private static boolean isSpace(ASTNode node) {
3908+
if (node == null) return false;
39083909
IElementType elementType = node.getElementType();
39093910
return elementType == KtTokens.WHITE_SPACE ||
39103911
elementType == KtTokens.BLOCK_COMMENT ||

rewrite-kotlin/src/main/java/org/openrewrite/kotlin/internal/PsiTreePrinter.java

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717

1818
import lombok.AllArgsConstructor;
1919
import lombok.Data;
20-
import org.jetbrains.kotlin.KtFakeSourceElement;
20+
import org.jetbrains.kotlin.KtFakePsiSourceElement;
2121
import org.jetbrains.kotlin.KtRealPsiSourceElement;
2222
import org.jetbrains.kotlin.KtSourceElement;
2323
import org.jetbrains.kotlin.com.intellij.openapi.util.TextRange;
@@ -29,7 +29,6 @@
2929
import org.jetbrains.kotlin.fir.declarations.FirProperty;
3030
import org.jetbrains.kotlin.fir.expressions.*;
3131
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference;
32-
import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTag;
3332
import org.jetbrains.kotlin.fir.types.*;
3433
import org.jetbrains.kotlin.fir.visitors.FirDefaultVisitor;
3534
import org.jetbrains.kotlin.ir.IrElement;
@@ -488,7 +487,7 @@ public static String printFirElement(FirElement firElement) {
488487

489488
if (source instanceof KtRealPsiSourceElement) {
490489
sb.append("Real ");
491-
} else if (source instanceof KtFakeSourceElement) {
490+
} else if (source instanceof KtFakePsiSourceElement) {
492491
sb.append("Fake ");
493492
} else {
494493
sb.append(source.getClass().getSimpleName());
@@ -547,7 +546,7 @@ private static String printConeKotlinType(ConeTypeProjection coneKotlinType) {
547546
return ((FirProperty) firElement).getName().toString();
548547
} else if (firElement instanceof FirResolvedTypeRef) {
549548
FirResolvedTypeRef resolvedTypeRef = (FirResolvedTypeRef) firElement;
550-
ConeKotlinType coneKotlinType = resolvedTypeRef.getType();
549+
ConeKotlinType coneKotlinType = resolvedTypeRef.getConeType();
551550
return printConeKotlinType(coneKotlinType);
552551
} else if (firElement instanceof FirResolvedNamedReference) {
553552
return ((FirResolvedNamedReference) firElement).getName().toString();
@@ -577,8 +576,8 @@ private static String printConeKotlinType(ConeTypeProjection coneKotlinType) {
577576
}
578577
return sb.toString();
579578
}
580-
} else if (firElement instanceof FirConstExpression) {
581-
Object value = ((FirConstExpression<?>) firElement).getValue();
579+
} else if (firElement instanceof FirLiteralExpression) {
580+
Object value = ((FirLiteralExpression) firElement).getValue();
582581
return value != null ? value.toString() : null;
583582
// return ((FirConstExpression<?>) firElement).getKind().toString();
584583
} else if (firElement instanceof FirWhenBranch) {
Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
/*
2+
* Copyright 2010-2024 JetBrains s.r.o. and Kotlin Programming Language contributors.
3+
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
4+
*/
5+
6+
package org.openrewrite.kotlin
7+
8+
import org.jetbrains.kotlin.backend.common.phaser.then
9+
import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments
10+
import org.jetbrains.kotlin.cli.common.environment.setIdeaIoUseFallback
11+
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity
12+
import org.jetbrains.kotlin.cli.common.messages.GroupingMessageCollector
13+
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
14+
import org.jetbrains.kotlin.cli.common.messages.MessageCollectorUtil
15+
import org.jetbrains.kotlin.cli.common.profiling.ProfilingCompilerPerformanceManager
16+
import org.jetbrains.kotlin.cli.common.reportCompilationCancelled
17+
import org.jetbrains.kotlin.cli.pipeline.AbstractCliPipeline
18+
import org.jetbrains.kotlin.cli.pipeline.ArgumentsPipelineArtifact
19+
import org.jetbrains.kotlin.cli.pipeline.CheckCompilationErrors
20+
import org.jetbrains.kotlin.cli.pipeline.PipelineContext
21+
import org.jetbrains.kotlin.cli.pipeline.jvm.JvmConfigurationPipelinePhase
22+
import org.jetbrains.kotlin.cli.pipeline.jvm.JvmFrontendPipelineArtifact
23+
import org.jetbrains.kotlin.cli.pipeline.jvm.JvmFrontendPipelinePhase
24+
import org.jetbrains.kotlin.com.intellij.openapi.Disposable
25+
import org.jetbrains.kotlin.config.Services
26+
import org.jetbrains.kotlin.config.phaser.CompilerPhase
27+
import org.jetbrains.kotlin.config.phaser.PhaseConfig
28+
import org.jetbrains.kotlin.config.phaser.invokeToplevel
29+
import org.jetbrains.kotlin.platform.jvm.JvmPlatforms.defaultJvmPlatform
30+
import org.jetbrains.kotlin.progress.CompilationCanceledException
31+
import org.jetbrains.kotlin.progress.CompilationCanceledStatus
32+
import org.jetbrains.kotlin.progress.ProgressIndicatorAndCompilationCanceledStatus
33+
import org.jetbrains.kotlin.util.CompilerType
34+
import org.jetbrains.kotlin.util.PerformanceManager
35+
import org.jetbrains.kotlin.util.PerformanceManagerImpl
36+
import org.jetbrains.kotlin.util.forEachStringMeasurement
37+
38+
/**
39+
* Pipeline to compile Kotlin code to FIR
40+
*
41+
* Inspired by [org.jetbrains.kotlin.cli.pipeline.jvm.JvmCliPipeline]
42+
*/
43+
class JvmFirPipeline(
44+
override val defaultPerformanceManager: PerformanceManager = PerformanceManagerImpl(
45+
defaultJvmPlatform,
46+
"Kotlin to FIR compiler"
47+
),
48+
// private val kotlinSourceRoots: List<String>
49+
) : AbstractCliPipeline<K2JVMCompilerArguments>() {
50+
override fun createCompoundPhase(arguments: K2JVMCompilerArguments): CompilerPhase<PipelineContext, ArgumentsPipelineArtifact<K2JVMCompilerArguments>, JvmFrontendPipelineArtifact> {
51+
return createRegularPipeline()
52+
// return when {
53+
// arguments.scriptingModeEnabled -> createScriptPipeline()
54+
// else -> createRegularPipeline()
55+
// }
56+
}
57+
58+
private fun createRegularPipeline(): CompilerPhase<PipelineContext, ArgumentsPipelineArtifact<K2JVMCompilerArguments>, JvmFrontendPipelineArtifact> =
59+
JvmConfigurationPipelinePhase then JvmFrontendPipelinePhase
60+
61+
// private fun createScriptPipeline(): CompilerPhase<PipelineContext, ArgumentsPipelineArtifact<K2JVMCompilerArguments>, JvmScriptPipelineArtifact> =
62+
// JvmConfigurationPipelinePhase then
63+
// JvmScriptPipelinePhase
64+
65+
// private val K2JVMCompilerArguments.scriptingModeEnabled: Boolean
66+
// get() = buildFile == null &&
67+
// !version &&
68+
// !allowNoSourceFiles &&
69+
// (script || expression != null || repl || freeArgs.isEmpty())
70+
71+
override fun isKaptMode(arguments: K2JVMCompilerArguments): Boolean {
72+
return arguments.pluginOptions?.any { it.startsWith("plugin:org.jetbrains.kotlin.kapt3") } == true
73+
}
74+
75+
override fun createPerformanceManager(
76+
arguments: K2JVMCompilerArguments,
77+
services: Services,
78+
): PerformanceManager {
79+
val externalManager = services[PerformanceManager::class.java]
80+
if (externalManager != null) return externalManager
81+
val argument = arguments.profileCompilerCommand ?: return defaultPerformanceManager
82+
return ProfilingCompilerPerformanceManager.create(argument)
83+
}
84+
85+
fun execute(
86+
arguments: K2JVMCompilerArguments,
87+
services: Services,
88+
originalMessageCollector: MessageCollector,
89+
disposable: Disposable
90+
): JvmFrontendPipelineArtifact? {
91+
val canceledStatus = services[CompilationCanceledStatus::class.java]
92+
ProgressIndicatorAndCompilationCanceledStatus.setCompilationCanceledStatus(canceledStatus)
93+
setIdeaIoUseFallback() // TODO (KT-73573): probably could be removed
94+
val performanceManager = createPerformanceManager(arguments, services).apply { compilerType = CompilerType.K2 }
95+
if (arguments.reportPerf || arguments.dumpPerf != null) {
96+
performanceManager.enableExtendedStats()
97+
}
98+
99+
val messageCollector = GroupingMessageCollector(
100+
originalMessageCollector,
101+
arguments.allWarningsAsErrors,
102+
arguments.reportAllWarnings
103+
)
104+
val argumentsInput = ArgumentsPipelineArtifact(
105+
arguments,
106+
services,
107+
disposable,
108+
messageCollector,
109+
performanceManager
110+
)
111+
112+
fun reportException(e: Throwable) {
113+
MessageCollectorUtil.reportException(
114+
messageCollector,
115+
e
116+
) // TODO (KT-73575): investigate reporting in case of OOM
117+
}
118+
119+
fun reportCompilationCanceled(e: CompilationCanceledException) {
120+
messageCollector.reportCompilationCancelled(e)
121+
}
122+
123+
return try {
124+
val code = runPhasedPipeline(argumentsInput)
125+
performanceManager.notifyCompilationFinished()
126+
if (arguments.reportPerf) {
127+
messageCollector.report(CompilerMessageSeverity.LOGGING, "PERF: " + performanceManager.getTargetInfo())
128+
performanceManager.unitStats.forEachStringMeasurement {
129+
messageCollector.report(CompilerMessageSeverity.LOGGING, "PERF: $it", null)
130+
}
131+
}
132+
133+
if (arguments.dumpPerf != null) {
134+
performanceManager.dumpPerformanceReport(arguments.dumpPerf!!)
135+
}
136+
code
137+
} catch (e: RuntimeException) {
138+
when (val cause = e.cause) {
139+
is CompilationCanceledException -> reportCompilationCanceled(cause)
140+
else -> reportException(e)
141+
}
142+
throw e
143+
} catch (t: Throwable) {
144+
reportException(t)
145+
throw t
146+
} finally {
147+
messageCollector.flush()
148+
}
149+
}
150+
151+
private fun runPhasedPipeline(input: ArgumentsPipelineArtifact<K2JVMCompilerArguments>): JvmFrontendPipelineArtifact? {
152+
val compoundPhase = createCompoundPhase(input.arguments)
153+
154+
val phaseConfig = PhaseConfig()
155+
val context = PipelineContext(
156+
input.messageCollector,
157+
input.diagnosticCollector,
158+
input.performanceManager,
159+
renderDiagnosticInternalName = input.arguments.renderInternalDiagnosticNames,
160+
kaptMode = isKaptMode(input.arguments)
161+
)
162+
try {
163+
val result = compoundPhase.invokeToplevel(
164+
phaseConfig,
165+
context,
166+
input
167+
)
168+
return result
169+
} finally {
170+
CheckCompilationErrors.CheckDiagnosticCollector.reportDiagnosticsToMessageCollector(context)
171+
}
172+
}
173+
}

0 commit comments

Comments
 (0)