diff --git a/jps-plugin/src/org/jetbrains/kotlin/jps/incremental/IncrementalCacheImpl.kt b/jps-plugin/src/org/jetbrains/kotlin/jps/incremental/IncrementalCacheImpl.kt index 9d02b54054a..5b4157eab37 100644 --- a/jps-plugin/src/org/jetbrains/kotlin/jps/incremental/IncrementalCacheImpl.kt +++ b/jps-plugin/src/org/jetbrains/kotlin/jps/incremental/IncrementalCacheImpl.kt @@ -84,8 +84,8 @@ open class IncrementalCacheImpl( private val protoMap = registerMap(ProtoMap(PROTO_MAP.storageFile)) private val constantsMap = registerMap(ConstantsMap(CONSTANTS_MAP.storageFile)) private val packagePartMap = registerMap(PackagePartMap(PACKAGE_PARTS.storageFile)) - private val multifileClassFacadeMap = registerMap(MultifileClassFacadeMap(MULTIFILE_CLASS_FACADES.storageFile)) - private val multifileClassPartMap = registerMap(MultifileClassPartMap(MULTIFILE_CLASS_PARTS.storageFile)) + private val multifileFacadeToParts = registerMap(MultifileClassFacadeMap(MULTIFILE_CLASS_FACADES.storageFile)) + private val partToMultifileFacade = registerMap(MultifileClassPartMap(MULTIFILE_CLASS_PARTS.storageFile)) private val sourceToClassesMap = registerMap(SourceToClassesMap(SOURCE_TO_CLASSES.storageFile)) private val dirtyOutputClassesMap = registerMap(DirtyOutputClassesMap(DIRTY_OUTPUT_CLASSES.storageFile)) private val subtypesMap = registerExperimentalMap(SubtypesMap(SUBTYPES.storageFile)) @@ -160,7 +160,12 @@ open class IncrementalCacheImpl( KotlinClassHeader.Kind.MULTIFILE_CLASS -> { val partNames = kotlinClass.classHeader.data?.toList() ?: throw AssertionError("Multifile class has no parts: ${kotlinClass.className}") - multifileClassFacadeMap.add(className, partNames) + multifileFacadeToParts[className] = partNames + // When a class is replaced with a facade with the same name, + // the class' proto wouldn't ever be deleted, + // because we don't write proto for multifile facades. + // As a workaround we can remove proto values for multifile facades. + protoMap.remove(className) // TODO NO_CHANGES? (delegates only) constantsMap.process(kotlinClass) + @@ -169,7 +174,7 @@ open class IncrementalCacheImpl( KotlinClassHeader.Kind.MULTIFILE_CLASS_PART -> { assert(sourceFiles.size == 1) { "Multifile class part from several source files: $sourceFiles" } packagePartMap.addPackagePart(className) - multifileClassPartMap.add(className.internalName, header.multifileClassName!!) + partToMultifileFacade.set(className.internalName, header.multifileClassName!!) protoMap.process(kotlinClass, isPackage = true) + constantsMap.process(kotlinClass) + @@ -254,11 +259,31 @@ open class IncrementalCacheImpl( info + newInfo } + val facadesWithRemovedParts = hashMapOf>() + for (dirtyClass in dirtyClasses) { + val facade = partToMultifileFacade.get(dirtyClass.internalName) ?: continue + val facadeClassName = JvmClassName.byInternalName(facade) + val removedParts = facadesWithRemovedParts.getOrPut(facadeClassName) { hashSetOf() } + removedParts.add(dirtyClass.internalName) + } + + for ((facade, removedParts) in facadesWithRemovedParts.entries) { + val allParts = multifileFacadeToParts[facade.internalName] ?: continue + val notRemovedParts = allParts.filter { it !in removedParts } + + if (notRemovedParts.isEmpty()) { + multifileFacadeToParts.remove(facade) + } + else { + multifileFacadeToParts[facade] = notRemovedParts + } + } + dirtyClasses.forEach { protoMap.remove(it) packagePartMap.remove(it) - multifileClassFacadeMap.remove(it) - multifileClassPartMap.remove(it) + multifileFacadeToParts.remove(it) + partToMultifileFacade.remove(it) constantsMap.remove(it) } @@ -289,7 +314,7 @@ open class IncrementalCacheImpl( override fun getObsoleteMultifileClasses(): Collection { val obsoleteMultifileClasses = linkedSetOf() for (dirtyClass in dirtyOutputClassesMap.getDirtyOutputClasses()) { - val dirtyFacade = multifileClassPartMap.getFacadeName(dirtyClass) ?: continue + val dirtyFacade = partToMultifileFacade.get(dirtyClass) ?: continue obsoleteMultifileClasses.add(dirtyFacade) } KotlinBuilder.LOG.debug("Obsolete multifile class facades: $obsoleteMultifileClasses") @@ -297,12 +322,12 @@ open class IncrementalCacheImpl( } override fun getStableMultifileFacadeParts(facadeInternalName: String): Collection? { - val partNames = multifileClassFacadeMap.getMultifileClassParts(facadeInternalName) ?: return null + val partNames = multifileFacadeToParts.get(facadeInternalName) ?: return null return partNames.filter { !dirtyOutputClassesMap.isDirty(it) } } override fun getMultifileFacade(partInternalName: String): String? { - return multifileClassPartMap.getFacadeName(partInternalName) + return partToMultifileFacade.get(partInternalName) } override fun getModuleMappingData(): ByteArray? { @@ -443,11 +468,11 @@ open class IncrementalCacheImpl( } private inner class MultifileClassFacadeMap(storageFile: File) : BasicStringMap>(storageFile, StringCollectionExternalizer) { - fun add(facadeName: JvmClassName, partNames: Collection) { + operator fun set(facadeName: JvmClassName, partNames: Collection) { storage[facadeName.internalName] = partNames } - fun getMultifileClassParts(facadeName: String): Collection? = storage[facadeName] + operator fun get(facadeName: String): Collection? = storage[facadeName] fun remove(className: JvmClassName) { storage.remove(className.internalName) @@ -457,11 +482,11 @@ open class IncrementalCacheImpl( } private inner class MultifileClassPartMap(storageFile: File) : BasicStringMap(storageFile, EnumeratorStringDescriptor.INSTANCE) { - fun add(partName: String, facadeName: String) { + fun set(partName: String, facadeName: String) { storage[partName] = facadeName } - fun getFacadeName(partName: String): String? { + fun get(partName: String): String? { return storage.get(partName) } diff --git a/jps-plugin/test/org/jetbrains/kotlin/jps/build/ExperimentalIncrementalJpsTestGenerated.java b/jps-plugin/test/org/jetbrains/kotlin/jps/build/ExperimentalIncrementalJpsTestGenerated.java index f40231060b8..67fde1a276f 100644 --- a/jps-plugin/test/org/jetbrains/kotlin/jps/build/ExperimentalIncrementalJpsTestGenerated.java +++ b/jps-plugin/test/org/jetbrains/kotlin/jps/build/ExperimentalIncrementalJpsTestGenerated.java @@ -1069,6 +1069,12 @@ public class ExperimentalIncrementalJpsTestGenerated extends AbstractExperimenta doTest(fileName); } + @TestMetadata("classToPackageFacade") + public void testClassToPackageFacade() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("jps-plugin/testData/incremental/classHierarchyAffected/classToPackageFacade/"); + doTest(fileName); + } + @TestMetadata("constructorVisibilityChanged") public void testConstructorVisibilityChanged() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("jps-plugin/testData/incremental/classHierarchyAffected/constructorVisibilityChanged/"); @@ -1153,6 +1159,12 @@ public class ExperimentalIncrementalJpsTestGenerated extends AbstractExperimenta doTest(fileName); } + @TestMetadata("packageFacadeToClass") + public void testPackageFacadeToClass() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("jps-plugin/testData/incremental/classHierarchyAffected/packageFacadeToClass/"); + doTest(fileName); + } + @TestMetadata("propertyNullabilityChanged") public void testPropertyNullabilityChanged() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("jps-plugin/testData/incremental/classHierarchyAffected/propertyNullabilityChanged/"); diff --git a/jps-plugin/testData/incremental/classHierarchyAffected/classToPackageFacade/A.kt b/jps-plugin/testData/incremental/classHierarchyAffected/classToPackageFacade/A.kt new file mode 100644 index 00000000000..0d0cb607aa5 --- /dev/null +++ b/jps-plugin/testData/incremental/classHierarchyAffected/classToPackageFacade/A.kt @@ -0,0 +1,11 @@ +open class A { + companion object { + @JvmStatic + fun f() {} + + @JvmStatic + fun g() {} + } + + fun h() {} +} \ No newline at end of file diff --git a/jps-plugin/testData/incremental/classHierarchyAffected/classToPackageFacade/A.kt.delete.1 b/jps-plugin/testData/incremental/classHierarchyAffected/classToPackageFacade/A.kt.delete.1 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/jps-plugin/testData/incremental/classHierarchyAffected/classToPackageFacade/AChild.kt b/jps-plugin/testData/incremental/classHierarchyAffected/classToPackageFacade/AChild.kt new file mode 100644 index 00000000000..84330c7a659 --- /dev/null +++ b/jps-plugin/testData/incremental/classHierarchyAffected/classToPackageFacade/AChild.kt @@ -0,0 +1,3 @@ +class AChild : A() { + fun j() {} +} \ No newline at end of file diff --git a/jps-plugin/testData/incremental/classHierarchyAffected/classToPackageFacade/AChild.kt.new.2 b/jps-plugin/testData/incremental/classHierarchyAffected/classToPackageFacade/AChild.kt.new.2 new file mode 100644 index 00000000000..418b0d7b34e --- /dev/null +++ b/jps-plugin/testData/incremental/classHierarchyAffected/classToPackageFacade/AChild.kt.new.2 @@ -0,0 +1,3 @@ +class AChild { + fun j() {} +} \ No newline at end of file diff --git a/jps-plugin/testData/incremental/classHierarchyAffected/classToPackageFacade/APartF.kt.new.1 b/jps-plugin/testData/incremental/classHierarchyAffected/classToPackageFacade/APartF.kt.new.1 new file mode 100644 index 00000000000..239196110cc --- /dev/null +++ b/jps-plugin/testData/incremental/classHierarchyAffected/classToPackageFacade/APartF.kt.new.1 @@ -0,0 +1,4 @@ +@file:JvmName("A") +@file:JvmMultifileClass + +fun f() {} \ No newline at end of file diff --git a/jps-plugin/testData/incremental/classHierarchyAffected/classToPackageFacade/APartG.kt.new.1 b/jps-plugin/testData/incremental/classHierarchyAffected/classToPackageFacade/APartG.kt.new.1 new file mode 100644 index 00000000000..12630fa19af --- /dev/null +++ b/jps-plugin/testData/incremental/classHierarchyAffected/classToPackageFacade/APartG.kt.new.1 @@ -0,0 +1,4 @@ +@file:JvmName("A") +@file:JvmMultifileClass + +fun g() {} \ No newline at end of file diff --git a/jps-plugin/testData/incremental/classHierarchyAffected/classToPackageFacade/build.log b/jps-plugin/testData/incremental/classHierarchyAffected/classToPackageFacade/build.log new file mode 100644 index 00000000000..11859745d3f --- /dev/null +++ b/jps-plugin/testData/incremental/classHierarchyAffected/classToPackageFacade/build.log @@ -0,0 +1,53 @@ +Cleaning output files: +out/production/module/A$Companion.class +out/production/module/A.class +End of files +Compiling files: +src/APartF.kt +src/APartG.kt +End of files +Cleaning output files: +out/production/module/AChild.class +out/production/module/GetAKt.class +out/production/module/META-INF/module.kotlin_module +out/production/module/UseFKt.class +out/production/module/UseGKt.class +out/production/module/UseHKt.class +End of files +Compiling files: +src/AChild.kt +src/getA.kt +src/useF.kt +src/useG.kt +src/useH.kt +End of files +COMPILATION FAILED +Unresolved reference: A +Unresolved reference: A +Unresolved reference: A +Unresolved reference: A + + +Cleaning output files: +out/production/module/A.class +End of files +Cleaning output files: +out/production/module/A__APartFKt.class +out/production/module/A__APartGKt.class +End of files +Compiling files: +src/AChild.kt +src/APartF.kt +src/APartG.kt +src/useF.kt +src/useG.kt +End of files +Cleaning output files: +out/production/module/GetAChildKt.class +out/production/module/META-INF/module.kotlin_module +out/production/module/UseJKt.class +End of files +Compiling files: +src/getAChild.kt +src/useJ.kt +End of files \ No newline at end of file diff --git a/jps-plugin/testData/incremental/classHierarchyAffected/classToPackageFacade/getA.kt b/jps-plugin/testData/incremental/classHierarchyAffected/classToPackageFacade/getA.kt new file mode 100644 index 00000000000..bd04874b85b --- /dev/null +++ b/jps-plugin/testData/incremental/classHierarchyAffected/classToPackageFacade/getA.kt @@ -0,0 +1 @@ +fun getA() = A() \ No newline at end of file diff --git a/jps-plugin/testData/incremental/classHierarchyAffected/classToPackageFacade/getA.kt.delete.2 b/jps-plugin/testData/incremental/classHierarchyAffected/classToPackageFacade/getA.kt.delete.2 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/jps-plugin/testData/incremental/classHierarchyAffected/classToPackageFacade/getAChild.kt b/jps-plugin/testData/incremental/classHierarchyAffected/classToPackageFacade/getAChild.kt new file mode 100644 index 00000000000..ed38025e9ef --- /dev/null +++ b/jps-plugin/testData/incremental/classHierarchyAffected/classToPackageFacade/getAChild.kt @@ -0,0 +1 @@ +fun getAChild() = AChild() \ No newline at end of file diff --git a/jps-plugin/testData/incremental/classHierarchyAffected/classToPackageFacade/useF.kt b/jps-plugin/testData/incremental/classHierarchyAffected/classToPackageFacade/useF.kt new file mode 100644 index 00000000000..9bd8424ac7c --- /dev/null +++ b/jps-plugin/testData/incremental/classHierarchyAffected/classToPackageFacade/useF.kt @@ -0,0 +1,3 @@ +fun useF() { + A.f() +} \ No newline at end of file diff --git a/jps-plugin/testData/incremental/classHierarchyAffected/classToPackageFacade/useF.kt.new.2 b/jps-plugin/testData/incremental/classHierarchyAffected/classToPackageFacade/useF.kt.new.2 new file mode 100644 index 00000000000..595d5dea9ea --- /dev/null +++ b/jps-plugin/testData/incremental/classHierarchyAffected/classToPackageFacade/useF.kt.new.2 @@ -0,0 +1,3 @@ +fun useF() { + f() +} \ No newline at end of file diff --git a/jps-plugin/testData/incremental/classHierarchyAffected/classToPackageFacade/useG.kt b/jps-plugin/testData/incremental/classHierarchyAffected/classToPackageFacade/useG.kt new file mode 100644 index 00000000000..4582166085a --- /dev/null +++ b/jps-plugin/testData/incremental/classHierarchyAffected/classToPackageFacade/useG.kt @@ -0,0 +1,3 @@ +fun useG() { + A.g() +} \ No newline at end of file diff --git a/jps-plugin/testData/incremental/classHierarchyAffected/classToPackageFacade/useG.kt.new.2 b/jps-plugin/testData/incremental/classHierarchyAffected/classToPackageFacade/useG.kt.new.2 new file mode 100644 index 00000000000..a27d417106a --- /dev/null +++ b/jps-plugin/testData/incremental/classHierarchyAffected/classToPackageFacade/useG.kt.new.2 @@ -0,0 +1,3 @@ +fun useG() { + g() +} \ No newline at end of file diff --git a/jps-plugin/testData/incremental/classHierarchyAffected/classToPackageFacade/useH.kt b/jps-plugin/testData/incremental/classHierarchyAffected/classToPackageFacade/useH.kt new file mode 100644 index 00000000000..73891bcb3d8 --- /dev/null +++ b/jps-plugin/testData/incremental/classHierarchyAffected/classToPackageFacade/useH.kt @@ -0,0 +1,3 @@ +fun useH() { + getA().h() +} \ No newline at end of file diff --git a/jps-plugin/testData/incremental/classHierarchyAffected/classToPackageFacade/useH.kt.delete.2 b/jps-plugin/testData/incremental/classHierarchyAffected/classToPackageFacade/useH.kt.delete.2 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/jps-plugin/testData/incremental/classHierarchyAffected/classToPackageFacade/useJ.kt b/jps-plugin/testData/incremental/classHierarchyAffected/classToPackageFacade/useJ.kt new file mode 100644 index 00000000000..9a8084e94cf --- /dev/null +++ b/jps-plugin/testData/incremental/classHierarchyAffected/classToPackageFacade/useJ.kt @@ -0,0 +1,3 @@ +fun useJ() { + getAChild().j() +} \ No newline at end of file diff --git a/jps-plugin/testData/incremental/classHierarchyAffected/packageFacadeToClass/A.kt.new.1 b/jps-plugin/testData/incremental/classHierarchyAffected/packageFacadeToClass/A.kt.new.1 new file mode 100644 index 00000000000..7d3c7f52835 --- /dev/null +++ b/jps-plugin/testData/incremental/classHierarchyAffected/packageFacadeToClass/A.kt.new.1 @@ -0,0 +1,9 @@ +class A { + companion object { + @JvmStatic + fun f() {} + + @JvmStatic + fun g() {} + } +} \ No newline at end of file diff --git a/jps-plugin/testData/incremental/classHierarchyAffected/packageFacadeToClass/AA.kt b/jps-plugin/testData/incremental/classHierarchyAffected/packageFacadeToClass/AA.kt new file mode 100644 index 00000000000..9ef19a4fd8e --- /dev/null +++ b/jps-plugin/testData/incremental/classHierarchyAffected/packageFacadeToClass/AA.kt @@ -0,0 +1,5 @@ +class AA { + companion object { + fun f() {} + } +} \ No newline at end of file diff --git a/jps-plugin/testData/incremental/classHierarchyAffected/packageFacadeToClass/APartF.kt b/jps-plugin/testData/incremental/classHierarchyAffected/packageFacadeToClass/APartF.kt new file mode 100644 index 00000000000..239196110cc --- /dev/null +++ b/jps-plugin/testData/incremental/classHierarchyAffected/packageFacadeToClass/APartF.kt @@ -0,0 +1,4 @@ +@file:JvmName("A") +@file:JvmMultifileClass + +fun f() {} \ No newline at end of file diff --git a/jps-plugin/testData/incremental/classHierarchyAffected/packageFacadeToClass/APartF.kt.delete.1 b/jps-plugin/testData/incremental/classHierarchyAffected/packageFacadeToClass/APartF.kt.delete.1 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/jps-plugin/testData/incremental/classHierarchyAffected/packageFacadeToClass/APartG.kt b/jps-plugin/testData/incremental/classHierarchyAffected/packageFacadeToClass/APartG.kt new file mode 100644 index 00000000000..12630fa19af --- /dev/null +++ b/jps-plugin/testData/incremental/classHierarchyAffected/packageFacadeToClass/APartG.kt @@ -0,0 +1,4 @@ +@file:JvmName("A") +@file:JvmMultifileClass + +fun g() {} \ No newline at end of file diff --git a/jps-plugin/testData/incremental/classHierarchyAffected/packageFacadeToClass/APartG.kt.delete.1 b/jps-plugin/testData/incremental/classHierarchyAffected/packageFacadeToClass/APartG.kt.delete.1 new file mode 100644 index 00000000000..7d3c7f52835 --- /dev/null +++ b/jps-plugin/testData/incremental/classHierarchyAffected/packageFacadeToClass/APartG.kt.delete.1 @@ -0,0 +1,9 @@ +class A { + companion object { + @JvmStatic + fun f() {} + + @JvmStatic + fun g() {} + } +} \ No newline at end of file diff --git a/jps-plugin/testData/incremental/classHierarchyAffected/packageFacadeToClass/UseFJava.java b/jps-plugin/testData/incremental/classHierarchyAffected/packageFacadeToClass/UseFJava.java new file mode 100644 index 00000000000..df661a79b09 --- /dev/null +++ b/jps-plugin/testData/incremental/classHierarchyAffected/packageFacadeToClass/UseFJava.java @@ -0,0 +1,5 @@ +class UseFJava { + void doUse() { + A.f(); + } +} \ No newline at end of file diff --git a/jps-plugin/testData/incremental/classHierarchyAffected/packageFacadeToClass/build.log b/jps-plugin/testData/incremental/classHierarchyAffected/packageFacadeToClass/build.log new file mode 100644 index 00000000000..3b8d85ae468 --- /dev/null +++ b/jps-plugin/testData/incremental/classHierarchyAffected/packageFacadeToClass/build.log @@ -0,0 +1,40 @@ +Cleaning output files: +out/production/module/A.class +out/production/module/A__APartFKt.class +out/production/module/META-INF/module.kotlin_module +End of files +Cleaning output files: +out/production/module/A__APartGKt.class +End of files +Compiling files: +src/A.kt +End of files +Cleaning output files: +out/production/module/META-INF/module.kotlin_module +out/production/module/UseFJava.class +out/production/module/UseFKt.class +out/production/module/UseGKt.class +End of files +Compiling files: +src/useF.kt +src/useG.kt +End of files +COMPILATION FAILED +Unresolved reference: f +Unresolved reference: g + + +Cleaning output files: +out/production/module/A.class +End of files +Cleaning output files: +out/production/module/A$Companion.class +End of files +Compiling files: +src/A.kt +src/useF.kt +src/useG.kt +End of files +Compiling files: +src/UseFJava.java +End of files \ No newline at end of file diff --git a/jps-plugin/testData/incremental/classHierarchyAffected/packageFacadeToClass/useAA.kt b/jps-plugin/testData/incremental/classHierarchyAffected/packageFacadeToClass/useAA.kt new file mode 100644 index 00000000000..8a4d0ff3e5a --- /dev/null +++ b/jps-plugin/testData/incremental/classHierarchyAffected/packageFacadeToClass/useAA.kt @@ -0,0 +1,3 @@ +fun useAA() { + AA.f() +} \ No newline at end of file diff --git a/jps-plugin/testData/incremental/classHierarchyAffected/packageFacadeToClass/useF.kt b/jps-plugin/testData/incremental/classHierarchyAffected/packageFacadeToClass/useF.kt new file mode 100644 index 00000000000..595d5dea9ea --- /dev/null +++ b/jps-plugin/testData/incremental/classHierarchyAffected/packageFacadeToClass/useF.kt @@ -0,0 +1,3 @@ +fun useF() { + f() +} \ No newline at end of file diff --git a/jps-plugin/testData/incremental/classHierarchyAffected/packageFacadeToClass/useF.kt.new.2 b/jps-plugin/testData/incremental/classHierarchyAffected/packageFacadeToClass/useF.kt.new.2 new file mode 100644 index 00000000000..9bd8424ac7c --- /dev/null +++ b/jps-plugin/testData/incremental/classHierarchyAffected/packageFacadeToClass/useF.kt.new.2 @@ -0,0 +1,3 @@ +fun useF() { + A.f() +} \ No newline at end of file diff --git a/jps-plugin/testData/incremental/classHierarchyAffected/packageFacadeToClass/useG.kt b/jps-plugin/testData/incremental/classHierarchyAffected/packageFacadeToClass/useG.kt new file mode 100644 index 00000000000..a27d417106a --- /dev/null +++ b/jps-plugin/testData/incremental/classHierarchyAffected/packageFacadeToClass/useG.kt @@ -0,0 +1,3 @@ +fun useG() { + g() +} \ No newline at end of file diff --git a/jps-plugin/testData/incremental/classHierarchyAffected/packageFacadeToClass/useG.kt.new.2 b/jps-plugin/testData/incremental/classHierarchyAffected/packageFacadeToClass/useG.kt.new.2 new file mode 100644 index 00000000000..4582166085a --- /dev/null +++ b/jps-plugin/testData/incremental/classHierarchyAffected/packageFacadeToClass/useG.kt.new.2 @@ -0,0 +1,3 @@ +fun useG() { + A.g() +} \ No newline at end of file