diff --git a/build-common/src/org/jetbrains/kotlin/incremental/ICReporter.kt b/build-common/src/org/jetbrains/kotlin/incremental/ICReporter.kt index 64afbf0323f..4e7a344035c 100644 --- a/build-common/src/org/jetbrains/kotlin/incremental/ICReporter.kt +++ b/build-common/src/org/jetbrains/kotlin/incremental/ICReporter.kt @@ -25,6 +25,20 @@ interface ICReporter { fun reportCompileIteration(incremental: Boolean, sourceFiles: Collection, exitCode: ExitCode) {} + fun reportMarkDirtyClass(affectedFiles: Iterable, classFqName: String) { + reportMarkDirty(affectedFiles, "dirty class $classFqName") + } + + fun reportMarkDirtyMember(affectedFiles: Iterable, scope: String, name: String) { + reportMarkDirty(affectedFiles, "dirty member $scope#$name") + } + + fun reportMarkDirty(affectedFiles: Iterable, reason: String) { + affectedFiles.forEach { file -> + reportVerbose { "${pathsAsString(file)} is marked dirty: $reason" } + } + } + fun pathsAsString(files: Iterable): String = files.joinToString { it.canonicalPath } diff --git a/build-common/src/org/jetbrains/kotlin/incremental/buildUtil.kt b/build-common/src/org/jetbrains/kotlin/incremental/buildUtil.kt index d9d263cb9ca..3df394b2c1e 100644 --- a/build-common/src/org/jetbrains/kotlin/incremental/buildUtil.kt +++ b/build-common/src/org/jetbrains/kotlin/incremental/buildUtil.kt @@ -31,8 +31,10 @@ import org.jetbrains.kotlin.modules.TargetId import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.progress.CompilationCanceledStatus import org.jetbrains.kotlin.synthetic.SAM_LOOKUP_NAME +import org.jetbrains.kotlin.utils.addToStdlib.flattenTo import java.io.File import java.util.* +import kotlin.collections.HashSet const val DELETE_MODULE_FILE_PROPERTY = "kotlin.delete.module.file.after.build" @@ -143,8 +145,7 @@ fun ChangesCollector.getDirtyData( val name = classFqName.shortName().identifier dirtyLookupSymbols.add(LookupSymbol(name, scope)) } - } - else if (change is ChangeInfo.MembersChanged) { + } else if (change is ChangeInfo.MembersChanged) { val fqNames = withSubtypes(change.fqName, caches) // need to recompile subtypes because changed member might break override dirtyClassesFqNames.addAll(fqNames) @@ -161,16 +162,16 @@ fun ChangesCollector.getDirtyData( } fun mapLookupSymbolsToFiles( - lookupStorage: LookupStorage, - lookupSymbols: Iterable, - reporter: ICReporter, - excludes: Set = emptySet() + lookupStorage: LookupStorage, + lookupSymbols: Iterable, + reporter: ICReporter, + excludes: Set = emptySet() ): Set { val dirtyFiles = HashSet() for (lookup in lookupSymbols) { val affectedFiles = lookupStorage.get(lookup).map(::File).filter { it !in excludes } - reporter.report { "${lookup.scope}#${lookup.name} caused recompilation of: ${reporter.pathsAsString(affectedFiles)}" } + reporter.reportMarkDirtyMember(affectedFiles, scope = lookup.scope, name = lookup.name) dirtyFiles.addAll(affectedFiles) } @@ -183,19 +184,22 @@ fun mapClassesFqNamesToFiles( reporter: ICReporter, excludes: Set = emptySet() ): Set { - val dirtyFiles = HashSet() + val fqNameToAffectedFiles = HashMap>() for (cache in caches) { - for (dirtyClassFqName in classesFqNames) { - val srcFile = cache.getSourceFileIfClass(dirtyClassFqName) + for (classFqName in classesFqNames) { + val srcFile = cache.getSourceFileIfClass(classFqName) if (srcFile == null || srcFile in excludes || srcFile.isJavaFile()) continue - reporter.report { "Class $dirtyClassFqName caused recompilation of: ${reporter.pathsAsString(srcFile)}" } - dirtyFiles.add(srcFile) + fqNameToAffectedFiles.getOrPut(classFqName) { HashSet() }.add(srcFile) } } - return dirtyFiles + for ((classFqName, affectedFiles) in fqNameToAffectedFiles) { + reporter.reportMarkDirtyClass(affectedFiles, classFqName.asString()) + } + + return fqNameToAffectedFiles.values.flattenTo(HashSet()) } fun withSubtypes( diff --git a/compiler/daemon/src/org/jetbrains/kotlin/daemon/report/RemoteICReporter.kt b/compiler/daemon/src/org/jetbrains/kotlin/daemon/report/RemoteICReporter.kt index cc5169478dc..2006c33a897 100644 --- a/compiler/daemon/src/org/jetbrains/kotlin/daemon/report/RemoteICReporter.kt +++ b/compiler/daemon/src/org/jetbrains/kotlin/daemon/report/RemoteICReporter.kt @@ -34,6 +34,7 @@ internal class RemoteICReporter( CompilationResultCategory.IC_COMPILE_ITERATION.code in compilationOptions.requestedCompilationResults private val shouldReportICLog = CompilationResultCategory.IC_LOG.code in compilationOptions.requestedCompilationResults private val icLogLines = arrayListOf() + private val recompilationReason = HashMap() override fun report(message: () -> String) { reportImpl(isMessageVerbose = false, message = message) @@ -64,9 +65,18 @@ internal class RemoteICReporter( } if (shouldReportICLog && incremental) { icLogLines.add("Compile iteration:") - sourceFiles.relativePaths(rootDir).forEach { - icLogLines.add(" $it") + sourceFiles.relativePaths(rootDir).forEach { file -> + val reason = recompilationReason[file]?.let { " <- $it" } ?: "" + icLogLines.add(" $file$reason") } + recompilationReason.clear() + } + } + + override fun reportMarkDirty(affectedFiles: Iterable, reason: String) { + super.reportMarkDirty(affectedFiles, reason) + if (shouldReportICLog) { + affectedFiles.forEach { recompilationReason[it] = reason } } } diff --git a/compiler/incremental-compilation-impl/src/org/jetbrains/kotlin/incremental/DirtyFilesContainer.kt b/compiler/incremental-compilation-impl/src/org/jetbrains/kotlin/incremental/DirtyFilesContainer.kt index a101de686ad..d5888b44f76 100644 --- a/compiler/incremental-compilation-impl/src/org/jetbrains/kotlin/incremental/DirtyFilesContainer.kt +++ b/compiler/incremental-compilation-impl/src/org/jetbrains/kotlin/incremental/DirtyFilesContainer.kt @@ -18,10 +18,13 @@ class DirtyFilesContainer( fun toMutableList(): MutableList = ArrayList(myDirtyFiles) - fun add(files: Iterable) { + fun add(files: Iterable, reason: String?) { val existingKotlinFiles = files.filter { it.isKotlinFile(sourceFilesExtensions) } if (existingKotlinFiles.isNotEmpty()) { myDirtyFiles.addAll(existingKotlinFiles) + if (reason != null) { + reporter.reportMarkDirty(existingKotlinFiles, reason) + } } } @@ -29,7 +32,8 @@ class DirtyFilesContainer( if (lookupSymbols.isEmpty()) return val dirtyFilesFromLookups = mapLookupSymbolsToFiles(caches.lookupCache, lookupSymbols, reporter) - add(dirtyFilesFromLookups) + // reason is null, because files are reported in mapLookupSymbolsToFiles + add(dirtyFilesFromLookups, reason = null) } fun addByDirtyClasses(dirtyClassesFqNames: Collection) { @@ -43,6 +47,7 @@ class DirtyFilesContainer( } val dirtyFilesFromFqNames = mapClassesFqNamesToFiles(listOf(caches.platformCache), fqNamesWithSubtypes, reporter) - add(dirtyFilesFromFqNames) + // reason is null, because files are reported in mapClassesFqNamesToFiles + add(dirtyFilesFromFqNames, reason = null) } } \ No newline at end of file diff --git a/compiler/incremental-compilation-impl/src/org/jetbrains/kotlin/incremental/IncrementalCompilerRunner.kt b/compiler/incremental-compilation-impl/src/org/jetbrains/kotlin/incremental/IncrementalCompilerRunner.kt index b092a200936..449e18d8d87 100644 --- a/compiler/incremental-compilation-impl/src/org/jetbrains/kotlin/incremental/IncrementalCompilerRunner.kt +++ b/compiler/incremental-compilation-impl/src/org/jetbrains/kotlin/incremental/IncrementalCompilerRunner.kt @@ -139,16 +139,16 @@ abstract class IncrementalCompilerRunner< protected abstract fun calculateSourcesToCompile(caches: CacheManager, changedFiles: ChangedFiles.Known, args: Args): CompilationMode protected fun initDirtyFiles(dirtyFiles: DirtyFilesContainer, changedFiles: ChangedFiles.Known) { - dirtyFiles.add(changedFiles.modified) - dirtyFiles.add(changedFiles.removed) + dirtyFiles.add(changedFiles.modified, "was modified since last time") + dirtyFiles.add(changedFiles.removed, "was removed since last time") if (dirtySourcesSinceLastTimeFile.exists()) { val files = dirtySourcesSinceLastTimeFile.readLines().map(::File) if (files.isNotEmpty()) { - reporter.report { "Source files added since last compilation: ${reporter.pathsAsString(files)}" } + reporter.reportVerbose { "Source files added since last compilation: ${reporter.pathsAsString(files)}" } } - dirtyFiles.add(files) + dirtyFiles.add(files, "was not compiled last time") } } diff --git a/jps-plugin/src/org/jetbrains/kotlin/jps/build/KotlinBuilder.kt b/jps-plugin/src/org/jetbrains/kotlin/jps/build/KotlinBuilder.kt index d6f50f1749e..6230e93bdd3 100644 --- a/jps-plugin/src/org/jetbrains/kotlin/jps/build/KotlinBuilder.kt +++ b/jps-plugin/src/org/jetbrains/kotlin/jps/build/KotlinBuilder.kt @@ -47,7 +47,6 @@ import org.jetbrains.kotlin.jps.incremental.withLookupStorage import org.jetbrains.kotlin.jps.model.kotlinKind import org.jetbrains.kotlin.jps.targets.KotlinJvmModuleBuildTarget import org.jetbrains.kotlin.jps.targets.KotlinModuleBuildTarget -import org.jetbrains.kotlin.jps.targets.KotlinUnsupportedModuleBuildTarget import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.preloading.ClassCondition import org.jetbrains.kotlin.utils.KotlinPaths