KAPT: Fix serialization of class structure data

When serializing ClasspathEntryData, ids assigned to types were
incorrect, resulting in corrupt data when deserializing files. This
happened if there were dependencies between classes.

Fixes KT-39876
Test: ClasspathAnalyzerTest
This commit is contained in:
Ivan Gavrilovic
2020-06-26 20:51:58 +01:00
committed by Yan Zhulanow
parent ccbb2eaba9
commit 11251a93ac
2 changed files with 31 additions and 3 deletions
@@ -108,6 +108,7 @@ class ClasspathEntryData : Serializable {
@Transient
var classAbiHash = mutableMapOf<String, ByteArray>()
@Transient
var classDependencies = mutableMapOf<String, ClassDependencies>()
@@ -118,7 +119,9 @@ class ClasspathEntryData : Serializable {
val names = LinkedHashMap<String, Int>()
sortedClassDependencies.forEach {
names[it.key] = names.size
if (it.key !in names) {
names[it.key] = names.size
}
it.value.abiTypes.forEach { type ->
if (type !in names) names[type] = names.size
}
@@ -134,9 +134,34 @@ class ClasspathAnalyzerTest {
assertTrue(data.classDependencies.isEmpty())
}
private fun emptyClass(internalName: String): ByteArray {
@Test
fun testJarsWithDependenciesWithinClasses() {
val inputJar = tmp.newFile("input.jar").also { jar ->
ZipOutputStream(jar.outputStream()).use {
it.putNextEntry(ZipEntry("test/A.class"))
it.write(emptyClass("test/A", "test/B"))
it.closeEntry()
it.putNextEntry(ZipEntry("test/B.class"))
it.write(emptyClass("test/B"))
it.closeEntry()
it.putNextEntry(ZipEntry("test/C.class"))
it.write(emptyClass("test/C"))
it.closeEntry()
}
}
val transform = StructureArtifactTransform().also { it.outputDirectory = tmp.newFolder() }
val outputs = transform.transform(inputJar)
val data = ClasspathEntryData.ClasspathEntrySerializer.loadFrom(outputs.single())
assertEquals(setOf("test/A", "test/B", "test/C"), data.classAbiHash.keys)
assertEquals(setOf("test/A", "test/B", "test/C"), data.classDependencies.keys)
}
private fun emptyClass(internalName: String, superClass: String = "java/lang/Object"): ByteArray {
val writer = ClassWriter(Opcodes.API_VERSION)
writer.visit(Opcodes.V1_8, Opcodes.ACC_PUBLIC, internalName, null, "java/lang/Object", emptyArray())
writer.visit(Opcodes.V1_8, Opcodes.ACC_PUBLIC, internalName, null, superClass, emptyArray())
return writer.toByteArray()
}
}