Recompile all class and member usages when flag and member are changed
Original commit: e7f8d7103f
This commit is contained in:
@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.jps.incremental
|
|||||||
import com.google.protobuf.MessageLite
|
import com.google.protobuf.MessageLite
|
||||||
import com.intellij.openapi.util.io.FileUtil
|
import com.intellij.openapi.util.io.FileUtil
|
||||||
import com.intellij.openapi.util.io.FileUtil.toSystemIndependentName
|
import com.intellij.openapi.util.io.FileUtil.toSystemIndependentName
|
||||||
|
import com.intellij.util.SmartList
|
||||||
import com.intellij.util.io.BooleanDataDescriptor
|
import com.intellij.util.io.BooleanDataDescriptor
|
||||||
import com.intellij.util.io.EnumeratorStringDescriptor
|
import com.intellij.util.io.EnumeratorStringDescriptor
|
||||||
import gnu.trove.THashSet
|
import gnu.trove.THashSet
|
||||||
@@ -371,20 +372,19 @@ class IncrementalCacheImpl(
|
|||||||
|
|
||||||
if (oldData == null || !checkChangesIsOpenPart) return CompilationResult(protoChanged = true)
|
if (oldData == null || !checkChangesIsOpenPart) return CompilationResult(protoChanged = true)
|
||||||
|
|
||||||
val diff = difference(oldData, data)
|
val difference = difference(oldData, data)
|
||||||
|
|
||||||
if (!IncrementalCompilation.isExperimental()) return CompilationResult(protoChanged = diff != DifferenceKind.NONE)
|
|
||||||
|
|
||||||
val fqName = if (isPackage) className.packageFqName else className.fqNameForClassNameWithoutDollars
|
val fqName = if (isPackage) className.packageFqName else className.fqNameForClassNameWithoutDollars
|
||||||
|
val changeList = SmartList<ChangeInfo>()
|
||||||
|
|
||||||
val changes =
|
if (difference.isClassSignatureChanged) {
|
||||||
when (diff) {
|
changeList.add(ChangeInfo.SignatureChanged(fqName))
|
||||||
is DifferenceKind.NONE -> emptySequence<ChangeInfo>()
|
}
|
||||||
is DifferenceKind.CLASS_SIGNATURE -> sequenceOf(ChangeInfo.SignatureChanged(fqName))
|
|
||||||
is DifferenceKind.MEMBERS -> sequenceOf(ChangeInfo.MembersChanged(fqName, diff.names))
|
|
||||||
}
|
|
||||||
|
|
||||||
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 =
|
operator fun contains(className: JvmClassName): Boolean =
|
||||||
|
|||||||
@@ -29,17 +29,21 @@ import org.jetbrains.kotlin.serialization.jvm.JvmProtoBufUtil
|
|||||||
import org.jetbrains.kotlin.utils.HashSetUtil
|
import org.jetbrains.kotlin.utils.HashSetUtil
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
sealed class DifferenceKind() {
|
data class Difference(
|
||||||
object NONE: DifferenceKind()
|
val isClassSignatureChanged: Boolean = false,
|
||||||
object CLASS_SIGNATURE: DifferenceKind()
|
val changedMembersNames: Set<String> = emptySet()
|
||||||
class MEMBERS(val names: Collection<String>): DifferenceKind()
|
)
|
||||||
}
|
|
||||||
|
|
||||||
fun difference(oldData: ProtoMapValue, newData: ProtoMapValue): DifferenceKind {
|
fun difference(oldData: ProtoMapValue, newData: ProtoMapValue): Difference {
|
||||||
if (oldData.isPackageFacade != newData.isPackageFacade) return DifferenceKind.CLASS_SIGNATURE
|
if (oldData.isPackageFacade != newData.isPackageFacade) return Difference(isClassSignatureChanged = true)
|
||||||
|
|
||||||
val differenceObject =
|
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()
|
return differenceObject.difference()
|
||||||
}
|
}
|
||||||
@@ -70,9 +74,7 @@ private abstract class DifferenceCalculator() {
|
|||||||
|
|
||||||
protected val compareObject by lazy { ProtoCompareGenerated(oldNameResolver, newNameResolver) }
|
protected val compareObject by lazy { ProtoCompareGenerated(oldNameResolver, newNameResolver) }
|
||||||
|
|
||||||
abstract fun difference(): DifferenceKind
|
abstract fun difference(): Difference
|
||||||
|
|
||||||
protected fun membersOrNone(names: Collection<String>): DifferenceKind = if (names.isEmpty()) DifferenceKind.NONE else DifferenceKind.MEMBERS(names)
|
|
||||||
|
|
||||||
protected fun calcDifferenceForMembers(oldList: List<MessageLite>, newList: List<MessageLite>): Collection<String> {
|
protected fun calcDifferenceForMembers(oldList: List<MessageLite>, newList: List<MessageLite>): Collection<String> {
|
||||||
val result = hashSetOf<String>()
|
val result = hashSetOf<String>()
|
||||||
@@ -172,15 +174,8 @@ private class DifferenceCalculatorForClass(oldData: ProtoMapValue, newData: Prot
|
|||||||
|
|
||||||
val diff = compareObject.difference(oldProto, newProto)
|
val diff = compareObject.difference(oldProto, newProto)
|
||||||
|
|
||||||
override fun difference(): DifferenceKind {
|
override fun difference(): Difference {
|
||||||
if (diff.isEmpty()) return DifferenceKind.NONE
|
var isClassSignatureChanged = false
|
||||||
|
|
||||||
CLASS_SIGNATURE_ENUMS.forEach { if (it in diff) return DifferenceKind.CLASS_SIGNATURE }
|
|
||||||
|
|
||||||
return membersOrNone(getChangedMembersNames())
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getChangedMembersNames(): Set<String> {
|
|
||||||
val names = hashSetOf<String>()
|
val names = hashSetOf<String>()
|
||||||
|
|
||||||
fun Int.oldToNames() = names.add(oldNameResolver.getString(this))
|
fun Int.oldToNames() = names.add(oldNameResolver.getString(this))
|
||||||
@@ -211,17 +206,14 @@ private class DifferenceCalculatorForClass(oldData: ProtoMapValue, newData: Prot
|
|||||||
ProtoBufClassKind.TYPE_TABLE -> {
|
ProtoBufClassKind.TYPE_TABLE -> {
|
||||||
// TODO
|
// TODO
|
||||||
}
|
}
|
||||||
ProtoBufClassKind.FLAGS,
|
in CLASS_SIGNATURE_ENUMS -> {
|
||||||
ProtoBufClassKind.FQ_NAME,
|
isClassSignatureChanged = true
|
||||||
ProtoBufClassKind.TYPE_PARAMETER_LIST,
|
}
|
||||||
ProtoBufClassKind.SUPERTYPE_LIST,
|
else -> throw IllegalArgumentException("Unsupported kind: $kind")
|
||||||
ProtoBufClassKind.CLASS_ANNOTATION_LIST ->
|
|
||||||
throw IllegalArgumentException("Unexpected kind: $kind")
|
|
||||||
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)
|
val diff = compareObject.difference(oldProto, newProto)
|
||||||
|
|
||||||
override fun difference(): DifferenceKind {
|
override fun difference(): Difference {
|
||||||
if (diff.isEmpty()) return DifferenceKind.NONE
|
|
||||||
|
|
||||||
return membersOrNone(getChangedMembersNames())
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getChangedMembersNames(): Set<String> {
|
|
||||||
val names = hashSetOf<String>()
|
val names = hashSetOf<String>()
|
||||||
|
|
||||||
fun calcDifferenceForNonPrivateMembers(members: (ProtoBuf.Package) -> List<MessageLite>): Collection<String> {
|
fun calcDifferenceForNonPrivateMembers(members: (ProtoBuf.Package) -> List<MessageLite>): Collection<String> {
|
||||||
@@ -261,11 +247,10 @@ private class DifferenceCalculatorForPackageFacade(oldData: ProtoMapValue, newDa
|
|||||||
ProtoBufPackageKind.TYPE_TABLE -> {
|
ProtoBufPackageKind.TYPE_TABLE -> {
|
||||||
// TODO
|
// TODO
|
||||||
}
|
}
|
||||||
else ->
|
else -> throw IllegalArgumentException("Unsupported kind: $kind")
|
||||||
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);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("flagsAndMemberInSameClassChanged")
|
||||||
|
public void testFlagsAndMemberInSameClassChanged() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("jps-plugin/testData/incremental/classHierarchyAffected/flagsAndMemberInSameClassChanged/");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("jvmNameChanged")
|
@TestMetadata("jvmNameChanged")
|
||||||
public void testJvmNameChanged() throws Exception {
|
public void testJvmNameChanged() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("jps-plugin/testData/incremental/classHierarchyAffected/jvmNameChanged/");
|
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.openapi.util.io.FileUtil
|
||||||
import com.intellij.testFramework.UsefulTestCase
|
import com.intellij.testFramework.UsefulTestCase
|
||||||
|
import com.intellij.util.SmartList
|
||||||
import org.jetbrains.kotlin.jps.incremental.storage.ProtoMapValue
|
import org.jetbrains.kotlin.jps.incremental.storage.ProtoMapValue
|
||||||
import org.jetbrains.kotlin.load.kotlin.header.isCompatibleClassKind
|
import org.jetbrains.kotlin.load.kotlin.header.isCompatibleClassKind
|
||||||
import org.jetbrains.kotlin.load.kotlin.header.isCompatibleFileFacadeKind
|
import org.jetbrains.kotlin.load.kotlin.header.isCompatibleFileFacadeKind
|
||||||
@@ -112,16 +113,21 @@ abstract class AbstractProtoComparisonTest : UsefulTestCase() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val changes = when (diff) {
|
val changes = SmartList<String>()
|
||||||
is DifferenceKind.NONE ->
|
|
||||||
"NONE"
|
if (diff.isClassSignatureChanged) {
|
||||||
is DifferenceKind.CLASS_SIGNATURE ->
|
changes.add("CLASS_SIGNATURE")
|
||||||
"CLASS_SIGNATURE"
|
|
||||||
is DifferenceKind.MEMBERS ->
|
|
||||||
"MEMBERS\n ${diff.names.sorted()}"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
private fun File.createSubDirectory(relativePath: String): File {
|
||||||
|
|||||||
+6
@@ -37,6 +37,12 @@ public class ProtoComparisonTestGenerated extends AbstractProtoComparisonTest {
|
|||||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("jps-plugin/testData/comparison/classSignatureChange"), Pattern.compile("^([^\\.]+)$"), true);
|
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")
|
@TestMetadata("classFlagsChanged")
|
||||||
public void testClassFlagsChanged() throws Exception {
|
public void testClassFlagsChanged() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("jps-plugin/testData/comparison/classSignatureChange/classFlagsChanged/");
|
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]
|
||||||
+2
-1
@@ -1 +1,2 @@
|
|||||||
changes in test/ClassWithClassAnnotationListChanged: CLASS_SIGNATURE
|
changes in test/ClassWithClassAnnotationListChanged: CLASS_SIGNATURE, MEMBERS
|
||||||
|
[<init>]
|
||||||
|
|||||||
+3
@@ -0,0 +1,3 @@
|
|||||||
|
open class A {
|
||||||
|
val x: Any = "A.x"
|
||||||
|
}
|
||||||
+3
@@ -0,0 +1,3 @@
|
|||||||
|
private open class A {
|
||||||
|
val x: Any? = null
|
||||||
|
}
|
||||||
+3
@@ -0,0 +1,3 @@
|
|||||||
|
open class A {
|
||||||
|
val x: Any? = null
|
||||||
|
}
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
class B : A()
|
||||||
+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
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
fun getA() = A()
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
fun getB() = B()
|
||||||
+3
@@ -0,0 +1,3 @@
|
|||||||
|
fun useA() {
|
||||||
|
getA().x.hashCode()
|
||||||
|
}
|
||||||
+3
@@ -0,0 +1,3 @@
|
|||||||
|
fun useA() {
|
||||||
|
getA().x?.hashCode()
|
||||||
|
}
|
||||||
+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