diff --git a/compiler/testData/codegen/bytecodeListing/specialBridges/signatureForSpecialBridge.kt b/compiler/testData/codegen/bytecodeListing/specialBridges/signatureForSpecialBridge.kt new file mode 100644 index 00000000000..b49589e3ded --- /dev/null +++ b/compiler/testData/codegen/bytecodeListing/specialBridges/signatureForSpecialBridge.kt @@ -0,0 +1,3 @@ +// WITH_SIGNATURES + +class MyMap : MutableMap by HashMap() diff --git a/compiler/testData/codegen/bytecodeListing/specialBridges/signatureForSpecialBridge.txt b/compiler/testData/codegen/bytecodeListing/specialBridges/signatureForSpecialBridge.txt new file mode 100644 index 00000000000..dd62ea01aae --- /dev/null +++ b/compiler/testData/codegen/bytecodeListing/specialBridges/signatureForSpecialBridge.txt @@ -0,0 +1,21 @@ +@kotlin.Metadata +public final class<Ljava/lang/Object;Ljava/util/Map;Lkotlin/jvm/internal/markers/KMutableMap;> MyMap { + public @org.jetbrains.annotations.NotNull <()Ljava/util/Collection;> method getValues(): java.util.Collection + public @org.jetbrains.annotations.NotNull <()Ljava/util/Set;>;> method getEntries(): java.util.Set + public @org.jetbrains.annotations.NotNull <()Ljava/util/Set;> method getKeys(): java.util.Set + public @org.jetbrains.annotations.Nullable <(Ljava/lang/Object;)TV;> method get(p0: java.lang.Object): java.lang.Object + public @org.jetbrains.annotations.Nullable <(Ljava/lang/Object;)TV;> method remove(p0: java.lang.Object): java.lang.Object + public <(Ljava/util/Map<+TK;+TV;>;)V> method putAll(@org.jetbrains.annotations.NotNull p0: java.util.Map): void + public @org.jetbrains.annotations.Nullable <(TK;TV;)TV;> method put(p0: java.lang.Object, p1: java.lang.Object): java.lang.Object + public method (): void + public method clear(): void + public method containsKey(p0: java.lang.Object): boolean + public method containsValue(p0: java.lang.Object): boolean + public final method entrySet(): java.util.Set + public method getSize(): int + public method isEmpty(): boolean + public final method keySet(): java.util.Set + public final method size(): int + public final method values(): java.util.Collection + private synthetic final field $$delegate_0: java.util.HashMap +} diff --git a/compiler/tests-common/org/jetbrains/kotlin/codegen/AbstractBytecodeListingTest.kt b/compiler/tests-common/org/jetbrains/kotlin/codegen/AbstractBytecodeListingTest.kt index e2a80d882b9..570c6d99f96 100644 --- a/compiler/tests-common/org/jetbrains/kotlin/codegen/AbstractBytecodeListingTest.kt +++ b/compiler/tests-common/org/jetbrains/kotlin/codegen/AbstractBytecodeListingTest.kt @@ -25,33 +25,45 @@ abstract class AbstractBytecodeListingTest : CodegenTestCase() { override fun doMultiFileTest(wholeFile: File, files: List, javaFilesDir: File?) { val txtFile = File(wholeFile.parentFile, wholeFile.nameWithoutExtension + ".txt") compile(files, javaFilesDir) - val actualTxt = BytecodeListingTextCollectingVisitor.getText(classFileFactory) + val actualTxt = BytecodeListingTextCollectingVisitor.getText(classFileFactory, withSignatures = isWithSignatures(wholeFile)) KotlinTestUtils.assertEqualsToFile(txtFile, actualTxt) } + + private fun isWithSignatures(wholeFile: File): Boolean = + WITH_SIGNATURES.containsMatchIn(wholeFile.readText()) + + companion object { + private val WITH_SIGNATURES = Regex.fromLiteral("// WITH_SIGNATURES") + } } -class BytecodeListingTextCollectingVisitor(val filter: Filter) : ClassVisitor(ASM5) { +class BytecodeListingTextCollectingVisitor(val filter: Filter, val withSignatures: Boolean) : ClassVisitor(ASM5) { companion object { @JvmOverloads - fun getText(factory: ClassFileFactory, filter: Filter = Filter.EMPTY, replaceHash: Boolean = true) = factory - .getClassFiles() - .sortedBy { it.relativePath } - .mapNotNull { - val cr = ClassReader(it.asByteArray()) - val visitor = BytecodeListingTextCollectingVisitor(filter) - cr.accept(visitor, ClassReader.SKIP_CODE) + fun getText( + factory: ClassFileFactory, + filter: Filter = Filter.EMPTY, + replaceHash: Boolean = true, + withSignatures: Boolean = false + ) = + factory.getClassFiles() + .sortedBy { it.relativePath } + .mapNotNull { + val cr = ClassReader(it.asByteArray()) + val visitor = BytecodeListingTextCollectingVisitor(filter, withSignatures) + cr.accept(visitor, ClassReader.SKIP_CODE) - if (!filter.shouldWriteClass(cr.access, cr.className)) { - return@mapNotNull null - } + if (!filter.shouldWriteClass(cr.access, cr.className)) { + return@mapNotNull null + } - if (replaceHash) { - KotlinTestUtils.replaceHash(visitor.text, "HASH") - } - else { - visitor.text - } - }.joinToString("\n\n", postfix = "\n") + if (replaceHash) { + KotlinTestUtils.replaceHash(visitor.text, "HASH") + } + else { + visitor.text + } + }.joinToString("\n\n", postfix = "\n") } interface Filter { @@ -74,6 +86,7 @@ class BytecodeListingTextCollectingVisitor(val filter: Filter) : ClassVisitor(AS private val classAnnotations = arrayListOf() private var className = "" private var classAccess = 0 + private var classSignature: String? = "" private fun addAnnotation(desc: String, list: MutableList = declarationsInsideClass.last().annotations) { val name = Type.getType(desc).className @@ -112,6 +125,9 @@ class BytecodeListingTextCollectingVisitor(val filter: Filter) : ClassVisitor(AS } arrayListOf().apply { handleModifiers(classAccess, this) }.forEach { append(it) } append(classOrInterface(classAccess)) + if (withSignatures) { + append("<$classSignature> ") + } append(" ") append(className) if (declarationsInsideClass.isNotEmpty()) { @@ -159,7 +175,10 @@ class BytecodeListingTextCollectingVisitor(val filter: Filter) : ClassVisitor(AS val annotations = parameterAnnotations.getOrElse(index, { emptyList() }).joinToString("") "${annotations}p$index: $parameter" }.joinToString() - declarationsInsideClass.add(Declaration("method $name($parameterWithAnnotations): $returnType", methodAnnotations)) + val signatureIfRequired = if (withSignatures) "<$signature> " else "" + declarationsInsideClass.add( + Declaration("${signatureIfRequired}method $name($parameterWithAnnotations): $returnType", methodAnnotations) + ) super.visitEnd() } } @@ -171,7 +190,8 @@ class BytecodeListingTextCollectingVisitor(val filter: Filter) : ClassVisitor(AS } val type = Type.getType(desc).className - val fieldDeclaration = Declaration("field $name: $type") + val fieldSignature = if (withSignatures) "<$signature> " else "" + val fieldDeclaration = Declaration("field $fieldSignature$name: $type") declarationsInsideClass.add(fieldDeclaration) handleModifiers(access) if (access and ACC_VOLATILE != 0) addModifier("volatile", fieldDeclaration.annotations) @@ -200,6 +220,7 @@ class BytecodeListingTextCollectingVisitor(val filter: Filter) : ClassVisitor(AS ) { className = name classAccess = access + classSignature = signature } override fun visitInnerClass(name: String, outerName: String?, innerName: String?, access: Int) { diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeListingTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeListingTestGenerated.java index 9ea53b8592f..33b0c55eb30 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeListingTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeListingTestGenerated.java @@ -241,5 +241,11 @@ public class BytecodeListingTestGenerated extends AbstractBytecodeListingTest { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeListing/specialBridges/removeAtTwoSpecialBridges.kt"); doTest(fileName); } + + @TestMetadata("signatureForSpecialBridge.kt") + public void testSignatureForSpecialBridge() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeListing/specialBridges/signatureForSpecialBridge.kt"); + doTest(fileName); + } } }