Recompile all class usages when constructor is changed
Original commit: 94d4dae1fe
This commit is contained in:
@@ -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()
|
||||
|
||||
@@ -353,8 +353,8 @@ open class IncrementalCacheImpl(
|
||||
val fqName = if (isPackage) className.packageFqName else className.fqNameForClassNameWithoutDollars
|
||||
val changeList = SmartList<ChangeInfo>()
|
||||
|
||||
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<String>) : 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"
|
||||
|
||||
@@ -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<String> = 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<String>()
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+6
@@ -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/");
|
||||
|
||||
+1
-1
@@ -104,7 +104,7 @@ abstract class AbstractProtoComparisonTest : UsefulTestCase() {
|
||||
|
||||
val changes = SmartList<String>()
|
||||
|
||||
if (diff.isClassSignatureChanged) {
|
||||
if (diff.isClassAffected) {
|
||||
changes.add("CLASS_SIGNATURE")
|
||||
}
|
||||
|
||||
|
||||
+5
-10
@@ -1,10 +1,5 @@
|
||||
changes in test/ClassWithPrimaryConstructorChanged: MEMBERS
|
||||
[<init>]
|
||||
changes in test/ClassWithPrimaryConstructorVisibilityChanged: MEMBERS
|
||||
[<init>]
|
||||
changes in test/ClassWithSecondaryConstructorVisibilityChanged: MEMBERS
|
||||
[<init>]
|
||||
changes in test/ClassWithSecondaryConstructorsAdded: MEMBERS
|
||||
[<init>]
|
||||
changes in test/ClassWithSecondaryConstructorsRemoved: MEMBERS
|
||||
[<init>]
|
||||
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
|
||||
|
||||
+1
-2
@@ -1,2 +1 @@
|
||||
changes in test/ClassWithClassAnnotationListChanged: CLASS_SIGNATURE, MEMBERS
|
||||
[<init>]
|
||||
changes in test/ClassWithClassAnnotationListChanged: CLASS_SIGNATURE
|
||||
|
||||
+1
@@ -0,0 +1 @@
|
||||
open class A(val x: Int)
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
open class A(val x: Int) {
|
||||
constructor(x: String) : this(x.toInt())
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
class AChild(x: Int) : A(x)
|
||||
+1
@@ -0,0 +1 @@
|
||||
fun A(x: String) = A(x.toInt())
|
||||
+37
@@ -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
|
||||
+1
@@ -0,0 +1 @@
|
||||
fun createAFromInt() = A(5)
|
||||
+1
@@ -0,0 +1 @@
|
||||
fun createAFromString() = A("5")
|
||||
+1
@@ -0,0 +1 @@
|
||||
fun useA(a: A) {}
|
||||
+1
@@ -0,0 +1 @@
|
||||
fun useAChild(a: AChild) {}
|
||||
Reference in New Issue
Block a user