Drop KotlinClassHeader#filePartClassNames, use 'data' instead
This commit is contained in:
@@ -27,7 +27,7 @@ import org.jetbrains.kotlin.serialization.jvm.JvmProtoBufUtil
|
|||||||
|
|
||||||
fun inlineFunctionsJvmNames(bytes: ByteArray): Set<String> {
|
fun inlineFunctionsJvmNames(bytes: ByteArray): Set<String> {
|
||||||
val header = readKotlinHeader(bytes)
|
val header = readKotlinHeader(bytes)
|
||||||
val annotationData = header.annotationData
|
val annotationData = header.data
|
||||||
val strings = header.strings
|
val strings = header.strings
|
||||||
|
|
||||||
if (annotationData == null || strings == null) return emptySet()
|
if (annotationData == null || strings == null) return emptySet()
|
||||||
|
|||||||
+1
-1
@@ -119,7 +119,7 @@ public final class DeserializedDescriptorResolver {
|
|||||||
errorReporter.reportIncompatibleMetadataVersion(kotlinClass.getClassId(), kotlinClass.getLocation(), header.getMetadataVersion());
|
errorReporter.reportIncompatibleMetadataVersion(kotlinClass.getClassId(), kotlinClass.getLocation(), header.getMetadataVersion());
|
||||||
}
|
}
|
||||||
else if (expectedKinds.contains(header.getKind())) {
|
else if (expectedKinds.contains(header.getKind())) {
|
||||||
return header.getAnnotationData();
|
return header.getData();
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
+1
-2
@@ -23,9 +23,8 @@ class KotlinClassHeader(
|
|||||||
val kind: KotlinClassHeader.Kind,
|
val kind: KotlinClassHeader.Kind,
|
||||||
val metadataVersion: JvmMetadataVersion,
|
val metadataVersion: JvmMetadataVersion,
|
||||||
val bytecodeVersion: JvmBytecodeBinaryVersion,
|
val bytecodeVersion: JvmBytecodeBinaryVersion,
|
||||||
val annotationData: Array<String>?,
|
val data: Array<String>?,
|
||||||
val strings: Array<String>?,
|
val strings: Array<String>?,
|
||||||
val filePartClassNames: Array<String>?,
|
|
||||||
val multifileClassName: String?,
|
val multifileClassName: String?,
|
||||||
val isInterfaceDefaultImpls: Boolean,
|
val isInterfaceDefaultImpls: Boolean,
|
||||||
val isLocalClass: Boolean
|
val isLocalClass: Boolean
|
||||||
|
|||||||
+6
-20
@@ -48,8 +48,7 @@ public class ReadKotlinClassHeaderAnnotationVisitor implements AnnotationVisitor
|
|||||||
private JvmMetadataVersion metadataVersion = null;
|
private JvmMetadataVersion metadataVersion = null;
|
||||||
private JvmBytecodeBinaryVersion bytecodeVersion = null;
|
private JvmBytecodeBinaryVersion bytecodeVersion = null;
|
||||||
private String multifileClassName = null;
|
private String multifileClassName = null;
|
||||||
private String[] filePartClassNames = null;
|
private String[] data = null;
|
||||||
private String[] annotationData = null;
|
|
||||||
private String[] strings = null;
|
private String[] strings = null;
|
||||||
private KotlinClassHeader.Kind headerKind = null;
|
private KotlinClassHeader.Kind headerKind = null;
|
||||||
private boolean isInterfaceDefaultImpls = false;
|
private boolean isInterfaceDefaultImpls = false;
|
||||||
@@ -62,9 +61,9 @@ public class ReadKotlinClassHeaderAnnotationVisitor implements AnnotationVisitor
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (metadataVersion == null || !metadataVersion.isCompatible()) {
|
if (metadataVersion == null || !metadataVersion.isCompatible()) {
|
||||||
annotationData = null;
|
data = null;
|
||||||
}
|
}
|
||||||
else if (shouldHaveData() && annotationData == null) {
|
else if (shouldHaveData() && data == null) {
|
||||||
// This means that the annotation is found and its ABI version is compatible, but there's no "data" string array in it.
|
// This means that the annotation is found and its ABI version is compatible, but there's no "data" string array in it.
|
||||||
// We tell the outside world that there's really no annotation at all
|
// We tell the outside world that there's really no annotation at all
|
||||||
return null;
|
return null;
|
||||||
@@ -74,7 +73,7 @@ public class ReadKotlinClassHeaderAnnotationVisitor implements AnnotationVisitor
|
|||||||
headerKind,
|
headerKind,
|
||||||
metadataVersion != null ? metadataVersion : JvmMetadataVersion.INVALID_VERSION,
|
metadataVersion != null ? metadataVersion : JvmMetadataVersion.INVALID_VERSION,
|
||||||
bytecodeVersion != null ? bytecodeVersion : JvmBytecodeBinaryVersion.INVALID_VERSION,
|
bytecodeVersion != null ? bytecodeVersion : JvmBytecodeBinaryVersion.INVALID_VERSION,
|
||||||
annotationData, strings, filePartClassNames, multifileClassName, isInterfaceDefaultImpls, isLocalClass
|
data, strings, multifileClassName, isInterfaceDefaultImpls, isLocalClass
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -140,36 +139,23 @@ public class ReadKotlinClassHeaderAnnotationVisitor implements AnnotationVisitor
|
|||||||
@Nullable
|
@Nullable
|
||||||
public AnnotationArrayArgumentVisitor visitArray(@NotNull Name name) {
|
public AnnotationArrayArgumentVisitor visitArray(@NotNull Name name) {
|
||||||
String string = name.asString();
|
String string = name.asString();
|
||||||
if (DATA_FIELD_NAME.equals(string)) {
|
if (DATA_FIELD_NAME.equals(string) || FILE_PART_CLASS_NAMES_FIELD_NAME.equals(string)) {
|
||||||
return dataArrayVisitor();
|
return dataArrayVisitor();
|
||||||
}
|
}
|
||||||
else if (STRINGS_FIELD_NAME.equals(string)) {
|
else if (STRINGS_FIELD_NAME.equals(string)) {
|
||||||
return stringsArrayVisitor();
|
return stringsArrayVisitor();
|
||||||
}
|
}
|
||||||
else if (FILE_PART_CLASS_NAMES_FIELD_NAME.equals(string)) {
|
|
||||||
return filePartClassNamesVisitor();
|
|
||||||
}
|
|
||||||
else {
|
else {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
|
||||||
private AnnotationArrayArgumentVisitor filePartClassNamesVisitor() {
|
|
||||||
return new CollectStringArrayAnnotationVisitor() {
|
|
||||||
@Override
|
|
||||||
protected void visitEnd(@NotNull String[] data) {
|
|
||||||
filePartClassNames = data;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
private AnnotationArrayArgumentVisitor dataArrayVisitor() {
|
private AnnotationArrayArgumentVisitor dataArrayVisitor() {
|
||||||
return new CollectStringArrayAnnotationVisitor() {
|
return new CollectStringArrayAnnotationVisitor() {
|
||||||
@Override
|
@Override
|
||||||
protected void visitEnd(@NotNull String[] data) {
|
protected void visitEnd(@NotNull String[] data) {
|
||||||
annotationData = data;
|
ReadKotlinClassHeaderAnnotationVisitor.this.data = data;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -76,10 +76,10 @@ fun isKotlinInternalCompiledFile(file: VirtualFile): Boolean {
|
|||||||
header.isLocalClass
|
header.isLocalClass
|
||||||
}
|
}
|
||||||
|
|
||||||
fun findMultifileClassParts(file: VirtualFile, classId: ClassId, kotlinClassHeader: KotlinClassHeader): List<KotlinJvmBinaryClass> {
|
fun findMultifileClassParts(file: VirtualFile, classId: ClassId, header: KotlinClassHeader): List<KotlinJvmBinaryClass> {
|
||||||
val packageFqName = classId.packageFqName
|
val packageFqName = classId.packageFqName
|
||||||
val partsFinder = DirectoryBasedClassFinder(file.parent!!, packageFqName)
|
val partsFinder = DirectoryBasedClassFinder(file.parent!!, packageFqName)
|
||||||
val partNames = kotlinClassHeader.filePartClassNames ?: return emptyList()
|
val partNames = header.data ?: return emptyList()
|
||||||
return partNames.mapNotNull {
|
return partNames.mapNotNull {
|
||||||
partsFinder.findKotlinClass(ClassId(packageFqName, Name.identifier(it.substringAfterLast('/'))))
|
partsFinder.findKotlinClass(ClassId(packageFqName, Name.identifier(it.substringAfterLast('/'))))
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -72,7 +72,7 @@ class DeserializerForClassfileDecompiler(
|
|||||||
}
|
}
|
||||||
val binaryClassForPackageClass = classFinder.findKotlinClass(ClassId.topLevel(facadeFqName))
|
val binaryClassForPackageClass = classFinder.findKotlinClass(ClassId.topLevel(facadeFqName))
|
||||||
val header = binaryClassForPackageClass?.classHeader
|
val header = binaryClassForPackageClass?.classHeader
|
||||||
val annotationData = header?.annotationData
|
val annotationData = header?.data
|
||||||
val strings = header?.strings
|
val strings = header?.strings
|
||||||
if (annotationData == null || strings == null) {
|
if (annotationData == null || strings == null) {
|
||||||
LOG.error("Could not read annotation data for $facadeFqName from ${binaryClassForPackageClass?.classId}")
|
LOG.error("Could not read annotation data for $facadeFqName from ${binaryClassForPackageClass?.classId}")
|
||||||
@@ -117,7 +117,7 @@ class DirectoryBasedDataFinder(
|
|||||||
override fun findClassData(classId: ClassId): ClassDataWithSource? {
|
override fun findClassData(classId: ClassId): ClassDataWithSource? {
|
||||||
val binaryClass = classFinder.findKotlinClass(classId) ?: return null
|
val binaryClass = classFinder.findKotlinClass(classId) ?: return null
|
||||||
val classHeader = binaryClass.classHeader
|
val classHeader = binaryClass.classHeader
|
||||||
val data = classHeader.annotationData
|
val data = classHeader.data
|
||||||
if (data == null) {
|
if (data == null) {
|
||||||
log.error("Annotation data missing for ${binaryClass.classId}")
|
log.error("Annotation data missing for ${binaryClass.classId}")
|
||||||
return null
|
return null
|
||||||
|
|||||||
+1
-1
@@ -70,7 +70,7 @@ open class KotlinClsStubBuilder : ClsStubBuilder() {
|
|||||||
return createMultifileClassStub(header, partFiles, classId.asSingleFqName(), components)
|
return createMultifileClassStub(header, partFiles, classId.asSingleFqName(), components)
|
||||||
}
|
}
|
||||||
|
|
||||||
val annotationData = header.annotationData
|
val annotationData = header.data
|
||||||
if (annotationData == null) {
|
if (annotationData == null) {
|
||||||
LOG.error("Corrupted kotlin header for file ${file.name}")
|
LOG.error("Corrupted kotlin header for file ${file.name}")
|
||||||
return null
|
return null
|
||||||
|
|||||||
+3
-3
@@ -75,18 +75,18 @@ fun createFileFacadeStub(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun createMultifileClassStub(
|
fun createMultifileClassStub(
|
||||||
kotlinClassHeader: KotlinClassHeader,
|
header: KotlinClassHeader,
|
||||||
partFiles: List<KotlinJvmBinaryClass>,
|
partFiles: List<KotlinJvmBinaryClass>,
|
||||||
facadeFqName: FqName,
|
facadeFqName: FqName,
|
||||||
components: ClsStubBuilderComponents
|
components: ClsStubBuilderComponents
|
||||||
): KotlinFileStubImpl {
|
): KotlinFileStubImpl {
|
||||||
val packageFqName = facadeFqName.parent()
|
val packageFqName = facadeFqName.parent()
|
||||||
val partNames = kotlinClassHeader.filePartClassNames?.asList()?.map { it.substringAfterLast('/') }
|
val partNames = header.data?.asList()?.map { it.substringAfterLast('/') }
|
||||||
val fileStub = KotlinFileStubForIde.forMultifileClassStub(facadeFqName, partNames, packageFqName.isRoot)
|
val fileStub = KotlinFileStubForIde.forMultifileClassStub(facadeFqName, partNames, packageFqName.isRoot)
|
||||||
setupFileStub(fileStub, packageFqName)
|
setupFileStub(fileStub, packageFqName)
|
||||||
for (partFile in partFiles) {
|
for (partFile in partFiles) {
|
||||||
val partHeader = partFile.classHeader
|
val partHeader = partFile.classHeader
|
||||||
val (nameResolver, packageProto) = JvmProtoBufUtil.readPackageDataFrom(partHeader.annotationData!!, partHeader.strings!!)
|
val (nameResolver, packageProto) = JvmProtoBufUtil.readPackageDataFrom(partHeader.data!!, partHeader.strings!!)
|
||||||
val partContext = components.createContext(nameResolver, packageFqName, TypeTable(packageProto.typeTable))
|
val partContext = components.createContext(nameResolver, packageFqName, TypeTable(packageProto.typeTable))
|
||||||
val container = ProtoContainer.Package(packageFqName, partContext.nameResolver, partContext.typeTable,
|
val container = ProtoContainer.Package(packageFqName, partContext.nameResolver, partContext.typeTable,
|
||||||
JvmPackagePartSource(partFile.classId))
|
JvmPackagePartSource(partFile.classId))
|
||||||
|
|||||||
@@ -158,7 +158,7 @@ open class IncrementalCacheImpl(
|
|||||||
additionalProcessChangedClass(kotlinClass, isPackage = true)
|
additionalProcessChangedClass(kotlinClass, isPackage = true)
|
||||||
}
|
}
|
||||||
KotlinClassHeader.Kind.MULTIFILE_CLASS -> {
|
KotlinClassHeader.Kind.MULTIFILE_CLASS -> {
|
||||||
val partNames = kotlinClass.classHeader.filePartClassNames?.toList()
|
val partNames = kotlinClass.classHeader.data?.toList()
|
||||||
?: throw AssertionError("Multifile class has no parts: ${kotlinClass.className}")
|
?: throw AssertionError("Multifile class has no parts: ${kotlinClass.className}")
|
||||||
multifileClassFacadeMap.add(className, partNames)
|
multifileClassFacadeMap.add(className, partNames)
|
||||||
|
|
||||||
@@ -324,7 +324,7 @@ open class IncrementalCacheImpl(
|
|||||||
|
|
||||||
fun process(kotlinClass: LocalFileKotlinClass, isPackage: Boolean): CompilationResult {
|
fun process(kotlinClass: LocalFileKotlinClass, isPackage: Boolean): CompilationResult {
|
||||||
val header = kotlinClass.classHeader
|
val header = kotlinClass.classHeader
|
||||||
val bytes = BitEncoding.decodeBytes(header.annotationData!!)
|
val bytes = BitEncoding.decodeBytes(header.data!!)
|
||||||
return put(kotlinClass.className, bytes, header.strings!!, isPackage, checkChangesIsOpenPart = true)
|
return put(kotlinClass.className, bytes, header.strings!!, isPackage, checkChangesIsOpenPart = true)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -498,7 +498,7 @@ open class IncrementalCacheImpl(
|
|||||||
private fun addToClassStorage(kotlinClass: LocalFileKotlinClass) {
|
private fun addToClassStorage(kotlinClass: LocalFileKotlinClass) {
|
||||||
if (!IncrementalCompilation.isExperimental()) return
|
if (!IncrementalCompilation.isExperimental()) return
|
||||||
|
|
||||||
val classData = JvmProtoBufUtil.readClassDataFrom(kotlinClass.classHeader.annotationData!!, kotlinClass.classHeader.strings!!)
|
val classData = JvmProtoBufUtil.readClassDataFrom(kotlinClass.classHeader.data!!, kotlinClass.classHeader.strings!!)
|
||||||
val supertypes = classData.classProto.supertypes(TypeTable(classData.classProto.typeTable))
|
val supertypes = classData.classProto.supertypes(TypeTable(classData.classProto.typeTable))
|
||||||
val parents = supertypes.map { classData.nameResolver.getClassId(it.className).asSingleFqName() }
|
val parents = supertypes.map { classData.nameResolver.getClassId(it.className).asSingleFqName() }
|
||||||
.filter { it.asString() != "kotlin.Any" }
|
.filter { it.asString() != "kotlin.Any" }
|
||||||
|
|||||||
+1
-1
@@ -132,7 +132,7 @@ fun classFileToString(classFile: File): String {
|
|||||||
|
|
||||||
val classHeader = LocalFileKotlinClass.create(classFile)?.classHeader
|
val classHeader = LocalFileKotlinClass.create(classFile)?.classHeader
|
||||||
|
|
||||||
val annotationDataEncoded = classHeader?.annotationData
|
val annotationDataEncoded = classHeader?.data
|
||||||
if (annotationDataEncoded != null) {
|
if (annotationDataEncoded != null) {
|
||||||
ByteArrayInputStream(BitEncoding.decodeBytes(annotationDataEncoded)).use {
|
ByteArrayInputStream(BitEncoding.decodeBytes(annotationDataEncoded)).use {
|
||||||
input ->
|
input ->
|
||||||
|
|||||||
+24
-36
@@ -20,6 +20,7 @@ import com.intellij.openapi.util.io.FileUtil
|
|||||||
import com.intellij.testFramework.UsefulTestCase
|
import com.intellij.testFramework.UsefulTestCase
|
||||||
import com.intellij.util.SmartList
|
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.KotlinJvmBinaryClass
|
||||||
import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader
|
import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader
|
||||||
import org.jetbrains.kotlin.serialization.jvm.BitEncoding
|
import org.jetbrains.kotlin.serialization.jvm.BitEncoding
|
||||||
import org.jetbrains.kotlin.test.KotlinTestUtils
|
import org.jetbrains.kotlin.test.KotlinTestUtils
|
||||||
@@ -28,7 +29,6 @@ import org.jetbrains.kotlin.utils.Printer
|
|||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
abstract class AbstractProtoComparisonTest : UsefulTestCase() {
|
abstract class AbstractProtoComparisonTest : UsefulTestCase() {
|
||||||
|
|
||||||
fun doTest(testDataPath: String) {
|
fun doTest(testDataPath: String) {
|
||||||
val testDir = KotlinTestUtils.tmpDir("testDirectory")
|
val testDir = KotlinTestUtils.tmpDir("testDirectory")
|
||||||
|
|
||||||
@@ -77,43 +77,31 @@ abstract class AbstractProtoComparisonTest : UsefulTestCase() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun Printer.printDifference(oldClassFile: File, newClassFile: File) {
|
private fun Printer.printDifference(oldClassFile: File, newClassFile: File) {
|
||||||
val oldLocalFileKotlinClass = LocalFileKotlinClass.create(oldClassFile)!!
|
fun KotlinJvmBinaryClass.readProto(): ProtoMapValue? {
|
||||||
val newLocalFileKotlinClass = LocalFileKotlinClass.create(newClassFile)!!
|
assert(classHeader.metadataVersion.isCompatible()) { "Incompatible class ($classHeader): $location" }
|
||||||
|
return when (classHeader.kind) {
|
||||||
val oldClassHeader = oldLocalFileKotlinClass.classHeader
|
KotlinClassHeader.Kind.CLASS, KotlinClassHeader.Kind.FILE_FACADE, KotlinClassHeader.Kind.MULTIFILE_CLASS_PART -> {
|
||||||
val newClassHeader = newLocalFileKotlinClass.classHeader
|
ProtoMapValue(
|
||||||
|
classHeader.kind != KotlinClassHeader.Kind.CLASS,
|
||||||
if (oldClassHeader.annotationData == null || newClassHeader.annotationData == null) {
|
BitEncoding.decodeBytes(classHeader.data!!),
|
||||||
println("skip ${oldLocalFileKotlinClass.classId}")
|
classHeader.strings!!
|
||||||
return
|
)
|
||||||
}
|
}
|
||||||
|
else -> {
|
||||||
val oldProtoBytes = BitEncoding.decodeBytes(oldClassHeader.annotationData!!)
|
println("skip $classId")
|
||||||
val newProtoBytes = BitEncoding.decodeBytes(newClassHeader.annotationData!!)
|
return null
|
||||||
|
}
|
||||||
assert(oldClassHeader.metadataVersion.isCompatible()) { "Incompatible class ($oldClassHeader): $oldClassFile" }
|
|
||||||
assert(newClassHeader.metadataVersion.isCompatible()) { "Incompatible class ($newClassHeader): $newClassFile" }
|
|
||||||
|
|
||||||
val oldProto = ProtoMapValue(
|
|
||||||
oldClassHeader.kind == KotlinClassHeader.Kind.FILE_FACADE ||
|
|
||||||
oldClassHeader.kind == KotlinClassHeader.Kind.MULTIFILE_CLASS_PART,
|
|
||||||
oldProtoBytes, oldClassHeader.strings!!
|
|
||||||
)
|
|
||||||
val newProto = ProtoMapValue(
|
|
||||||
newClassHeader.kind == KotlinClassHeader.Kind.FILE_FACADE ||
|
|
||||||
newClassHeader.kind == KotlinClassHeader.Kind.MULTIFILE_CLASS_PART,
|
|
||||||
newProtoBytes, newClassHeader.strings!!
|
|
||||||
)
|
|
||||||
|
|
||||||
val diff = when (newClassHeader.kind) {
|
|
||||||
KotlinClassHeader.Kind.CLASS, KotlinClassHeader.Kind.FILE_FACADE, KotlinClassHeader.Kind.MULTIFILE_CLASS_PART ->
|
|
||||||
difference(oldProto, newProto)
|
|
||||||
else -> {
|
|
||||||
println("ignore ${oldLocalFileKotlinClass.classId}")
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val oldClass = LocalFileKotlinClass.create(oldClassFile)!!
|
||||||
|
val newClass = LocalFileKotlinClass.create(newClassFile)!!
|
||||||
|
|
||||||
|
val diff = difference(
|
||||||
|
oldClass.readProto() ?: return,
|
||||||
|
newClass.readProto() ?: return
|
||||||
|
)
|
||||||
|
|
||||||
val changes = SmartList<String>()
|
val changes = SmartList<String>()
|
||||||
|
|
||||||
if (diff.isClassSignatureChanged) {
|
if (diff.isClassSignatureChanged) {
|
||||||
@@ -128,7 +116,7 @@ abstract class AbstractProtoComparisonTest : UsefulTestCase() {
|
|||||||
changes.add("NONE")
|
changes.add("NONE")
|
||||||
}
|
}
|
||||||
|
|
||||||
println("changes in ${oldLocalFileKotlinClass.classId}: ${changes.joinToString()}")
|
println("changes in ${oldClass.classId}: ${changes.joinToString()}")
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun File.createSubDirectory(relativePath: String): File {
|
private fun File.createSubDirectory(relativePath: String): File {
|
||||||
|
|||||||
Reference in New Issue
Block a user