FIR: extend cli pipeline with incremental compilation logic

use it in the IncrementalCompilationRunner
This commit is contained in:
Ilya Chernikov
2021-11-13 20:10:25 +01:00
committed by teamcity
parent 6b61488099
commit 275135a1b2
20 changed files with 886 additions and 203 deletions
@@ -16,7 +16,6 @@
package org.jetbrains.kotlin.cli.jvm
import com.intellij.ide.highlighter.JavaFileType
import com.intellij.openapi.Disposable
import org.jetbrains.kotlin.backend.jvm.jvmPhases
import org.jetbrains.kotlin.cli.common.*
@@ -46,7 +45,6 @@ import org.jetbrains.kotlin.load.kotlin.incremental.components.IncrementalCompil
import org.jetbrains.kotlin.metadata.deserialization.BinaryVersion
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmMetadataVersion
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmProtoBufUtil
import org.jetbrains.kotlin.modules.JavaRootPath
import org.jetbrains.kotlin.utils.KotlinPaths
import java.io.File
@@ -119,40 +117,9 @@ class K2JVMCompiler : CLICompiler<K2JVMCompilerArguments>() {
messageCollector.report(LOGGING, "Configuring the compilation environment")
try {
val destination = arguments.destination?.let { File(it) }
val buildFile = arguments.buildFile?.let { File(it) }
val moduleChunk = if (buildFile != null) {
fun strongWarning(message: String) {
messageCollector.report(STRONG_WARNING, message)
}
if (destination != null) {
strongWarning("The '-d' option with a directory destination is ignored because '-Xbuild-file' is specified")
}
if (arguments.javaSourceRoots != null) {
strongWarning("The '-Xjava-source-roots' option is ignored because '-Xbuild-file' is specified")
}
if (arguments.javaPackagePrefix != null) {
strongWarning("The '-Xjava-package-prefix' option is ignored because '-Xbuild-file' is specified")
}
configuration.configureContentRootsFromClassPath(arguments)
val sanitizedCollector = FilteringMessageCollector(messageCollector, VERBOSE::contains)
configuration.put(JVMConfigurationKeys.MODULE_XML_FILE, buildFile)
CompileEnvironmentUtil.loadModuleChunk(buildFile, sanitizedCollector)
} else {
if (destination != null) {
if (destination.path.endsWith(".jar")) {
configuration.put(JVMConfigurationKeys.OUTPUT_JAR, destination)
} else {
configuration.put(JVMConfigurationKeys.OUTPUT_DIRECTORY, destination)
}
}
val module = ModuleBuilder(moduleName, destination?.path ?: ".", "java-production")
module.configureFromArgs(arguments)
ModuleChunk(listOf(module))
}
val moduleChunk = configuration.configureModuleChunk(arguments, buildFile)
val chunk = moduleChunk.modules
configuration.configureSourceRoots(chunk, buildFile)
@@ -195,30 +162,6 @@ class K2JVMCompiler : CLICompiler<K2JVMCompilerArguments>() {
}
}
private fun ModuleBuilder.configureFromArgs(args: K2JVMCompilerArguments) {
args.friendPaths?.forEach { addFriendDir(it) }
args.classpath?.split(File.pathSeparator)?.forEach { addClasspathEntry(it) }
args.javaSourceRoots?.forEach {
addJavaSourceRoot(JavaRootPath(it, args.javaPackagePrefix))
}
val commonSources = args.commonSources?.toSet().orEmpty()
for (arg in args.freeArgs) {
if (arg.endsWith(JavaFileType.DOT_DEFAULT_EXTENSION)) {
addJavaSourceRoot(JavaRootPath(arg, args.javaPackagePrefix))
} else {
addSourceFiles(arg)
if (arg in commonSources) {
addCommonSourceFiles(arg)
}
if (File(arg).isDirectory) {
addJavaSourceRoot(JavaRootPath(arg, args.javaPackagePrefix))
}
}
}
}
override fun MutableList<String>.addPlatformOptions(arguments: K2JVMCompilerArguments) {
if (arguments.scriptTemplates?.isNotEmpty() == true) {
add("plugin:kotlin.scripting:script-templates=${arguments.scriptTemplates!!.joinToString(",")}")
@@ -302,5 +245,50 @@ class K2JVMCompiler : CLICompiler<K2JVMCompilerArguments>() {
}
}
fun CompilerConfiguration.configureModuleChunk(
arguments: K2JVMCompilerArguments,
buildFile: File?
): ModuleChunk {
val destination = arguments.destination?.let { File(it) }
return if (buildFile != null) {
val messageCollector = getNotNull(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY)
fun strongWarning(message: String) {
messageCollector.report(STRONG_WARNING, message)
}
if (destination != null) {
strongWarning("The '-d' option with a directory destination is ignored because '-Xbuild-file' is specified")
}
if (arguments.javaSourceRoots != null) {
strongWarning("The '-Xjava-source-roots' option is ignored because '-Xbuild-file' is specified")
}
if (arguments.javaPackagePrefix != null) {
strongWarning("The '-Xjava-package-prefix' option is ignored because '-Xbuild-file' is specified")
}
configureContentRootsFromClassPath(arguments)
val sanitizedCollector = FilteringMessageCollector(messageCollector, VERBOSE::contains)
put(JVMConfigurationKeys.MODULE_XML_FILE, buildFile)
CompileEnvironmentUtil.loadModuleChunk(buildFile, sanitizedCollector)
} else {
if (destination != null) {
if (destination.path.endsWith(".jar")) {
put(JVMConfigurationKeys.OUTPUT_JAR, destination)
} else {
put(JVMConfigurationKeys.OUTPUT_DIRECTORY, destination)
}
}
val module = ModuleBuilder(
this[CommonConfigurationKeys.MODULE_NAME] ?: JvmProtoBufUtil.DEFAULT_MODULE_NAME,
destination?.path ?: ".", "java-production"
)
module.configureFromArgs(arguments)
ModuleChunk(listOf(module))
}
}
fun main(args: Array<String>) = K2JVMCompiler.main(args)
@@ -186,7 +186,7 @@ object FirKotlinToJvmBytecodeCompiler {
val providerAndScopeForIncrementalCompilation = createComponentsForIncrementalCompilation(sourceScope)
providerAndScopeForIncrementalCompilation?.scope?.let {
providerAndScopeForIncrementalCompilation?.precompiledBinariesFileScope?.let {
librariesScope -= it
}
@@ -274,7 +274,7 @@ object FirKotlinToJvmBytecodeCompiler {
private fun CompilationContext.createComponentsForIncrementalCompilation(
sourceScope: AbstractProjectFileSearchScope
): FirSessionFactory.ProviderAndScopeForIncrementalCompilation? {
): FirSessionFactory.IncrementalCompilationContext? {
if (targetIds == null || incrementalComponents == null) return null
val directoryWithIncrementalPartsFromPreviousCompilation =
moduleConfiguration[JVMConfigurationKeys.OUTPUT_DIRECTORY]
@@ -288,7 +288,7 @@ object FirKotlinToJvmBytecodeCompiler {
projectEnvironment.getPackagePartProvider(sourceScope),
targetIds.map(incrementalComponents::getIncrementalCache)
)
return FirSessionFactory.ProviderAndScopeForIncrementalCompilation(packagePartProvider, incrementalCompilationScope)
return FirSessionFactory.IncrementalCompilationContext(emptyList(), packagePartProvider, incrementalCompilationScope)
}
private fun CompilationContext.runBackend(
@@ -368,7 +368,7 @@ object FirKotlinToJvmBytecodeCompiler {
)
}
internal fun findMainClass(fir: List<FirFile>): FqName? {
fun findMainClass(fir: List<FirFile>): FqName? {
// TODO: replace with proper main function detector, KT-44557
val compatibleClasses = mutableListOf<FqName>()
val visitor = object : FirVisitorVoid() {
@@ -382,7 +382,7 @@ object KotlinToJVMBytecodeCompiler {
}
}
internal fun CompilerConfiguration.configureSourceRoots(chunk: List<Module>, buildFile: File? = null) {
fun CompilerConfiguration.configureSourceRoots(chunk: List<Module>, buildFile: File? = null) {
for (module in chunk) {
val commonSources = getBuildFilePaths(buildFile, module.getCommonSourceFiles()).toSet()
@@ -77,6 +77,17 @@ open class VfsBasedProjectEnvironment(
} ?: GlobalSearchScope.EMPTY_SCOPE
)
override fun getSearchScopeByDirectories(directories: Iterable<File>): AbstractProjectFileSearchScope =
PsiBasedProjectFileSearchScope(
directories
.mapNotNull { localFileSystem.findFileByPath(it.absolutePath) }
.toSet()
.takeIf { it.isNotEmpty() }
?.let {
KotlinToJVMBytecodeCompiler.DirectoriesScope(project, it)
} ?: GlobalSearchScope.EMPTY_SCOPE
)
fun getSearchScopeByPsiFiles(files: Iterable<PsiFile>, allowOutOfProjectRoots: Boolean= false): AbstractProjectFileSearchScope =
PsiBasedProjectFileSearchScope(
files.map { it.virtualFile }.let {
@@ -5,6 +5,7 @@
package org.jetbrains.kotlin.cli.jvm.compiler
import com.intellij.ide.highlighter.JavaFileType
import com.intellij.openapi.project.Project
import com.intellij.openapi.vfs.VfsUtilCore
import com.intellij.openapi.vfs.VirtualFile
@@ -12,9 +13,11 @@ import com.intellij.openapi.vfs.VirtualFileSystem
import org.jetbrains.kotlin.backend.common.output.OutputFileCollection
import org.jetbrains.kotlin.backend.common.output.SimpleOutputFileCollection
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
import org.jetbrains.kotlin.cli.common.messages.OutputMessageUtil
import org.jetbrains.kotlin.cli.common.modules.ModuleBuilder
import org.jetbrains.kotlin.cli.common.output.writeAll
import org.jetbrains.kotlin.codegen.state.GenerationState
import org.jetbrains.kotlin.codegen.state.GenerationStateEventCallback
@@ -22,6 +25,7 @@ import org.jetbrains.kotlin.config.CommonConfigurationKeys
import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.config.JVMConfigurationKeys
import org.jetbrains.kotlin.javac.JavacWrapper
import org.jetbrains.kotlin.modules.JavaRootPath
import org.jetbrains.kotlin.modules.Module
import org.jetbrains.kotlin.modules.TargetId
import org.jetbrains.kotlin.name.FqName
@@ -148,3 +152,28 @@ fun writeOutputs(
return true
}
fun ModuleBuilder.configureFromArgs(args: K2JVMCompilerArguments) {
args.friendPaths?.forEach { addFriendDir(it) }
args.classpath?.split(File.pathSeparator)?.forEach { addClasspathEntry(it) }
args.javaSourceRoots?.forEach {
addJavaSourceRoot(JavaRootPath(it, args.javaPackagePrefix))
}
val commonSources = args.commonSources?.toSet().orEmpty()
for (arg in args.freeArgs) {
if (arg.endsWith(JavaFileType.DOT_DEFAULT_EXTENSION)) {
addJavaSourceRoot(JavaRootPath(arg, args.javaPackagePrefix))
} else {
addSourceFiles(arg)
if (arg in commonSources) {
addCommonSourceFiles(arg)
}
if (File(arg).isDirectory) {
addJavaSourceRoot(JavaRootPath(arg, args.javaPackagePrefix))
}
}
}
}
@@ -45,15 +45,18 @@ import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.backend.jvm.FirJvmBackendClassResolver
import org.jetbrains.kotlin.fir.backend.jvm.FirJvmBackendExtension
import org.jetbrains.kotlin.fir.checkers.registerExtendedCommonCheckers
import org.jetbrains.kotlin.fir.extensions.FirExtensionRegistrar
import org.jetbrains.kotlin.fir.java.FirProjectSessionProvider
import org.jetbrains.kotlin.fir.moduleData
import org.jetbrains.kotlin.fir.pipeline.buildFirViaLightTree
import org.jetbrains.kotlin.fir.pipeline.convertToIr
import org.jetbrains.kotlin.fir.pipeline.runCheckers
import org.jetbrains.kotlin.fir.pipeline.runResolution
import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider
import org.jetbrains.kotlin.fir.session.FirSessionFactory
import org.jetbrains.kotlin.fir.session.environment.AbstractProjectEnvironment
import org.jetbrains.kotlin.fir.session.environment.AbstractProjectFileSearchScope
import org.jetbrains.kotlin.javac.JavacWrapper
import org.jetbrains.kotlin.load.kotlin.MetadataFinderFactory
import org.jetbrains.kotlin.load.kotlin.PackagePartProvider
import org.jetbrains.kotlin.load.kotlin.VirtualFileFinderFactory
@@ -88,7 +91,7 @@ fun compileModulesUsingFrontendIrAndLightTree(
"ATTENTION!\n This build uses in-dev FIR: \n -Xuse-fir"
)
val outputs = mutableMapOf<Module, GenerationState>()
val outputs = mutableListOf<GenerationState>()
var mainClassFqName: FqName? = null
for (module in chunk) {
@@ -108,41 +111,120 @@ fun compileModulesUsingFrontendIrAndLightTree(
val diagnosticsReporter = DiagnosticReporterFactory.createReporter()
val (moduleMainClassName, generationState) = compileModule(
ModuleCompilerInput(
TargetId(module),
CommonPlatforms.defaultCommonPlatform, commonSources,
JvmPlatforms.unspecifiedJvmPlatform, platformSources,
moduleConfiguration
),
ModuleCompilerEnvironment(projectEnvironment, diagnosticsReporter)
val compilerInput = ModuleCompilerInput(
TargetId(module),
CommonPlatforms.defaultCommonPlatform, commonSources,
JvmPlatforms.unspecifiedJvmPlatform, platformSources,
moduleConfiguration
)
val compilerEnvironment = ModuleCompilerEnvironment(projectEnvironment, diagnosticsReporter)
val analysisResults = compileModuleToAnalyzedFir(
compilerInput,
compilerEnvironment,
emptyList(),
null,
)
// TODO: consider what to do if many modules has main classes
if (mainClassFqName == null && moduleConfiguration.get(JVMConfigurationKeys.OUTPUT_JAR) != null) {
mainClassFqName = findMainClass(analysisResults.fir)
}
val irInput = convertAnalyzedFirToIr(compilerInput, analysisResults, compilerEnvironment)
val codegenOutput = generateCodeFromIr(irInput, compilerEnvironment)
FirDiagnosticsCompilerResultsReporter.reportToMessageCollector(
diagnosticsReporter,
messageCollector,
moduleConfiguration.getBoolean(CLIConfigurationKeys.RENDER_DIAGNOSTIC_INTERNAL_NAME)
)
outputs[module] = generationState
// TODO: consider what to do if many modules contain main class
if (mainClassFqName == null) {
mainClassFqName = moduleMainClassName
}
outputs.add(codegenOutput.generationState)
}
return writeOutputs(
(projectEnvironment as? VfsBasedProjectEnvironment)?.project,
projectEnvironment,
compilerConfiguration,
chunk,
outputs,
mainClassFqName
)
}
fun compileModule(
fun convertAnalyzedFirToIr(
input: ModuleCompilerInput,
analysisResults: ModuleCompilerAnalyzedOutput,
environment: ModuleCompilerEnvironment
): ModuleCompilerIrBackendInput {
val extensions = JvmGeneratorExtensionsImpl(input.configuration)
// fir2ir
val irGenerationExtensions =
(environment.projectEnvironment as? VfsBasedProjectEnvironment)?.project?.let { IrGenerationExtension.getInstances(it) }
val (irModuleFragment, symbolTable, components) =
analysisResults.session.convertToIr(
analysisResults.scopeSession, analysisResults.fir, extensions, irGenerationExtensions ?: emptyList()
)
return ModuleCompilerIrBackendInput(
input.targetId,
input.configuration,
extensions,
irModuleFragment,
symbolTable,
components,
analysisResults.session
)
}
fun generateCodeFromIr(
input: ModuleCompilerIrBackendInput,
environment: ModuleCompilerEnvironment
): ModuleCompilerOutput {
// IR
val codegenFactory = JvmIrCodegenFactory(
input.configuration,
input.configuration.get(CLIConfigurationKeys.PHASE_CONFIG),
jvmGeneratorExtensions = input.extensions
)
val dummyBindingContext = NoScopeRecordCliBindingTrace().bindingContext
val generationState = GenerationState.Builder(
(environment.projectEnvironment as VfsBasedProjectEnvironment).project, ClassBuilderFactories.BINARIES,
input.irModuleFragment.descriptor, dummyBindingContext, emptyList()/* !! */,
input.configuration
).codegenFactory(
codegenFactory
).targetId(
input.targetId
).moduleName(
input.targetId.name
).outDirectory(
input.configuration[JVMConfigurationKeys.OUTPUT_DIRECTORY]
).onIndependentPartCompilationEnd(
createOutputFilesFlushingCallbackIfPossible(input.configuration)
).isIrBackend(
true
).jvmBackendClassResolver(
FirJvmBackendClassResolver(input.components)
).diagnosticReporter(
environment.diagnosticsReporter
).build()
generationState.beforeCompile()
codegenFactory.generateModuleInFrontendIRMode(
generationState, input.irModuleFragment, input.symbolTable, input.extensions,
FirJvmBackendExtension(input.firSession, input.components)
)
CodegenFactory.doCheckCancelled(generationState)
generationState.factory.done()
return ModuleCompilerOutput(generationState)
}
fun compileModuleToAnalyzedFir(
input: ModuleCompilerInput,
environment: ModuleCompilerEnvironment,
previousStepsSymbolProviders: List<FirSymbolProvider>,
incrementalExcludesScope: AbstractProjectFileSearchScope?,
): ModuleCompilerAnalyzedOutput {
var sourcesScope = environment.projectEnvironment.getSearchScopeByIoFiles(input.platformSources) //!!
val sessionProvider = FirProjectSessionProvider()
val extendedAnalysisMode = input.configuration.getBoolean(CommonConfigurationKeys.USE_FIR_EXTENDED_CHECKERS)
@@ -160,6 +242,8 @@ fun compileModule(
commonSourcesScope,
CommonPlatformAnalyzerServices,
sessionProvider,
previousStepsSymbolProviders,
incrementalExcludesScope,
extendedAnalysisMode,
needRegisterJavaElementFinder = false
)
@@ -173,6 +257,8 @@ fun compileModule(
sourcesScope,
JvmPlatformAnalyzerServices,
sessionProvider,
previousStepsSymbolProviders,
incrementalExcludesScope,
extendedAnalysisMode,
needRegisterJavaElementFinder = true
) {
@@ -180,6 +266,7 @@ fun compileModule(
sourceDependsOnDependencies(listOf(commonSession.moduleData))
}
friendDependencies(input.configuration[JVMConfigurationKeys.FRIEND_PATHS] ?: emptyList())
sourceFriendsDependencies(input.friendFirModules)
}
// raw fir
@@ -197,56 +284,43 @@ fun compileModule(
// checkers
session.runCheckers(scopeSession, fir, environment.diagnosticsReporter)
val mainClassFqName: FqName? = runIf(input.configuration.get(JVMConfigurationKeys.OUTPUT_JAR) != null) {
findMainClass(fir)
return ModuleCompilerAnalyzedOutput(session, scopeSession, fir)
}
fun writeOutputs(
projectEnvironment: AbstractProjectEnvironment,
configuration: CompilerConfiguration,
outputs: Collection<GenerationState>,
mainClassFqName: FqName?
): Boolean {
try {
for (state in outputs) {
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled()
writeOutput(state.configuration, state.factory, mainClassFqName)
}
} finally {
outputs.forEach(GenerationState::destroy)
}
val extensions = JvmGeneratorExtensionsImpl(input.configuration)
if (configuration.getBoolean(JVMConfigurationKeys.COMPILE_JAVA)) {
val singleState = outputs.singleOrNull()
if (singleState != null) {
return JavacWrapper.getInstance((projectEnvironment as VfsBasedProjectEnvironment).project).use {
it.compile(singleState.outDirectory)
}
} else {
configuration.getNotNull(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY).report(
CompilerMessageSeverity.WARNING,
"A chunk contains multiple modules (${outputs.joinToString { it.moduleName }}). " +
"-Xuse-javac option couldn't be used to compile java files"
)
}
}
// fir2ir
val irGenerationExtensions = (environment.projectEnvironment as? VfsBasedProjectEnvironment)?.project?.let { IrGenerationExtension.getInstances(it) }
val (irModuleFragment, symbolTable, components) = session.convertToIr(scopeSession, fir, extensions, irGenerationExtensions ?: emptyList())
// IR
val codegenFactory = JvmIrCodegenFactory(
input.configuration,
input.configuration.get(CLIConfigurationKeys.PHASE_CONFIG),
jvmGeneratorExtensions = extensions
)
val dummyBindingContext = NoScopeRecordCliBindingTrace().bindingContext
val generationState = GenerationState.Builder(
(environment.projectEnvironment as VfsBasedProjectEnvironment).project, ClassBuilderFactories.BINARIES,
irModuleFragment.descriptor, dummyBindingContext, emptyList()/* !! */,
input.configuration
).codegenFactory(
codegenFactory
).targetId(
input.targetId
).moduleName(
input.targetId.name
).outDirectory(
input.configuration[JVMConfigurationKeys.OUTPUT_DIRECTORY]
).onIndependentPartCompilationEnd(
createOutputFilesFlushingCallbackIfPossible(input.configuration)
).isIrBackend(
true
).jvmBackendClassResolver(
FirJvmBackendClassResolver(components)
).diagnosticReporter(
environment.diagnosticsReporter
).build()
generationState.beforeCompile()
codegenFactory.generateModuleInFrontendIRMode(
generationState, irModuleFragment, symbolTable, extensions, FirJvmBackendExtension(session, components)
)
CodegenFactory.doCheckCancelled(generationState)
generationState.factory.done()
return ModuleCompilerOutput(mainClassFqName, generationState)
return true
}
fun createSession(
name: String,
platform: TargetPlatform,
@@ -255,6 +329,8 @@ fun createSession(
sourceScope: AbstractProjectFileSearchScope,
analyzerServices: PlatformDependentAnalyzerServices,
sessionProvider: FirProjectSessionProvider?,
previousStepsSymbolProviders: List<FirSymbolProvider>,
incrementalExcludesScope: AbstractProjectFileSearchScope?,
extendedAnalysisMode: Boolean,
needRegisterJavaElementFinder: Boolean,
dependenciesConfigurator: DependencyListForCliModule.Builder.() -> Unit = {},
@@ -262,9 +338,16 @@ fun createSession(
var librariesScope = projectEnvironment.getSearchScopeForProjectLibraries()
val providerAndScopeForIncrementalCompilation =
createComponentsForIncrementalCompilation(moduleConfiguration, projectEnvironment, sourceScope)?.also {
librariesScope -= it.scope
}
createContextForIncrementalCompilation(
moduleConfiguration,
projectEnvironment,
sourceScope,
previousStepsSymbolProviders,
incrementalExcludesScope
)
?.also { (_, _, precompiledBinariesFileScope) ->
precompiledBinariesFileScope?.let { librariesScope -= it }
}
return FirSessionFactory.createSessionWithDependencies(
Name.identifier(name),
@@ -293,27 +376,31 @@ fun createSession(
}
}
private fun createComponentsForIncrementalCompilation(
private fun createContextForIncrementalCompilation(
compilerConfiguration: CompilerConfiguration,
projectEnvironment: AbstractProjectEnvironment,
sourceScope: AbstractProjectFileSearchScope
): FirSessionFactory.ProviderAndScopeForIncrementalCompilation? {
sourceScope: AbstractProjectFileSearchScope,
previousStepsSymbolProviders: List<FirSymbolProvider>,
incrementalExcludesScope: AbstractProjectFileSearchScope?,
): FirSessionFactory.IncrementalCompilationContext? {
val targetIds = compilerConfiguration.get(JVMConfigurationKeys.MODULES)?.map(::TargetId)
val incrementalComponents = compilerConfiguration.get(JVMConfigurationKeys.INCREMENTAL_COMPILATION_COMPONENTS)
if (targetIds == null || incrementalComponents == null) return null
val directoryWithIncrementalPartsFromPreviousCompilation =
compilerConfiguration[JVMConfigurationKeys.OUTPUT_DIRECTORY]
?: return null
val incrementalCompilationScope = directoryWithIncrementalPartsFromPreviousCompilation.walk()
.filter { it.extension == "class" }
.let { projectEnvironment.getSearchScopeByIoFiles(it.asIterable()) }
.takeIf { !it.isEmpty }
?: return null
val packagePartProvider = IncrementalPackagePartProvider(
projectEnvironment.getPackagePartProvider(sourceScope),
targetIds.map(incrementalComponents::getIncrementalCache)
val incrementalCompilationScope =
compilerConfiguration[JVMConfigurationKeys.OUTPUT_DIRECTORY]?.let { dir ->
projectEnvironment.getSearchScopeByDirectories(setOf(dir)).let {
if (incrementalExcludesScope?.isEmpty != false) it
else it - incrementalExcludesScope
}
}
return if (incrementalCompilationScope == null && previousStepsSymbolProviders.isEmpty()) null
else FirSessionFactory.IncrementalCompilationContext(
previousStepsSymbolProviders, IncrementalPackagePartProvider(
projectEnvironment.getPackagePartProvider(sourceScope),
targetIds.map(incrementalComponents::getIncrementalCache)
), incrementalCompilationScope
)
return FirSessionFactory.ProviderAndScopeForIncrementalCompilation(packagePartProvider, incrementalCompilationScope)
}
private class ProjectEnvironmentWithCoreEnvironmentEmulation(
@@ -417,13 +504,17 @@ fun createProjectEnvironment(
}
}
private fun contentRootToVirtualFile(root: JvmContentRoot, locaFileSystem: VirtualFileSystem, jarFileSystem: VirtualFileSystem, messageCollector: MessageCollector): VirtualFile? =
private fun contentRootToVirtualFile(
root: JvmContentRootBase, locaFileSystem: VirtualFileSystem, jarFileSystem: VirtualFileSystem, messageCollector: MessageCollector
): VirtualFile? =
when (root) {
// TODO: find out why non-existent location is not reported for JARs, add comment or fix
is JvmClasspathRoot ->
if (root.file.isFile) jarFileSystem.findJarRoot(root.file) else locaFileSystem.findExistingRoot(root, "Classpath entry", messageCollector)
if (root.file.isFile) jarFileSystem.findJarRoot(root.file)
else locaFileSystem.findExistingRoot(root, "Classpath entry", messageCollector)
is JvmModulePathRoot ->
if (root.file.isFile) jarFileSystem.findJarRoot(root.file) else locaFileSystem.findExistingRoot(root, "Java module root", messageCollector)
if (root.file.isFile) jarFileSystem.findJarRoot(root.file)
else locaFileSystem.findExistingRoot(root, "Java module root", messageCollector)
is JavaSourceRoot ->
locaFileSystem.findExistingRoot(root, "Java source root", messageCollector)
else ->
@@ -433,7 +524,9 @@ private fun contentRootToVirtualFile(root: JvmContentRoot, locaFileSystem: Virtu
private fun VirtualFileSystem.findJarRoot(file: File): VirtualFile? =
findFileByPath("$file${URLUtil.JAR_SEPARATOR}")
private fun VirtualFileSystem.findExistingRoot(root: JvmContentRoot, rootDescription: String, messageCollector: MessageCollector): VirtualFile? {
private fun VirtualFileSystem.findExistingRoot(
root: JvmContentRoot, rootDescription: String, messageCollector: MessageCollector
): VirtualFile? {
return findFileByPath(root.file.absolutePath).also {
if (it == null) {
messageCollector.report(
@@ -5,10 +5,18 @@
package org.jetbrains.kotlin.cli.jvm.compiler.pipeline
import org.jetbrains.kotlin.backend.jvm.JvmGeneratorExtensionsImpl
import org.jetbrains.kotlin.codegen.state.GenerationState
import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.diagnostics.impl.BaseDiagnosticsCollector
import org.jetbrains.kotlin.fir.FirModuleData
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.backend.Fir2IrComponents
import org.jetbrains.kotlin.fir.declarations.FirFile
import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.fir.session.environment.AbstractProjectEnvironment
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
import org.jetbrains.kotlin.ir.util.SymbolTable
import org.jetbrains.kotlin.modules.TargetId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.platform.TargetPlatform
@@ -22,7 +30,8 @@ data class ModuleCompilerInput(
val commonSources: Collection<File>,
val platform: TargetPlatform,
val platformSources: Collection<File>,
val configuration: CompilerConfiguration
val configuration: CompilerConfiguration,
val friendFirModules: Collection<FirModuleData> = emptyList()
)
data class ModuleCompilerEnvironment(
@@ -31,9 +40,23 @@ data class ModuleCompilerEnvironment(
)
data class ModuleCompilerOutput(
val mainClassName: FqName?,
val generationState: GenerationState
)
// ---
data class ModuleCompilerAnalyzedOutput(
val session: FirSession,
val scopeSession: ScopeSession,
val fir: List<FirFile>
)
data class ModuleCompilerIrBackendInput(
val targetId: TargetId,
val configuration: CompilerConfiguration,
val extensions: JvmGeneratorExtensionsImpl,
val irModuleFragment: IrModuleFragment,
val symbolTable: SymbolTable,
val components: Fir2IrComponents,
val firSession: FirSession
)