From ed5b6e07aad9cce78e91de0635f089279b7a1626 Mon Sep 17 00:00:00 2001 From: Alexey Tsvetkov Date: Mon, 15 May 2017 14:17:10 +0300 Subject: [PATCH] Implement JS proto comparison --- build-common/build-common.iml | 1 + .../incremental/ProtoCompareGenerated.kt | 395 ++++++++++++------ .../incremental/protoDifferenceUtils.kt | 105 +++-- .../jetbrains/kotlin/TestWithWorkingDir.kt | 13 +- .../protobuf/GenerateProtoBufCompare.kt | 20 +- .../kotlin/generators/tests/GenerateTests.kt | 10 + jps-plugin/jps-tests/jps-tests.iml | 3 + .../AbstractJsProtoComparisonTest.kt | 97 +++++ .../AbstractJvmProtoComparisonTest.kt | 3 +- .../AbstractProtoComparisonTest.kt | 9 +- .../JsProtoComparisonTestGenerated.java | 221 ++++++++++ .../classWitnEnumChanged/js.result.out | 4 + 12 files changed, 701 insertions(+), 180 deletions(-) rename {compiler/incremental-compilation-impl => build-common}/test/org/jetbrains/kotlin/TestWithWorkingDir.kt (76%) create mode 100644 jps-plugin/jps-tests/test/org/jetbrains/kotlin/jps/incremental/AbstractJsProtoComparisonTest.kt create mode 100644 jps-plugin/jps-tests/test/org/jetbrains/kotlin/jps/incremental/JsProtoComparisonTestGenerated.java create mode 100644 jps-plugin/testData/comparison/classMembersOnlyChanged/classWitnEnumChanged/js.result.out diff --git a/build-common/build-common.iml b/build-common/build-common.iml index 1e267bfca8d..b38d7bfdeca 100644 --- a/build-common/build-common.iml +++ b/build-common/build-common.iml @@ -15,5 +15,6 @@ + \ No newline at end of file diff --git a/build-common/src/org/jetbrains/kotlin/incremental/ProtoCompareGenerated.kt b/build-common/src/org/jetbrains/kotlin/incremental/ProtoCompareGenerated.kt index 812429c9f3c..67ffbe36918 100644 --- a/build-common/src/org/jetbrains/kotlin/incremental/ProtoCompareGenerated.kt +++ b/build-common/src/org/jetbrains/kotlin/incremental/ProtoCompareGenerated.kt @@ -20,6 +20,7 @@ import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.serialization.ProtoBuf import org.jetbrains.kotlin.serialization.deserialization.NameResolver import org.jetbrains.kotlin.serialization.jvm.JvmProtoBuf +import org.jetbrains.kotlin.serialization.js.JsProtoBuf import org.jetbrains.kotlin.utils.Interner import java.util.* @@ -62,6 +63,11 @@ open class ProtoCompareGenerated(val oldNameResolver: NameResolver, val newNameR if (!checkEquals(old.getExtension(JvmProtoBuf.packageLocalVariable, i), new.getExtension(JvmProtoBuf.packageLocalVariable, i))) return false } + if (old.hasExtension(JsProtoBuf.packageFqName) != new.hasExtension(JsProtoBuf.packageFqName)) return false + if (old.hasExtension(JsProtoBuf.packageFqName)) { + if (old.getExtension(JsProtoBuf.packageFqName) != new.getExtension(JsProtoBuf.packageFqName)) return false + } + return true } enum class ProtoBufPackageKind { @@ -70,8 +76,9 @@ open class ProtoCompareGenerated(val oldNameResolver: NameResolver, val newNameR TYPE_ALIAS_LIST, TYPE_TABLE, SINCE_KOTLIN_INFO_TABLE, - PACKAGE_MODULE_NAME, - PACKAGE_LOCAL_VARIABLE_LIST + JVM_EXT_PACKAGE_MODULE_NAME, + JVM_EXT_PACKAGE_LOCAL_VARIABLE_LIST, + JS_EXT_PACKAGE_FQ_NAME } fun difference(old: ProtoBuf.Package, new: ProtoBuf.Package): EnumSet { @@ -93,15 +100,20 @@ open class ProtoCompareGenerated(val oldNameResolver: NameResolver, val newNameR if (!checkEquals(old.sinceKotlinInfoTable, new.sinceKotlinInfoTable)) result.add(ProtoBufPackageKind.SINCE_KOTLIN_INFO_TABLE) } - if (old.hasExtension(JvmProtoBuf.packageModuleName) != new.hasExtension(JvmProtoBuf.packageModuleName)) result.add(ProtoBufPackageKind.PACKAGE_MODULE_NAME) + if (old.hasExtension(JvmProtoBuf.packageModuleName) != new.hasExtension(JvmProtoBuf.packageModuleName)) result.add(ProtoBufPackageKind.JVM_EXT_PACKAGE_MODULE_NAME) if (old.hasExtension(JvmProtoBuf.packageModuleName)) { - if (!checkStringEquals(old.getExtension(JvmProtoBuf.packageModuleName), new.getExtension(JvmProtoBuf.packageModuleName))) result.add(ProtoBufPackageKind.PACKAGE_MODULE_NAME) + if (!checkStringEquals(old.getExtension(JvmProtoBuf.packageModuleName), new.getExtension(JvmProtoBuf.packageModuleName))) result.add(ProtoBufPackageKind.JVM_EXT_PACKAGE_MODULE_NAME) } - if (old.getExtensionCount(JvmProtoBuf.packageLocalVariable) != new.getExtensionCount(JvmProtoBuf.packageLocalVariable)) result.add(ProtoBufPackageKind.PACKAGE_LOCAL_VARIABLE_LIST) + if (old.getExtensionCount(JvmProtoBuf.packageLocalVariable) != new.getExtensionCount(JvmProtoBuf.packageLocalVariable)) result.add(ProtoBufPackageKind.JVM_EXT_PACKAGE_LOCAL_VARIABLE_LIST) for(i in 0..old.getExtensionCount(JvmProtoBuf.packageLocalVariable) - 1) { - if (!checkEquals(old.getExtension(JvmProtoBuf.packageLocalVariable, i), new.getExtension(JvmProtoBuf.packageLocalVariable, i))) result.add(ProtoBufPackageKind.PACKAGE_LOCAL_VARIABLE_LIST) + if (!checkEquals(old.getExtension(JvmProtoBuf.packageLocalVariable, i), new.getExtension(JvmProtoBuf.packageLocalVariable, i))) result.add(ProtoBufPackageKind.JVM_EXT_PACKAGE_LOCAL_VARIABLE_LIST) + } + + if (old.hasExtension(JsProtoBuf.packageFqName) != new.hasExtension(JsProtoBuf.packageFqName)) result.add(ProtoBufPackageKind.JS_EXT_PACKAGE_FQ_NAME) + if (old.hasExtension(JsProtoBuf.packageFqName)) { + if (old.getExtension(JsProtoBuf.packageFqName) != new.getExtension(JsProtoBuf.packageFqName)) result.add(ProtoBufPackageKind.JS_EXT_PACKAGE_FQ_NAME) } return result @@ -166,6 +178,17 @@ open class ProtoCompareGenerated(val oldNameResolver: NameResolver, val newNameR if (!checkEquals(old.getExtension(JvmProtoBuf.classLocalVariable, i), new.getExtension(JvmProtoBuf.classLocalVariable, i))) return false } + if (old.getExtensionCount(JsProtoBuf.classAnnotation) != new.getExtensionCount(JsProtoBuf.classAnnotation)) return false + + for(i in 0..old.getExtensionCount(JsProtoBuf.classAnnotation) - 1) { + if (!checkEquals(old.getExtension(JsProtoBuf.classAnnotation, i), new.getExtension(JsProtoBuf.classAnnotation, i))) return false + } + + if (old.hasExtension(JsProtoBuf.classContainingFileId) != new.hasExtension(JsProtoBuf.classContainingFileId)) return false + if (old.hasExtension(JsProtoBuf.classContainingFileId)) { + if (old.getExtension(JsProtoBuf.classContainingFileId) != new.getExtension(JsProtoBuf.classContainingFileId)) return false + } + return true } enum class ProtoBufClassKind { @@ -185,8 +208,10 @@ open class ProtoCompareGenerated(val oldNameResolver: NameResolver, val newNameR TYPE_TABLE, SINCE_KOTLIN_INFO, SINCE_KOTLIN_INFO_TABLE, - CLASS_MODULE_NAME, - CLASS_LOCAL_VARIABLE_LIST + JVM_EXT_CLASS_MODULE_NAME, + JVM_EXT_CLASS_LOCAL_VARIABLE_LIST, + JS_EXT_CLASS_ANNOTATION_LIST, + JS_EXT_CLASS_CONTAINING_FILE_ID } fun difference(old: ProtoBuf.Class, new: ProtoBuf.Class): EnumSet { @@ -239,15 +264,26 @@ open class ProtoCompareGenerated(val oldNameResolver: NameResolver, val newNameR if (!checkEquals(old.sinceKotlinInfoTable, new.sinceKotlinInfoTable)) result.add(ProtoBufClassKind.SINCE_KOTLIN_INFO_TABLE) } - if (old.hasExtension(JvmProtoBuf.classModuleName) != new.hasExtension(JvmProtoBuf.classModuleName)) result.add(ProtoBufClassKind.CLASS_MODULE_NAME) + if (old.hasExtension(JvmProtoBuf.classModuleName) != new.hasExtension(JvmProtoBuf.classModuleName)) result.add(ProtoBufClassKind.JVM_EXT_CLASS_MODULE_NAME) if (old.hasExtension(JvmProtoBuf.classModuleName)) { - if (!checkStringEquals(old.getExtension(JvmProtoBuf.classModuleName), new.getExtension(JvmProtoBuf.classModuleName))) result.add(ProtoBufClassKind.CLASS_MODULE_NAME) + if (!checkStringEquals(old.getExtension(JvmProtoBuf.classModuleName), new.getExtension(JvmProtoBuf.classModuleName))) result.add(ProtoBufClassKind.JVM_EXT_CLASS_MODULE_NAME) } - if (old.getExtensionCount(JvmProtoBuf.classLocalVariable) != new.getExtensionCount(JvmProtoBuf.classLocalVariable)) result.add(ProtoBufClassKind.CLASS_LOCAL_VARIABLE_LIST) + if (old.getExtensionCount(JvmProtoBuf.classLocalVariable) != new.getExtensionCount(JvmProtoBuf.classLocalVariable)) result.add(ProtoBufClassKind.JVM_EXT_CLASS_LOCAL_VARIABLE_LIST) for(i in 0..old.getExtensionCount(JvmProtoBuf.classLocalVariable) - 1) { - if (!checkEquals(old.getExtension(JvmProtoBuf.classLocalVariable, i), new.getExtension(JvmProtoBuf.classLocalVariable, i))) result.add(ProtoBufClassKind.CLASS_LOCAL_VARIABLE_LIST) + if (!checkEquals(old.getExtension(JvmProtoBuf.classLocalVariable, i), new.getExtension(JvmProtoBuf.classLocalVariable, i))) result.add(ProtoBufClassKind.JVM_EXT_CLASS_LOCAL_VARIABLE_LIST) + } + + if (old.getExtensionCount(JsProtoBuf.classAnnotation) != new.getExtensionCount(JsProtoBuf.classAnnotation)) result.add(ProtoBufClassKind.JS_EXT_CLASS_ANNOTATION_LIST) + + for(i in 0..old.getExtensionCount(JsProtoBuf.classAnnotation) - 1) { + if (!checkEquals(old.getExtension(JsProtoBuf.classAnnotation, i), new.getExtension(JsProtoBuf.classAnnotation, i))) result.add(ProtoBufClassKind.JS_EXT_CLASS_ANNOTATION_LIST) + } + + if (old.hasExtension(JsProtoBuf.classContainingFileId) != new.hasExtension(JsProtoBuf.classContainingFileId)) result.add(ProtoBufClassKind.JS_EXT_CLASS_CONTAINING_FILE_ID) + if (old.hasExtension(JsProtoBuf.classContainingFileId)) { + if (old.getExtension(JsProtoBuf.classContainingFileId) != new.getExtension(JsProtoBuf.classContainingFileId)) result.add(ProtoBufClassKind.JS_EXT_CLASS_CONTAINING_FILE_ID) } return result @@ -305,6 +341,17 @@ open class ProtoCompareGenerated(val oldNameResolver: NameResolver, val newNameR if (!checkEquals(old.getExtension(JvmProtoBuf.methodSignature), new.getExtension(JvmProtoBuf.methodSignature))) return false } + if (old.getExtensionCount(JsProtoBuf.functionAnnotation) != new.getExtensionCount(JsProtoBuf.functionAnnotation)) return false + + for(i in 0..old.getExtensionCount(JsProtoBuf.functionAnnotation) - 1) { + if (!checkEquals(old.getExtension(JsProtoBuf.functionAnnotation, i), new.getExtension(JsProtoBuf.functionAnnotation, i))) return false + } + + if (old.hasExtension(JsProtoBuf.functionContainingFileId) != new.hasExtension(JsProtoBuf.functionContainingFileId)) return false + if (old.hasExtension(JsProtoBuf.functionContainingFileId)) { + if (old.getExtension(JsProtoBuf.functionContainingFileId) != new.getExtension(JsProtoBuf.functionContainingFileId)) return false + } + return true } @@ -368,6 +415,22 @@ open class ProtoCompareGenerated(val oldNameResolver: NameResolver, val newNameR if (!checkEquals(old.getExtension(JvmProtoBuf.propertySignature), new.getExtension(JvmProtoBuf.propertySignature))) return false } + if (old.getExtensionCount(JsProtoBuf.propertyAnnotation) != new.getExtensionCount(JsProtoBuf.propertyAnnotation)) return false + + for(i in 0..old.getExtensionCount(JsProtoBuf.propertyAnnotation) - 1) { + if (!checkEquals(old.getExtension(JsProtoBuf.propertyAnnotation, i), new.getExtension(JsProtoBuf.propertyAnnotation, i))) return false + } + + if (old.hasExtension(JsProtoBuf.compileTimeValue) != new.hasExtension(JsProtoBuf.compileTimeValue)) return false + if (old.hasExtension(JsProtoBuf.compileTimeValue)) { + if (!checkEquals(old.getExtension(JsProtoBuf.compileTimeValue), new.getExtension(JsProtoBuf.compileTimeValue))) return false + } + + if (old.hasExtension(JsProtoBuf.propertyContainingFileId) != new.hasExtension(JsProtoBuf.propertyContainingFileId)) return false + if (old.hasExtension(JsProtoBuf.propertyContainingFileId)) { + if (old.getExtension(JsProtoBuf.propertyContainingFileId) != new.getExtension(JsProtoBuf.propertyContainingFileId)) return false + } + return true } @@ -453,6 +516,12 @@ open class ProtoCompareGenerated(val oldNameResolver: NameResolver, val newNameR if (!checkEquals(old.getExtension(JvmProtoBuf.typeParameterAnnotation, i), new.getExtension(JvmProtoBuf.typeParameterAnnotation, i))) return false } + if (old.getExtensionCount(JsProtoBuf.typeParameterAnnotation) != new.getExtensionCount(JsProtoBuf.typeParameterAnnotation)) return false + + for(i in 0..old.getExtensionCount(JsProtoBuf.typeParameterAnnotation) - 1) { + if (!checkEquals(old.getExtension(JsProtoBuf.typeParameterAnnotation, i), new.getExtension(JsProtoBuf.typeParameterAnnotation, i))) return false + } + return true } @@ -535,6 +604,12 @@ open class ProtoCompareGenerated(val oldNameResolver: NameResolver, val newNameR if (old.getExtension(JvmProtoBuf.isRaw) != new.getExtension(JvmProtoBuf.isRaw)) return false } + if (old.getExtensionCount(JsProtoBuf.typeAnnotation) != new.getExtensionCount(JsProtoBuf.typeAnnotation)) return false + + for(i in 0..old.getExtensionCount(JsProtoBuf.typeAnnotation) - 1) { + if (!checkEquals(old.getExtension(JsProtoBuf.typeAnnotation, i), new.getExtension(JsProtoBuf.typeAnnotation, i))) return false + } + return true } @@ -556,6 +631,12 @@ open class ProtoCompareGenerated(val oldNameResolver: NameResolver, val newNameR if (!checkEquals(old.getExtension(JvmProtoBuf.constructorSignature), new.getExtension(JvmProtoBuf.constructorSignature))) return false } + if (old.getExtensionCount(JsProtoBuf.constructorAnnotation) != new.getExtensionCount(JsProtoBuf.constructorAnnotation)) return false + + for(i in 0..old.getExtensionCount(JsProtoBuf.constructorAnnotation) - 1) { + if (!checkEquals(old.getExtension(JsProtoBuf.constructorAnnotation, i), new.getExtension(JsProtoBuf.constructorAnnotation, i))) return false + } + return true } @@ -565,6 +646,20 @@ open class ProtoCompareGenerated(val oldNameResolver: NameResolver, val newNameR if (!checkStringEquals(old.name, new.name)) return false } + if (old.getExtensionCount(JsProtoBuf.enumEntryAnnotation) != new.getExtensionCount(JsProtoBuf.enumEntryAnnotation)) return false + + for(i in 0..old.getExtensionCount(JsProtoBuf.enumEntryAnnotation) - 1) { + if (!checkEquals(old.getExtension(JsProtoBuf.enumEntryAnnotation, i), new.getExtension(JsProtoBuf.enumEntryAnnotation, i))) return false + } + + return true + } + + open fun checkEquals(old: ProtoBuf.Annotation, new: ProtoBuf.Annotation): Boolean { + if (!checkClassIdEquals(old.id, new.id)) return false + + if (!checkEqualsAnnotationArgument(old, new)) return false + return true } @@ -596,6 +691,12 @@ open class ProtoCompareGenerated(val oldNameResolver: NameResolver, val newNameR if (old.varargElementTypeId != new.varargElementTypeId) return false } + if (old.getExtensionCount(JsProtoBuf.parameterAnnotation) != new.getExtensionCount(JsProtoBuf.parameterAnnotation)) return false + + for(i in 0..old.getExtensionCount(JsProtoBuf.parameterAnnotation) - 1) { + if (!checkEquals(old.getExtension(JsProtoBuf.parameterAnnotation, i), new.getExtension(JsProtoBuf.parameterAnnotation, i))) return false + } + return true } @@ -637,10 +738,48 @@ open class ProtoCompareGenerated(val oldNameResolver: NameResolver, val newNameR return true } - open fun checkEquals(old: ProtoBuf.Annotation, new: ProtoBuf.Annotation): Boolean { - if (!checkClassIdEquals(old.id, new.id)) return false + open fun checkEquals(old: ProtoBuf.Annotation.Argument.Value, new: ProtoBuf.Annotation.Argument.Value): Boolean { + if (old.hasType() != new.hasType()) return false + if (old.hasType()) { + if (old.type != new.type) return false + } - if (!checkEqualsAnnotationArgument(old, new)) return false + if (old.hasIntValue() != new.hasIntValue()) return false + if (old.hasIntValue()) { + if (old.intValue != new.intValue) return false + } + + if (old.hasFloatValue() != new.hasFloatValue()) return false + if (old.hasFloatValue()) { + if (old.floatValue != new.floatValue) return false + } + + if (old.hasDoubleValue() != new.hasDoubleValue()) return false + if (old.hasDoubleValue()) { + if (old.doubleValue != new.doubleValue) return false + } + + if (old.hasStringValue() != new.hasStringValue()) return false + if (old.hasStringValue()) { + if (!checkStringEquals(old.stringValue, new.stringValue)) return false + } + + if (old.hasClassId() != new.hasClassId()) return false + if (old.hasClassId()) { + if (!checkClassIdEquals(old.classId, new.classId)) return false + } + + if (old.hasEnumValueId() != new.hasEnumValueId()) return false + if (old.hasEnumValueId()) { + if (!checkStringEquals(old.enumValueId, new.enumValueId)) return false + } + + if (old.hasAnnotation() != new.hasAnnotation()) return false + if (old.hasAnnotation()) { + if (!checkEquals(old.annotation, new.annotation)) return false + } + + if (!checkEqualsAnnotationArgumentValueArrayElement(old, new)) return false return true } @@ -693,6 +832,14 @@ open class ProtoCompareGenerated(val oldNameResolver: NameResolver, val newNameR return true } + open fun checkEquals(old: ProtoBuf.Annotation.Argument, new: ProtoBuf.Annotation.Argument): Boolean { + if (!checkStringEquals(old.nameId, new.nameId)) return false + + if (!checkEquals(old.value, new.value)) return false + + return true + } + open fun checkEquals(old: JvmProtoBuf.JvmFieldSignature, new: JvmProtoBuf.JvmFieldSignature): Boolean { if (old.hasName() != new.hasName()) return false if (old.hasName()) { @@ -707,60 +854,6 @@ open class ProtoCompareGenerated(val oldNameResolver: NameResolver, val newNameR return true } - open fun checkEquals(old: ProtoBuf.Annotation.Argument, new: ProtoBuf.Annotation.Argument): Boolean { - if (!checkStringEquals(old.nameId, new.nameId)) return false - - if (!checkEquals(old.value, new.value)) return false - - return true - } - - open fun checkEquals(old: ProtoBuf.Annotation.Argument.Value, new: ProtoBuf.Annotation.Argument.Value): Boolean { - if (old.hasType() != new.hasType()) return false - if (old.hasType()) { - if (old.type != new.type) return false - } - - if (old.hasIntValue() != new.hasIntValue()) return false - if (old.hasIntValue()) { - if (old.intValue != new.intValue) return false - } - - if (old.hasFloatValue() != new.hasFloatValue()) return false - if (old.hasFloatValue()) { - if (old.floatValue != new.floatValue) return false - } - - if (old.hasDoubleValue() != new.hasDoubleValue()) return false - if (old.hasDoubleValue()) { - if (old.doubleValue != new.doubleValue) return false - } - - if (old.hasStringValue() != new.hasStringValue()) return false - if (old.hasStringValue()) { - if (!checkStringEquals(old.stringValue, new.stringValue)) return false - } - - if (old.hasClassId() != new.hasClassId()) return false - if (old.hasClassId()) { - if (!checkClassIdEquals(old.classId, new.classId)) return false - } - - if (old.hasEnumValueId() != new.hasEnumValueId()) return false - if (old.hasEnumValueId()) { - if (!checkStringEquals(old.enumValueId, new.enumValueId)) return false - } - - if (old.hasAnnotation() != new.hasAnnotation()) return false - if (old.hasAnnotation()) { - if (!checkEquals(old.annotation, new.annotation)) return false - } - - if (!checkEqualsAnnotationArgumentValueArrayElement(old, new)) return false - - return true - } - open fun checkEqualsPackageFunction(old: ProtoBuf.Package, new: ProtoBuf.Package): Boolean { if (old.functionCount != new.functionCount) return false @@ -1083,6 +1176,10 @@ fun ProtoBuf.Package.hashCode(stringIndexes: (Int) -> Int, fqNameIndexes: (Int) hashCode = 31 * hashCode + getExtension(JvmProtoBuf.packageLocalVariable, i).hashCode(stringIndexes, fqNameIndexes) } + if (hasExtension(JsProtoBuf.packageFqName)) { + hashCode = 31 * hashCode + getExtension(JsProtoBuf.packageFqName) + } + return hashCode } @@ -1159,6 +1256,14 @@ fun ProtoBuf.Class.hashCode(stringIndexes: (Int) -> Int, fqNameIndexes: (Int) -> hashCode = 31 * hashCode + getExtension(JvmProtoBuf.classLocalVariable, i).hashCode(stringIndexes, fqNameIndexes) } + for(i in 0..getExtensionCount(JsProtoBuf.classAnnotation) - 1) { + hashCode = 31 * hashCode + getExtension(JsProtoBuf.classAnnotation, i).hashCode(stringIndexes, fqNameIndexes) + } + + if (hasExtension(JsProtoBuf.classContainingFileId)) { + hashCode = 31 * hashCode + getExtension(JsProtoBuf.classContainingFileId) + } + return hashCode } @@ -1211,6 +1316,14 @@ fun ProtoBuf.Function.hashCode(stringIndexes: (Int) -> Int, fqNameIndexes: (Int) hashCode = 31 * hashCode + getExtension(JvmProtoBuf.methodSignature).hashCode(stringIndexes, fqNameIndexes) } + for(i in 0..getExtensionCount(JsProtoBuf.functionAnnotation) - 1) { + hashCode = 31 * hashCode + getExtension(JsProtoBuf.functionAnnotation, i).hashCode(stringIndexes, fqNameIndexes) + } + + if (hasExtension(JsProtoBuf.functionContainingFileId)) { + hashCode = 31 * hashCode + getExtension(JsProtoBuf.functionContainingFileId) + } + return hashCode } @@ -1267,6 +1380,18 @@ fun ProtoBuf.Property.hashCode(stringIndexes: (Int) -> Int, fqNameIndexes: (Int) hashCode = 31 * hashCode + getExtension(JvmProtoBuf.propertySignature).hashCode(stringIndexes, fqNameIndexes) } + for(i in 0..getExtensionCount(JsProtoBuf.propertyAnnotation) - 1) { + hashCode = 31 * hashCode + getExtension(JsProtoBuf.propertyAnnotation, i).hashCode(stringIndexes, fqNameIndexes) + } + + if (hasExtension(JsProtoBuf.compileTimeValue)) { + hashCode = 31 * hashCode + getExtension(JsProtoBuf.compileTimeValue).hashCode(stringIndexes, fqNameIndexes) + } + + if (hasExtension(JsProtoBuf.propertyContainingFileId)) { + hashCode = 31 * hashCode + getExtension(JsProtoBuf.propertyContainingFileId) + } + return hashCode } @@ -1361,6 +1486,10 @@ fun ProtoBuf.TypeParameter.hashCode(stringIndexes: (Int) -> Int, fqNameIndexes: hashCode = 31 * hashCode + getExtension(JvmProtoBuf.typeParameterAnnotation, i).hashCode(stringIndexes, fqNameIndexes) } + for(i in 0..getExtensionCount(JsProtoBuf.typeParameterAnnotation) - 1) { + hashCode = 31 * hashCode + getExtension(JsProtoBuf.typeParameterAnnotation, i).hashCode(stringIndexes, fqNameIndexes) + } + return hashCode } @@ -1431,6 +1560,10 @@ fun ProtoBuf.Type.hashCode(stringIndexes: (Int) -> Int, fqNameIndexes: (Int) -> hashCode = 31 * hashCode + getExtension(JvmProtoBuf.isRaw).hashCode() } + for(i in 0..getExtensionCount(JsProtoBuf.typeAnnotation) - 1) { + hashCode = 31 * hashCode + getExtension(JsProtoBuf.typeAnnotation, i).hashCode(stringIndexes, fqNameIndexes) + } + return hashCode } @@ -1453,6 +1586,10 @@ fun ProtoBuf.Constructor.hashCode(stringIndexes: (Int) -> Int, fqNameIndexes: (I hashCode = 31 * hashCode + getExtension(JvmProtoBuf.constructorSignature).hashCode(stringIndexes, fqNameIndexes) } + for(i in 0..getExtensionCount(JsProtoBuf.constructorAnnotation) - 1) { + hashCode = 31 * hashCode + getExtension(JsProtoBuf.constructorAnnotation, i).hashCode(stringIndexes, fqNameIndexes) + } + return hashCode } @@ -1463,6 +1600,22 @@ fun ProtoBuf.EnumEntry.hashCode(stringIndexes: (Int) -> Int, fqNameIndexes: (Int hashCode = 31 * hashCode + stringIndexes(name) } + for(i in 0..getExtensionCount(JsProtoBuf.enumEntryAnnotation) - 1) { + hashCode = 31 * hashCode + getExtension(JsProtoBuf.enumEntryAnnotation, i).hashCode(stringIndexes, fqNameIndexes) + } + + return hashCode +} + +fun ProtoBuf.Annotation.hashCode(stringIndexes: (Int) -> Int, fqNameIndexes: (Int) -> Int): Int { + var hashCode = 1 + + hashCode = 31 * hashCode + fqNameIndexes(id) + + for(i in 0..argumentCount - 1) { + hashCode = 31 * hashCode + getArgument(i).hashCode(stringIndexes, fqNameIndexes) + } + return hashCode } @@ -1491,6 +1644,10 @@ fun ProtoBuf.ValueParameter.hashCode(stringIndexes: (Int) -> Int, fqNameIndexes: hashCode = 31 * hashCode + varargElementTypeId } + for(i in 0..getExtensionCount(JsProtoBuf.parameterAnnotation) - 1) { + hashCode = 31 * hashCode + getExtension(JsProtoBuf.parameterAnnotation, i).hashCode(stringIndexes, fqNameIndexes) + } + return hashCode } @@ -1530,13 +1687,43 @@ fun JvmProtoBuf.JvmPropertySignature.hashCode(stringIndexes: (Int) -> Int, fqNam return hashCode } -fun ProtoBuf.Annotation.hashCode(stringIndexes: (Int) -> Int, fqNameIndexes: (Int) -> Int): Int { +fun ProtoBuf.Annotation.Argument.Value.hashCode(stringIndexes: (Int) -> Int, fqNameIndexes: (Int) -> Int): Int { var hashCode = 1 - hashCode = 31 * hashCode + fqNameIndexes(id) + if (hasType()) { + hashCode = 31 * hashCode + type.hashCode() + } - for(i in 0..argumentCount - 1) { - hashCode = 31 * hashCode + getArgument(i).hashCode(stringIndexes, fqNameIndexes) + if (hasIntValue()) { + hashCode = 31 * hashCode + intValue.hashCode() + } + + if (hasFloatValue()) { + hashCode = 31 * hashCode + floatValue.hashCode() + } + + if (hasDoubleValue()) { + hashCode = 31 * hashCode + doubleValue.hashCode() + } + + if (hasStringValue()) { + hashCode = 31 * hashCode + stringIndexes(stringValue) + } + + if (hasClassId()) { + hashCode = 31 * hashCode + fqNameIndexes(classId) + } + + if (hasEnumValueId()) { + hashCode = 31 * hashCode + stringIndexes(enumValueId) + } + + if (hasAnnotation()) { + hashCode = 31 * hashCode + annotation.hashCode(stringIndexes, fqNameIndexes) + } + + for(i in 0..arrayElementCount - 1) { + hashCode = 31 * hashCode + getArrayElement(i).hashCode(stringIndexes, fqNameIndexes) } return hashCode @@ -1586,6 +1773,16 @@ fun ProtoBuf.Type.Argument.hashCode(stringIndexes: (Int) -> Int, fqNameIndexes: return hashCode } +fun ProtoBuf.Annotation.Argument.hashCode(stringIndexes: (Int) -> Int, fqNameIndexes: (Int) -> Int): Int { + var hashCode = 1 + + hashCode = 31 * hashCode + stringIndexes(nameId) + + hashCode = 31 * hashCode + value.hashCode(stringIndexes, fqNameIndexes) + + return hashCode +} + fun JvmProtoBuf.JvmFieldSignature.hashCode(stringIndexes: (Int) -> Int, fqNameIndexes: (Int) -> Int): Int { var hashCode = 1 @@ -1599,55 +1796,3 @@ fun JvmProtoBuf.JvmFieldSignature.hashCode(stringIndexes: (Int) -> Int, fqNameIn return hashCode } - -fun ProtoBuf.Annotation.Argument.hashCode(stringIndexes: (Int) -> Int, fqNameIndexes: (Int) -> Int): Int { - var hashCode = 1 - - hashCode = 31 * hashCode + stringIndexes(nameId) - - hashCode = 31 * hashCode + value.hashCode(stringIndexes, fqNameIndexes) - - return hashCode -} - -fun ProtoBuf.Annotation.Argument.Value.hashCode(stringIndexes: (Int) -> Int, fqNameIndexes: (Int) -> Int): Int { - var hashCode = 1 - - if (hasType()) { - hashCode = 31 * hashCode + type.hashCode() - } - - if (hasIntValue()) { - hashCode = 31 * hashCode + intValue.hashCode() - } - - if (hasFloatValue()) { - hashCode = 31 * hashCode + floatValue.hashCode() - } - - if (hasDoubleValue()) { - hashCode = 31 * hashCode + doubleValue.hashCode() - } - - if (hasStringValue()) { - hashCode = 31 * hashCode + stringIndexes(stringValue) - } - - if (hasClassId()) { - hashCode = 31 * hashCode + fqNameIndexes(classId) - } - - if (hasEnumValueId()) { - hashCode = 31 * hashCode + stringIndexes(enumValueId) - } - - if (hasAnnotation()) { - hashCode = 31 * hashCode + annotation.hashCode(stringIndexes, fqNameIndexes) - } - - for(i in 0..arrayElementCount - 1) { - hashCode = 31 * hashCode + getArrayElement(i).hashCode(stringIndexes, fqNameIndexes) - } - - return hashCode -} diff --git a/build-common/src/org/jetbrains/kotlin/incremental/protoDifferenceUtils.kt b/build-common/src/org/jetbrains/kotlin/incremental/protoDifferenceUtils.kt index 912ac97f107..7ad8151bf4b 100644 --- a/build-common/src/org/jetbrains/kotlin/incremental/protoDifferenceUtils.kt +++ b/build-common/src/org/jetbrains/kotlin/incremental/protoDifferenceUtils.kt @@ -34,21 +34,42 @@ data class Difference( val changedMembersNames: Set = emptySet() ) -fun difference(oldData: ProtoMapValue, newData: ProtoMapValue): Difference { - if (!oldData.isPackageFacade && newData.isPackageFacade) return Difference(isClassAffected = true, areSubclassesAffected = true) +sealed class ProtoData +data class ClassProtoData(val proto: ProtoBuf.Class, val nameResolver: NameResolver) : ProtoData() +data class PackagePartProtoData(val proto: ProtoBuf.Package, val nameResolver: NameResolver) : ProtoData() - if (oldData.isPackageFacade && !newData.isPackageFacade) return Difference(isClassAffected = true) +fun ProtoMapValue.toProtoData(): ProtoData = + if (isPackageFacade) { + val packageData = JvmProtoBufUtil.readPackageDataFrom(bytes, strings) + PackagePartProtoData(packageData.packageProto, packageData.nameResolver) + } + else { + val classData = JvmProtoBufUtil.readClassDataFrom(bytes, strings) + ClassProtoData(classData.classProto, classData.nameResolver) + } - val differenceObject = - if (oldData.isPackageFacade) { - DifferenceCalculatorForPackageFacade(oldData, newData) +fun difference(oldValue: ProtoMapValue, newValue: ProtoMapValue): Difference = + difference(oldValue.toProtoData(), newValue.toProtoData()) + +fun difference(oldData: ProtoData, newData: ProtoData): Difference = + when (oldData) { + is ClassProtoData -> { + when (newData) { + is ClassProtoData -> + DifferenceCalculatorForClass(oldData, newData).difference() + is PackagePartProtoData -> + Difference(isClassAffected = true, areSubclassesAffected = true) + } } - else { - DifferenceCalculatorForClass(oldData, newData) + is PackagePartProtoData -> { + when (newData) { + is ClassProtoData -> + Difference(isClassAffected = true) + is PackagePartProtoData -> + DifferenceCalculatorForPackageFacade(oldData, newData).difference() + } } - - return differenceObject.difference() -} + } internal val MessageLite.isPrivate: Boolean get() = Visibilities.isPrivate(Deserialization.visibility( @@ -72,11 +93,8 @@ private fun MessageLite.name(nameResolver: NameResolver): String { internal fun List.names(nameResolver: NameResolver): List = map { it.name(nameResolver) } -private abstract class DifferenceCalculator() { - protected abstract val oldNameResolver: NameResolver - protected abstract val newNameResolver: NameResolver - - protected val compareObject by lazy { ProtoCompareGenerated(oldNameResolver, newNameResolver) } +private abstract class DifferenceCalculator { + protected abstract val compareObject: ProtoCompareGenerated abstract fun difference(): Difference @@ -158,19 +176,18 @@ private abstract class DifferenceCalculator() { } } -private class DifferenceCalculatorForClass(oldData: ProtoMapValue, newData: ProtoMapValue) : DifferenceCalculator() { - val oldClassData = JvmProtoBufUtil.readClassDataFrom(oldData.bytes, oldData.strings) - val newClassData = JvmProtoBufUtil.readClassDataFrom(newData.bytes, newData.strings) - - val oldProto = oldClassData.classProto - val newProto = newClassData.classProto - - override val oldNameResolver = oldClassData.nameResolver - override val newNameResolver = newClassData.nameResolver - - val diff = compareObject.difference(oldProto, newProto) +private class DifferenceCalculatorForClass( + private val oldData: ClassProtoData, + private val newData: ClassProtoData +) : DifferenceCalculator() { + override val compareObject = ProtoCompareGenerated(oldData.nameResolver, newData.nameResolver) override fun difference(): Difference { + val (oldProto, oldNameResolver) = oldData + val (newProto, newNameResolver) = newData + + val diff = compareObject.difference(oldProto, newProto) + var isClassAffected = false var areSubclassesAffected = false val names = hashSetOf() @@ -233,10 +250,12 @@ private class DifferenceCalculatorForClass(oldData: ProtoMapValue, newData: Prot isClassAffected = true areSubclassesAffected = true } - ProtoBufClassKind.CLASS_MODULE_NAME -> { - // TODO + ProtoBufClassKind.JVM_EXT_CLASS_MODULE_NAME, + ProtoBufClassKind.JS_EXT_CLASS_ANNOTATION_LIST, + ProtoBufClassKind.JS_EXT_CLASS_CONTAINING_FILE_ID -> { + // TODO } - ProtoBufClassKind.CLASS_LOCAL_VARIABLE_LIST -> { + ProtoBufClassKind.JVM_EXT_CLASS_LOCAL_VARIABLE_LIST -> { // Not affected, local variables are not accessible outside of a file } } @@ -246,19 +265,18 @@ private class DifferenceCalculatorForClass(oldData: ProtoMapValue, newData: Prot } } -private class DifferenceCalculatorForPackageFacade(oldData: ProtoMapValue, newData: ProtoMapValue) : DifferenceCalculator() { - val oldPackageData = JvmProtoBufUtil.readPackageDataFrom(oldData.bytes, oldData.strings) - val newPackageData = JvmProtoBufUtil.readPackageDataFrom(newData.bytes, newData.strings) - - val oldProto = oldPackageData.packageProto - val newProto = newPackageData.packageProto - - override val oldNameResolver = oldPackageData.nameResolver - override val newNameResolver = newPackageData.nameResolver - - val diff = compareObject.difference(oldProto, newProto) +private class DifferenceCalculatorForPackageFacade( + private val oldData: PackagePartProtoData, + private val newData: PackagePartProtoData +) : DifferenceCalculator() { + override val compareObject = ProtoCompareGenerated(oldData.nameResolver, newData.nameResolver) override fun difference(): Difference { + val oldProto = oldData.proto + val newProto = newData.proto + + val diff = compareObject.difference(oldProto, newProto) + val names = hashSetOf() fun calcDifferenceForNonPrivateMembers(members: (ProtoBuf.Package) -> List): Collection { @@ -278,10 +296,11 @@ private class DifferenceCalculatorForPackageFacade(oldData: ProtoMapValue, newDa names.addAll(calcDifferenceForNonPrivateMembers(ProtoBuf.Package::getTypeAliasList)) ProtoBufPackageKind.TYPE_TABLE, ProtoBufPackageKind.SINCE_KOTLIN_INFO_TABLE, - ProtoBufPackageKind.PACKAGE_MODULE_NAME -> { + ProtoBufPackageKind.JVM_EXT_PACKAGE_MODULE_NAME, + ProtoBufPackageKind.JS_EXT_PACKAGE_FQ_NAME-> { // TODO } - ProtoBufPackageKind.PACKAGE_LOCAL_VARIABLE_LIST -> { + ProtoBufPackageKind.JVM_EXT_PACKAGE_LOCAL_VARIABLE_LIST -> { // Not affected, local variables are not accessible outside of a file } } diff --git a/compiler/incremental-compilation-impl/test/org/jetbrains/kotlin/TestWithWorkingDir.kt b/build-common/test/org/jetbrains/kotlin/TestWithWorkingDir.kt similarity index 76% rename from compiler/incremental-compilation-impl/test/org/jetbrains/kotlin/TestWithWorkingDir.kt rename to build-common/test/org/jetbrains/kotlin/TestWithWorkingDir.kt index d80a93864e0..a63532fcb88 100644 --- a/compiler/incremental-compilation-impl/test/org/jetbrains/kotlin/TestWithWorkingDir.kt +++ b/build-common/test/org/jetbrains/kotlin/TestWithWorkingDir.kt @@ -1,5 +1,5 @@ /* - * Copyright 2010-2016 JetBrains s.r.o. + * Copyright 2010-2017 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,22 +17,25 @@ package org.jetbrains.kotlin import com.intellij.openapi.util.io.FileUtil +import junit.framework.TestCase import org.junit.After import org.junit.Before import java.io.File import kotlin.properties.Delegates -abstract class TestWithWorkingDir { +abstract class TestWithWorkingDir : TestCase() { protected var workingDir: File by Delegates.notNull() private set @Before - open fun setUp() { - workingDir = FileUtil.createTempDirectory(this::class.java.simpleName, null) + public override fun setUp() { + super.setUp() + workingDir = FileUtil.createTempDirectory(this::class.java.simpleName, null, /* deleteOnExit = */ true) } @After - open fun tearDown() { + public override fun tearDown() { workingDir.deleteRecursively() + super.tearDown() } } \ No newline at end of file diff --git a/generators/src/org/jetbrains/kotlin/generators/protobuf/GenerateProtoBufCompare.kt b/generators/src/org/jetbrains/kotlin/generators/protobuf/GenerateProtoBufCompare.kt index 570d75664d7..68e824f1d57 100644 --- a/generators/src/org/jetbrains/kotlin/generators/protobuf/GenerateProtoBufCompare.kt +++ b/generators/src/org/jetbrains/kotlin/generators/protobuf/GenerateProtoBufCompare.kt @@ -20,8 +20,10 @@ import org.jetbrains.kotlin.generators.util.GeneratorsFileUtil import org.jetbrains.kotlin.protobuf.Descriptors import org.jetbrains.kotlin.serialization.DebugExtOptionsProtoBuf import org.jetbrains.kotlin.serialization.DebugProtoBuf +import org.jetbrains.kotlin.serialization.js.DebugJsProtoBuf import org.jetbrains.kotlin.serialization.jvm.DebugJvmProtoBuf import org.jetbrains.kotlin.utils.Printer +import org.jetbrains.rpc.requestToByteBuf import java.io.File import java.util.* @@ -60,7 +62,9 @@ class GenerateProtoBufCompare { private val CHECK_CLASS_ID_EQUALS_NAME = "checkClassIdEquals" private val HASH_CODE_NAME = "hashCode" - private val extensionsMap = DebugJvmProtoBuf.getDescriptor().extensions.groupBy { it.containingType } + private val jvmExtensions = DebugJvmProtoBuf.getDescriptor().extensions + private val jsExtensions = DebugJsProtoBuf.getDescriptor().extensions + private val extensionsMap = (jvmExtensions + jsExtensions).groupBy { it.containingType } private val allMessages: MutableSet = linkedSetOf() private val messagesToProcess: Queue = LinkedList() @@ -77,6 +81,7 @@ class GenerateProtoBufCompare { p.println("import org.jetbrains.kotlin.serialization.ProtoBuf") p.println("import org.jetbrains.kotlin.serialization.deserialization.NameResolver") p.println("import org.jetbrains.kotlin.serialization.jvm.JvmProtoBuf") + p.println("import org.jetbrains.kotlin.serialization.js.JsProtoBuf") p.println("import org.jetbrains.kotlin.utils.Interner") p.println("import java.util.*") p.println() @@ -429,7 +434,18 @@ class GenerateProtoBufCompare { } private val Descriptors.FieldDescriptor.enumName: String - get() = (name.javaName + (if (isRepeated) "List" else "")).replace("[A-Z]".toRegex()) { "_" + it.value }.toUpperCase() + get() { + var extensionPrefix = "" + if (isExtension) { + if (this in jvmExtensions) { + extensionPrefix = "jvmExt_" + } + if (this in jsExtensions) { + extensionPrefix = "jsExt_" + } + } + return (extensionPrefix + name.javaName + (if (isRepeated) "List" else "")).replace("[A-Z]".toRegex()) { "_" + it.value }.toUpperCase() + } private fun Descriptors.FieldDescriptor.helperMethodName(): String { val packageHeader = this.file.`package` diff --git a/generators/src/org/jetbrains/kotlin/generators/tests/GenerateTests.kt b/generators/src/org/jetbrains/kotlin/generators/tests/GenerateTests.kt index e067d48ae2a..3280efdb3fe 100755 --- a/generators/src/org/jetbrains/kotlin/generators/tests/GenerateTests.kt +++ b/generators/src/org/jetbrains/kotlin/generators/tests/GenerateTests.kt @@ -150,6 +150,7 @@ import org.jetbrains.kotlin.j2k.AbstractJavaToKotlinConverterMultiFileTest import org.jetbrains.kotlin.j2k.AbstractJavaToKotlinConverterSingleFileTest import org.jetbrains.kotlin.jps.build.* import org.jetbrains.kotlin.jps.build.android.AbstractAndroidJpsTestCase +import org.jetbrains.kotlin.jps.incremental.AbstractJsProtoComparisonTest import org.jetbrains.kotlin.jps.incremental.AbstractJvmProtoComparisonTest import org.jetbrains.kotlin.js.test.AbstractDceTest import org.jetbrains.kotlin.js.test.AbstractJsLineNumberTest @@ -1211,15 +1212,24 @@ fun main(args: Array) { } } + testGroup("jps-plugin/jps-tests/test", "jps-plugin/testData") { + fun TestGroup.TestClass.commonProtoComparisonTests() { model("comparison/classSignatureChange", extension = null, excludeParentDirs = true) model("comparison/classPrivateOnlyChange", extension = null, excludeParentDirs = true) model("comparison/classMembersOnlyChanged", extension = null, excludeParentDirs = true) model("comparison/packageMembers", extension = null, excludeParentDirs = true) model("comparison/unchanged", extension = null, excludeParentDirs = true) } + testClass { + commonProtoComparisonTests() model("comparison/jvmOnly", extension = null, excludeParentDirs = true) + } + + testClass { + commonProtoComparisonTests() + } } testGroup("plugins/plugins-tests/tests", "plugins/android-extensions/android-extensions-compiler/testData") { diff --git a/jps-plugin/jps-tests/jps-tests.iml b/jps-plugin/jps-tests/jps-tests.iml index 3363179a26b..b4cb296a6a6 100644 --- a/jps-plugin/jps-tests/jps-tests.iml +++ b/jps-plugin/jps-tests/jps-tests.iml @@ -20,6 +20,9 @@ + + + \ No newline at end of file diff --git a/jps-plugin/jps-tests/test/org/jetbrains/kotlin/jps/incremental/AbstractJsProtoComparisonTest.kt b/jps-plugin/jps-tests/test/org/jetbrains/kotlin/jps/incremental/AbstractJsProtoComparisonTest.kt new file mode 100644 index 00000000000..ec8f4f73c5f --- /dev/null +++ b/jps-plugin/jps-tests/test/org/jetbrains/kotlin/jps/incremental/AbstractJsProtoComparisonTest.kt @@ -0,0 +1,97 @@ +/* + * Copyright 2010-2017 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.jps.incremental + +import org.jetbrains.kotlin.cli.common.arguments.K2JSCompilerArguments +import org.jetbrains.kotlin.cli.common.arguments.K2JsArgumentConstants +import org.jetbrains.kotlin.cli.js.K2JSCompiler +import org.jetbrains.kotlin.config.Services +import org.jetbrains.kotlin.incremental.ClassProtoData +import org.jetbrains.kotlin.incremental.Difference +import org.jetbrains.kotlin.incremental.difference as differenceImpl +import org.jetbrains.kotlin.incremental.PackagePartProtoData +import org.jetbrains.kotlin.incremental.ProtoData +import org.jetbrains.kotlin.incremental.utils.TestMessageCollector +import org.jetbrains.kotlin.incremental.js.IncrementalResultsConsumer +import org.jetbrains.kotlin.incremental.js.IncrementalResultsConsumerImpl +import org.jetbrains.kotlin.name.ClassId +import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.serialization.ProtoBuf +import org.jetbrains.kotlin.serialization.deserialization.NameResolverImpl +import org.jetbrains.kotlin.serialization.js.JsProtoBuf +import org.jetbrains.kotlin.serialization.js.JsSerializerProtocol +import org.junit.Assert +import java.io.File + +abstract class AbstractJsProtoComparisonTest : AbstractProtoComparisonTest() { + override fun expectedOutputFile(testDir: File): File = + File(testDir, "js.result.out") + .takeIf { it.exists() } + ?: super.expectedOutputFile(testDir) + + override fun compileAndGetClasses(sourceDir: File, outputDir: File): Map { + val incrementalResults = IncrementalResultsConsumerImpl() + // todo: find out if it is safe to call directly + val services = Services.Builder().run { + register(IncrementalResultsConsumer::class.java, incrementalResults) + build() + } + + val ktFiles = sourceDir.walkMatching { it.name.endsWith(".kt") }.map { it.canonicalPath }.toList() + val messageCollector = TestMessageCollector() + val args = K2JSCompilerArguments().apply { + outputFile = File(outputDir, "out.js").canonicalPath + metaInfo = true + main = K2JsArgumentConstants.NO_CALL + freeArgs.addAll(ktFiles) + } + + K2JSCompiler().exec(messageCollector, services, args).let { exitCode -> + val expectedOutput = "OK" + val actualOutput = (listOf(exitCode.name) + messageCollector.errors).joinToString("\n") + Assert.assertEquals(expectedOutput, actualOutput) + } + + val classes = hashMapOf() + + for ((sourceFile, protoBytes, _) in incrementalResults.packageParts) { + val proto = ProtoBuf.PackageFragment.parseFrom(protoBytes, JsSerializerProtocol.extensionRegistry) + val nameResolver = NameResolverImpl(proto.strings, proto.qualifiedNames) + + proto.class_List.forEach { + val classId = nameResolver.getClassId(it.fqName) + classes[classId] = ClassProtoData(it, nameResolver) + } + + proto.`package`.apply { + val packageFqName = if (hasExtension(JsProtoBuf.packageFqName)) { + nameResolver.getPackageFqName(getExtension(JsProtoBuf.packageFqName)) + } + else FqName.ROOT + + val packagePartClassId = ClassId(packageFqName, Name.identifier(sourceFile.nameWithoutExtension.capitalize() + "Kt")) + classes[packagePartClassId] = PackagePartProtoData(this, nameResolver) + } + } + + return classes + } + + override fun difference(oldData: ProtoData, newData: ProtoData): Difference? = + differenceImpl(oldData, newData) +} diff --git a/jps-plugin/jps-tests/test/org/jetbrains/kotlin/jps/incremental/AbstractJvmProtoComparisonTest.kt b/jps-plugin/jps-tests/test/org/jetbrains/kotlin/jps/incremental/AbstractJvmProtoComparisonTest.kt index 36ce3fc2eba..f14ea22eab1 100644 --- a/jps-plugin/jps-tests/test/org/jetbrains/kotlin/jps/incremental/AbstractJvmProtoComparisonTest.kt +++ b/jps-plugin/jps-tests/test/org/jetbrains/kotlin/jps/incremental/AbstractJvmProtoComparisonTest.kt @@ -20,7 +20,6 @@ import org.jetbrains.kotlin.incremental.Difference import org.jetbrains.kotlin.incremental.LocalFileKotlinClass import org.jetbrains.kotlin.incremental.difference import org.jetbrains.kotlin.incremental.storage.ProtoMapValue -import org.jetbrains.kotlin.incremental.testingUtils.copyTestSources import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinaryClass import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader import org.jetbrains.kotlin.name.ClassId @@ -40,7 +39,7 @@ abstract class AbstractJvmProtoComparisonTest : AbstractProtoComparisonTest : UsefulTestCase() { +abstract class AbstractProtoComparisonTest : TestWithWorkingDir() { protected abstract fun compileAndGetClasses(sourceDir: File, outputDir: File): Map protected abstract fun difference(oldData: PROTO_DATA, newData: PROTO_DATA): Difference? + protected open fun expectedOutputFile(testDir: File): File = + File(testDir, "result.out") + fun doTest(testDataPath: String) { val testDir = File(testDataPath) - val workingDir = KotlinTestUtils.tmpDir("testDirectory") val oldClassMap = classesForPrefixedSources(testDir, workingDir, "old") val newClassMap = classesForPrefixedSources(testDir, workingDir, "new") @@ -69,7 +72,7 @@ abstract class AbstractProtoComparisonTest : UsefulTestCase() { p.println("CHANGES in $classId: ${changes.joinToString()}") } - KotlinTestUtils.assertEqualsToFile(File(testDataPath + File.separator + "result.out"), sb.toString()) + KotlinTestUtils.assertEqualsToFile(expectedOutputFile(testDir), sb.toString()) } private fun classesForPrefixedSources(testDir: File, workingDir: File, prefix: String): Map { diff --git a/jps-plugin/jps-tests/test/org/jetbrains/kotlin/jps/incremental/JsProtoComparisonTestGenerated.java b/jps-plugin/jps-tests/test/org/jetbrains/kotlin/jps/incremental/JsProtoComparisonTestGenerated.java new file mode 100644 index 00000000000..57af389c73c --- /dev/null +++ b/jps-plugin/jps-tests/test/org/jetbrains/kotlin/jps/incremental/JsProtoComparisonTestGenerated.java @@ -0,0 +1,221 @@ +/* + * Copyright 2010-2017 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.jps.incremental; + +import com.intellij.testFramework.TestDataPath; +import org.jetbrains.kotlin.test.JUnit3RunnerWithInners; +import org.jetbrains.kotlin.test.KotlinTestUtils; +import org.jetbrains.kotlin.test.TargetBackend; +import org.jetbrains.kotlin.test.TestMetadata; +import org.junit.runner.RunWith; + +import java.io.File; +import java.util.regex.Pattern; + +/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */ +@SuppressWarnings("all") +@RunWith(JUnit3RunnerWithInners.class) +public class JsProtoComparisonTestGenerated extends AbstractJsProtoComparisonTest { + @TestMetadata("jps-plugin/testData/comparison/classSignatureChange") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class ClassSignatureChange extends AbstractJsProtoComparisonTest { + public void testAllFilesPresentInClassSignatureChange() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("jps-plugin/testData/comparison/classSignatureChange"), Pattern.compile("^([^\\.]+)$"), TargetBackend.ANY, true); + } + + @TestMetadata("classAnnotationListChanged") + public void testClassAnnotationListChanged() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("jps-plugin/testData/comparison/classSignatureChange/classAnnotationListChanged/"); + doTest(fileName); + } + + @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/"); + doTest(fileName); + } + + @TestMetadata("classTypeParameterListChanged") + public void testClassTypeParameterListChanged() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("jps-plugin/testData/comparison/classSignatureChange/classTypeParameterListChanged/"); + doTest(fileName); + } + + @TestMetadata("classWithSuperTypeListChanged") + public void testClassWithSuperTypeListChanged() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("jps-plugin/testData/comparison/classSignatureChange/classWithSuperTypeListChanged/"); + doTest(fileName); + } + } + + @TestMetadata("jps-plugin/testData/comparison/classPrivateOnlyChange") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class ClassPrivateOnlyChange extends AbstractJsProtoComparisonTest { + public void testAllFilesPresentInClassPrivateOnlyChange() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("jps-plugin/testData/comparison/classPrivateOnlyChange"), Pattern.compile("^([^\\.]+)$"), TargetBackend.ANY, true); + } + + @TestMetadata("classWithPrivateFunChanged") + public void testClassWithPrivateFunChanged() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("jps-plugin/testData/comparison/classPrivateOnlyChange/classWithPrivateFunChanged/"); + doTest(fileName); + } + + @TestMetadata("classWithPrivatePrimaryConstructorChanged") + public void testClassWithPrivatePrimaryConstructorChanged() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("jps-plugin/testData/comparison/classPrivateOnlyChange/classWithPrivatePrimaryConstructorChanged/"); + doTest(fileName); + } + + @TestMetadata("classWithPrivateSecondaryConstructorChanged") + public void testClassWithPrivateSecondaryConstructorChanged() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("jps-plugin/testData/comparison/classPrivateOnlyChange/classWithPrivateSecondaryConstructorChanged/"); + doTest(fileName); + } + + @TestMetadata("classWithPrivateValChanged") + public void testClassWithPrivateValChanged() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("jps-plugin/testData/comparison/classPrivateOnlyChange/classWithPrivateValChanged/"); + doTest(fileName); + } + + @TestMetadata("classWithPrivateVarChanged") + public void testClassWithPrivateVarChanged() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("jps-plugin/testData/comparison/classPrivateOnlyChange/classWithPrivateVarChanged/"); + doTest(fileName); + } + } + + @TestMetadata("jps-plugin/testData/comparison/classMembersOnlyChanged") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class ClassMembersOnlyChanged extends AbstractJsProtoComparisonTest { + public void testAllFilesPresentInClassMembersOnlyChanged() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("jps-plugin/testData/comparison/classMembersOnlyChanged"), Pattern.compile("^([^\\.]+)$"), TargetBackend.ANY, true); + } + + @TestMetadata("classWithCompanionObjectChanged") + public void testClassWithCompanionObjectChanged() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("jps-plugin/testData/comparison/classMembersOnlyChanged/classWithCompanionObjectChanged/"); + doTest(fileName); + } + + @TestMetadata("classWithConstructorChanged") + public void testClassWithConstructorChanged() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("jps-plugin/testData/comparison/classMembersOnlyChanged/classWithConstructorChanged/"); + doTest(fileName); + } + + @TestMetadata("classWithFunAndValChanged") + public void testClassWithFunAndValChanged() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("jps-plugin/testData/comparison/classMembersOnlyChanged/classWithFunAndValChanged/"); + doTest(fileName); + } + + @TestMetadata("classWithNestedClassesChanged") + public void testClassWithNestedClassesChanged() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("jps-plugin/testData/comparison/classMembersOnlyChanged/classWithNestedClassesChanged/"); + doTest(fileName); + } + + @TestMetadata("classWitnEnumChanged") + public void testClassWitnEnumChanged() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("jps-plugin/testData/comparison/classMembersOnlyChanged/classWitnEnumChanged/"); + doTest(fileName); + } + + @TestMetadata("defaultValues") + public void testDefaultValues() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("jps-plugin/testData/comparison/classMembersOnlyChanged/defaultValues/"); + doTest(fileName); + } + + @TestMetadata("membersFlagsChanged") + public void testMembersFlagsChanged() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("jps-plugin/testData/comparison/classMembersOnlyChanged/membersFlagsChanged/"); + doTest(fileName); + } + + @TestMetadata("sealedClassImplAdded") + public void testSealedClassImplAdded() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("jps-plugin/testData/comparison/classMembersOnlyChanged/sealedClassImplAdded/"); + doTest(fileName); + } + } + + @TestMetadata("jps-plugin/testData/comparison/packageMembers") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class PackageMembers extends AbstractJsProtoComparisonTest { + public void testAllFilesPresentInPackageMembers() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("jps-plugin/testData/comparison/packageMembers"), Pattern.compile("^([^\\.]+)$"), TargetBackend.ANY, true); + } + + @TestMetadata("defaultValues") + public void testDefaultValues() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("jps-plugin/testData/comparison/packageMembers/defaultValues/"); + doTest(fileName); + } + + @TestMetadata("membersFlagsChanged") + public void testMembersFlagsChanged() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("jps-plugin/testData/comparison/packageMembers/membersFlagsChanged/"); + doTest(fileName); + } + + @TestMetadata("packageFacadePrivateOnlyChanges") + public void testPackageFacadePrivateOnlyChanges() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("jps-plugin/testData/comparison/packageMembers/packageFacadePrivateOnlyChanges/"); + doTest(fileName); + } + + @TestMetadata("packageFacadePublicChanges") + public void testPackageFacadePublicChanges() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("jps-plugin/testData/comparison/packageMembers/packageFacadePublicChanges/"); + doTest(fileName); + } + } + + @TestMetadata("jps-plugin/testData/comparison/unchanged") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Unchanged extends AbstractJsProtoComparisonTest { + public void testAllFilesPresentInUnchanged() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("jps-plugin/testData/comparison/unchanged"), Pattern.compile("^([^\\.]+)$"), TargetBackend.ANY, true); + } + + @TestMetadata("unchangedClass") + public void testUnchangedClass() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("jps-plugin/testData/comparison/unchanged/unchangedClass/"); + doTest(fileName); + } + + @TestMetadata("unchangedPackageFacade") + public void testUnchangedPackageFacade() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("jps-plugin/testData/comparison/unchanged/unchangedPackageFacade/"); + doTest(fileName); + } + } +} diff --git a/jps-plugin/testData/comparison/classMembersOnlyChanged/classWitnEnumChanged/js.result.out b/jps-plugin/testData/comparison/classMembersOnlyChanged/classWitnEnumChanged/js.result.out new file mode 100644 index 00000000000..add71453244 --- /dev/null +++ b/jps-plugin/testData/comparison/classMembersOnlyChanged/classWitnEnumChanged/js.result.out @@ -0,0 +1,4 @@ +REMOVED test/EnumClassWithChanges.CONST_2 +ADDED test/EnumClassWithChanges.CONST_3 +ADDED test/EnumClassWithChanges.CONST_4 +CHANGES in test/EnumClassWithChanges: CLASS_SIGNATURE