diff --git a/jps/jps-plugin/src/org/jetbrains/kotlin/jps/incremental/IncrementalCacheImpl.kt b/jps/jps-plugin/src/org/jetbrains/kotlin/jps/incremental/IncrementalCacheImpl.kt index 831473cf1b4..fd8e1219255 100644 --- a/jps/jps-plugin/src/org/jetbrains/kotlin/jps/incremental/IncrementalCacheImpl.kt +++ b/jps/jps-plugin/src/org/jetbrains/kotlin/jps/incremental/IncrementalCacheImpl.kt @@ -47,6 +47,8 @@ import org.jetbrains.jps.builders.BuildTarget import org.jetbrains.jps.builders.storage.BuildDataPaths import com.intellij.util.io.BooleanDataDescriptor import java.util.ArrayList +import org.jetbrains.annotations.TestOnly +import org.jetbrains.kotlin.utils.Printer val INLINE_ANNOTATION_DESC = "Lkotlin/inline;" @@ -100,6 +102,11 @@ public class IncrementalCacheImpl(targetDataRoot: File) : StorageOwner, Incremen private val cacheFormatVersion = CacheFormatVersion(targetDataRoot) + TestOnly + public fun dump(): String { + return maps.map { it.dump() }.join("\n\n") + } + public fun saveFileToCache(sourceFiles: Collection, classFile: File): RecompilationDecision { if (classFile.extension.toLowerCase() != "class") return DO_NOTHING @@ -231,6 +238,26 @@ public class IncrementalCacheImpl(targetDataRoot: File) : StorageOwner, Incremen public fun close() { storage.close() } + + TestOnly + public fun dump(): String { + return with(StringBuilder()) { + with(Printer(this)) { + println(this@BasicMap.javaClass.getSimpleName()) + pushIndent() + + for (key in storage.getAllKeysWithExistingMapping().sort()) { + println("$key -> ${dumpValue(storage[key])}") + } + + popIndent() + } + + this + }.toString() + } + + protected abstract fun dumpValue(value: V): String } private abstract class ClassFileBasedMap : BasicMap() { @@ -275,6 +302,10 @@ public class IncrementalCacheImpl(targetDataRoot: File) : StorageOwner, Incremen public fun get(className: JvmClassName): ByteArray? { return storage[className.getInternalName()] } + + override fun dumpValue(value: ByteArray): String { + return java.lang.Long.toHexString(value.md5()) + } } private inner class ConstantsMap : ClassFileBasedMap>() { @@ -319,6 +350,19 @@ public class IncrementalCacheImpl(targetDataRoot: File) : StorageOwner, Incremen } return true } + + override fun dumpValue(value: Map): String { + return StringBuilder { + append("{") + for (key in value.keySet().sort()) { + if (length() != 1) { + append(", ") + } + append("$key -> ${value[key]}") + } + append("}") + }.toString() + } } private object ConstantsMapExternalizer : DataExternalizer> { @@ -437,6 +481,19 @@ public class IncrementalCacheImpl(targetDataRoot: File) : StorageOwner, Incremen } return true } + + override fun dumpValue(value: Map): String { + return StringBuilder { + append("{") + for (key in value.keySet().sort()) { + if (length() != 1) { + append(", ") + } + append("$key -> ${java.lang.Long.toHexString(value[key]!!)}") + } + append("}") + }.toString() + } } private object InlineFunctionsMapExternalizer : DataExternalizer> { @@ -484,6 +541,8 @@ public class IncrementalCacheImpl(targetDataRoot: File) : StorageOwner, Incremen public fun get(sourceFile: File): String? { return storage[sourceFile.getAbsolutePath()] } + + override fun dumpValue(value: String) = value } private inner class RemovedPackagePartMap : BasicMap() { @@ -504,6 +563,8 @@ public class IncrementalCacheImpl(targetDataRoot: File) : StorageOwner, Incremen public fun clear() { storage.getAllKeysWithExistingMapping().forEach { storage.remove(it) } } + + override fun dumpValue(value: Boolean) = "" } enum class RecompilationDecision { diff --git a/jps/jps-plugin/test/org/jetbrains/kotlin/jps/build/AbstractIncrementalJpsTest.kt b/jps/jps-plugin/test/org/jetbrains/kotlin/jps/build/AbstractIncrementalJpsTest.kt index 70b954886d4..1bb35a2852e 100644 --- a/jps/jps-plugin/test/org/jetbrains/kotlin/jps/build/AbstractIncrementalJpsTest.kt +++ b/jps/jps-plugin/test/org/jetbrains/kotlin/jps/build/AbstractIncrementalJpsTest.kt @@ -36,9 +36,11 @@ import org.jetbrains.jps.incremental.messages.BuildMessage import kotlin.test.assertFalse import java.util.regex.Pattern import kotlin.test.assertEquals -import org.jetbrains.jps.model.java.JpsJavaDependencyExtension import org.jetbrains.jps.model.JpsModuleRootModificationUtil import com.intellij.openapi.util.io.FileUtilRt +import org.jetbrains.jps.cmdline.ProjectDescriptor +import junit.framework.TestCase +import org.jetbrains.kotlin.jps.incremental.getKotlinCache public abstract class AbstractIncrementalJpsTest : JpsBuildTestCase() { class object { @@ -65,7 +67,7 @@ public abstract class AbstractIncrementalJpsTest : JpsBuildTestCase() { protected open val customTest: Boolean get() = false - fun buildGetLog(scope: CompileScopeTestBuilder = CompileScopeTestBuilder.make().all()): String { + fun build(scope: CompileScopeTestBuilder = CompileScopeTestBuilder.make().all()): MakeResult { val workDirPath = FileUtil.toSystemIndependentName(workDir.getAbsolutePath()) val logger = MyLogger(workDirPath) val descriptor = createProjectDescriptor(BuildLoggingManager(logger)) @@ -78,10 +80,10 @@ public abstract class AbstractIncrementalJpsTest : JpsBuildTestCase() { .map { it.getMessageText() } .map { it.replaceAll("^.+:\\d+:\\s+", "").trim() } .joinToString("\n") - return logger.log + "$COMPILATION_FAILED\n" + errorMessages + "\n" + return MakeResult(logger.log + "$COMPILATION_FAILED\n" + errorMessages + "\n", true, null) } else { - return logger.log + return MakeResult(logger.log, false, createMappingsDump(descriptor)) } } finally { descriptor.release() @@ -89,16 +91,16 @@ public abstract class AbstractIncrementalJpsTest : JpsBuildTestCase() { } private fun initialMake() { - val log = buildGetLog() - assertFalse(COMPILATION_FAILED in log, "Initial make failed:\n$log") + val makeResult = build() + assertFalse(makeResult.makeFailed, "Initial make failed:\n$makeResult") } - private fun make(): String { - return buildGetLog() + private fun make(): MakeResult { + return build() } - private fun rebuild(): String { - return buildGetLog(CompileScopeTestBuilder.rebuild().allModules()) + private fun rebuild(): MakeResult { + return build(CompileScopeTestBuilder.rebuild().allModules()) } private fun getModificationsToPerform(moduleNames: Collection?): List> { @@ -160,24 +162,28 @@ public abstract class AbstractIncrementalJpsTest : JpsBuildTestCase() { } } - private fun rebuildAndCheckOutput(lastMakeFailed: Boolean) { + private fun rebuildAndCheckOutput(makeOverallResult: MakeResult) { val outDir = File(getAbsolutePath("out")) val outAfterMake = File(getAbsolutePath("out-after-make")) FileUtil.copyDir(outDir, outAfterMake) - val rebuildLog = rebuild() - val rebuildFailed = rebuildLog.contains(COMPILATION_FAILED) - assertEquals(rebuildFailed, lastMakeFailed, "Rebuild failed: $rebuildFailed, last make failed: $lastMakeFailed. Rebuild log: $rebuildLog") + val rebuildResult = rebuild() + assertEquals(rebuildResult.makeFailed, makeOverallResult.makeFailed, + "Rebuild failed: ${rebuildResult.makeFailed}, last make failed: ${makeOverallResult.makeFailed}. Rebuild result: $rebuildResult") - assertEqualDirectories(outDir, outAfterMake, lastMakeFailed) + assertEqualDirectories(outDir, outAfterMake, makeOverallResult.makeFailed) + + if (!makeOverallResult.makeFailed) { + TestCase.assertEquals(rebuildResult.mappingsDump, makeOverallResult.mappingsDump) + } FileUtil.delete(outAfterMake) } - private fun clearCachesRebuildAndCheckOutput(lastMakeFailed: Boolean) { + private fun clearCachesRebuildAndCheckOutput(makeOverallResult: MakeResult) { FileUtil.delete(BuildDataPathsImpl(myDataStorageRoot).getDataStorageRoot()!!) - rebuildAndCheckOutput(lastMakeFailed) + rebuildAndCheckOutput(makeOverallResult) } private fun readModuleDependencies(): Map>? { @@ -207,31 +213,45 @@ public abstract class AbstractIncrementalJpsTest : JpsBuildTestCase() { val moduleNames = configureModules() initialMake() - val (log, lastMakeFailed) = performModificationsAndMake(moduleNames) - UsefulTestCase.assertSameLinesWithFile(File(testDataDir, "build.log").getAbsolutePath(), log) + val makeOverallResult = performModificationsAndMake(moduleNames) + UsefulTestCase.assertSameLinesWithFile(File(testDataDir, "build.log").getAbsolutePath(), makeOverallResult.log) - rebuildAndCheckOutput(lastMakeFailed) - clearCachesRebuildAndCheckOutput(lastMakeFailed) + rebuildAndCheckOutput(makeOverallResult) + clearCachesRebuildAndCheckOutput(makeOverallResult) } + private fun createMappingsDump(project: ProjectDescriptor) = + createKotlinIncrementalCacheDump(project) - private data class MakeLogAndFailureFlag(val log: String, val makeFailed: Boolean) + private fun createKotlinIncrementalCacheDump(project: ProjectDescriptor): String { + return StringBuilder { + for (target in project.getBuildTargetIndex().getAllTargets().sortBy { it.getPresentableName() }) { + append("\n") + append(project.dataManager.getKotlinCache(target).dump()) + append("\n\n\n") + } + }.toString() + } - private fun performModificationsAndMake(moduleNames: Set?): MakeLogAndFailureFlag { + private data class MakeResult(val log: String, val makeFailed: Boolean, val mappingsDump: String?) + + private fun performModificationsAndMake(moduleNames: Set?): MakeResult { val logs = ArrayList() val modifications = getModificationsToPerform(moduleNames) var lastCompilationFailed = false + var lastMappingsDump: String? = null for (step in modifications) { step.forEach { it.perform(workDir) } performAdditionalModifications() - val log = make() - lastCompilationFailed = log.contains(COMPILATION_FAILED) - logs.add(log) + val makeResult = make() + logs.add(makeResult.log) + lastCompilationFailed = makeResult.makeFailed + lastMappingsDump = makeResult.mappingsDump } - return MakeLogAndFailureFlag(logs.join("\n\n"), lastCompilationFailed) + return MakeResult(logs.join("\n\n"), lastCompilationFailed, lastMappingsDump) } protected open fun performAdditionalModifications() {