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.openapi.vfs.StandardFileSystems
import com.intellij.testFramework.LightVirtualFile import com.intellij.testFramework.LightVirtualFile
import com.intellij.testFramework.UsefulTestCase import com.intellij.testFramework.UsefulTestCase
import com.intellij.util.ArrayUtil
import com.intellij.util.io.URLUtil import com.intellij.util.io.URLUtil
import com.intellij.util.io.ZipUtil import com.intellij.util.io.ZipUtil
import org.jetbrains.jps.ModuleChunk 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.BuildMessage
import org.jetbrains.jps.incremental.messages.CompilerMessage import org.jetbrains.jps.incremental.messages.CompilerMessage
import org.jetbrains.jps.model.JpsModuleRootModificationUtil 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.JavaSourceRootType
import org.jetbrains.jps.model.java.JpsJavaDependencyScope import org.jetbrains.jps.model.java.JpsJavaDependencyScope
import org.jetbrains.jps.model.java.JpsJavaExtensionService import org.jetbrains.jps.model.java.JpsJavaExtensionService
@@ -510,7 +510,14 @@ open class KotlinJpsBuildTest : AbstractKotlinJpsBuildTestCase() {
assertFilesExistInOutput(module, "Foo.class", "Bar.class") assertFilesExistInOutput(module, "Foo.class", "Bar.class")
assertFilesNotExistInOutput(module, *EXCLUDE_FILES) 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/Excluded.kt"), null, NOTHING)
checkWhen(touch("src/dir/YetAnotherExcluded.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") assertFilesExistInOutput(module, "Foo.class", "Bar.class")
assertFilesNotExistInOutput(module, *EXCLUDE_FILES) assertFilesNotExistInOutput(module, *EXCLUDE_FILES)
checkWhen(touch("src/foo.kt"), null, arrayOf(klass("kotlinProject", "Foo"))) if (IncrementalCompilation.isEnabled()) {
checkWhen(touch("src/dir/subdir/bar.kt"), null, arrayOf(klass("kotlinProject", "Bar"))) 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/Excluded.kt"), null, NOTHING)
checkWhen(touch("src/dir/subdir/YetAnotherExcluded.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") assertFilesExistInOutput(module, "Foo.class", "Bar.class")
assertFilesNotExistInOutput(module, *EXCLUDE_FILES) 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/Excluded.kt"), null, NOTHING)
checkWhen(touch("src/exclude/YetAnotherExcluded.kt"), null, NOTHING) checkWhen(touch("src/exclude/YetAnotherExcluded.kt"), null, NOTHING)
@@ -547,8 +567,15 @@ open class KotlinJpsBuildTest : AbstractKotlinJpsBuildTestCase() {
fun testKotlinProjectTwoFilesInOnePackage() { fun testKotlinProjectTwoFilesInOnePackage() {
doTest() doTest()
checkWhen(touch("src/test1.kt"), null, packageClasses("kotlinProject", "src/test1.kt", "_DefaultPackage")) if (IncrementalCompilation.isEnabled()) {
checkWhen(touch("src/test2.kt"), null, packageClasses("kotlinProject", "src/test2.kt", "_DefaultPackage")) 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, checkWhen(arrayOf(del("src/test1.kt"), del("src/test2.kt")), NOTHING,
arrayOf(packagePartClass("kotlinProject", "src/test1.kt", "_DefaultPackage"), arrayOf(packagePartClass("kotlinProject", "src/test1.kt", "_DefaultPackage"),
@@ -596,8 +623,15 @@ open class KotlinJpsBuildTest : AbstractKotlinJpsBuildTestCase() {
result.assertSuccessful() result.assertSuccessful()
checkWhen(touch("src/kt2.kt"), null, packageClasses("kotlinProject", "src/kt2.kt", "kt2.Kt2Kt")) if (IncrementalCompilation.isEnabled()) {
checkWhen(touch("module2/src/kt1.kt"), null, packageClasses("module2", "module2/src/kt1.kt", "kt1.Kt1Kt")) 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() { fun testCircularDependenciesSamePackage() {
@@ -611,8 +645,16 @@ open class KotlinJpsBuildTest : AbstractKotlinJpsBuildTestCase() {
UsefulTestCase.assertSameElements(getMethodsOfClass(facadeWithA), "<clinit>", "a", "getA") UsefulTestCase.assertSameElements(getMethodsOfClass(facadeWithA), "<clinit>", "a", "getA")
UsefulTestCase.assertSameElements(getMethodsOfClass(facadeWithB), "<clinit>", "b", "getB", "setB") 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() { fun testCircularDependenciesSamePackageWithTests() {
@@ -626,8 +668,15 @@ open class KotlinJpsBuildTest : AbstractKotlinJpsBuildTestCase() {
UsefulTestCase.assertSameElements(getMethodsOfClass(facadeWithA), "<clinit>", "a", "funA", "getA") UsefulTestCase.assertSameElements(getMethodsOfClass(facadeWithA), "<clinit>", "a", "funA", "getA")
UsefulTestCase.assertSameElements(getMethodsOfClass(facadeWithB), "<clinit>", "b", "funB", "getB", "setB") UsefulTestCase.assertSameElements(getMethodsOfClass(facadeWithB), "<clinit>", "b", "funB", "getB", "setB")
checkWhen(touch("module1/src/a.kt"), null, packageClasses("module1", "module1/src/a.kt", "test.TestPackage")) if (IncrementalCompilation.isEnabled()) {
checkWhen(touch("module2/src/b.kt"), null, packageClasses("module2", "module2/src/b.kt", "test.TestPackage")) 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() { fun testInternalFromAnotherModule() {
@@ -849,7 +898,13 @@ open class KotlinJpsBuildTest : AbstractKotlinJpsBuildTestCase() {
initProject(JVM_MOCK_RUNTIME) initProject(JVM_MOCK_RUNTIME)
buildAllModules().assertSuccessful() 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 val storageRoot = BuildDataPathsImpl(myDataStorageRoot).dataStorageRoot
assertTrue(File(storageRoot, "targets/java-production/kotlinProject/kotlin").exists()) assertTrue(File(storageRoot, "targets/java-production/kotlinProject/kotlin").exists())
@@ -1074,6 +1129,29 @@ open class KotlinJpsBuildTest : AbstractKotlinJpsBuildTestCase() {
return klass(moduleName, AsmUtil.internalNameByFqNameWithoutInnerClasses(packagePartFqName)) 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 { protected enum class Operation {
CHANGE, CHANGE,
DELETE DELETE
@@ -238,7 +238,13 @@ class KotlinBuilder : ModuleLevelBuilder(BuilderCategory.SOURCE_PROCESSOR) {
val isChunkRebuilding = JavaBuilderUtil.isForcedRecompilationAllJavaModules(context) val isChunkRebuilding = JavaBuilderUtil.isForcedRecompilationAllJavaModules(context)
|| targets.any { rebuildAfterCacheVersionChanged[it] == true } || 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) { if (isChunkRebuilding) {
targets.forEach { hasKotlin[it] = false } targets.forEach { hasKotlin[it] = false }
} }
@@ -9,6 +9,12 @@ Cleaning output files:
out/production/module2/META-INF/module2.kotlin_module out/production/module2/META-INF/module2.kotlin_module
out/production/module2/foo/AKt.class out/production/module2/foo/AKt.class
End of files 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: Compiling files:
module2/src/a.kt module2/src/a.kt
module2/src/b.kt module2/src/b.kt
@@ -33,6 +39,12 @@ Cleaning output files:
out/production/module2/META-INF/module2.kotlin_module out/production/module2/META-INF/module2.kotlin_module
out/production/module2/foo/AKt.class out/production/module2/foo/AKt.class
End of files 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: Compiling files:
module2/src/a.kt module2/src/a.kt
module2/src/b.kt module2/src/b.kt
@@ -9,6 +9,12 @@ Cleaning output files:
out/production/module2/META-INF/module2.kotlin_module out/production/module2/META-INF/module2.kotlin_module
out/production/module2/foo/AKt.class out/production/module2/foo/AKt.class
End of files 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: Compiling files:
module2/src/a.kt module2/src/a.kt
module2/src/b.kt module2/src/b.kt