diff --git a/jps/jps-plugin/src/org/jetbrains/kotlin/jps/build/KotlinBuilder.kt b/jps/jps-plugin/src/org/jetbrains/kotlin/jps/build/KotlinBuilder.kt index 13db9d22d31..edcfde1f205 100644 --- a/jps/jps-plugin/src/org/jetbrains/kotlin/jps/build/KotlinBuilder.kt +++ b/jps/jps-plugin/src/org/jetbrains/kotlin/jps/build/KotlinBuilder.kt @@ -753,8 +753,9 @@ private fun CompilationResult.doProcessChangesUsingLookups( KotlinBuilder.LOG.debug("Process $change") if (change is ChangeInfo.SignatureChanged) { - for (classFqName in withSubtypes(change.fqName, allCaches)) { + val fqNames = if (!change.areSubclassesAffected) listOf(change.fqName) else withSubtypes(change.fqName, allCaches) + for (classFqName in fqNames) { assert(!classFqName.isRoot) { "classFqName is root when processing $change" } val scope = classFqName.parent().asString() 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 6e1aa6b5f28..9d02b54054a 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 @@ -353,8 +353,8 @@ open class IncrementalCacheImpl( val fqName = if (isPackage) className.packageFqName else className.fqNameForClassNameWithoutDollars val changeList = SmartList() - if (difference.isClassSignatureChanged) { - changeList.add(ChangeInfo.SignatureChanged(fqName)) + if (difference.isClassAffected) { + changeList.add(ChangeInfo.SignatureChanged(fqName, difference.areSubclassesAffected)) } if (difference.changedMembersNames.isNotEmpty()) { @@ -566,7 +566,7 @@ sealed class ChangeInfo(val fqName: FqName) { class Removed(fqName: FqName, names: Collection) : MembersChanged(fqName, names) - class SignatureChanged(fqName: FqName) : ChangeInfo(fqName) + class SignatureChanged(fqName: FqName, val areSubclassesAffected: Boolean) : ChangeInfo(fqName) protected open fun toStringProperties(): String = "fqName = $fqName" diff --git a/jps/jps-plugin/src/org/jetbrains/kotlin/jps/incremental/protoDifferenceUtils.kt b/jps/jps-plugin/src/org/jetbrains/kotlin/jps/incremental/protoDifferenceUtils.kt index b2d0d43f7a6..3f7971857ad 100644 --- a/jps/jps-plugin/src/org/jetbrains/kotlin/jps/incremental/protoDifferenceUtils.kt +++ b/jps/jps-plugin/src/org/jetbrains/kotlin/jps/incremental/protoDifferenceUtils.kt @@ -30,12 +30,15 @@ import org.jetbrains.kotlin.utils.HashSetUtil import java.util.* data class Difference( - val isClassSignatureChanged: Boolean = false, + val isClassAffected: Boolean = false, + val areSubclassesAffected: Boolean = false, val changedMembersNames: Set = emptySet() ) fun difference(oldData: ProtoMapValue, newData: ProtoMapValue): Difference { - if (oldData.isPackageFacade != newData.isPackageFacade) return Difference(isClassSignatureChanged = true) + if (!oldData.isPackageFacade && newData.isPackageFacade) return Difference(isClassAffected = true, areSubclassesAffected = true) + + if (oldData.isPackageFacade && !newData.isPackageFacade) return Difference(isClassAffected = true) val differenceObject = if (oldData.isPackageFacade) { @@ -174,7 +177,8 @@ private class DifferenceCalculatorForClass(oldData: ProtoMapValue, newData: Prot val diff = compareObject.difference(oldProto, newProto) override fun difference(): Difference { - var isClassSignatureChanged = false + var isClassAffected = false + var areSubclassesAffected = false val names = hashSetOf() val classIsSealed = newProto.isSealed && oldProto.isSealed @@ -197,31 +201,37 @@ private class DifferenceCalculatorForClass(oldData: ProtoMapValue, newData: Prot if (classIsSealed) { // when class is sealed, adding an implementation can break exhaustive when expressions // the workaround is to recompile all class usages - isClassSignatureChanged = true + isClassAffected = true } names.addAll(calcDifferenceForNames(oldProto.nestedClassNameList, newProto.nestedClassNameList)) } - ProtoBufClassKind.CONSTRUCTOR_LIST -> - names.addAll(calcDifferenceForNonPrivateMembers(ProtoBuf.Class::getConstructorList)) + ProtoBufClassKind.CONSTRUCTOR_LIST -> { + val differentNonPrivateConstructors = calcDifferenceForNonPrivateMembers(ProtoBuf.Class::getConstructorList) + + if (differentNonPrivateConstructors.isNotEmpty()) { + isClassAffected = true + } + } ProtoBufClassKind.FUNCTION_LIST -> names.addAll(calcDifferenceForNonPrivateMembers(ProtoBuf.Class::getFunctionList)) ProtoBufClassKind.PROPERTY_LIST -> names.addAll(calcDifferenceForNonPrivateMembers(ProtoBuf.Class::getPropertyList)) ProtoBufClassKind.ENUM_ENTRY_LIST -> { - isClassSignatureChanged = true + isClassAffected = true } ProtoBufClassKind.TYPE_TABLE -> { // TODO } in CLASS_SIGNATURE_ENUMS -> { - isClassSignatureChanged = true + isClassAffected = true + areSubclassesAffected = true } else -> throw IllegalArgumentException("Unsupported kind: $kind") } } - return Difference(isClassSignatureChanged, names) + return Difference(isClassAffected, areSubclassesAffected, names) } } @@ -259,7 +269,7 @@ private class DifferenceCalculatorForPackageFacade(oldData: ProtoMapValue, newDa } } - return Difference(isClassSignatureChanged = false, changedMembersNames = names) + return Difference(changedMembersNames = names) } } diff --git a/jps/jps-plugin/test/org/jetbrains/kotlin/jps/build/ExperimentalIncrementalJpsTestGenerated.java b/jps/jps-plugin/test/org/jetbrains/kotlin/jps/build/ExperimentalIncrementalJpsTestGenerated.java index 7981276a283..f40231060b8 100644 --- a/jps/jps-plugin/test/org/jetbrains/kotlin/jps/build/ExperimentalIncrementalJpsTestGenerated.java +++ b/jps/jps-plugin/test/org/jetbrains/kotlin/jps/build/ExperimentalIncrementalJpsTestGenerated.java @@ -1165,6 +1165,12 @@ public class ExperimentalIncrementalJpsTestGenerated extends AbstractExperimenta doTest(fileName); } + @TestMetadata("secondaryConstructorAdded") + public void testSecondaryConstructorAdded() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("jps-plugin/testData/incremental/classHierarchyAffected/secondaryConstructorAdded/"); + doTest(fileName); + } + @TestMetadata("starProjectionUpperBoundChanged") public void testStarProjectionUpperBoundChanged() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("jps-plugin/testData/incremental/classHierarchyAffected/starProjectionUpperBoundChanged/"); diff --git a/jps/jps-plugin/test/org/jetbrains/kotlin/jps/incremental/AbstractProtoComparisonTest.kt b/jps/jps-plugin/test/org/jetbrains/kotlin/jps/incremental/AbstractProtoComparisonTest.kt index 6193643825c..b5664c77f93 100644 --- a/jps/jps-plugin/test/org/jetbrains/kotlin/jps/incremental/AbstractProtoComparisonTest.kt +++ b/jps/jps-plugin/test/org/jetbrains/kotlin/jps/incremental/AbstractProtoComparisonTest.kt @@ -104,7 +104,7 @@ abstract class AbstractProtoComparisonTest : UsefulTestCase() { val changes = SmartList() - if (diff.isClassSignatureChanged) { + if (diff.isClassAffected) { changes.add("CLASS_SIGNATURE") } diff --git a/jps/jps-plugin/testData/comparison/classMembersOnlyChanged/classWithConstructorChanged/result.out b/jps/jps-plugin/testData/comparison/classMembersOnlyChanged/classWithConstructorChanged/result.out index db18d890625..08fa3f65113 100644 --- a/jps/jps-plugin/testData/comparison/classMembersOnlyChanged/classWithConstructorChanged/result.out +++ b/jps/jps-plugin/testData/comparison/classMembersOnlyChanged/classWithConstructorChanged/result.out @@ -1,10 +1,5 @@ -changes in test/ClassWithPrimaryConstructorChanged: MEMBERS - [] -changes in test/ClassWithPrimaryConstructorVisibilityChanged: MEMBERS - [] -changes in test/ClassWithSecondaryConstructorVisibilityChanged: MEMBERS - [] -changes in test/ClassWithSecondaryConstructorsAdded: MEMBERS - [] -changes in test/ClassWithSecondaryConstructorsRemoved: MEMBERS - [] +changes in test/ClassWithPrimaryConstructorChanged: CLASS_SIGNATURE +changes in test/ClassWithPrimaryConstructorVisibilityChanged: CLASS_SIGNATURE +changes in test/ClassWithSecondaryConstructorVisibilityChanged: CLASS_SIGNATURE +changes in test/ClassWithSecondaryConstructorsAdded: CLASS_SIGNATURE +changes in test/ClassWithSecondaryConstructorsRemoved: CLASS_SIGNATURE diff --git a/jps/jps-plugin/testData/comparison/classSignatureChange/classWithClassAnnotationListChanged/result.out b/jps/jps-plugin/testData/comparison/classSignatureChange/classWithClassAnnotationListChanged/result.out index 557be9e6f1f..d447c5da3f9 100644 --- a/jps/jps-plugin/testData/comparison/classSignatureChange/classWithClassAnnotationListChanged/result.out +++ b/jps/jps-plugin/testData/comparison/classSignatureChange/classWithClassAnnotationListChanged/result.out @@ -1,2 +1 @@ -changes in test/ClassWithClassAnnotationListChanged: CLASS_SIGNATURE, MEMBERS - [] +changes in test/ClassWithClassAnnotationListChanged: CLASS_SIGNATURE diff --git a/jps/jps-plugin/testData/incremental/classHierarchyAffected/secondaryConstructorAdded/A.kt b/jps/jps-plugin/testData/incremental/classHierarchyAffected/secondaryConstructorAdded/A.kt new file mode 100644 index 00000000000..ec5e9d1cc8f --- /dev/null +++ b/jps/jps-plugin/testData/incremental/classHierarchyAffected/secondaryConstructorAdded/A.kt @@ -0,0 +1 @@ +open class A(val x: Int) \ No newline at end of file diff --git a/jps/jps-plugin/testData/incremental/classHierarchyAffected/secondaryConstructorAdded/A.kt.new.1 b/jps/jps-plugin/testData/incremental/classHierarchyAffected/secondaryConstructorAdded/A.kt.new.1 new file mode 100644 index 00000000000..9da909efd27 --- /dev/null +++ b/jps/jps-plugin/testData/incremental/classHierarchyAffected/secondaryConstructorAdded/A.kt.new.1 @@ -0,0 +1,3 @@ +open class A(val x: Int) { + constructor(x: String) : this(x.toInt()) +} \ No newline at end of file diff --git a/jps/jps-plugin/testData/incremental/classHierarchyAffected/secondaryConstructorAdded/AChild.kt b/jps/jps-plugin/testData/incremental/classHierarchyAffected/secondaryConstructorAdded/AChild.kt new file mode 100644 index 00000000000..8efe9a14b55 --- /dev/null +++ b/jps/jps-plugin/testData/incremental/classHierarchyAffected/secondaryConstructorAdded/AChild.kt @@ -0,0 +1 @@ +class AChild(x: Int) : A(x) \ No newline at end of file diff --git a/jps/jps-plugin/testData/incremental/classHierarchyAffected/secondaryConstructorAdded/AConstructorFunction.kt b/jps/jps-plugin/testData/incremental/classHierarchyAffected/secondaryConstructorAdded/AConstructorFunction.kt new file mode 100644 index 00000000000..2cffa7e5c2e --- /dev/null +++ b/jps/jps-plugin/testData/incremental/classHierarchyAffected/secondaryConstructorAdded/AConstructorFunction.kt @@ -0,0 +1 @@ +fun A(x: String) = A(x.toInt()) \ No newline at end of file diff --git a/jps/jps-plugin/testData/incremental/classHierarchyAffected/secondaryConstructorAdded/AConstructorFunction.kt.delete.2 b/jps/jps-plugin/testData/incremental/classHierarchyAffected/secondaryConstructorAdded/AConstructorFunction.kt.delete.2 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/jps/jps-plugin/testData/incremental/classHierarchyAffected/secondaryConstructorAdded/build.log b/jps/jps-plugin/testData/incremental/classHierarchyAffected/secondaryConstructorAdded/build.log new file mode 100644 index 00000000000..f9971a4960e --- /dev/null +++ b/jps/jps-plugin/testData/incremental/classHierarchyAffected/secondaryConstructorAdded/build.log @@ -0,0 +1,37 @@ +Cleaning output files: +out/production/module/A.class +End of files +Compiling files: +src/A.kt +End of files +Cleaning output files: +out/production/module/AChild.class +out/production/module/AConstructorFunctionKt.class +out/production/module/CreateAFromIntKt.class +out/production/module/CreateAFromStringKt.class +out/production/module/META-INF/module.kotlin_module +out/production/module/UseAKt.class +End of files +Compiling files: +src/AChild.kt +src/AConstructorFunction.kt +src/createAFromInt.kt +src/createAFromString.kt +src/useA.kt +End of files +COMPILATION FAILED +Overload resolution ambiguity: +public constructor A(x: kotlin.String) defined in A +public fun A(x: kotlin.String): A defined in root package + + +Cleaning output files: +out/production/module/A.class +End of files +Compiling files: +src/A.kt +src/AChild.kt +src/createAFromInt.kt +src/createAFromString.kt +src/useA.kt +End of files \ No newline at end of file diff --git a/jps/jps-plugin/testData/incremental/classHierarchyAffected/secondaryConstructorAdded/createAFromInt.kt b/jps/jps-plugin/testData/incremental/classHierarchyAffected/secondaryConstructorAdded/createAFromInt.kt new file mode 100644 index 00000000000..e38e845051b --- /dev/null +++ b/jps/jps-plugin/testData/incremental/classHierarchyAffected/secondaryConstructorAdded/createAFromInt.kt @@ -0,0 +1 @@ +fun createAFromInt() = A(5) \ No newline at end of file diff --git a/jps/jps-plugin/testData/incremental/classHierarchyAffected/secondaryConstructorAdded/createAFromString.kt b/jps/jps-plugin/testData/incremental/classHierarchyAffected/secondaryConstructorAdded/createAFromString.kt new file mode 100644 index 00000000000..bb9d0e7339f --- /dev/null +++ b/jps/jps-plugin/testData/incremental/classHierarchyAffected/secondaryConstructorAdded/createAFromString.kt @@ -0,0 +1 @@ +fun createAFromString() = A("5") \ No newline at end of file diff --git a/jps/jps-plugin/testData/incremental/classHierarchyAffected/secondaryConstructorAdded/useA.kt b/jps/jps-plugin/testData/incremental/classHierarchyAffected/secondaryConstructorAdded/useA.kt new file mode 100644 index 00000000000..900c1a151f3 --- /dev/null +++ b/jps/jps-plugin/testData/incremental/classHierarchyAffected/secondaryConstructorAdded/useA.kt @@ -0,0 +1 @@ +fun useA(a: A) {} \ No newline at end of file diff --git a/jps/jps-plugin/testData/incremental/classHierarchyAffected/secondaryConstructorAdded/useAChild.kt b/jps/jps-plugin/testData/incremental/classHierarchyAffected/secondaryConstructorAdded/useAChild.kt new file mode 100644 index 00000000000..6cd856e3233 --- /dev/null +++ b/jps/jps-plugin/testData/incremental/classHierarchyAffected/secondaryConstructorAdded/useAChild.kt @@ -0,0 +1 @@ +fun useAChild(a: AChild) {} \ No newline at end of file