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")
|
KotlinBuilder.LOG.debug("Process $change")
|
||||||
|
|
||||||
if (change is ChangeInfo.SignatureChanged) {
|
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" }
|
assert(!classFqName.isRoot) { "classFqName is root when processing $change" }
|
||||||
|
|
||||||
val scope = classFqName.parent().asString()
|
val scope = classFqName.parent().asString()
|
||||||
|
|||||||
@@ -353,8 +353,8 @@ open class IncrementalCacheImpl(
|
|||||||
val fqName = if (isPackage) className.packageFqName else className.fqNameForClassNameWithoutDollars
|
val fqName = if (isPackage) className.packageFqName else className.fqNameForClassNameWithoutDollars
|
||||||
val changeList = SmartList<ChangeInfo>()
|
val changeList = SmartList<ChangeInfo>()
|
||||||
|
|
||||||
if (difference.isClassSignatureChanged) {
|
if (difference.isClassAffected) {
|
||||||
changeList.add(ChangeInfo.SignatureChanged(fqName))
|
changeList.add(ChangeInfo.SignatureChanged(fqName, difference.areSubclassesAffected))
|
||||||
}
|
}
|
||||||
|
|
||||||
if (difference.changedMembersNames.isNotEmpty()) {
|
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 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"
|
protected open fun toStringProperties(): String = "fqName = $fqName"
|
||||||
|
|||||||
@@ -30,12 +30,15 @@ import org.jetbrains.kotlin.utils.HashSetUtil
|
|||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
data class Difference(
|
data class Difference(
|
||||||
val isClassSignatureChanged: Boolean = false,
|
val isClassAffected: Boolean = false,
|
||||||
|
val areSubclassesAffected: Boolean = false,
|
||||||
val changedMembersNames: Set<String> = emptySet()
|
val changedMembersNames: Set<String> = emptySet()
|
||||||
)
|
)
|
||||||
|
|
||||||
fun difference(oldData: ProtoMapValue, newData: ProtoMapValue): Difference {
|
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 =
|
val differenceObject =
|
||||||
if (oldData.isPackageFacade) {
|
if (oldData.isPackageFacade) {
|
||||||
@@ -174,7 +177,8 @@ private class DifferenceCalculatorForClass(oldData: ProtoMapValue, newData: Prot
|
|||||||
val diff = compareObject.difference(oldProto, newProto)
|
val diff = compareObject.difference(oldProto, newProto)
|
||||||
|
|
||||||
override fun difference(): Difference {
|
override fun difference(): Difference {
|
||||||
var isClassSignatureChanged = false
|
var isClassAffected = false
|
||||||
|
var areSubclassesAffected = false
|
||||||
val names = hashSetOf<String>()
|
val names = hashSetOf<String>()
|
||||||
val classIsSealed = newProto.isSealed && oldProto.isSealed
|
val classIsSealed = newProto.isSealed && oldProto.isSealed
|
||||||
|
|
||||||
@@ -197,31 +201,37 @@ private class DifferenceCalculatorForClass(oldData: ProtoMapValue, newData: Prot
|
|||||||
if (classIsSealed) {
|
if (classIsSealed) {
|
||||||
// when class is sealed, adding an implementation can break exhaustive when expressions
|
// when class is sealed, adding an implementation can break exhaustive when expressions
|
||||||
// the workaround is to recompile all class usages
|
// the workaround is to recompile all class usages
|
||||||
isClassSignatureChanged = true
|
isClassAffected = true
|
||||||
}
|
}
|
||||||
|
|
||||||
names.addAll(calcDifferenceForNames(oldProto.nestedClassNameList, newProto.nestedClassNameList))
|
names.addAll(calcDifferenceForNames(oldProto.nestedClassNameList, newProto.nestedClassNameList))
|
||||||
}
|
}
|
||||||
ProtoBufClassKind.CONSTRUCTOR_LIST ->
|
ProtoBufClassKind.CONSTRUCTOR_LIST -> {
|
||||||
names.addAll(calcDifferenceForNonPrivateMembers(ProtoBuf.Class::getConstructorList))
|
val differentNonPrivateConstructors = calcDifferenceForNonPrivateMembers(ProtoBuf.Class::getConstructorList)
|
||||||
|
|
||||||
|
if (differentNonPrivateConstructors.isNotEmpty()) {
|
||||||
|
isClassAffected = true
|
||||||
|
}
|
||||||
|
}
|
||||||
ProtoBufClassKind.FUNCTION_LIST ->
|
ProtoBufClassKind.FUNCTION_LIST ->
|
||||||
names.addAll(calcDifferenceForNonPrivateMembers(ProtoBuf.Class::getFunctionList))
|
names.addAll(calcDifferenceForNonPrivateMembers(ProtoBuf.Class::getFunctionList))
|
||||||
ProtoBufClassKind.PROPERTY_LIST ->
|
ProtoBufClassKind.PROPERTY_LIST ->
|
||||||
names.addAll(calcDifferenceForNonPrivateMembers(ProtoBuf.Class::getPropertyList))
|
names.addAll(calcDifferenceForNonPrivateMembers(ProtoBuf.Class::getPropertyList))
|
||||||
ProtoBufClassKind.ENUM_ENTRY_LIST -> {
|
ProtoBufClassKind.ENUM_ENTRY_LIST -> {
|
||||||
isClassSignatureChanged = true
|
isClassAffected = true
|
||||||
}
|
}
|
||||||
ProtoBufClassKind.TYPE_TABLE -> {
|
ProtoBufClassKind.TYPE_TABLE -> {
|
||||||
// TODO
|
// TODO
|
||||||
}
|
}
|
||||||
in CLASS_SIGNATURE_ENUMS -> {
|
in CLASS_SIGNATURE_ENUMS -> {
|
||||||
isClassSignatureChanged = true
|
isClassAffected = true
|
||||||
|
areSubclassesAffected = true
|
||||||
}
|
}
|
||||||
else -> throw IllegalArgumentException("Unsupported kind: $kind")
|
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);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("secondaryConstructorAdded")
|
||||||
|
public void testSecondaryConstructorAdded() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("jps-plugin/testData/incremental/classHierarchyAffected/secondaryConstructorAdded/");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("starProjectionUpperBoundChanged")
|
@TestMetadata("starProjectionUpperBoundChanged")
|
||||||
public void testStarProjectionUpperBoundChanged() throws Exception {
|
public void testStarProjectionUpperBoundChanged() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("jps-plugin/testData/incremental/classHierarchyAffected/starProjectionUpperBoundChanged/");
|
String fileName = KotlinTestUtils.navigationMetadata("jps-plugin/testData/incremental/classHierarchyAffected/starProjectionUpperBoundChanged/");
|
||||||
|
|||||||
+1
-1
@@ -104,7 +104,7 @@ abstract class AbstractProtoComparisonTest : UsefulTestCase() {
|
|||||||
|
|
||||||
val changes = SmartList<String>()
|
val changes = SmartList<String>()
|
||||||
|
|
||||||
if (diff.isClassSignatureChanged) {
|
if (diff.isClassAffected) {
|
||||||
changes.add("CLASS_SIGNATURE")
|
changes.add("CLASS_SIGNATURE")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+5
-10
@@ -1,10 +1,5 @@
|
|||||||
changes in test/ClassWithPrimaryConstructorChanged: MEMBERS
|
changes in test/ClassWithPrimaryConstructorChanged: CLASS_SIGNATURE
|
||||||
[<init>]
|
changes in test/ClassWithPrimaryConstructorVisibilityChanged: CLASS_SIGNATURE
|
||||||
changes in test/ClassWithPrimaryConstructorVisibilityChanged: MEMBERS
|
changes in test/ClassWithSecondaryConstructorVisibilityChanged: CLASS_SIGNATURE
|
||||||
[<init>]
|
changes in test/ClassWithSecondaryConstructorsAdded: CLASS_SIGNATURE
|
||||||
changes in test/ClassWithSecondaryConstructorVisibilityChanged: MEMBERS
|
changes in test/ClassWithSecondaryConstructorsRemoved: CLASS_SIGNATURE
|
||||||
[<init>]
|
|
||||||
changes in test/ClassWithSecondaryConstructorsAdded: MEMBERS
|
|
||||||
[<init>]
|
|
||||||
changes in test/ClassWithSecondaryConstructorsRemoved: MEMBERS
|
|
||||||
[<init>]
|
|
||||||
|
|||||||
+1
-2
@@ -1,2 +1 @@
|
|||||||
changes in test/ClassWithClassAnnotationListChanged: CLASS_SIGNATURE, MEMBERS
|
changes in test/ClassWithClassAnnotationListChanged: CLASS_SIGNATURE
|
||||||
[<init>]
|
|
||||||
|
|||||||
+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