KT-45777: Allow 2 levels of granularity when tracking changes

1. CLASS_LEVEL: allows tracking whether a .class file has changed
     without tracking what specific parts of the .class file (e.g.,
     fields or methods) have changed.

  2. CLASS_MEMBER_LEVEL: allows tracking not only whether a .class file
     has changed but also what specific parts of the .class file (e.g.,
     fields or methods) have changed.

 The idea is that for better performance we will use CLASS_LEVEL for
 classpath entries that are usually unchanged, and CLASS_MEMBER_LEVEL
 for classpath entries that are frequently changed. We'll work out the
 specifics in a following commit after some measurements.

Support running kotlinc on Windows in ClasspathSnapshotTestCommon
Also add tests for different Kotlin class kinds.
Add unit tests for CLASS_LEVEL snapshotting and diffing

Test: Updated ClasspathSnapshotterTest + ClasspathChangesComputerTest
Add ClasspathChangesComputerTest.testMixedClassSnapshotGranularities
This commit is contained in:
Hung Nguyen
2022-01-17 19:06:04 +00:00
committed by nataliya.valtman
parent 05457c291d
commit d2193f3873
76 changed files with 1170 additions and 566 deletions
@@ -1,5 +1,6 @@
package com.example
@Suppress("NOTHING_TO_INLINE")
class SomeClass {
// Constants are not allowed in a class, only allowed at the top level or in an object.
@@ -1,5 +1,6 @@
package com.example
@Suppress("NOTHING_TO_INLINE")
class SomeClass {
// Constants are not allowed in a class, only allowed at the top level or in an object.
@@ -0,0 +1,10 @@
package com.example;
public class CoarseGrainedFirstBuild_CoarseGrainedSecondBuild_Class {
public long modifiedField = 0;
public long modifiedMethod() {
return 0;
}
}
@@ -0,0 +1,10 @@
package com.example;
public class CoarseGrainedFirstBuild_FineGrainedSecondBuild_Class {
public long modifiedField = 0;
public long modifiedMethod() {
return 0;
}
}
@@ -0,0 +1,10 @@
package com.example;
public class FineGrainedFirstBuild_CoarseGrainedSecondBuild_Class {
public long modifiedField = 0;
public long modifiedMethod() {
return 0;
}
}
@@ -0,0 +1,10 @@
package com.example;
public class FineGrainedFirstBuild_FineGrainedSecondBuild_Class {
public long modifiedField = 0;
public long modifiedMethod() {
return 0;
}
}
@@ -0,0 +1,10 @@
package com.example;
public class CoarseGrainedFirstBuild_CoarseGrainedSecondBuild_Class {
public int modifiedField = 0;
public int modifiedMethod() {
return 0;
}
}
@@ -0,0 +1,10 @@
package com.example;
public class CoarseGrainedFirstBuild_FineGrainedSecondBuild_Class {
public int modifiedField = 0;
public int modifiedMethod() {
return 0;
}
}
@@ -0,0 +1,10 @@
package com.example;
public class FineGrainedFirstBuild_CoarseGrainedSecondBuild_Class {
public int modifiedField = 0;
public int modifiedMethod() {
return 0;
}
}
@@ -0,0 +1,10 @@
package com.example;
public class FineGrainedFirstBuild_FineGrainedSecondBuild_Class {
public int modifiedField = 0;
public int modifiedMethod() {
return 0;
}
}
@@ -0,0 +1,6 @@
package com.example
class CoarseGrainedFirstBuild_CoarseGrainedSecondBuild_Class {
val modifiedProperty: Long = 0
fun modifiedFunction(): Long = 0
}
@@ -0,0 +1,6 @@
package com.example
class CoarseGrainedFirstBuild_FineGrainedSecondBuild_Class {
val modifiedProperty: Long = 0
fun modifiedFunction(): Long = 0
}
@@ -0,0 +1,6 @@
package com.example
class FineGrainedFirstBuild_CoarseGrainedSecondBuild_Class {
val modifiedProperty: Long = 0
fun modifiedFunction(): Long = 0
}
@@ -0,0 +1,6 @@
package com.example
class FineGrainedFirstBuild_FineGrainedSecondBuild_Class {
val modifiedProperty: Long = 0
fun modifiedFunction(): Long = 0
}
@@ -0,0 +1,6 @@
package com.example
class CoarseGrainedFirstBuild_CoarseGrainedSecondBuild_Class {
val modifiedProperty: Int = 0
fun modifiedFunction(): Int = 0
}
@@ -0,0 +1,6 @@
package com.example
class CoarseGrainedFirstBuild_FineGrainedSecondBuild_Class {
val modifiedProperty: Int = 0
fun modifiedFunction(): Int = 0
}
@@ -0,0 +1,6 @@
package com.example
class FineGrainedFirstBuild_CoarseGrainedSecondBuild_Class {
val modifiedProperty: Int = 0
fun modifiedFunction(): Int = 0
}
@@ -0,0 +1,6 @@
package com.example
class FineGrainedFirstBuild_FineGrainedSecondBuild_Class {
val modifiedProperty: Int = 0
fun modifiedFunction(): Int = 0
}
@@ -1,6 +1,6 @@
package com.example
@java.lang.Deprecated // Changed annotation
@kotlin.Deprecated("") // Changed annotation
class ModifiedClassUnchangedMembers {
val unchangedProperty = 0
fun unchangedFunction() {}
@@ -1,52 +0,0 @@
{
"classId": {
"packageFqName": {
"fqName": {
"fqName": "com.example"
}
},
"relativeClassName": {
"fqName": {
"fqName": "SimpleClass"
}
},
"local": false
},
"supertypes": [
{
"internalName": "java/lang/Object"
}
],
"classAbiExcludingMembers": {
"abiValue": "{\n \"version\": 52,\n \"access\": 32,\n \"name\": \"com/example/SimpleClass\",\n \"superName\": \"java/lang/Object\",\n \"interfaces\": [],\n \"sourceFile\": \"SimpleClass.java\",\n \"innerClasses\": [],\n \"fields\": [],\n \"methods\": [],\n \"api\": 589824\n}",
"name": "com/example/SimpleClass",
"abiHash": 5093067435262353961
},
"fieldsAbi": [
{
"abiValue": "{\n \"access\": 1,\n \"name\": \"publicField\",\n \"desc\": \"I\",\n \"api\": 589824\n}",
"name": "publicField",
"abiHash": -4066101678319939363
}
],
"methodsAbi": [
{
"abiValue": "{\n \"access\": 0,\n \"name\": \"\\u003cinit\\u003e\",\n \"desc\": \"()V\",\n \"exceptions\": [],\n \"visibleAnnotableParameterCount\": 0,\n \"invisibleAnnotableParameterCount\": 0,\n \"instructions\": {\n \"size\": 0\n },\n \"tryCatchBlocks\": [],\n \"maxStack\": 0,\n \"maxLocals\": 0,\n \"localVariables\": [],\n \"visited\": false,\n \"api\": 589824\n}",
"name": "\u003cinit\u003e",
"abiHash": -8222317811013429324
},
{
"abiValue": "{\n \"access\": 1,\n \"name\": \"publicMethod\",\n \"desc\": \"()I\",\n \"exceptions\": [],\n \"visibleAnnotableParameterCount\": 0,\n \"invisibleAnnotableParameterCount\": 0,\n \"instructions\": {\n \"size\": 0\n },\n \"tryCatchBlocks\": [],\n \"maxStack\": 0,\n \"maxLocals\": 0,\n \"localVariables\": [],\n \"visited\": false,\n \"api\": 589824\n}",
"name": "publicMethod",
"abiHash": -4555436938653125191
}
],
"className$delegate": {
"initializer": {},
"_value": {}
},
"withHash$delegate": {
"initializer": {},
"_value": {}
}
}
@@ -0,0 +1,21 @@
{
"classId": {
"packageFqName": {
"fqName": {
"fqName": "com.example"
}
},
"relativeClassName": {
"fqName": {
"fqName": "SimpleClass"
}
},
"local": false
},
"classAbiHash": 2419143040117344894,
"supertypes": [
{
"internalName": "java/lang/Object"
}
]
}
@@ -0,0 +1,47 @@
{
"classId": {
"packageFqName": {
"fqName": {
"fqName": "com.example"
}
},
"relativeClassName": {
"fqName": {
"fqName": "SimpleClass"
}
},
"local": false
},
"classAbiHash": 7253633932031152470,
"classMemberLevelSnapshot": {
"classAbiExcludingMembers": {
"abiValue": "{\n \"version\": 52,\n \"access\": 33,\n \"name\": \"com/example/SimpleClass\",\n \"superName\": \"java/lang/Object\",\n \"interfaces\": [],\n \"sourceFile\": \"SimpleClass.java\",\n \"innerClasses\": [],\n \"fields\": [],\n \"methods\": [],\n \"api\": 589824\n}",
"name": "com/example/SimpleClass",
"abiHash": -1986494095366785349
},
"fieldsAbi": [
{
"abiValue": "{\n \"access\": 1,\n \"name\": \"publicField\",\n \"desc\": \"Ljava/lang/String;\",\n \"api\": 589824\n}",
"name": "publicField",
"abiHash": 1021768301411937004
}
],
"methodsAbi": [
{
"abiValue": "{\n \"access\": 1,\n \"name\": \"\\u003cinit\\u003e\",\n \"desc\": \"()V\",\n \"exceptions\": [],\n \"visibleAnnotableParameterCount\": 0,\n \"invisibleAnnotableParameterCount\": 0,\n \"instructions\": {\n \"size\": 0\n },\n \"tryCatchBlocks\": [],\n \"maxStack\": 0,\n \"maxLocals\": 0,\n \"localVariables\": [],\n \"visited\": false,\n \"api\": 589824\n}",
"name": "\u003cinit\u003e",
"abiHash": 5725188035643409224
},
{
"abiValue": "{\n \"access\": 1,\n \"name\": \"publicMethod\",\n \"desc\": \"()Ljava/lang/String;\",\n \"exceptions\": [],\n \"visibleAnnotableParameterCount\": 0,\n \"invisibleAnnotableParameterCount\": 0,\n \"instructions\": {\n \"size\": 0\n },\n \"tryCatchBlocks\": [],\n \"maxStack\": 0,\n \"maxLocals\": 0,\n \"localVariables\": [],\n \"visited\": false,\n \"api\": 589824\n}",
"name": "publicMethod",
"abiHash": 8210873051092995586
}
]
},
"supertypes": [
{
"internalName": "java/lang/Object"
}
]
}
@@ -0,0 +1,16 @@
package com.example;
public class SimpleClass {
public String publicField = "publicField's value";
private String privateField = "privateField's value";
public String publicMethod() {
return "publicMethod's body";
}
private String privateMethod() {
return "privateMethod's body";
}
}
@@ -0,0 +1,4 @@
package com.example
val propertyInFileFacade = "propertyInFileFacade's value"
fun functionInFileFacade() = "functionInFileFacade's body"
@@ -0,0 +1,7 @@
@file:JvmName("MultifileClass")
@file:JvmMultifileClass
package com.example
val propertyInMultifileClass1 = "propertyInMultifileClass1's value"
fun functionInMultifileClass1() = "functionInMultifileClass1's body"
@@ -0,0 +1,7 @@
@file:JvmName("MultifileClass")
@file:JvmMultifileClass
package com.example
val propertyInMultifileClass2 = "propertyInMultifileClass2's value"
fun functionInMultifileClass2() = "functionInMultifileClass2's body"
@@ -0,0 +1,21 @@
{
"classId": {
"packageFqName": {
"fqName": {
"fqName": "com.example"
}
},
"relativeClassName": {
"fqName": {
"fqName": "SimpleClass"
}
},
"local": false
},
"classAbiHash": -2605231127310346403,
"supertypes": [
{
"internalName": "java/lang/Object"
}
]
}
@@ -1,5 +1,19 @@
{
"classInfo": {
"classId": {
"packageFqName": {
"fqName": {
"fqName": "com.example"
}
},
"relativeClassName": {
"fqName": {
"fqName": "SimpleClass"
}
},
"local": false
},
"classAbiHash": -2605231127310346403,
"classMemberLevelSnapshot": {
"classId": {
"packageFqName": {
"fqName": {
@@ -15,7 +29,7 @@
},
"classKind": "CLASS",
"classHeaderData": [
"\u0000\u0014\n\u0002\u0018\u0002\n\u0002\u0010\u0000\n\u0002\b\u0002\n\u0002\u0010\b\n\u0002\b\u0005\u0018\u00002\u00020\u0001B\u0005¢\u0006\u0002\u0010\u0002J\b\u0010\b\u001a\u00020\u0004H\u0002J\u0006\u0010\t\u001a\u00020\u0004R\u000e\u0010\u0003\u001a\u00020\u0004X‚D¢\u0006\u0002\n\u0000R\u0014\u0010\u0005\u001a\u00020\u0004X†D¢\u0006\b\n\u0000\u001a\u0004\b\u0006\u0010\u0007"
"\u0000\u0014\n\u0002\u0018\u0002\n\u0002\u0010\u0000\n\u0002\b\u0002\n\u0002\u0010\u000e\n\u0002\b\u0005\u0018\u00002\u00020\u0001B\u0005¢\u0006\u0002\u0010\u0002J\b\u0010\b\u001a\u00020\u0004H\u0002J\u0006\u0010\t\u001a\u00020\u0004R\u000e\u0010\u0003\u001a\u00020\u0004X‚D¢\u0006\u0002\n\u0000R\u0014\u0010\u0005\u001a\u00020\u0004X†D¢\u0006\b\n\u0000\u001a\u0004\b\u0006\u0010\u0007"
],
"classHeaderStrings": [
"Lcom/example/SimpleClass;",
@@ -25,7 +39,7 @@
"",
"publicProperty",
"getPublicProperty",
"()I",
"()Ljava/lang/String;",
"privateFunction",
"publicFunction"
],
@@ -48,9 +62,5 @@
{
"internalName": "java/lang/Object"
}
],
"withHash$delegate": {
"initializer": {},
"_value": {}
}
]
}
@@ -0,0 +1,12 @@
package com.example
class SimpleClass {
val publicProperty: String = "publicProperty's value"
private val privateProperty: String = "privateProperty's value"
fun publicFunction(): String = "publicFunction's body"
private fun privateFunction(): String = "privateFunction's body"
}
@@ -1,16 +0,0 @@
package com.example;
class SimpleClass {
public long publicField = 0;
private long privateField = 0;
public long publicMethod() {
return 0;
}
private long privateMethod() {
return 0;
}
}
@@ -1,16 +0,0 @@
package com.example;
class SimpleClass {
public int publicField = 1000;
private int privateField = 1000;
public int publicMethod() {
return 1000;
}
private int privateMethod() {
return 1000;
}
}
@@ -1,12 +0,0 @@
package com.example
class SimpleClass {
val publicProperty: Long = 0
private val privateProperty: Long = 0
fun publicFunction(): Long = 0
private fun privateFunction(): Long = 0
}
@@ -1,12 +0,0 @@
package com.example
class SimpleClass {
val publicProperty: Int = 1000
private val privateProperty: Int = 1000
fun publicFunction(): Int = 1000
private fun privateFunction(): Int = 1000
}
@@ -1,16 +0,0 @@
package com.example;
class SimpleClass {
public int publicField = 0;
private int privateField = 0;
public int publicMethod() {
return 0;
}
private int privateMethod() {
return 0;
}
}
@@ -1,12 +0,0 @@
package com.example
class SimpleClass {
val publicProperty: Int = 0
private val privateProperty: Int = 0
fun publicFunction(): Int = 0
private fun privateFunction(): Int = 0
}