diff --git a/build-common/src/org/jetbrains/kotlin/incremental/ClasspathChanges.kt b/build-common/src/org/jetbrains/kotlin/incremental/ClasspathChanges.kt new file mode 100644 index 00000000000..f9db44aa940 --- /dev/null +++ b/build-common/src/org/jetbrains/kotlin/incremental/ClasspathChanges.kt @@ -0,0 +1,76 @@ +/* + * 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 org.jetbrains.kotlin.name.FqName +import java.io.ObjectInputStream +import java.io.ObjectOutputStream +import java.io.Serializable + +/** + * Changes to the classpath of the `KotlinCompile` task, used to compute the source files that need to be recompiled during an incremental + * run. + */ +sealed class ClasspathChanges : Serializable { + + class Available() : ClasspathChanges() { + + lateinit var lookupSymbols: List + private set + + lateinit var fqNames: List + private set + + constructor(lookupSymbols: List, fqNames: List) : this() { + this.lookupSymbols = lookupSymbols + this.fqNames = fqNames + } + + private fun writeObject(out: ObjectOutputStream) { + out.writeInt(lookupSymbols.size) + lookupSymbols.forEach { + out.writeUTF(it.name) + out.writeUTF(it.scope) + } + + out.writeInt(fqNames.size) + fqNames.forEach { + out.writeUTF(it.asString()) + } + } + + private fun readObject(ois: ObjectInputStream) { + val lookupSymbolsSize = ois.readInt() + val lookupSymbols = ArrayList(lookupSymbolsSize) + repeat(lookupSymbolsSize) { + val name = ois.readUTF() + val scope = ois.readUTF() + lookupSymbols.add(LookupSymbol(name, scope)) + } + this.lookupSymbols = lookupSymbols + + val fqNamesSize = ois.readInt() + val fqNames = ArrayList(fqNamesSize) + repeat(fqNamesSize) { + val fqNameString = ois.readUTF() + fqNames.add(FqName(fqNameString)) + } + this.fqNames = fqNames + } + + companion object { + private const val serialVersionUID = 0L + } + } + + sealed class NotAvailable : ClasspathChanges() { + object UnableToCompute : NotAvailable() + object ForNonIncrementalRun : NotAvailable() + object ClasspathSnapshotIsDisabled : NotAvailable() + object ReservedForTestsOnly : NotAvailable() + object ForJSCompiler : NotAvailable() + } +} diff --git a/compiler/daemon/daemon-common/src/org/jetbrains/kotlin/daemon/common/CompilationOptions.kt b/compiler/daemon/daemon-common/src/org/jetbrains/kotlin/daemon/common/CompilationOptions.kt index 640082b79ad..5ab9ed9c269 100644 --- a/compiler/daemon/daemon-common/src/org/jetbrains/kotlin/daemon/common/CompilationOptions.kt +++ b/compiler/daemon/daemon-common/src/org/jetbrains/kotlin/daemon/common/CompilationOptions.kt @@ -16,6 +16,7 @@ package org.jetbrains.kotlin.daemon.common +import org.jetbrains.kotlin.incremental.ClasspathChanges import org.jetbrains.kotlin.incremental.IncrementalModuleInfo import java.io.File import java.io.Serializable @@ -52,6 +53,7 @@ class IncrementalCompilationOptions( val areFileChangesKnown: Boolean, val modifiedFiles: List?, val deletedFiles: List?, + val classpathChanges: ClasspathChanges, val workingDir: File, compilerMode: CompilerMode, targetPlatform: CompileService.TargetPlatform, @@ -87,6 +89,7 @@ class IncrementalCompilationOptions( "areFileChangesKnown=$areFileChangesKnown, " + "modifiedFiles=$modifiedFiles, " + "deletedFiles=$deletedFiles, " + + "classpathChanges=$classpathChanges, " + "workingDir=$workingDir, " + "multiModuleICSettings=$multiModuleICSettings, " + "usePreciseJavaTracking=$usePreciseJavaTracking" + diff --git a/compiler/daemon/src/org/jetbrains/kotlin/daemon/CompileServiceImpl.kt b/compiler/daemon/src/org/jetbrains/kotlin/daemon/CompileServiceImpl.kt index ee342ec72f9..db9a6a6a018 100644 --- a/compiler/daemon/src/org/jetbrains/kotlin/daemon/CompileServiceImpl.kt +++ b/compiler/daemon/src/org/jetbrains/kotlin/daemon/CompileServiceImpl.kt @@ -601,7 +601,8 @@ abstract class CompileServiceImplBase( outputFiles = incrementalCompilationOptions.outputFiles, usePreciseJavaTracking = incrementalCompilationOptions.usePreciseJavaTracking, modulesApiHistory = modulesApiHistory, - kotlinSourceFilesExtensions = allKotlinExtensions + kotlinSourceFilesExtensions = allKotlinExtensions, + classpathChanges = incrementalCompilationOptions.classpathChanges ) return try { compiler.compile(allKotlinFiles, k2jvmArgs, compilerMessageCollector, changedFiles, projectRoot) diff --git a/compiler/incremental-compilation-impl/src/org/jetbrains/kotlin/incremental/IncrementalJvmCompilerRunner.kt b/compiler/incremental-compilation-impl/src/org/jetbrains/kotlin/incremental/IncrementalJvmCompilerRunner.kt index cf10554526d..cd4ce90f98f 100644 --- a/compiler/incremental-compilation-impl/src/org/jetbrains/kotlin/incremental/IncrementalJvmCompilerRunner.kt +++ b/compiler/incremental-compilation-impl/src/org/jetbrains/kotlin/incremental/IncrementalJvmCompilerRunner.kt @@ -22,6 +22,7 @@ import com.intellij.psi.PsiClass import com.intellij.psi.PsiFile import com.intellij.psi.PsiFileFactory import com.intellij.psi.PsiJavaFile +import org.jetbrains.annotations.TestOnly import org.jetbrains.kotlin.build.DEFAULT_KOTLIN_SOURCE_FILES_EXTENSIONS import org.jetbrains.kotlin.build.GeneratedFile import org.jetbrains.kotlin.build.GeneratedJvmClass @@ -46,6 +47,11 @@ import org.jetbrains.kotlin.incremental.multiproject.EmptyModulesApiHistory import org.jetbrains.kotlin.incremental.multiproject.ModulesApiHistory import org.jetbrains.kotlin.incremental.util.BufferingMessageCollector import org.jetbrains.kotlin.incremental.util.Either +import org.jetbrains.kotlin.incremental.ClasspathChanges.NotAvailable.UnableToCompute +import org.jetbrains.kotlin.incremental.ClasspathChanges.NotAvailable.ForJSCompiler +import org.jetbrains.kotlin.incremental.ClasspathChanges.NotAvailable.ReservedForTestsOnly +import org.jetbrains.kotlin.incremental.ClasspathChanges.NotAvailable.ForNonIncrementalRun +import org.jetbrains.kotlin.incremental.ClasspathChanges.NotAvailable.ClasspathSnapshotIsDisabled import org.jetbrains.kotlin.load.java.JavaClassesTracker import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader import org.jetbrains.kotlin.load.kotlin.incremental.components.IncrementalCompilationComponents @@ -55,6 +61,7 @@ import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name import java.io.File +@TestOnly fun makeIncrementally( cachesDir: File, sourceRoots: Iterable, @@ -80,7 +87,8 @@ fun makeIncrementally( outputFiles = emptyList(), buildHistoryFile = buildHistoryFile, modulesApiHistory = EmptyModulesApiHistory, - kotlinSourceFilesExtensions = kotlinExtensions + kotlinSourceFilesExtensions = kotlinExtensions, + classpathChanges = ReservedForTestsOnly ) //TODO set properly compiler.compile(sourceFiles, args, messageCollector, providedChangedFiles = null) @@ -116,7 +124,8 @@ class IncrementalJvmCompilerRunner( buildHistoryFile: File, outputFiles: Collection, private val modulesApiHistory: ModulesApiHistory, - override val kotlinSourceFilesExtensions: List = DEFAULT_KOTLIN_SOURCE_FILES_EXTENSIONS + override val kotlinSourceFilesExtensions: List = DEFAULT_KOTLIN_SOURCE_FILES_EXTENSIONS, + private val classpathChanges: ClasspathChanges, ) : IncrementalCompilerRunner( workingDir, "caches-jvm", @@ -208,10 +217,23 @@ class IncrementalJvmCompilerRunner( val lastBuildInfo = BuildInfo.read(lastBuildInfoFile) ?: return CompilationMode.Rebuild(BuildAttribute.NO_BUILD_HISTORY) reporter.reportVerbose { "Last Kotlin Build info -- $lastBuildInfo" } - val classpathChanges = reporter.measure(BuildTime.IC_ANALYZE_CHANGES_IN_DEPENDENCIES) { - val scopes = caches.lookupCache.lookupMap.keys.map { if (it.scope.isBlank()) it.name else it.scope }.distinct() - getClasspathChanges(args.classpathAsList, changedFiles, lastBuildInfo, modulesApiHistory, reporter, - abiSnapshots, withSnapshot, caches.platformCache, scopes) + val classpathChanges = when (classpathChanges) { + // Note: classpathChanges is deserialized so they are no longer singleton objects and need to be compared using `is` (not `==`). + is ClasspathChanges.Available -> ChangesEither.Known(classpathChanges.lookupSymbols, classpathChanges.fqNames) + is ClasspathChanges.NotAvailable -> when (classpathChanges) { + is UnableToCompute, is ClasspathSnapshotIsDisabled, is ReservedForTestsOnly -> { + reporter.measure(BuildTime.IC_ANALYZE_CHANGES_IN_DEPENDENCIES) { + val scopes = caches.lookupCache.lookupMap.keys.map { if (it.scope.isBlank()) it.name else it.scope }.distinct() + getClasspathChanges( + args.classpathAsList, changedFiles, lastBuildInfo, modulesApiHistory, reporter, abiSnapshots, withSnapshot, + caches.platformCache, scopes + ) + } + } + is ForNonIncrementalRun, is ForJSCompiler -> { + error("Unexpected type for this code path: ${classpathChanges.javaClass.name}.") + } + } } @Suppress("UNUSED_VARIABLE") // for sealed when diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/compilerRunner/GradleKotlinCompilerWork.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/compilerRunner/GradleKotlinCompilerWork.kt index d4a725d2d52..6c4e93a8834 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/compilerRunner/GradleKotlinCompilerWork.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/compilerRunner/GradleKotlinCompilerWork.kt @@ -271,6 +271,7 @@ internal class GradleKotlinCompilerWork @Inject constructor( areFileChangesKnown = knownChangedFiles != null, modifiedFiles = knownChangedFiles?.modified, deletedFiles = knownChangedFiles?.removed, + classpathChanges = icEnv.classpathChanges, workingDir = icEnv.workingDir, reportCategories = reportCategories(isVerbose), reportSeverity = reportSeverity(isVerbose), diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/compilerRunner/IncrementalCompilationEnvironment.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/compilerRunner/IncrementalCompilationEnvironment.kt index 22e8c3ae554..ec09810466c 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/compilerRunner/IncrementalCompilationEnvironment.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/compilerRunner/IncrementalCompilationEnvironment.kt @@ -7,11 +7,13 @@ package org.jetbrains.kotlin.compilerRunner import org.jetbrains.kotlin.daemon.common.MultiModuleICSettings import org.jetbrains.kotlin.incremental.ChangedFiles +import org.jetbrains.kotlin.incremental.ClasspathChanges import java.io.File import java.io.Serializable internal class IncrementalCompilationEnvironment( val changedFiles: ChangedFiles, + val classpathChanges: ClasspathChanges, val workingDir: File, val usePreciseJavaTracking: Boolean = false, val disableMultiModuleIC: Boolean = false, diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/Tasks.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/Tasks.kt index 1b1e3da86bd..19b0b174d50 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/Tasks.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/Tasks.kt @@ -24,10 +24,7 @@ import org.gradle.api.tasks.compile.JavaCompile import org.gradle.api.tasks.incremental.IncrementalTaskInputs import org.gradle.workers.WorkerExecutor import org.jetbrains.kotlin.build.DEFAULT_KOTLIN_SOURCE_FILES_EXTENSIONS -import org.jetbrains.kotlin.build.report.metrics.BuildMetricsReporter -import org.jetbrains.kotlin.build.report.metrics.BuildMetricsReporterImpl -import org.jetbrains.kotlin.build.report.metrics.BuildTime -import org.jetbrains.kotlin.build.report.metrics.measure +import org.jetbrains.kotlin.build.report.metrics.* import org.jetbrains.kotlin.cli.common.CompilerSystemProperties import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments import org.jetbrains.kotlin.cli.common.arguments.CommonToolArguments @@ -56,6 +53,7 @@ import org.jetbrains.kotlin.gradle.plugin.statistics.KotlinBuildStatsService import org.jetbrains.kotlin.gradle.report.ReportingSettings import org.jetbrains.kotlin.gradle.targets.js.ir.isProduceUnzippedKlib import org.jetbrains.kotlin.gradle.utils.* +import org.jetbrains.kotlin.incremental.ClasspathChanges import org.jetbrains.kotlin.incremental.ChangedFiles import org.jetbrains.kotlin.incremental.IncrementalCompilerRunner import org.jetbrains.kotlin.library.impl.isKotlinLibrary @@ -627,14 +625,20 @@ abstract class KotlinCompile @Inject constructor( val outputItemCollector = OutputItemsCollectorImpl() val compilerRunner = compilerRunner.get() - if (classpathSnapshotProperties.useClasspathSnapshot.get()) { - getClasspathChanges() - } val icEnv = if (isIncrementalCompilationEnabled()) { + val classpathChanges = when { + !classpathSnapshotProperties.useClasspathSnapshot.get() -> ClasspathChanges.NotAvailable.ClasspathSnapshotIsDisabled + else -> when (changedFiles) { + is ChangedFiles.Known -> getClasspathChanges() + is ChangedFiles.Unknown -> ClasspathChanges.NotAvailable.ForNonIncrementalRun + is ChangedFiles.Dependencies -> error("Unexpected type: ${changedFiles.javaClass.name}") + } + } logger.info(USING_JVM_INCREMENTAL_COMPILATION_MESSAGE) IncrementalCompilationEnvironment( - changedFiles, - taskBuildDirectory.get().asFile, + changedFiles = changedFiles, + classpathChanges = classpathChanges, + workingDir = taskBuildDirectory.get().asFile, usePreciseJavaTracking = usePreciseJavaTracking, disableMultiModuleIC = disableMultiModuleIC, multiModuleICSettings = multiModuleICSettings @@ -659,7 +663,7 @@ abstract class KotlinCompile @Inject constructor( ) with(classpathSnapshotProperties) { - if (useClasspathSnapshot.get()) { + if (isIncrementalCompilationEnabled() && useClasspathSnapshot.get()) { copyClasspathSnapshotFilesToDir(classpathSnapshot.files.toList(), classpathSnapshotDir.get().asFile) } } @@ -722,10 +726,12 @@ abstract class KotlinCompile @Inject constructor( return super.source(*sources) } - private fun getClasspathChanges() { + private fun getClasspathChanges(): ClasspathChanges { + val currentSnapshotFiles = classpathSnapshotProperties.classpathSnapshot.files.toList() + val previousSnapshotFiles = getClasspathSnapshotFilesInDir(classpathSnapshotProperties.classpathSnapshotDir.get().asFile) + // TODO WORK-IN-PROGRESS - val currentClasspathSnapshotFiles = classpathSnapshotProperties.classpathSnapshot.files.toList() - val previousClasspathSnapshotFiles = getClasspathSnapshotFilesInDir(classpathSnapshotProperties.classpathSnapshotDir.get().asFile) + return ClasspathChanges.NotAvailable.UnableToCompute } /** @@ -1034,6 +1040,7 @@ abstract class Kotlin2JsCompile @Inject constructor( logger.info(USING_JS_INCREMENTAL_COMPILATION_MESSAGE) IncrementalCompilationEnvironment( changedFiles, + ClasspathChanges.NotAvailable.ForJSCompiler, taskBuildDirectory.get().asFile, multiModuleICSettings = multiModuleICSettings )