FIR: extend cli pipeline with incremental compilation logic
use it in the IncrementalCompilationRunner
This commit is contained in:
@@ -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)
|
||||
|
||||
+4
-4
@@ -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() {
|
||||
|
||||
+1
-1
@@ -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))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+178
-85
@@ -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(
|
||||
|
||||
+25
-2
@@ -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
|
||||
)
|
||||
@@ -68,9 +68,13 @@ object FirSessionFactory {
|
||||
}
|
||||
}
|
||||
|
||||
data class ProviderAndScopeForIncrementalCompilation(
|
||||
val packagePartProvider: PackagePartProvider,
|
||||
val scope: AbstractProjectFileSearchScope
|
||||
data class IncrementalCompilationContext(
|
||||
// assuming that providers here do not intersect with the one being built from precompiled binaries
|
||||
// (maybe easiest way to achieve is to delete libraries
|
||||
// TODO: consider passing something more abstract instead of precompiler component, in order to avoid file ops here
|
||||
val previousFirSessionsSymbolProviders: Collection<FirSymbolProvider>,
|
||||
val precomiledBinariesPackagePartProvider: PackagePartProvider?,
|
||||
val precompiledBinariesFileScope: AbstractProjectFileSearchScope?
|
||||
)
|
||||
|
||||
inline fun createSessionWithDependencies(
|
||||
@@ -83,7 +87,7 @@ object FirSessionFactory {
|
||||
sourceScope: AbstractProjectFileSearchScope,
|
||||
librariesScope: AbstractProjectFileSearchScope,
|
||||
lookupTracker: LookupTracker?,
|
||||
providerAndScopeForIncrementalCompilation: ProviderAndScopeForIncrementalCompilation?,
|
||||
incrementalCompilationContext: IncrementalCompilationContext?,
|
||||
extensionRegistrars: List<FirExtensionRegistrar>,
|
||||
needRegisterJavaElementFinder: Boolean,
|
||||
dependenciesConfigurator: DependencyListForCliModule.Builder.() -> Unit = {},
|
||||
@@ -114,7 +118,7 @@ object FirSessionFactory {
|
||||
sessionProvider,
|
||||
sourceScope,
|
||||
projectEnvironment,
|
||||
providerAndScopeForIncrementalCompilation,
|
||||
incrementalCompilationContext,
|
||||
extensionRegistrars,
|
||||
languageVersionSettings = languageVersionSettings,
|
||||
lookupTracker = lookupTracker,
|
||||
@@ -128,7 +132,7 @@ object FirSessionFactory {
|
||||
sessionProvider: FirProjectSessionProvider,
|
||||
scope: AbstractProjectFileSearchScope,
|
||||
projectEnvironment: AbstractProjectEnvironment,
|
||||
providerAndScopeForIncrementalCompilation: ProviderAndScopeForIncrementalCompilation?,
|
||||
incrementalCompilationContext: IncrementalCompilationContext?,
|
||||
extensionRegistrars: List<FirExtensionRegistrar>,
|
||||
languageVersionSettings: LanguageVersionSettings = LanguageVersionSettingsImpl.DEFAULT,
|
||||
lookupTracker: LookupTracker? = null,
|
||||
@@ -151,17 +155,19 @@ object FirSessionFactory {
|
||||
val firProvider = FirProviderImpl(this, kotlinScopeProvider)
|
||||
register(FirProvider::class, firProvider)
|
||||
|
||||
val symbolProviderForBinariesFromIncrementalCompilation = providerAndScopeForIncrementalCompilation?.let {
|
||||
JvmClassFileBasedSymbolProvider(
|
||||
this@session,
|
||||
SingleModuleDataProvider(moduleData),
|
||||
kotlinScopeProvider,
|
||||
it.packagePartProvider,
|
||||
projectEnvironment.getKotlinClassFinder(it.scope),
|
||||
projectEnvironment.getFirJavaFacade(this, moduleData, it.scope),
|
||||
defaultDeserializationOrigin = FirDeclarationOrigin.Precompiled
|
||||
)
|
||||
}
|
||||
val symbolProviderForBinariesFromIncrementalCompilation =
|
||||
incrementalCompilationContext?.let { (_, precomiledBinariesPackagePartProvider, precompiledBinariesFileScope) ->
|
||||
if (precomiledBinariesPackagePartProvider == null || precompiledBinariesFileScope == null) null
|
||||
else JvmClassFileBasedSymbolProvider(
|
||||
this@session,
|
||||
SingleModuleDataProvider(moduleData),
|
||||
kotlinScopeProvider,
|
||||
precomiledBinariesPackagePartProvider,
|
||||
projectEnvironment.getKotlinClassFinder(precompiledBinariesFileScope),
|
||||
projectEnvironment.getFirJavaFacade(this, moduleData, precompiledBinariesFileScope),
|
||||
defaultDeserializationOrigin = FirDeclarationOrigin.Precompiled
|
||||
)
|
||||
}
|
||||
|
||||
FirSessionConfigurator(this).apply {
|
||||
registerCommonCheckers()
|
||||
@@ -180,6 +186,7 @@ object FirSessionFactory {
|
||||
this,
|
||||
listOfNotNull(
|
||||
firProvider.symbolProvider,
|
||||
*(incrementalCompilationContext?.previousFirSessionsSymbolProviders?.toTypedArray() ?: emptyArray()),
|
||||
symbolProviderForBinariesFromIncrementalCompilation,
|
||||
generatedSymbolsProvider,
|
||||
JavaSymbolProvider(this, projectEnvironment.getFirJavaFacade(this, moduleData, scope)),
|
||||
|
||||
+2
@@ -49,6 +49,8 @@ interface AbstractProjectEnvironment {
|
||||
|
||||
fun getSearchScopeByIoFiles(files: Iterable<File>, allowOutOfProjectRoots: Boolean = false): AbstractProjectFileSearchScope
|
||||
|
||||
fun getSearchScopeByDirectories(directories: Iterable<File>): AbstractProjectFileSearchScope
|
||||
|
||||
fun getSearchScopeForProjectLibraries(): AbstractProjectFileSearchScope
|
||||
|
||||
fun getSearchScopeForProjectJavaSources(): AbstractProjectFileSearchScope
|
||||
|
||||
@@ -13,6 +13,9 @@ dependencies {
|
||||
api(project(":compiler:frontend.java"))
|
||||
api(project(":compiler:cli"))
|
||||
api(project(":compiler:cli-js"))
|
||||
api(project(":compiler:fir:entrypoint"))
|
||||
api(project(":compiler:ir.serialization.jvm"))
|
||||
api(project(":compiler:backend.jvm.entrypoint"))
|
||||
api(project(":kotlin-build-common"))
|
||||
api(project(":daemon-common"))
|
||||
implementation(commonDependency("com.google.code.gson:gson"))
|
||||
|
||||
+2
-2
@@ -16,8 +16,8 @@ class DirtyFilesContainer(
|
||||
) {
|
||||
private val myDirtyFiles = HashSet<File>()
|
||||
|
||||
fun toMutableList(): MutableList<File> =
|
||||
ArrayList(myDirtyFiles)
|
||||
fun toMutableLinkedSet(): LinkedHashSet<File> =
|
||||
LinkedHashSet(myDirtyFiles)
|
||||
|
||||
fun add(files: Iterable<File>, reason: String?) {
|
||||
val existingKotlinFiles = files.filter { it.isKotlinFile(sourceFilesExtensions) }
|
||||
|
||||
+20
-10
@@ -54,7 +54,7 @@ abstract class IncrementalCompilerRunner<
|
||||
) {
|
||||
|
||||
protected val cacheDirectory = File(workingDir, cacheDirName)
|
||||
private val dirtySourcesSinceLastTimeFile = File(workingDir, DIRTY_SOURCES_FILE_NAME)
|
||||
protected val dirtySourcesSinceLastTimeFile = File(workingDir, DIRTY_SOURCES_FILE_NAME)
|
||||
protected val lastBuildInfoFile = File(workingDir, LAST_BUILD_INFO_FILE_NAME)
|
||||
private val abiSnapshotFile = File(workingDir, ABI_SNAPSHOT_FILE_NAME)
|
||||
protected open val kotlinSourceFilesExtensions: List<String> = DEFAULT_KOTLIN_SOURCE_FILES_EXTENSIONS
|
||||
@@ -297,14 +297,16 @@ abstract class IncrementalCompilerRunner<
|
||||
}
|
||||
|
||||
protected abstract fun runCompiler(
|
||||
sourcesToCompile: Set<File>,
|
||||
sourcesToCompile: List<File>,
|
||||
args: Args,
|
||||
caches: CacheManager,
|
||||
services: Services,
|
||||
messageCollector: MessageCollector
|
||||
): ExitCode
|
||||
messageCollector: MessageCollector,
|
||||
allSources: List<File>,
|
||||
isIncremental: Boolean
|
||||
): Pair<ExitCode, Collection<File>>
|
||||
|
||||
private fun compileIncrementally(
|
||||
protected open fun compileIncrementally(
|
||||
args: Args,
|
||||
caches: CacheManager,
|
||||
allKotlinSources: List<File>,
|
||||
@@ -322,11 +324,11 @@ abstract class IncrementalCompilerRunner<
|
||||
|
||||
val dirtySources = when (compilationMode) {
|
||||
is CompilationMode.Incremental -> {
|
||||
compilationMode.dirtyFiles.toMutableList()
|
||||
compilationMode.dirtyFiles.toMutableLinkedSet()
|
||||
}
|
||||
is CompilationMode.Rebuild -> {
|
||||
reporter.addAttribute(compilationMode.reason)
|
||||
allKotlinSources.toMutableList()
|
||||
LinkedHashSet(allKotlinSources)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -362,10 +364,18 @@ abstract class IncrementalCompilerRunner<
|
||||
val bufferingMessageCollector = BufferingMessageCollector()
|
||||
val messageCollectorAdapter = MessageCollectorToOutputItemsCollectorAdapter(bufferingMessageCollector, outputItemsCollector)
|
||||
|
||||
exitCode = reporter.measure(BuildTime.COMPILATION_ROUND) {
|
||||
runCompiler(sourcesToCompile.toSet(), args, caches, services, messageCollectorAdapter)
|
||||
val compiledSources = reporter.measure(BuildTime.COMPILATION_ROUND) {
|
||||
runCompiler(
|
||||
sourcesToCompile, args, caches, services, messageCollectorAdapter,
|
||||
allKotlinSources, compilationMode is CompilationMode.Incremental
|
||||
)
|
||||
}.let { (ec, compiled) ->
|
||||
exitCode = ec
|
||||
compiled
|
||||
}
|
||||
|
||||
dirtySources.addAll(compiledSources)
|
||||
|
||||
val generatedFiles = outputItemsCollector.outputs.map(SimpleOutputItem::toGeneratedFile)
|
||||
if (compilationMode is CompilationMode.Incremental) {
|
||||
// todo: feels dirty, can this be refactored?
|
||||
@@ -378,7 +388,7 @@ abstract class IncrementalCompilerRunner<
|
||||
}
|
||||
}
|
||||
|
||||
reporter.reportCompileIteration(compilationMode is CompilationMode.Incremental, sourcesToCompile, exitCode)
|
||||
reporter.reportCompileIteration(compilationMode is CompilationMode.Incremental, compiledSources, exitCode)
|
||||
bufferingMessageCollector.flush(originalMessageCollector)
|
||||
|
||||
if (exitCode != ExitCode.OK) break
|
||||
|
||||
+356
@@ -0,0 +1,356 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.incremental
|
||||
|
||||
import com.intellij.ide.highlighter.JavaFileType
|
||||
import com.intellij.openapi.util.Disposer
|
||||
import com.intellij.psi.PsiJavaModule
|
||||
import org.jetbrains.kotlin.backend.common.extensions.IrGenerationExtension
|
||||
import org.jetbrains.kotlin.backend.jvm.JvmGeneratorExtensionsImpl
|
||||
import org.jetbrains.kotlin.backend.jvm.serialization.JvmIdSignatureDescriptor
|
||||
import org.jetbrains.kotlin.build.DEFAULT_KOTLIN_SOURCE_FILES_EXTENSIONS
|
||||
import org.jetbrains.kotlin.build.report.BuildReporter
|
||||
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
|
||||
import org.jetbrains.kotlin.cli.common.ExitCode
|
||||
import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments
|
||||
import org.jetbrains.kotlin.cli.common.computeKotlinPaths
|
||||
import org.jetbrains.kotlin.cli.common.config.addKotlinSourceRoot
|
||||
import org.jetbrains.kotlin.cli.common.config.kotlinSourceRoots
|
||||
import org.jetbrains.kotlin.cli.common.environment.setIdeaIoUseFallback
|
||||
import org.jetbrains.kotlin.cli.common.fir.FirDiagnosticsCompilerResultsReporter
|
||||
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity
|
||||
import org.jetbrains.kotlin.cli.common.messages.GroupingMessageCollector
|
||||
import org.jetbrains.kotlin.cli.common.messages.IrMessageCollector
|
||||
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
|
||||
import org.jetbrains.kotlin.cli.common.modules.ModuleBuilder
|
||||
import org.jetbrains.kotlin.cli.common.setupCommonArguments
|
||||
import org.jetbrains.kotlin.cli.jvm.*
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.VfsBasedProjectEnvironment
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.findMainClass
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.forAllFiles
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.pipeline.*
|
||||
import org.jetbrains.kotlin.cli.jvm.config.ClassicFrontendSpecificJvmConfigurationKeys
|
||||
import org.jetbrains.kotlin.cli.jvm.config.JvmClasspathRoot
|
||||
import org.jetbrains.kotlin.cli.jvm.config.JvmModulePathRoot
|
||||
import org.jetbrains.kotlin.cli.jvm.config.addJavaSourceRoot
|
||||
import org.jetbrains.kotlin.cli.jvm.plugins.PluginCliParser
|
||||
import org.jetbrains.kotlin.config.*
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticReporterFactory
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.backend.Fir2IrConverter
|
||||
import org.jetbrains.kotlin.fir.backend.jvm.Fir2IrJvmSpecialAnnotationSymbolProvider
|
||||
import org.jetbrains.kotlin.fir.backend.jvm.FirJvmKotlinMangler
|
||||
import org.jetbrains.kotlin.fir.backend.jvm.FirJvmVisibilityConverter
|
||||
import org.jetbrains.kotlin.fir.languageVersionSettings
|
||||
import org.jetbrains.kotlin.fir.moduleData
|
||||
import org.jetbrains.kotlin.fir.resolve.providers.firProvider
|
||||
import org.jetbrains.kotlin.fir.resolve.providers.impl.FirProviderImpl
|
||||
import org.jetbrains.kotlin.fir.session.environment.AbstractProjectFileSearchScope
|
||||
import org.jetbrains.kotlin.incremental.components.ExpectActualTracker
|
||||
import org.jetbrains.kotlin.incremental.components.InlineConstTracker
|
||||
import org.jetbrains.kotlin.incremental.components.LookupTracker
|
||||
import org.jetbrains.kotlin.incremental.multiproject.ModulesApiHistory
|
||||
import org.jetbrains.kotlin.ir.backend.jvm.serialization.JvmDescriptorMangler
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrFactoryImpl
|
||||
import org.jetbrains.kotlin.ir.util.IrMessageLogger
|
||||
import org.jetbrains.kotlin.load.java.JavaClassesTracker
|
||||
import org.jetbrains.kotlin.load.kotlin.incremental.components.IncrementalCompilationComponents
|
||||
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmMetadataVersion
|
||||
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmProtoBufUtil
|
||||
import org.jetbrains.kotlin.modules.TargetId
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.platform.CommonPlatforms
|
||||
import org.jetbrains.kotlin.platform.jvm.JvmPlatforms
|
||||
import org.jetbrains.kotlin.progress.CompilationCanceledException
|
||||
import java.io.File
|
||||
|
||||
class IncrementalFirJvmCompilerRunner(
|
||||
workingDir: File,
|
||||
reporter: BuildReporter,
|
||||
buildHistoryFile: File,
|
||||
outputFiles: Collection<File>,
|
||||
modulesApiHistory: ModulesApiHistory,
|
||||
kotlinSourceFilesExtensions: List<String> = DEFAULT_KOTLIN_SOURCE_FILES_EXTENSIONS,
|
||||
classpathChanges: ClasspathChanges
|
||||
) : IncrementalJvmCompilerRunner(
|
||||
workingDir,
|
||||
reporter,
|
||||
false,
|
||||
buildHistoryFile,
|
||||
outputFiles,
|
||||
modulesApiHistory,
|
||||
kotlinSourceFilesExtensions,
|
||||
classpathChanges
|
||||
) {
|
||||
|
||||
override fun runCompiler(
|
||||
sourcesToCompile: List<File>,
|
||||
args: K2JVMCompilerArguments,
|
||||
caches: IncrementalJvmCachesManager,
|
||||
services: Services,
|
||||
messageCollector: MessageCollector,
|
||||
allSources: List<File>,
|
||||
isIncremental: Boolean
|
||||
): Pair<ExitCode, Collection<File>> {
|
||||
// val isIncremental = true // TODO
|
||||
val collector = GroupingMessageCollector(messageCollector, args.allWarningsAsErrors)
|
||||
// from K2JVMCompiler (~)
|
||||
val moduleName = args.moduleName ?: JvmProtoBufUtil.DEFAULT_MODULE_NAME
|
||||
val targetId = TargetId(moduleName, "java-production") // TODO: get rid of magic constant
|
||||
|
||||
val dirtySources = linkedSetOf<File>().apply { addAll(sourcesToCompile) }
|
||||
|
||||
// TODO: probably shoudl be passed along with sourcesToCompile
|
||||
// TODO: file path normalization
|
||||
val commonSources = args.commonSources?.mapTo(mutableSetOf(), ::File).orEmpty()
|
||||
|
||||
val exitCode = ExitCode.OK
|
||||
val allCompiledSources = LinkedHashSet<File>()
|
||||
val rootDisposable = Disposer.newDisposable()
|
||||
|
||||
try {
|
||||
// - configuration
|
||||
val configuration = CompilerConfiguration().apply {
|
||||
|
||||
put(CLIConfigurationKeys.ORIGINAL_MESSAGE_COLLECTOR_KEY, messageCollector)
|
||||
put(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY, collector)
|
||||
put(IrMessageLogger.IR_MESSAGE_LOGGER, IrMessageCollector(collector))
|
||||
|
||||
setupCommonArguments(args) { JvmMetadataVersion(*it) }
|
||||
|
||||
if (IncrementalCompilation.isEnabledForJvm()) {
|
||||
putIfNotNull(CommonConfigurationKeys.LOOKUP_TRACKER, services[LookupTracker::class.java])
|
||||
|
||||
putIfNotNull(CommonConfigurationKeys.EXPECT_ACTUAL_TRACKER, services[ExpectActualTracker::class.java])
|
||||
|
||||
putIfNotNull(CommonConfigurationKeys.INLINE_CONST_TRACKER, services[InlineConstTracker::class.java])
|
||||
|
||||
putIfNotNull(
|
||||
JVMConfigurationKeys.INCREMENTAL_COMPILATION_COMPONENTS,
|
||||
services[IncrementalCompilationComponents::class.java]
|
||||
)
|
||||
|
||||
putIfNotNull(ClassicFrontendSpecificJvmConfigurationKeys.JAVA_CLASSES_TRACKER, services[JavaClassesTracker::class.java])
|
||||
}
|
||||
|
||||
setupJvmSpecificArguments(args)
|
||||
}
|
||||
|
||||
val paths = computeKotlinPaths(collector, args)
|
||||
if (collector.hasErrors()) return ExitCode.COMPILATION_ERROR to emptyList()
|
||||
|
||||
// -- plugins
|
||||
val pluginClasspaths: Iterable<String> = args.pluginClasspaths?.asIterable() ?: emptyList()
|
||||
val pluginOptions = args.pluginOptions?.toMutableList() ?: ArrayList()
|
||||
// TODO: add scripting support when ready in FIR
|
||||
val pluginLoadResult = PluginCliParser.loadPluginsSafe(pluginClasspaths, pluginOptions, configuration)
|
||||
if (pluginLoadResult != ExitCode.OK) return pluginLoadResult to emptyList()
|
||||
// -- /plugins
|
||||
|
||||
with(configuration) {
|
||||
configureJavaModulesContentRoots(args)
|
||||
configureStandardLibs(paths, args)
|
||||
configureAdvancedJvmOptions(args)
|
||||
configureKlibPaths(args)
|
||||
|
||||
val destination = File(args.destination ?: ".")
|
||||
if (destination.path.endsWith(".jar")) {
|
||||
put(JVMConfigurationKeys.OUTPUT_JAR, destination)
|
||||
} else {
|
||||
put(JVMConfigurationKeys.OUTPUT_DIRECTORY, destination)
|
||||
}
|
||||
addAll(JVMConfigurationKeys.MODULES, listOf(ModuleBuilder(targetId.name, destination.path, targetId.type)))
|
||||
|
||||
configureBaseRoots(args)
|
||||
configureSourceRootsFromSources(allSources, commonSources, args.javaPackagePrefix)
|
||||
}
|
||||
// - /configuration
|
||||
|
||||
setIdeaIoUseFallback()
|
||||
|
||||
// -AbstractProjectEnvironment-
|
||||
val projectEnvironment =
|
||||
createProjectEnvironment(configuration, rootDisposable, EnvironmentConfigFiles.JVM_CONFIG_FILES, messageCollector)
|
||||
|
||||
// -sources
|
||||
val allPlatformSourceFiles = linkedSetOf<File>() // TODO: get from caller
|
||||
val allCommonSourceFiles = linkedSetOf<File>()
|
||||
|
||||
configuration.kotlinSourceRoots.forAllFiles(configuration, projectEnvironment.project) { virtualFile, isCommon ->
|
||||
val file = File(virtualFile.canonicalPath ?: virtualFile.path)
|
||||
if (!file.isFile) error("TODO: better error: file not found $virtualFile")
|
||||
if (isCommon) allCommonSourceFiles.add(file)
|
||||
else allPlatformSourceFiles.add(file)
|
||||
}
|
||||
|
||||
val diagnosticsReporter = DiagnosticReporterFactory.createReporter()
|
||||
val compilerEnvironment = ModuleCompilerEnvironment(projectEnvironment, diagnosticsReporter)
|
||||
|
||||
// !! main class - maybe from cache?
|
||||
var mainClassFqName: FqName? = null
|
||||
|
||||
var incrementalExcludesScope: AbstractProjectFileSearchScope? = null
|
||||
|
||||
fun firIncrementalCycle(): ModuleCompilerAnalyzedOutput? {
|
||||
while (true) {
|
||||
|
||||
val compilerInput = ModuleCompilerInput(
|
||||
targetId,
|
||||
CommonPlatforms.defaultCommonPlatform, dirtySources.filter { it in allCommonSourceFiles },
|
||||
JvmPlatforms.unspecifiedJvmPlatform, dirtySources.filter { it in allPlatformSourceFiles },
|
||||
configuration
|
||||
)
|
||||
|
||||
val analysisResults =
|
||||
compileModuleToAnalyzedFir(
|
||||
compilerInput,
|
||||
compilerEnvironment,
|
||||
emptyList(),
|
||||
incrementalExcludesScope,
|
||||
)
|
||||
|
||||
// TODO: consider what to do if many compilations find a main class
|
||||
if (mainClassFqName == null && configuration.get(JVMConfigurationKeys.OUTPUT_JAR) != null) {
|
||||
mainClassFqName = findMainClass(analysisResults.fir)
|
||||
}
|
||||
|
||||
allCompiledSources.addAll(dirtySources)
|
||||
|
||||
if (diagnosticsReporter.hasErrors) {
|
||||
FirDiagnosticsCompilerResultsReporter.reportToMessageCollector(
|
||||
diagnosticsReporter,
|
||||
collector,
|
||||
configuration.getBoolean(CLIConfigurationKeys.RENDER_DIAGNOSTIC_INTERNAL_NAME)
|
||||
)
|
||||
return null
|
||||
}
|
||||
|
||||
val newDirtySources =
|
||||
collectNewDirtySources(analysisResults, targetId, configuration, caches, allCompiledSources, reporter)
|
||||
|
||||
if (!isIncremental || newDirtySources.isEmpty()) return analysisResults
|
||||
|
||||
caches.platformCache.markDirty(newDirtySources)
|
||||
val newDirtyFilesOutputsScope =
|
||||
projectEnvironment.getSearchScopeByIoFiles(caches.inputsCache.getOutputForSourceFiles(newDirtySources))
|
||||
incrementalExcludesScope = incrementalExcludesScope.let {
|
||||
when {
|
||||
newDirtyFilesOutputsScope.isEmpty -> it
|
||||
it == null || it.isEmpty -> newDirtyFilesOutputsScope
|
||||
else -> it + newDirtyFilesOutputsScope
|
||||
}
|
||||
}
|
||||
caches.inputsCache.removeOutputForSourceFiles(newDirtySources)
|
||||
dirtySources.addAll(newDirtySources)
|
||||
projectEnvironment.localFileSystem.refresh(false)
|
||||
}
|
||||
}
|
||||
|
||||
val cycleResult = firIncrementalCycle() ?: return ExitCode.COMPILATION_ERROR to allCompiledSources
|
||||
|
||||
val extensions = JvmGeneratorExtensionsImpl(configuration)
|
||||
val irGenerationExtensions =
|
||||
(projectEnvironment as? VfsBasedProjectEnvironment)?.project?.let { IrGenerationExtension.getInstances(it) }.orEmpty()
|
||||
val mangler = JvmDescriptorMangler(null)
|
||||
val signaturer = JvmIdSignatureDescriptor(JvmDescriptorMangler(null))
|
||||
val allCommonFirFiles = cycleResult.session.moduleData.dependsOnDependencies
|
||||
.map { it.session }
|
||||
.filter { it.kind == FirSession.Kind.Source }
|
||||
.flatMap { (it.firProvider as FirProviderImpl).getAllFirFiles() }
|
||||
|
||||
val (irModuleFragment, symbolTable, components) = Fir2IrConverter.createModuleFragment(
|
||||
cycleResult.session, cycleResult.scopeSession, cycleResult.fir + allCommonFirFiles,
|
||||
cycleResult.session.languageVersionSettings, mangler, signaturer,
|
||||
extensions, FirJvmKotlinMangler(cycleResult.session), IrFactoryImpl,
|
||||
FirJvmVisibilityConverter,
|
||||
Fir2IrJvmSpecialAnnotationSymbolProvider(),
|
||||
irGenerationExtensions
|
||||
)
|
||||
|
||||
val irInput = ModuleCompilerIrBackendInput(
|
||||
targetId,
|
||||
configuration,
|
||||
extensions,
|
||||
irModuleFragment,
|
||||
symbolTable,
|
||||
components,
|
||||
cycleResult.session
|
||||
)
|
||||
|
||||
val codegenOutput = generateCodeFromIr(irInput, compilerEnvironment)
|
||||
|
||||
FirDiagnosticsCompilerResultsReporter.reportToMessageCollector(
|
||||
diagnosticsReporter,
|
||||
collector,
|
||||
configuration.getBoolean(CLIConfigurationKeys.RENDER_DIAGNOSTIC_INTERNAL_NAME)
|
||||
)
|
||||
|
||||
writeOutputs(
|
||||
projectEnvironment,
|
||||
configuration,
|
||||
listOf(codegenOutput.generationState),
|
||||
mainClassFqName
|
||||
)
|
||||
} catch (e: CompilationCanceledException) {
|
||||
collector.report(CompilerMessageSeverity.INFO, "Compilation was canceled", null)
|
||||
return ExitCode.OK to allCompiledSources
|
||||
} catch (e: RuntimeException) {
|
||||
val cause = e.cause
|
||||
if (cause is CompilationCanceledException) {
|
||||
collector.report(CompilerMessageSeverity.INFO, "Compilation was canceled", null)
|
||||
return ExitCode.OK to allCompiledSources
|
||||
} else {
|
||||
throw e
|
||||
}
|
||||
} finally {
|
||||
collector.flush()
|
||||
Disposer.dispose(rootDisposable)
|
||||
}
|
||||
return exitCode to allCompiledSources
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun CompilerConfiguration.configureBaseRoots(args: K2JVMCompilerArguments) {
|
||||
|
||||
var isJava9Module = false
|
||||
args.javaSourceRoots?.forEach {
|
||||
val file = File(it)
|
||||
val packagePrefix = args.javaPackagePrefix
|
||||
addJavaSourceRoot(file, packagePrefix)
|
||||
if (!isJava9Module && packagePrefix == null && (file.name == PsiJavaModule.MODULE_INFO_FILE ||
|
||||
(file.isDirectory && file.listFiles()?.any { it.name == PsiJavaModule.MODULE_INFO_FILE } == true))
|
||||
) {
|
||||
isJava9Module = true
|
||||
}
|
||||
}
|
||||
|
||||
args.classpath?.split(File.pathSeparator)?.forEach { classpathRoot ->
|
||||
add(
|
||||
CLIConfigurationKeys.CONTENT_ROOTS,
|
||||
if (isJava9Module) JvmModulePathRoot(File(classpathRoot)) else JvmClasspathRoot(File(classpathRoot))
|
||||
)
|
||||
}
|
||||
|
||||
// TODO: modularJdkRoot (now seems only processed from the build file
|
||||
}
|
||||
|
||||
fun CompilerConfiguration.configureSourceRootsFromSources(
|
||||
allSources: Collection<File>, commonSources: Set<File>, javaPackagePrefix: String?
|
||||
) {
|
||||
for (sourceFile in allSources) {
|
||||
if (sourceFile.name.endsWith(JavaFileType.DOT_DEFAULT_EXTENSION)) {
|
||||
addJavaSourceRoot(sourceFile, javaPackagePrefix)
|
||||
} else {
|
||||
addKotlinSourceRoot(sourceFile.path, isCommon = sourceFile in commonSources)
|
||||
|
||||
if (sourceFile.isDirectory) {
|
||||
addJavaSourceRoot(sourceFile, javaPackagePrefix)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+6
-4
@@ -192,18 +192,20 @@ class IncrementalJsCompilerRunner(
|
||||
}
|
||||
|
||||
override fun runCompiler(
|
||||
sourcesToCompile: Set<File>,
|
||||
sourcesToCompile: List<File>,
|
||||
args: K2JSCompilerArguments,
|
||||
caches: IncrementalJsCachesManager,
|
||||
services: Services,
|
||||
messageCollector: MessageCollector
|
||||
): ExitCode {
|
||||
messageCollector: MessageCollector,
|
||||
allSources: List<File>,
|
||||
isIncremental: Boolean
|
||||
): Pair<ExitCode, Collection<File>> {
|
||||
val freeArgsBackup = args.freeArgs
|
||||
|
||||
val compiler = K2JSCompiler()
|
||||
return try {
|
||||
args.freeArgs += sourcesToCompile.map { it.absolutePath }
|
||||
compiler.exec(messageCollector, services, args)
|
||||
compiler.exec(messageCollector, services, args) to sourcesToCompile
|
||||
} finally {
|
||||
args.freeArgs = freeArgsBackup
|
||||
reportPerformanceData(compiler.defaultPerformanceManager)
|
||||
|
||||
+25
-16
@@ -86,17 +86,24 @@ fun makeIncrementally(
|
||||
val buildReporter = BuildReporter(icReporter = reporter, buildMetricsReporter = DoNothingBuildMetricsReporter)
|
||||
|
||||
withIC(args) {
|
||||
val compiler = IncrementalJvmCompilerRunner(
|
||||
cachesDir,
|
||||
buildReporter,
|
||||
// Use precise setting in case of non-Gradle build
|
||||
usePreciseJavaTracking = !args.useFir, // TODO: add fir-based java classes tracker when available and set this to true
|
||||
outputFiles = emptyList(),
|
||||
buildHistoryFile = buildHistoryFile,
|
||||
modulesApiHistory = EmptyModulesApiHistory,
|
||||
kotlinSourceFilesExtensions = kotlinExtensions,
|
||||
classpathChanges = ClasspathSnapshotDisabled
|
||||
)
|
||||
val compiler =
|
||||
if (args.useFir)
|
||||
IncrementalFirJvmCompilerRunner(
|
||||
cachesDir, buildReporter, buildHistoryFile, emptyList(), EmptyModulesApiHistory, kotlinExtensions, ClasspathSnapshotDisabled
|
||||
)
|
||||
else
|
||||
IncrementalJvmCompilerRunner(
|
||||
cachesDir,
|
||||
buildReporter,
|
||||
// Use precise setting in case of non-Gradle build
|
||||
usePreciseJavaTracking = !args.useFir, // TODO: add fir-based java classes tracker when available and set this to true
|
||||
outputFiles = emptyList(),
|
||||
buildHistoryFile = buildHistoryFile,
|
||||
modulesApiHistory = EmptyModulesApiHistory,
|
||||
kotlinSourceFilesExtensions = kotlinExtensions,
|
||||
classpathChanges = ClasspathSnapshotDisabled
|
||||
)
|
||||
//TODO set properly
|
||||
compiler.compile(sourceFiles, args, messageCollector, providedChangedFiles = null)
|
||||
}
|
||||
}
|
||||
@@ -116,7 +123,7 @@ inline fun <R> withIC(args: CommonCompilerArguments, enabled: Boolean = true, fn
|
||||
}
|
||||
}
|
||||
|
||||
class IncrementalJvmCompilerRunner(
|
||||
open class IncrementalJvmCompilerRunner(
|
||||
workingDir: File,
|
||||
reporter: BuildReporter,
|
||||
private val usePreciseJavaTracking: Boolean,
|
||||
@@ -453,12 +460,14 @@ class IncrementalJvmCompilerRunner(
|
||||
}
|
||||
|
||||
override fun runCompiler(
|
||||
sourcesToCompile: Set<File>,
|
||||
sourcesToCompile: List<File>,
|
||||
args: K2JVMCompilerArguments,
|
||||
caches: IncrementalJvmCachesManager,
|
||||
services: Services,
|
||||
messageCollector: MessageCollector
|
||||
): ExitCode {
|
||||
messageCollector: MessageCollector,
|
||||
allSources: List<File>,
|
||||
isIncremental: Boolean
|
||||
): Pair<ExitCode, Collection<File>> {
|
||||
val compiler = K2JVMCompiler()
|
||||
val freeArgsBackup = args.freeArgs.toList()
|
||||
args.freeArgs += sourcesToCompile.map { it.absolutePath }
|
||||
@@ -466,7 +475,7 @@ class IncrementalJvmCompilerRunner(
|
||||
val exitCode = compiler.exec(messageCollector, services, args)
|
||||
args.freeArgs = freeArgsBackup
|
||||
reportPerformanceData(compiler.defaultPerformanceManager)
|
||||
return exitCode
|
||||
return exitCode to sourcesToCompile
|
||||
}
|
||||
|
||||
override fun performWorkAfterSuccessfulCompilation(caches: IncrementalJvmCachesManager) {
|
||||
|
||||
+4
@@ -47,6 +47,10 @@ class InputsCache(
|
||||
}
|
||||
}
|
||||
|
||||
fun getOutputForSourceFiles(sources: Iterable<File>): List<File> = sources.flatMap {
|
||||
sourceToOutputMap[it]
|
||||
}
|
||||
|
||||
// generatedFiles can contain multiple entries with the same source file
|
||||
// for example Kapt3 IC will generate a .java stub and .class stub for each source file
|
||||
fun registerOutputForSourceFiles(generatedFiles: List<GeneratedFile>) {
|
||||
|
||||
+146
@@ -0,0 +1,146 @@
|
||||
/*
|
||||
* Copyright 2010-2022 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.incremental
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.pop
|
||||
import org.jetbrains.kotlin.backend.common.push
|
||||
import org.jetbrains.kotlin.backend.jvm.metadata.MetadataSerializer
|
||||
import org.jetbrains.kotlin.build.report.ICReporter
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.pipeline.ModuleCompilerAnalyzedOutput
|
||||
import org.jetbrains.kotlin.codegen.serialization.JvmSerializationBindings
|
||||
import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||
import org.jetbrains.kotlin.fir.FirElement
|
||||
import org.jetbrains.kotlin.fir.backend.FirMetadataSource
|
||||
import org.jetbrains.kotlin.fir.backend.jvm.makeLocalFirMetadataSerializerForMetadataSource
|
||||
import org.jetbrains.kotlin.fir.declarations.*
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.classId
|
||||
import org.jetbrains.kotlin.fir.scopes.jvm.computeJvmDescriptor
|
||||
import org.jetbrains.kotlin.fir.visitors.FirVisitor
|
||||
import org.jetbrains.kotlin.metadata.ProtoBuf
|
||||
import org.jetbrains.kotlin.modules.TargetId
|
||||
import org.jetbrains.kotlin.name.SpecialNames
|
||||
import org.jetbrains.kotlin.resolve.jvm.JvmClassName
|
||||
import org.jetbrains.org.objectweb.asm.commons.Method
|
||||
import java.io.File
|
||||
|
||||
internal fun collectNewDirtySources(
|
||||
analysisResults: ModuleCompilerAnalyzedOutput,
|
||||
targetId: TargetId,
|
||||
configuration: CompilerConfiguration,
|
||||
caches: IncrementalJvmCachesManager,
|
||||
alreadyCompiledSources: Set<File>,
|
||||
reporter: ICReporter
|
||||
): LinkedHashSet<File> {
|
||||
val changesCollector = ChangesCollector()
|
||||
val globalSerializationBindings = JvmSerializationBindings()
|
||||
analysisResults.fir.forEach {
|
||||
it.accept(object : FirVisitor<Unit, MutableList<MetadataSerializer>>() {
|
||||
|
||||
inline fun withMetadataSerializer(
|
||||
metadata: FirMetadataSource,
|
||||
data: MutableList<MetadataSerializer>,
|
||||
body: (MetadataSerializer) -> Unit
|
||||
) {
|
||||
val serializer = makeLocalFirMetadataSerializerForMetadataSource(
|
||||
metadata,
|
||||
analysisResults.session,
|
||||
analysisResults.scopeSession,
|
||||
globalSerializationBindings,
|
||||
data.lastOrNull(),
|
||||
targetId,
|
||||
configuration
|
||||
)
|
||||
data.push(serializer)
|
||||
body(serializer)
|
||||
data.pop()
|
||||
}
|
||||
|
||||
override fun visitElement(element: FirElement, data: MutableList<MetadataSerializer>) {
|
||||
element.acceptChildren(this, data)
|
||||
}
|
||||
|
||||
override fun visitRegularClass(regularClass: FirRegularClass, data: MutableList<MetadataSerializer>) {
|
||||
visitClass(regularClass, data)
|
||||
}
|
||||
|
||||
override fun visitAnonymousObject(anonymousObject: FirAnonymousObject, data: MutableList<MetadataSerializer>) {
|
||||
visitClass(anonymousObject, data)
|
||||
}
|
||||
|
||||
override fun visitFile(file: FirFile, data: MutableList<MetadataSerializer>) {
|
||||
val metadata = FirMetadataSource.File(file)
|
||||
withMetadataSerializer(metadata, data) {
|
||||
file.acceptChildren(this, data)
|
||||
// TODO: compare package fragments?
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitSimpleFunction(simpleFunction: FirSimpleFunction, data: MutableList<MetadataSerializer>) {
|
||||
data.firstOrNull()?.let { serializer ->
|
||||
super.visitFunction(simpleFunction, data)
|
||||
serializer.bindMethodMetadata(
|
||||
FirMetadataSource.Function(simpleFunction),
|
||||
Method(simpleFunction.name.asString(), simpleFunction.computeJvmDescriptor())
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitConstructor(constructor: FirConstructor, data: MutableList<MetadataSerializer>) {
|
||||
super.visitConstructor(constructor, data)
|
||||
data.first().bindMethodMetadata(
|
||||
FirMetadataSource.Function(constructor),
|
||||
Method(SpecialNames.INIT.asString(), constructor.computeJvmDescriptor(""))
|
||||
)
|
||||
}
|
||||
|
||||
override fun visitProperty(property: FirProperty, data: MutableList<MetadataSerializer>) {
|
||||
property.acceptChildren(this, data)
|
||||
// data.firstOrNull()?.let {
|
||||
// property.acceptChildren(this, data)
|
||||
// it.bindPropertyMetadata(
|
||||
// FirMetadataSource.Property(property),
|
||||
// Method(property.name.asString(), ""),//property.computeJvmDescriptor())
|
||||
// IrDeclarationOrigin.DEFINED
|
||||
// )
|
||||
// }
|
||||
}
|
||||
|
||||
override fun visitClass(klass: FirClass, data: MutableList<MetadataSerializer>) {
|
||||
val metadata = FirMetadataSource.Class(klass)
|
||||
withMetadataSerializer(metadata, data) { serializer ->
|
||||
klass.acceptChildren(this, data)
|
||||
serializer.serialize(metadata)?.let { (classProto, nameTable) ->
|
||||
caches.platformCache.collectClassChangesByFeMetadata(
|
||||
JvmClassName.byClassId(klass.classId),
|
||||
classProto as ProtoBuf.Class,
|
||||
nameTable,
|
||||
changesCollector
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}, mutableListOf())
|
||||
}
|
||||
|
||||
val (dirtyLookupSymbols, dirtyClassFqNames, forceRecompile) = changesCollector.getDirtyData(listOf(caches.platformCache), reporter)
|
||||
|
||||
val forceToRecompileFiles = mapClassesFqNamesToFiles(listOf(caches.platformCache), forceRecompile, reporter)
|
||||
|
||||
return linkedSetOf<File>().apply {
|
||||
addAll(mapLookupSymbolsToFiles(caches.lookupCache, dirtyLookupSymbols, reporter, excludes = alreadyCompiledSources))
|
||||
addAll(
|
||||
mapClassesFqNamesToFiles(
|
||||
listOf(caches.platformCache),
|
||||
dirtyClassFqNames,
|
||||
reporter,
|
||||
excludes = alreadyCompiledSources
|
||||
)
|
||||
)
|
||||
if (!alreadyCompiledSources.containsAll(forceToRecompileFiles)) {
|
||||
addAll(forceToRecompileFiles)
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -93,7 +93,7 @@ class FirFrontendFacade(
|
||||
PsiBasedProjectFileSearchScope(sourcesScope),
|
||||
PsiBasedProjectFileSearchScope(librariesScope),
|
||||
lookupTracker = null,
|
||||
providerAndScopeForIncrementalCompilation = null,
|
||||
incrementalCompilationContext = null,
|
||||
extensionRegistrars = FirExtensionRegistrar.getInstances(project),
|
||||
needRegisterJavaElementFinder = true,
|
||||
dependenciesConfigurator = {
|
||||
|
||||
+1
-1
@@ -97,7 +97,7 @@ abstract class AbstractFirBaseDiagnosticsTest : BaseDiagnosticsTest() {
|
||||
sourceScope = PsiBasedProjectFileSearchScope(scope),
|
||||
librariesScope = PsiBasedProjectFileSearchScope(allProjectScope),
|
||||
lookupTracker = null,
|
||||
providerAndScopeForIncrementalCompilation = null,
|
||||
incrementalCompilationContext = null,
|
||||
extensionRegistrars = emptyList(),
|
||||
needRegisterJavaElementFinder = true
|
||||
) {
|
||||
|
||||
@@ -41,7 +41,7 @@ fun createSessionForTests(
|
||||
sourceScope,
|
||||
librariesScope,
|
||||
lookupTracker = null,
|
||||
providerAndScopeForIncrementalCompilation = null,
|
||||
incrementalCompilationContext = null,
|
||||
extensionRegistrars = emptyList(),
|
||||
needRegisterJavaElementFinder = true,
|
||||
dependenciesConfigurator = {
|
||||
@@ -72,7 +72,7 @@ fun createSessionForTests(
|
||||
PsiBasedProjectFileSearchScope(sourceScope),
|
||||
PsiBasedProjectFileSearchScope(librariesScope),
|
||||
lookupTracker = null,
|
||||
providerAndScopeForIncrementalCompilation = null,
|
||||
incrementalCompilationContext = null,
|
||||
extensionRegistrars = emptyList(),
|
||||
needRegisterJavaElementFinder = true,
|
||||
dependenciesConfigurator = {
|
||||
|
||||
Reference in New Issue
Block a user