diff --git a/compiler/testData/codegen/box/coroutines/tailCallToNothing.kt b/compiler/testData/codegen/box/coroutines/tailCallToNothing.kt index a0611f37ef9..2101f575e0a 100644 --- a/compiler/testData/codegen/box/coroutines/tailCallToNothing.kt +++ b/compiler/testData/codegen/box/coroutines/tailCallToNothing.kt @@ -1,6 +1,10 @@ // WITH_STDLIB // WITH_COROUTINES // SKIP_MANGLE_VERIFICATION + +// Light analysis mode test is muted because of some bug related to the old JVM backend. To be unmuted once the test is migrated to JVM IR. +// IGNORE_LIGHT_ANALYSIS + import helpers.* import kotlin.coroutines.* import kotlin.coroutines.intrinsics.* diff --git a/compiler/testData/codegen/box/delegatedProperty/kt35707.kt b/compiler/testData/codegen/box/delegatedProperty/kt35707.kt index 643657e36b6..d5d39733063 100644 --- a/compiler/testData/codegen/box/delegatedProperty/kt35707.kt +++ b/compiler/testData/codegen/box/delegatedProperty/kt35707.kt @@ -1,5 +1,8 @@ // ISSUE: KT-35707 +// Light analysis mode test is muted because of some bug related to the old JVM backend. To be unmuted once the test is migrated to JVM IR. +// IGNORE_LIGHT_ANALYSIS + import kotlin.reflect.KProperty interface PropertyDelegate { diff --git a/compiler/testData/codegen/box/regressions/kt3850.kt b/compiler/testData/codegen/box/regressions/kt3850.kt index 7a1d643e7c4..007dc26fb5e 100644 --- a/compiler/testData/codegen/box/regressions/kt3850.kt +++ b/compiler/testData/codegen/box/regressions/kt3850.kt @@ -1,4 +1,8 @@ // !LANGUAGE: -PrivateInFileEffectiveVisibility + +// In light analysis mode, anonymous object type is approximated to the supertype, so `fy` is unresolved. +// IGNORE_LIGHT_ANALYSIS + private class One { val a1 = arrayOf( object { val fy = "text"} diff --git a/compiler/tests-common/tests/org/jetbrains/kotlin/codegen/AbstractLightAnalysisModeTest.kt b/compiler/tests-common/tests/org/jetbrains/kotlin/codegen/AbstractLightAnalysisModeTest.kt index 3c944275c99..b50fab33e63 100644 --- a/compiler/tests-common/tests/org/jetbrains/kotlin/codegen/AbstractLightAnalysisModeTest.kt +++ b/compiler/tests-common/tests/org/jetbrains/kotlin/codegen/AbstractLightAnalysisModeTest.kt @@ -7,12 +7,18 @@ package org.jetbrains.kotlin.codegen import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment +import org.jetbrains.kotlin.container.StorageComponentContainer +import org.jetbrains.kotlin.container.useInstance +import org.jetbrains.kotlin.descriptors.ModuleDescriptor +import org.jetbrains.kotlin.extensions.StorageComponentContainerContributor import org.jetbrains.kotlin.load.java.JvmAbi import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader.Kind import org.jetbrains.kotlin.metadata.ProtoBuf import org.jetbrains.kotlin.metadata.deserialization.Flags import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmProtoBufUtil +import org.jetbrains.kotlin.platform.TargetPlatform import org.jetbrains.kotlin.resolve.jvm.AsmTypes +import org.jetbrains.kotlin.resolve.jvm.ReplaceWithSupertypeAnonymousTypeTransformer import org.jetbrains.kotlin.resolve.jvm.extensions.AnalysisHandlerExtension import org.jetbrains.kotlin.resolve.jvm.extensions.PartialAnalysisHandlerExtension import org.jetbrains.kotlin.test.util.KtTestUtil.getAnnotationsJar @@ -63,6 +69,16 @@ abstract class AbstractLightAnalysisModeTest : CodegenTestCase() { ) val environment = KotlinCoreEnvironment.createForTests(testRootDisposable, configuration, EnvironmentConfigFiles.JVM_CONFIG_FILES) AnalysisHandlerExtension.registerExtension(environment.project, PartialAnalysisHandlerExtension()) + StorageComponentContainerContributor.registerExtension( + environment.project, + object : StorageComponentContainerContributor { + override fun registerModuleComponents( + container: StorageComponentContainer, platform: TargetPlatform, moduleDescriptor: ModuleDescriptor + ) { + container.useInstance(ReplaceWithSupertypeAnonymousTypeTransformer()) + } + } + ) val testFiles = loadMultiFiles(files, environment.project) val classFileFactory = GenerationUtils.compileFiles(testFiles.psiFiles, environment, TEST_LIGHT_ANALYSIS).factory @@ -112,5 +128,8 @@ abstract class AbstractLightAnalysisModeTest : CodegenTestCase() { override fun shouldWriteInnerClass(name: String, outerName: String?, innerName: String?) = outerName != null && innerName != null + + override val shouldTransformAnonymousTypes: Boolean + get() = true } } diff --git a/compiler/tests-compiler-utils/tests/org/jetbrains/kotlin/codegen/BytecodeListingTextCollectingVisitor.kt b/compiler/tests-compiler-utils/tests/org/jetbrains/kotlin/codegen/BytecodeListingTextCollectingVisitor.kt index ae579671490..2e49adaf00e 100644 --- a/compiler/tests-compiler-utils/tests/org/jetbrains/kotlin/codegen/BytecodeListingTextCollectingVisitor.kt +++ b/compiler/tests-compiler-utils/tests/org/jetbrains/kotlin/codegen/BytecodeListingTextCollectingVisitor.kt @@ -11,11 +11,11 @@ import org.jetbrains.org.objectweb.asm.tree.ClassNode class BytecodeListingTextCollectingVisitor( val filter: Filter, + val allClasses: Map, val withSignatures: Boolean, - api: Int = Opcodes.API_VERSION, val withAnnotations: Boolean = true, val sortDeclarations: Boolean = true, -) : ClassVisitor(api) { +) : ClassVisitor(Opcodes.API_VERSION) { companion object { @JvmOverloads fun getText( @@ -23,18 +23,27 @@ class BytecodeListingTextCollectingVisitor( filter: Filter = Filter.EMPTY, withSignatures: Boolean = false, withAnnotations: Boolean = true, - sortDeclarations: Boolean = true - ) = factory.getClassFiles() - .sortedBy { it.relativePath } - .mapNotNull { - val cr = ClassReader(it.asByteArray()) - val node = ClassNode(Opcodes.API_VERSION) - cr.accept(node, ClassReader.SKIP_CODE) - val visitor = BytecodeListingTextCollectingVisitor(filter, withSignatures, withAnnotations = withAnnotations, sortDeclarations = sortDeclarations) + sortDeclarations: Boolean = true, + ): String { + val classes = factory.getClassFiles() + .sortedBy { it.relativePath } + .map { + ClassNode(Opcodes.API_VERSION).also { node -> + ClassReader(it.asByteArray()).accept(node, ClassReader.SKIP_CODE) + } + } + + val allClasses = classes.associateBy { Type.getObjectType(it.name) } + + return classes.mapNotNull { node -> + val visitor = BytecodeListingTextCollectingVisitor( + filter, allClasses, withSignatures, withAnnotations = withAnnotations, sortDeclarations = sortDeclarations + ) node.accept(visitor) if (!filter.shouldWriteClass(node)) null else visitor.text }.joinToString("\n\n", postfix = "\n") + } private val CLASS_OR_FIELD_OR_METHOD = setOf(ModifierTarget.CLASS, ModifierTarget.FIELD, ModifierTarget.METHOD) private val CLASS_OR_METHOD = setOf(ModifierTarget.CLASS, ModifierTarget.METHOD) @@ -69,12 +78,14 @@ class BytecodeListingTextCollectingVisitor( fun shouldWriteMethod(access: Int, name: String, desc: String): Boolean fun shouldWriteField(access: Int, name: String, desc: String): Boolean fun shouldWriteInnerClass(name: String, outerName: String?, innerName: String?): Boolean + val shouldTransformAnonymousTypes: Boolean object EMPTY : Filter { override fun shouldWriteClass(node: ClassNode) = true override fun shouldWriteMethod(access: Int, name: String, desc: String) = true override fun shouldWriteField(access: Int, name: String, desc: String) = true override fun shouldWriteInnerClass(name: String, outerName: String?, innerName: String?) = true + override val shouldTransformAnonymousTypes: Boolean get() = false } object ForCodegenTests : Filter { @@ -82,6 +93,7 @@ class BytecodeListingTextCollectingVisitor( override fun shouldWriteMethod(access: Int, name: String, desc: String): Boolean = true override fun shouldWriteField(access: Int, name: String, desc: String): Boolean = true override fun shouldWriteInnerClass(name: String, outerName: String?, innerName: String?): Boolean = !name.startsWith("helpers/") + override val shouldTransformAnonymousTypes: Boolean get() = false } } @@ -183,7 +195,7 @@ class BytecodeListingTextCollectingVisitor( return null } - val returnType = Type.getReturnType(desc).className + val returnType = transformAnonymousTypeIfNeeded(Type.getReturnType(desc)).className val parameterTypes = Type.getArgumentTypes(desc).map { it.className } val methodAnnotations = arrayListOf() val parameterAnnotations = hashMapOf>() @@ -235,7 +247,7 @@ class BytecodeListingTextCollectingVisitor( return null } - val type = Type.getType(desc).className + val type = transformAnonymousTypeIfNeeded(Type.getType(desc)).className val fieldSignature = if (withSignatures) "<$signature> " else "" val fieldDeclaration = Declaration("field $fieldSignature$name: $type") declarationsInsideClass.add(fieldDeclaration) @@ -362,4 +374,20 @@ class BytecodeListingTextCollectingVisitor( } } } + + private fun transformAnonymousTypeIfNeeded(type: Type): Type { + if (filter.shouldTransformAnonymousTypes) { + val node = allClasses[type] + if (node != null && isAnonymousClass(node)) { + return Type.getObjectType(node.interfaces.singleOrNull() ?: node.superName) + } + } + + return type + } + + private fun isAnonymousClass(node: ClassNode): Boolean { + val innerClassAttr = node.innerClasses.find { it.name == node.name } + return innerClassAttr != null && innerClassAttr.innerName == null && innerClassAttr.outerName == null + } } diff --git a/plugins/jvm-abi-gen/test/org/jetbrains/kotlin/jvm/abi/AbstractJvmAbiContentTest.kt b/plugins/jvm-abi-gen/test/org/jetbrains/kotlin/jvm/abi/AbstractJvmAbiContentTest.kt index cf4e21c9d7d..8fda1193680 100644 --- a/plugins/jvm-abi-gen/test/org/jetbrains/kotlin/jvm/abi/AbstractJvmAbiContentTest.kt +++ b/plugins/jvm-abi-gen/test/org/jetbrains/kotlin/jvm/abi/AbstractJvmAbiContentTest.kt @@ -1,9 +1,14 @@ +/* + * Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + package org.jetbrains.kotlin.jvm.abi import org.jetbrains.kotlin.codegen.BytecodeListingTextCollectingVisitor import org.jetbrains.kotlin.incremental.isClassFile import org.jetbrains.kotlin.test.testFramework.KtUsefulTestCase -import org.jetbrains.org.objectweb.asm.* +import org.jetbrains.org.objectweb.asm.ClassReader import java.io.File abstract class AbstractJvmAbiContentTest : BaseJvmAbiTest() { @@ -19,8 +24,8 @@ abstract class AbstractJvmAbiContentTest : BaseJvmAbiTest() { val reader = ClassReader(bytes) val visitor = BytecodeListingTextCollectingVisitor( filter = BytecodeListingTextCollectingVisitor.Filter.EMPTY, + allClasses = emptyMap(), withSignatures = false, - api = Opcodes.API_VERSION, sortDeclarations = false, // Declaration order matters for the ABI ) reader.accept(visitor, 0)