Request CHUNK_REBUILD when IC is off and there are dirty Kotlin files

Otherwise unexpected compile error might happen,
when there are Groovy files, but they are not dirty,
so Groovy builder does not generate source stubs,
and Kotlin builder is filtering out output directory
from classpath (because it may contain outdated Java classes).

Previously the issue was not detected,
because it was not possible to turn off the IC completely (in JPS),
only switch to the legacy IC.

    #KT-20138
This commit is contained in:
Alexey Tsvetkov
2017-09-19 06:30:00 +03:00
parent c290212901
commit 7a5e0e1107
4 changed files with 117 additions and 15 deletions
@@ -24,7 +24,6 @@ import com.intellij.openapi.util.text.StringUtil
import com.intellij.openapi.vfs.StandardFileSystems
import com.intellij.testFramework.LightVirtualFile
import com.intellij.testFramework.UsefulTestCase
import com.intellij.util.ArrayUtil
import com.intellij.util.io.URLUtil
import com.intellij.util.io.ZipUtil
import org.jetbrains.jps.ModuleChunk
@@ -43,6 +42,7 @@ import org.jetbrains.jps.incremental.ModuleLevelBuilder
import org.jetbrains.jps.incremental.messages.BuildMessage
import org.jetbrains.jps.incremental.messages.CompilerMessage
import org.jetbrains.jps.model.JpsModuleRootModificationUtil
import org.jetbrains.jps.model.JpsProject
import org.jetbrains.jps.model.java.JavaSourceRootType
import org.jetbrains.jps.model.java.JpsJavaDependencyScope
import org.jetbrains.jps.model.java.JpsJavaExtensionService
@@ -510,7 +510,14 @@ open class KotlinJpsBuildTest : AbstractKotlinJpsBuildTestCase() {
assertFilesExistInOutput(module, "Foo.class", "Bar.class")
assertFilesNotExistInOutput(module, *EXCLUDE_FILES)
checkWhen(touch("src/foo.kt"), null, arrayOf(klass("kotlinProject", "Foo")))
if (IncrementalCompilation.isEnabled()) {
checkWhen(touch("src/foo.kt"), null, arrayOf(klass("kotlinProject", "Foo")))
}
else {
val allClasses = myProject.outputPaths()
checkWhen(touch("src/foo.kt"), null, allClasses)
}
checkWhen(touch("src/Excluded.kt"), null, NOTHING)
checkWhen(touch("src/dir/YetAnotherExcluded.kt"), null, NOTHING)
}
@@ -522,8 +529,15 @@ open class KotlinJpsBuildTest : AbstractKotlinJpsBuildTestCase() {
assertFilesExistInOutput(module, "Foo.class", "Bar.class")
assertFilesNotExistInOutput(module, *EXCLUDE_FILES)
checkWhen(touch("src/foo.kt"), null, arrayOf(klass("kotlinProject", "Foo")))
checkWhen(touch("src/dir/subdir/bar.kt"), null, arrayOf(klass("kotlinProject", "Bar")))
if (IncrementalCompilation.isEnabled()) {
checkWhen(touch("src/foo.kt"), null, arrayOf(klass("kotlinProject", "Foo")))
checkWhen(touch("src/dir/subdir/bar.kt"), null, arrayOf(klass("kotlinProject", "Bar")))
}
else {
val allClasses = myProject.outputPaths()
checkWhen(touch("src/foo.kt"), null, allClasses)
checkWhen(touch("src/dir/subdir/bar.kt"), null, allClasses)
}
checkWhen(touch("src/dir/Excluded.kt"), null, NOTHING)
checkWhen(touch("src/dir/subdir/YetAnotherExcluded.kt"), null, NOTHING)
@@ -536,7 +550,13 @@ open class KotlinJpsBuildTest : AbstractKotlinJpsBuildTestCase() {
assertFilesExistInOutput(module, "Foo.class", "Bar.class")
assertFilesNotExistInOutput(module, *EXCLUDE_FILES)
checkWhen(touch("src/foo.kt"), null, arrayOf(klass("kotlinProject", "Foo")))
if (IncrementalCompilation.isEnabled()) {
checkWhen(touch("src/foo.kt"), null, arrayOf(klass("kotlinProject", "Foo")))
}
else {
val allClasses = myProject.outputPaths()
checkWhen(touch("src/foo.kt"), null, allClasses)
}
checkWhen(touch("src/exclude/Excluded.kt"), null, NOTHING)
checkWhen(touch("src/exclude/YetAnotherExcluded.kt"), null, NOTHING)
@@ -547,8 +567,15 @@ open class KotlinJpsBuildTest : AbstractKotlinJpsBuildTestCase() {
fun testKotlinProjectTwoFilesInOnePackage() {
doTest()
checkWhen(touch("src/test1.kt"), null, packageClasses("kotlinProject", "src/test1.kt", "_DefaultPackage"))
checkWhen(touch("src/test2.kt"), null, packageClasses("kotlinProject", "src/test2.kt", "_DefaultPackage"))
if (IncrementalCompilation.isEnabled()) {
checkWhen(touch("src/test1.kt"), null, packageClasses("kotlinProject", "src/test1.kt", "_DefaultPackage"))
checkWhen(touch("src/test2.kt"), null, packageClasses("kotlinProject", "src/test2.kt", "_DefaultPackage"))
}
else {
val allClasses = myProject.outputPaths()
checkWhen(touch("src/test1.kt"), null, allClasses)
checkWhen(touch("src/test2.kt"), null, allClasses)
}
checkWhen(arrayOf(del("src/test1.kt"), del("src/test2.kt")), NOTHING,
arrayOf(packagePartClass("kotlinProject", "src/test1.kt", "_DefaultPackage"),
@@ -596,8 +623,15 @@ open class KotlinJpsBuildTest : AbstractKotlinJpsBuildTestCase() {
result.assertSuccessful()
checkWhen(touch("src/kt2.kt"), null, packageClasses("kotlinProject", "src/kt2.kt", "kt2.Kt2Kt"))
checkWhen(touch("module2/src/kt1.kt"), null, packageClasses("module2", "module2/src/kt1.kt", "kt1.Kt1Kt"))
if (IncrementalCompilation.isEnabled()) {
checkWhen(touch("src/kt2.kt"), null, packageClasses("kotlinProject", "src/kt2.kt", "kt2.Kt2Kt"))
checkWhen(touch("module2/src/kt1.kt"), null, packageClasses("module2", "module2/src/kt1.kt", "kt1.Kt1Kt"))
}
else {
val allClasses = myProject.outputPaths()
checkWhen(touch("src/kt2.kt"), null, allClasses)
checkWhen(touch("module2/src/kt1.kt"), null, allClasses)
}
}
fun testCircularDependenciesSamePackage() {
@@ -611,8 +645,16 @@ open class KotlinJpsBuildTest : AbstractKotlinJpsBuildTestCase() {
UsefulTestCase.assertSameElements(getMethodsOfClass(facadeWithA), "<clinit>", "a", "getA")
UsefulTestCase.assertSameElements(getMethodsOfClass(facadeWithB), "<clinit>", "b", "getB", "setB")
checkWhen(touch("module1/src/a.kt"), null, packageClasses("module1", "module1/src/a.kt", "test.TestPackage"))
checkWhen(touch("module2/src/b.kt"), null, packageClasses("module2", "module2/src/b.kt", "test.TestPackage"))
if (IncrementalCompilation.isEnabled()) {
checkWhen(touch("module1/src/a.kt"), null, packageClasses("module1", "module1/src/a.kt", "test.TestPackage"))
checkWhen(touch("module2/src/b.kt"), null, packageClasses("module2", "module2/src/b.kt", "test.TestPackage"))
}
else {
val allClasses = myProject.outputPaths()
checkWhen(touch("module1/src/a.kt"), null, allClasses)
checkWhen(touch("module2/src/b.kt"), null, allClasses)
}
}
fun testCircularDependenciesSamePackageWithTests() {
@@ -626,8 +668,15 @@ open class KotlinJpsBuildTest : AbstractKotlinJpsBuildTestCase() {
UsefulTestCase.assertSameElements(getMethodsOfClass(facadeWithA), "<clinit>", "a", "funA", "getA")
UsefulTestCase.assertSameElements(getMethodsOfClass(facadeWithB), "<clinit>", "b", "funB", "getB", "setB")
checkWhen(touch("module1/src/a.kt"), null, packageClasses("module1", "module1/src/a.kt", "test.TestPackage"))
checkWhen(touch("module2/src/b.kt"), null, packageClasses("module2", "module2/src/b.kt", "test.TestPackage"))
if (IncrementalCompilation.isEnabled()) {
checkWhen(touch("module1/src/a.kt"), null, packageClasses("module1", "module1/src/a.kt", "test.TestPackage"))
checkWhen(touch("module2/src/b.kt"), null, packageClasses("module2", "module2/src/b.kt", "test.TestPackage"))
}
else {
val allProductionClasses = myProject.outputPaths(tests = false)
checkWhen(touch("module1/src/a.kt"), null, allProductionClasses)
checkWhen(touch("module2/src/b.kt"), null, allProductionClasses)
}
}
fun testInternalFromAnotherModule() {
@@ -849,7 +898,13 @@ open class KotlinJpsBuildTest : AbstractKotlinJpsBuildTestCase() {
initProject(JVM_MOCK_RUNTIME)
buildAllModules().assertSuccessful()
checkWhen(touch("src/utils.kt"), null, packageClasses("kotlinProject", "src/utils.kt", "_DefaultPackage"))
if (IncrementalCompilation.isEnabled()) {
checkWhen(touch("src/utils.kt"), null, packageClasses("kotlinProject", "src/utils.kt", "_DefaultPackage"))
}
else {
val allClasses = findModule("kotlinProject").outputFilesPaths()
checkWhen(touch("src/utils.kt"), null, allClasses.toTypedArray())
}
val storageRoot = BuildDataPathsImpl(myDataStorageRoot).dataStorageRoot
assertTrue(File(storageRoot, "targets/java-production/kotlinProject/kotlin").exists())
@@ -1074,6 +1129,29 @@ open class KotlinJpsBuildTest : AbstractKotlinJpsBuildTestCase() {
return klass(moduleName, AsmUtil.internalNameByFqNameWithoutInnerClasses(packagePartFqName))
}
private fun JpsProject.outputPaths(production: Boolean = true, tests: Boolean = true) =
modules.flatMap { it.outputFilesPaths(production = production, tests = tests) }.toTypedArray()
private fun JpsModule.outputFilesPaths(production: Boolean = true, tests: Boolean = true): List<String> {
val outputFiles = arrayListOf<File>()
if (production) {
prodOut.walk().filterTo(outputFiles) { it.isFile }
}
if (tests) {
testsOut.walk().filterTo(outputFiles) { it.isFile }
}
return outputFiles.map { it.relativeTo(workDir).path }
}
private val JpsModule.prodOut: File
get() = outDir(forTests = false)
private val JpsModule.testsOut: File
get() = outDir(forTests = true)
private fun JpsModule.outDir(forTests: Boolean) =
JpsJavaExtensionService.getInstance().getOutputDirectory(this, forTests)!!
protected enum class Operation {
CHANGE,
DELETE
@@ -238,7 +238,13 @@ class KotlinBuilder : ModuleLevelBuilder(BuilderCategory.SOURCE_PROCESSOR) {
val isChunkRebuilding = JavaBuilderUtil.isForcedRecompilationAllJavaModules(context)
|| targets.any { rebuildAfterCacheVersionChanged[it] == true }
if (!hasKotlinDirtyOrRemovedFiles(dirtyFilesHolder, chunk)) {
if (hasKotlinDirtyOrRemovedFiles(dirtyFilesHolder, chunk)) {
if (!isChunkRebuilding && !IncrementalCompilation.isEnabled()) {
targets.forEach { rebuildAfterCacheVersionChanged[it] = true }
return CHUNK_REBUILD_REQUIRED
}
}
else {
if (isChunkRebuilding) {
targets.forEach { hasKotlin[it] = false }
}
@@ -9,6 +9,12 @@ Cleaning output files:
out/production/module2/META-INF/module2.kotlin_module
out/production/module2/foo/AKt.class
End of files
Exit code: CHUNK_REBUILD_REQUIRED
------------------------------------------
Cleaning output files:
out/production/module2/foo/BKt.class
out/production/module2/foo/CKt.class
End of files
Compiling files:
module2/src/a.kt
module2/src/b.kt
@@ -33,6 +39,12 @@ Cleaning output files:
out/production/module2/META-INF/module2.kotlin_module
out/production/module2/foo/AKt.class
End of files
Exit code: CHUNK_REBUILD_REQUIRED
------------------------------------------
Cleaning output files:
out/production/module2/foo/BKt.class
out/production/module2/foo/CKt.class
End of files
Compiling files:
module2/src/a.kt
module2/src/b.kt
@@ -9,6 +9,12 @@ Cleaning output files:
out/production/module2/META-INF/module2.kotlin_module
out/production/module2/foo/AKt.class
End of files
Exit code: CHUNK_REBUILD_REQUIRED
------------------------------------------
Cleaning output files:
out/production/module2/foo/BKt.class
out/production/module2/foo/CKt.class
End of files
Compiling files:
module2/src/a.kt
module2/src/b.kt