Recompile all class and member usages when flag and member are changed
This commit is contained in:
@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.jps.incremental
|
||||
import com.google.protobuf.MessageLite
|
||||
import com.intellij.openapi.util.io.FileUtil
|
||||
import com.intellij.openapi.util.io.FileUtil.toSystemIndependentName
|
||||
import com.intellij.util.SmartList
|
||||
import com.intellij.util.io.BooleanDataDescriptor
|
||||
import com.intellij.util.io.EnumeratorStringDescriptor
|
||||
import gnu.trove.THashSet
|
||||
@@ -371,20 +372,19 @@ class IncrementalCacheImpl(
|
||||
|
||||
if (oldData == null || !checkChangesIsOpenPart) return CompilationResult(protoChanged = true)
|
||||
|
||||
val diff = difference(oldData, data)
|
||||
|
||||
if (!IncrementalCompilation.isExperimental()) return CompilationResult(protoChanged = diff != DifferenceKind.NONE)
|
||||
|
||||
val difference = difference(oldData, data)
|
||||
val fqName = if (isPackage) className.packageFqName else className.fqNameForClassNameWithoutDollars
|
||||
val changeList = SmartList<ChangeInfo>()
|
||||
|
||||
val changes =
|
||||
when (diff) {
|
||||
is DifferenceKind.NONE -> emptySequence<ChangeInfo>()
|
||||
is DifferenceKind.CLASS_SIGNATURE -> sequenceOf(ChangeInfo.SignatureChanged(fqName))
|
||||
is DifferenceKind.MEMBERS -> sequenceOf(ChangeInfo.MembersChanged(fqName, diff.names))
|
||||
}
|
||||
if (difference.isClassSignatureChanged) {
|
||||
changeList.add(ChangeInfo.SignatureChanged(fqName))
|
||||
}
|
||||
|
||||
return CompilationResult(protoChanged = diff != DifferenceKind.NONE, changes = changes)
|
||||
if (difference.changedMembersNames.isNotEmpty()) {
|
||||
changeList.add(ChangeInfo.MembersChanged(fqName, difference.changedMembersNames))
|
||||
}
|
||||
|
||||
return CompilationResult(protoChanged = changeList.isNotEmpty(), changes = changeList.asSequence())
|
||||
}
|
||||
|
||||
operator fun contains(className: JvmClassName): Boolean =
|
||||
|
||||
@@ -29,17 +29,21 @@ import org.jetbrains.kotlin.serialization.jvm.JvmProtoBufUtil
|
||||
import org.jetbrains.kotlin.utils.HashSetUtil
|
||||
import java.util.*
|
||||
|
||||
sealed class DifferenceKind() {
|
||||
object NONE: DifferenceKind()
|
||||
object CLASS_SIGNATURE: DifferenceKind()
|
||||
class MEMBERS(val names: Collection<String>): DifferenceKind()
|
||||
}
|
||||
data class Difference(
|
||||
val isClassSignatureChanged: Boolean = false,
|
||||
val changedMembersNames: Set<String> = emptySet()
|
||||
)
|
||||
|
||||
fun difference(oldData: ProtoMapValue, newData: ProtoMapValue): DifferenceKind {
|
||||
if (oldData.isPackageFacade != newData.isPackageFacade) return DifferenceKind.CLASS_SIGNATURE
|
||||
fun difference(oldData: ProtoMapValue, newData: ProtoMapValue): Difference {
|
||||
if (oldData.isPackageFacade != newData.isPackageFacade) return Difference(isClassSignatureChanged = true)
|
||||
|
||||
val differenceObject =
|
||||
if (oldData.isPackageFacade) DifferenceCalculatorForPackageFacade(oldData, newData) else DifferenceCalculatorForClass(oldData, newData)
|
||||
if (oldData.isPackageFacade) {
|
||||
DifferenceCalculatorForPackageFacade(oldData, newData)
|
||||
}
|
||||
else {
|
||||
DifferenceCalculatorForClass(oldData, newData)
|
||||
}
|
||||
|
||||
return differenceObject.difference()
|
||||
}
|
||||
@@ -70,9 +74,7 @@ private abstract class DifferenceCalculator() {
|
||||
|
||||
protected val compareObject by lazy { ProtoCompareGenerated(oldNameResolver, newNameResolver) }
|
||||
|
||||
abstract fun difference(): DifferenceKind
|
||||
|
||||
protected fun membersOrNone(names: Collection<String>): DifferenceKind = if (names.isEmpty()) DifferenceKind.NONE else DifferenceKind.MEMBERS(names)
|
||||
abstract fun difference(): Difference
|
||||
|
||||
protected fun calcDifferenceForMembers(oldList: List<MessageLite>, newList: List<MessageLite>): Collection<String> {
|
||||
val result = hashSetOf<String>()
|
||||
@@ -172,15 +174,8 @@ private class DifferenceCalculatorForClass(oldData: ProtoMapValue, newData: Prot
|
||||
|
||||
val diff = compareObject.difference(oldProto, newProto)
|
||||
|
||||
override fun difference(): DifferenceKind {
|
||||
if (diff.isEmpty()) return DifferenceKind.NONE
|
||||
|
||||
CLASS_SIGNATURE_ENUMS.forEach { if (it in diff) return DifferenceKind.CLASS_SIGNATURE }
|
||||
|
||||
return membersOrNone(getChangedMembersNames())
|
||||
}
|
||||
|
||||
private fun getChangedMembersNames(): Set<String> {
|
||||
override fun difference(): Difference {
|
||||
var isClassSignatureChanged = false
|
||||
val names = hashSetOf<String>()
|
||||
|
||||
fun Int.oldToNames() = names.add(oldNameResolver.getString(this))
|
||||
@@ -211,17 +206,14 @@ private class DifferenceCalculatorForClass(oldData: ProtoMapValue, newData: Prot
|
||||
ProtoBufClassKind.TYPE_TABLE -> {
|
||||
// TODO
|
||||
}
|
||||
ProtoBufClassKind.FLAGS,
|
||||
ProtoBufClassKind.FQ_NAME,
|
||||
ProtoBufClassKind.TYPE_PARAMETER_LIST,
|
||||
ProtoBufClassKind.SUPERTYPE_LIST,
|
||||
ProtoBufClassKind.CLASS_ANNOTATION_LIST ->
|
||||
throw IllegalArgumentException("Unexpected kind: $kind")
|
||||
else ->
|
||||
throw IllegalArgumentException("Unsupported kind: $kind")
|
||||
in CLASS_SIGNATURE_ENUMS -> {
|
||||
isClassSignatureChanged = true
|
||||
}
|
||||
else -> throw IllegalArgumentException("Unsupported kind: $kind")
|
||||
}
|
||||
}
|
||||
return names
|
||||
|
||||
return Difference(isClassSignatureChanged, names)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -237,13 +229,7 @@ private class DifferenceCalculatorForPackageFacade(oldData: ProtoMapValue, newDa
|
||||
|
||||
val diff = compareObject.difference(oldProto, newProto)
|
||||
|
||||
override fun difference(): DifferenceKind {
|
||||
if (diff.isEmpty()) return DifferenceKind.NONE
|
||||
|
||||
return membersOrNone(getChangedMembersNames())
|
||||
}
|
||||
|
||||
private fun getChangedMembersNames(): Set<String> {
|
||||
override fun difference(): Difference {
|
||||
val names = hashSetOf<String>()
|
||||
|
||||
fun calcDifferenceForNonPrivateMembers(members: (ProtoBuf.Package) -> List<MessageLite>): Collection<String> {
|
||||
@@ -261,11 +247,10 @@ private class DifferenceCalculatorForPackageFacade(oldData: ProtoMapValue, newDa
|
||||
ProtoBufPackageKind.TYPE_TABLE -> {
|
||||
// TODO
|
||||
}
|
||||
else ->
|
||||
throw IllegalArgumentException("Unsupported kind: $kind")
|
||||
else -> throw IllegalArgumentException("Unsupported kind: $kind")
|
||||
}
|
||||
}
|
||||
|
||||
return names
|
||||
return Difference(isClassSignatureChanged = false, changedMembersNames = names)
|
||||
}
|
||||
}
|
||||
|
||||
+6
@@ -1081,6 +1081,12 @@ public class ExperimentalIncrementalJpsTestGenerated extends AbstractExperimenta
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("flagsAndMemberInSameClassChanged")
|
||||
public void testFlagsAndMemberInSameClassChanged() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("jps-plugin/testData/incremental/classHierarchyAffected/flagsAndMemberInSameClassChanged/");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("jvmNameChanged")
|
||||
public void testJvmNameChanged() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("jps-plugin/testData/incremental/classHierarchyAffected/jvmNameChanged/");
|
||||
|
||||
+14
-8
@@ -18,6 +18,7 @@ package org.jetbrains.kotlin.jps.incremental
|
||||
|
||||
import com.intellij.openapi.util.io.FileUtil
|
||||
import com.intellij.testFramework.UsefulTestCase
|
||||
import com.intellij.util.SmartList
|
||||
import org.jetbrains.kotlin.jps.incremental.storage.ProtoMapValue
|
||||
import org.jetbrains.kotlin.load.kotlin.header.isCompatibleClassKind
|
||||
import org.jetbrains.kotlin.load.kotlin.header.isCompatibleFileFacadeKind
|
||||
@@ -112,16 +113,21 @@ abstract class AbstractProtoComparisonTest : UsefulTestCase() {
|
||||
}
|
||||
}
|
||||
|
||||
val changes = when (diff) {
|
||||
is DifferenceKind.NONE ->
|
||||
"NONE"
|
||||
is DifferenceKind.CLASS_SIGNATURE ->
|
||||
"CLASS_SIGNATURE"
|
||||
is DifferenceKind.MEMBERS ->
|
||||
"MEMBERS\n ${diff.names.sorted()}"
|
||||
val changes = SmartList<String>()
|
||||
|
||||
if (diff.isClassSignatureChanged) {
|
||||
changes.add("CLASS_SIGNATURE")
|
||||
}
|
||||
|
||||
println("changes in ${oldLocalFileKotlinClass.classId}: $changes")
|
||||
if (diff.changedMembersNames.isNotEmpty()) {
|
||||
changes.add("MEMBERS\n ${diff.changedMembersNames.sorted()}")
|
||||
}
|
||||
|
||||
if (changes.isEmpty()) {
|
||||
changes.add("NONE")
|
||||
}
|
||||
|
||||
println("changes in ${oldLocalFileKotlinClass.classId}: ${changes.joinToString()}")
|
||||
}
|
||||
|
||||
private fun File.createSubDirectory(relativePath: String): File {
|
||||
|
||||
@@ -37,6 +37,12 @@ public class ProtoComparisonTestGenerated extends AbstractProtoComparisonTest {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("jps-plugin/testData/comparison/classSignatureChange"), Pattern.compile("^([^\\.]+)$"), true);
|
||||
}
|
||||
|
||||
@TestMetadata("classFlagsAndMembersChanged")
|
||||
public void testClassFlagsAndMembersChanged() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("jps-plugin/testData/comparison/classSignatureChange/classFlagsAndMembersChanged/");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("classFlagsChanged")
|
||||
public void testClassFlagsChanged() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("jps-plugin/testData/comparison/classSignatureChange/classFlagsChanged/");
|
||||
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
package test
|
||||
|
||||
open class A {
|
||||
fun f() {}
|
||||
}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
package test
|
||||
|
||||
class A
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
changes in test/A: CLASS_SIGNATURE, MEMBERS
|
||||
[f]
|
||||
Vendored
+2
-1
@@ -1 +1,2 @@
|
||||
changes in test/ClassWithClassAnnotationListChanged: CLASS_SIGNATURE
|
||||
changes in test/ClassWithClassAnnotationListChanged: CLASS_SIGNATURE, MEMBERS
|
||||
[<init>]
|
||||
|
||||
Vendored
+3
@@ -0,0 +1,3 @@
|
||||
open class A {
|
||||
val x: Any = "A.x"
|
||||
}
|
||||
Vendored
+3
@@ -0,0 +1,3 @@
|
||||
private open class A {
|
||||
val x: Any? = null
|
||||
}
|
||||
Vendored
+3
@@ -0,0 +1,3 @@
|
||||
open class A {
|
||||
val x: Any? = null
|
||||
}
|
||||
Vendored
+1
@@ -0,0 +1 @@
|
||||
class B : A()
|
||||
Vendored
+56
@@ -0,0 +1,56 @@
|
||||
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/B.class
|
||||
out/production/module/GetAKt.class
|
||||
out/production/module/GetBKt.class
|
||||
out/production/module/META-INF/module.kotlin_module
|
||||
out/production/module/UseAKt.class
|
||||
out/production/module/UseBKt.class
|
||||
End of files
|
||||
Compiling files:
|
||||
src/B.kt
|
||||
src/getA.kt
|
||||
src/getB.kt
|
||||
src/useA.kt
|
||||
src/useB.kt
|
||||
End of files
|
||||
COMPILATION FAILED
|
||||
Cannot access 'A': it is 'private' in file
|
||||
Subclass effective visibility 'public' should be the same or less permissive than its superclass effective visibility 'private'
|
||||
Function effective visibility 'public' should be the same or less permissive than its return type effective visibility 'private'
|
||||
Cannot access 'A': it is 'private' in file
|
||||
Cannot access 'A': it is 'private' in file
|
||||
Only safe (?.) or non-null asserted (!!.) calls are allowed on a nullable receiver of type kotlin.Any?
|
||||
Cannot access 'x': it is 'invisible_fake' in 'B'
|
||||
Only safe (?.) or non-null asserted (!!.) calls are allowed on a nullable receiver of type kotlin.Any?
|
||||
|
||||
|
||||
Cleaning output files:
|
||||
out/production/module/A.class
|
||||
End of files
|
||||
Compiling files:
|
||||
src/A.kt
|
||||
src/B.kt
|
||||
src/getA.kt
|
||||
src/getB.kt
|
||||
src/useA.kt
|
||||
src/useB.kt
|
||||
End of files
|
||||
COMPILATION FAILED
|
||||
Only safe (?.) or non-null asserted (!!.) calls are allowed on a nullable receiver of type kotlin.Any?
|
||||
Only safe (?.) or non-null asserted (!!.) calls are allowed on a nullable receiver of type kotlin.Any?
|
||||
|
||||
|
||||
Compiling files:
|
||||
src/A.kt
|
||||
src/B.kt
|
||||
src/getA.kt
|
||||
src/getB.kt
|
||||
src/useA.kt
|
||||
src/useB.kt
|
||||
End of files
|
||||
Vendored
+1
@@ -0,0 +1 @@
|
||||
fun getA() = A()
|
||||
Vendored
+1
@@ -0,0 +1 @@
|
||||
fun getB() = B()
|
||||
Vendored
+3
@@ -0,0 +1,3 @@
|
||||
fun useA() {
|
||||
getA().x.hashCode()
|
||||
}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
fun useA() {
|
||||
getA().x?.hashCode()
|
||||
}
|
||||
Vendored
+3
@@ -0,0 +1,3 @@
|
||||
fun useB() {
|
||||
getB().x.hashCode()
|
||||
}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
fun useB() {
|
||||
getB().x?.hashCode()
|
||||
}
|
||||
Reference in New Issue
Block a user