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