[Analysis API] Add API for code compilation

The API replaces 'KotlinCompilerIde' in the IntelliJ IDEA plugin.
Code moved to Analysis API as its K2 implementation severely depends on
the internal compiler API (FIR).

The API is going to be used in the JVM debugger evaluator, and in
the Bytecode Tool Window.

In this commit, only ordinary Kotlin are supported.
In later commits, there will be also support for 'KtCodeFragment' files,
as well as some test coverage.
This commit is contained in:
Yan Zhulanow
2023-07-05 22:45:54 +09:00
committed by Space Team
parent 441735c2a8
commit 0f6f22d76b
29 changed files with 1103 additions and 4 deletions
+1
View File
@@ -12,6 +12,7 @@ dependencies {
compileOnly(commonDependency("org.jetbrains.kotlin:kotlin-reflect")) { isTransitive = false }
compileOnly(project(":compiler:psi"))
implementation(project(":compiler:backend"))
compileOnly(project(":core:compiler.common"))
compileOnly(project(":core:compiler.common.jvm"))
compileOnly(project(":core:compiler.common.js"))
@@ -64,7 +64,8 @@ public abstract class KtAnalysisSession(final override val token: KtLifetimeToke
KtSignatureSubstitutorMixIn,
KtScopeSubstitutionMixIn,
KtSymbolProviderByJavaPsiMixIn,
KtResolveExtensionInfoProviderMixIn {
KtResolveExtensionInfoProviderMixIn,
KtCompilerFacilityMixIn {
public abstract val useSiteModule: KtModule
@@ -165,6 +166,9 @@ public abstract class KtAnalysisSession(final override val token: KtLifetimeToke
internal val resolveExtensionInfoProvider: KtResolveExtensionInfoProvider get() = resolveExtensionInfoProviderImpl
protected abstract val resolveExtensionInfoProviderImpl: KtResolveExtensionInfoProvider
internal val compilerFacility: KtCompilerFacility get() = compilerFacilityImpl
protected abstract val compilerFacilityImpl: KtCompilerFacility
@KtAnalysisApiInternals
public val substitutorFactory: KtSubstitutorFactory get() = substitutorFactoryImpl
protected abstract val substitutorFactoryImpl: KtSubstitutorFactory
@@ -0,0 +1,102 @@
/*
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.analysis.api.components
import org.jetbrains.kotlin.analysis.api.diagnostics.KtDiagnostic
import org.jetbrains.kotlin.analysis.api.lifetime.withValidityAssertion
import org.jetbrains.kotlin.codegen.ClassBuilderFactory
import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.config.CommonConfigurationKeys
import org.jetbrains.kotlin.config.CompilerConfigurationKey
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.KtCodeFragment
import java.io.File
/**
* Compilation result.
*/
public sealed class KtCompilationResult {
/**
* Successful compilation result.
*
* @property output Output files produced by the compiler. For the JVM target, these are class files and '.kotlin_module'.
*/
public class Success(public val output: List<KtCompiledFile>) : KtCompilationResult()
/**
* Failed compilation result.
*
* @property errors Non-recoverable errors either during code analysis, or during code generation.
*/
public class Failure(public val errors: List<KtDiagnostic>) : KtCompilationResult()
}
public interface KtCompiledFile {
/**
* Path of the compiled file relative to the root of the output directory.
*/
public val path: String
/**
* Source files that were compiled to produce this file.
*/
public val sourceFiles: List<File>
/**
* Content of the compiled file.
*/
public val content: ByteArray
}
/**
* `true` if the compiled file is a Java class file.
*/
public val KtCompiledFile.isClassFile: Boolean
get() = path.endsWith(".class", ignoreCase = true)
/**
* Compilation target platform.
*/
public sealed class KtCompilerTarget {
/** JVM target (produces '.class' files). */
public class Jvm(public val classBuilderFactory: ClassBuilderFactory) : KtCompilerTarget()
}
public abstract class KtCompilerFacility : KtAnalysisSessionComponent() {
public companion object {
/** Filter for the allowed errors. Compilation will be aborted if there are errors that this filter rejects. */
public val ALLOWED_ERROR_FILTER: CompilerConfigurationKey<(KtDiagnostic) -> Boolean> =
CompilerConfigurationKey<(KtDiagnostic) -> Boolean>("error filter")
}
public abstract fun compile(file: KtFile, configuration: CompilerConfiguration, target: KtCompilerTarget): KtCompilationResult
}
public interface KtCompilerFacilityMixIn : KtAnalysisSessionMixIn {
/**
* Compile the given [file].
*
* @param file A file to compile.
* The file must be either a source module file, or a [KtCodeFragment].
* For a [KtCodeFragment], a source module context, a compiled library source context, or an empty context(`null`) are supported.
*
* @param configuration Compiler configuration.
* It is recommended to submit at least the module name ([CommonConfigurationKeys.MODULE_NAME])
* and language version settings ([CommonConfigurationKeys.LANGUAGE_VERSION_SETTINGS]).
*
* @param target Compilation target platform.
*
* @return Compilation result.
*
* The function _does not_ wrap unchecked exceptions from the compiler.
* The implementation should wrap the `compile()` call into a `try`/`catch` block if necessary.
*/
public fun compile(file: KtFile, configuration: CompilerConfiguration, target: KtCompilerTarget): KtCompilationResult {
return withValidityAssertion {
analysisSession.compilerFacility.compile(file, configuration, target)
}
}
}