diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/checkers/JvmReflectionAPICallChecker.kt b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/checkers/JvmReflectionAPICallChecker.kt index 9908c5b5efe..9ed53eb303d 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/checkers/JvmReflectionAPICallChecker.kt +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/checkers/JvmReflectionAPICallChecker.kt @@ -17,8 +17,8 @@ package org.jetbrains.kotlin.resolve.jvm.checkers import com.intellij.psi.PsiElement +import org.jetbrains.kotlin.builtins.ReflectionTypes import org.jetbrains.kotlin.descriptors.ModuleDescriptor -import org.jetbrains.kotlin.descriptors.NotFoundClasses import org.jetbrains.kotlin.descriptors.findClassAcrossModuleDependencies import org.jetbrains.kotlin.load.java.JvmAbi import org.jetbrains.kotlin.resolve.calls.checkers.AbstractReflectionApiCallChecker @@ -32,10 +32,10 @@ import org.jetbrains.kotlin.storage.getValue * of reflection API which will fail at runtime. */ class JvmReflectionAPICallChecker( - private val module: ModuleDescriptor, - notFoundClasses: NotFoundClasses, - storageManager: StorageManager -) : AbstractReflectionApiCallChecker(module, notFoundClasses, storageManager) { + private val module: ModuleDescriptor, + reflectionTypes: ReflectionTypes, + storageManager: StorageManager +) : AbstractReflectionApiCallChecker(reflectionTypes, storageManager) { override val isWholeReflectionApiAvailable by storageManager.createLazyValue { module.findClassAcrossModuleDependencies(JvmAbi.REFLECTION_FACTORY_IMPL) != null } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/AbstractReflectionApiCallChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/AbstractReflectionApiCallChecker.kt index b3dbdfe6cb5..b4d0ab703d2 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/AbstractReflectionApiCallChecker.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/AbstractReflectionApiCallChecker.kt @@ -21,8 +21,7 @@ import org.jetbrains.kotlin.builtins.KOTLIN_REFLECT_FQ_NAME import org.jetbrains.kotlin.builtins.ReflectionTypes import org.jetbrains.kotlin.descriptors.CallableDescriptor import org.jetbrains.kotlin.descriptors.ClassDescriptor -import org.jetbrains.kotlin.descriptors.ModuleDescriptor -import org.jetbrains.kotlin.descriptors.NotFoundClasses +import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall @@ -36,18 +35,21 @@ private val ANY_MEMBER_NAMES = setOf("equals", "hashCode", "toString") * Checks that there are no usages of reflection API which will fail at runtime. */ abstract class AbstractReflectionApiCallChecker( - private val module: ModuleDescriptor, - private val notFoundClasses: NotFoundClasses, + private val reflectionTypes: ReflectionTypes, storageManager: StorageManager ) : CallChecker { protected abstract val isWholeReflectionApiAvailable: Boolean protected abstract fun report(element: PsiElement, context: CallCheckerContext) private val kPropertyClasses by storageManager.createLazyValue { - val reflectionTypes = ReflectionTypes(module, notFoundClasses) setOf(reflectionTypes.kProperty0, reflectionTypes.kProperty1, reflectionTypes.kProperty2) } + private val kClass by storageManager.createLazyValue { reflectionTypes.kClass } + + protected open fun isAllowedKClassMember(name: Name): Boolean = + name.asString() == "simpleName" + final override fun check(resolvedCall: ResolvedCall<*>, reportOn: PsiElement, context: CallCheckerContext) { if (isWholeReflectionApiAvailable) return @@ -68,6 +70,7 @@ abstract class AbstractReflectionApiCallChecker( return name.asString() in ANY_MEMBER_NAMES || name == OperatorNameConventions.INVOKE || name.asString() == "name" || + DescriptorUtils.isSubclass(containingClass, kClass) && isAllowedKClassMember(descriptor.name) || (name.asString() == "get" || name.asString() == "set") && containingClass.isKPropertyClass() } @@ -79,4 +82,3 @@ abstract class AbstractReflectionApiCallChecker( return fqName == KOTLIN_REFLECT_FQ_NAME.toUnsafe() || fqName.asString().startsWith(KOTLIN_REFLECT_FQ_NAME.asString() + ".") } } - diff --git a/compiler/testData/codegen/box/reflection/classLiterals/builtinClassLiterals.kt b/compiler/testData/codegen/box/reflection/classLiterals/builtinClassLiterals.kt index ec1ce610ec7..4238d30fcc4 100644 --- a/compiler/testData/codegen/box/reflection/classLiterals/builtinClassLiterals.kt +++ b/compiler/testData/codegen/box/reflection/classLiterals/builtinClassLiterals.kt @@ -1,8 +1,5 @@ -// IGNORE_BACKEND: JS_IR -// TODO: muted automatically, investigate should it be ran for JS or not -// IGNORE_BACKEND: JS, NATIVE - -// WITH_REFLECT +// TARGET_BACKEND: JVM +// WITH_RUNTIME import kotlin.test.assertEquals @@ -16,6 +13,10 @@ fun box(): String { assertEquals("Array", Array::class.simpleName) assertEquals("Array", Array::class.simpleName) + assertEquals("Array", Array>::class.simpleName) + + assertEquals("IntArray", IntArray::class.simpleName) + assertEquals("DoubleArray", DoubleArray::class.simpleName) assertEquals("Companion", Int.Companion::class.simpleName) assertEquals("Companion", Double.Companion::class.simpleName) @@ -24,9 +25,16 @@ fun box(): String { assertEquals("IntRange", IntRange::class.simpleName) assertEquals("List", List::class.simpleName) + assertEquals("Entry", Map.Entry::class.simpleName) - // TODO: this is wrong but should be fixed + // TODO: KT-11754 assertEquals("List", MutableList::class.simpleName) + assertEquals("Entry", MutableMap.MutableEntry::class.simpleName) + + assertEquals("Function0", Function0::class.simpleName) + assertEquals("Function1", Function1::class.simpleName) + assertEquals("Function5", Function5::class.simpleName) + assertEquals("FunctionN", Function42::class.simpleName) return "OK" } diff --git a/compiler/testData/codegen/box/reflection/classes/classSimpleName.kt b/compiler/testData/codegen/box/reflection/classes/classSimpleName.kt index 9034d25e684..d88cd3c5749 100644 --- a/compiler/testData/codegen/box/reflection/classes/classSimpleName.kt +++ b/compiler/testData/codegen/box/reflection/classes/classSimpleName.kt @@ -1,6 +1,5 @@ // TARGET_BACKEND: JVM - -// WITH_REFLECT +// WITH_RUNTIME import kotlin.test.assertEquals @@ -10,7 +9,6 @@ fun box(): String { assertEquals("Klass", Klass::class.simpleName) assertEquals("Date", java.util.Date::class.simpleName) assertEquals("ObjectRef", kotlin.jvm.internal.Ref.ObjectRef::class.simpleName) - assertEquals("Void", java.lang.Void::class.simpleName) return "OK" } diff --git a/compiler/testData/codegen/box/reflection/classes/javaVoid.kt b/compiler/testData/codegen/box/reflection/classes/javaVoid.kt index 85d3be34cef..69eb3654890 100644 --- a/compiler/testData/codegen/box/reflection/classes/javaVoid.kt +++ b/compiler/testData/codegen/box/reflection/classes/javaVoid.kt @@ -13,5 +13,7 @@ fun box(): String { assertEquals(Void.TYPE, Void.TYPE.kotlin.javaPrimitiveType) assertEquals(Void::class.java, Void.TYPE.kotlin.javaObjectType) + assertEquals("Void", Void::class.simpleName) + return "OK" } diff --git a/compiler/testData/codegen/box/reflection/classes/localClassSimpleName.kt b/compiler/testData/codegen/box/reflection/classes/localClassSimpleName.kt index e39a2d551c9..20cf07478cc 100644 --- a/compiler/testData/codegen/box/reflection/classes/localClassSimpleName.kt +++ b/compiler/testData/codegen/box/reflection/classes/localClassSimpleName.kt @@ -1,6 +1,6 @@ // IGNORE_BACKEND: JVM_IR // IGNORE_BACKEND: NATIVE -// WITH_REFLECT +// WITH_RUNTIME import kotlin.reflect.KClass import kotlin.test.assertEquals diff --git a/compiler/testData/codegen/box/reflection/noReflectAtRuntime/javaClass.kt b/compiler/testData/codegen/box/reflection/noReflectAtRuntime/javaClass.kt index ddf1a3a1d3b..041918dda19 100644 --- a/compiler/testData/codegen/box/reflection/noReflectAtRuntime/javaClass.kt +++ b/compiler/testData/codegen/box/reflection/noReflectAtRuntime/javaClass.kt @@ -15,11 +15,11 @@ fun box(): String { assertEquals("Klass", jClass.getSimpleName()) assertEquals("Klass", kjClass.getSimpleName()) assertEquals("Klass", kkClass.java.simpleName) + assertEquals("Klass", kClass.simpleName) assertEquals(kjClass, jjClass) - try { kClass.simpleName; return "Fail 1" } catch (e: Error) {} - try { kClass.qualifiedName; return "Fail 2" } catch (e: Error) {} - try { kClass.members; return "Fail 3" } catch (e: Error) {} + try { kClass.qualifiedName; return "Fail qualifiedName" } catch (e: Error) {} + try { kClass.members; return "Fail members" } catch (e: Error) {} val jlError = Error::class.java val kljError = Error::class @@ -29,6 +29,7 @@ fun box(): String { assertEquals("Error", jlError.getSimpleName()) assertEquals("Error", jljError.getSimpleName()) assertEquals("Error", jlkError.java.simpleName) + assertEquals("Error", kljError.simpleName) return "OK" } diff --git a/compiler/testData/codegen/box/reflection/noReflectAtRuntime/javaVoid.kt b/compiler/testData/codegen/box/reflection/noReflectAtRuntime/javaVoid.kt index b54e5a5b066..8d18fe14955 100644 --- a/compiler/testData/codegen/box/reflection/noReflectAtRuntime/javaVoid.kt +++ b/compiler/testData/codegen/box/reflection/noReflectAtRuntime/javaVoid.kt @@ -13,5 +13,7 @@ fun box(): String { assertEquals(Void.TYPE, Void.TYPE.kotlin.javaPrimitiveType) assertEquals(Void::class.java, Void.TYPE.kotlin.javaObjectType) + assertEquals("Void", Void::class.simpleName) + return "OK" } diff --git a/compiler/testData/diagnostics/tests/reflection/noReflectionInClassPath.kt b/compiler/testData/diagnostics/tests/reflection/noReflectionInClassPath.kt index 9845d3ca0ba..c55fb0ae62d 100644 --- a/compiler/testData/diagnostics/tests/reflection/noReflectionInClassPath.kt +++ b/compiler/testData/diagnostics/tests/reflection/noReflectionInClassPath.kt @@ -17,11 +17,11 @@ fun n11() = (Foo::func)(Foo("")) fun y01() = Foo::prop.getter fun y02() = Foo::class.members -fun y03() = Foo::class.simpleName +fun y03() = Foo::class.simpleName fun y04() = Foo::class.properties fun kclass(k: KClass<*>, kt: KClass) { - k.simpleName + k.simpleName k.qualifiedName k.members k.constructors diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KClassImpl.kt b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KClassImpl.kt index f0cc00577b3..ba7b9767921 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KClassImpl.kt +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KClassImpl.kt @@ -19,6 +19,9 @@ package kotlin.reflect.jvm.internal import org.jetbrains.kotlin.builtins.CompanionObjectMapping import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.descriptors.runtime.components.ReflectKotlinClass +import org.jetbrains.kotlin.descriptors.runtime.structure.functionClassArity +import org.jetbrains.kotlin.descriptors.runtime.structure.wrapperByPrimitive import org.jetbrains.kotlin.incremental.components.NoLookupLocation import org.jetbrains.kotlin.load.java.JvmAbi import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader @@ -32,13 +35,11 @@ import org.jetbrains.kotlin.resolve.scopes.MemberScope import org.jetbrains.kotlin.serialization.deserialization.MemberDeserializer import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedClassDescriptor import org.jetbrains.kotlin.utils.compact +import kotlin.jvm.internal.ClassReference import kotlin.jvm.internal.TypeIntrinsics import kotlin.reflect.* import kotlin.reflect.jvm.internal.KDeclarationContainerImpl.MemberBelonginess.DECLARED import kotlin.reflect.jvm.internal.KDeclarationContainerImpl.MemberBelonginess.INHERITED -import org.jetbrains.kotlin.descriptors.runtime.components.ReflectKotlinClass -import org.jetbrains.kotlin.descriptors.runtime.structure.functionClassArity -import org.jetbrains.kotlin.descriptors.runtime.structure.wrapperByPrimitive internal class KClassImpl(override val jClass: Class) : KDeclarationContainerImpl(), KClass, KClassifierImpl { inner class Data : KDeclarationContainerImpl.Data() { @@ -55,16 +56,6 @@ internal class KClassImpl(override val jClass: Class) : KDeclaration val annotations: List by ReflectProperties.lazySoft { descriptor.computeAnnotations() } - val simpleName: String? by ReflectProperties.lazySoft { - if (jClass.isAnonymousClass) return@lazySoft null - - val classId = classId - when { - classId.isLocal -> calculateLocalClassName(jClass) - else -> classId.shortClassName.asString() - } - } - val qualifiedName: String? by ReflectProperties.lazySoft { if (jClass.isAnonymousClass) return@lazySoft null @@ -75,17 +66,6 @@ internal class KClassImpl(override val jClass: Class) : KDeclaration } } - private fun calculateLocalClassName(jClass: Class<*>): String { - val name = jClass.simpleName - jClass.enclosingMethod?.let { method -> - return name.substringAfter(method.name + "$") - } - jClass.enclosingConstructor?.let { constructor -> - return name.substringAfter(constructor.name + "$") - } - return name.substringAfter('$') - } - @Suppress("UNCHECKED_CAST") val constructors: Collection> by ReflectProperties.lazySoft { constructorDescriptors.map { descriptor -> @@ -180,7 +160,14 @@ internal class KClassImpl(override val jClass: Class) : KDeclaration override val annotations: List get() = data().annotations - private val classId: ClassId get() = RuntimeTypeMapper.mapJvmClassToKotlinClassId(jClass) + private val classId: ClassId + get() = RuntimeTypeMapper.mapJvmClassToKotlinClassId(jClass).also { result -> + if (!jClass.isAnonymousClass && !jClass.isLocalClass) { + assert(result.shortClassName.asString() == simpleName) { + "Incorrect class name computed for class ${jClass.name}. Result: $result. Expected simple name $simpleName" + } + } + } // Note that we load members from the container's default type, which might be confusing. For example, a function declared in a // generic class "A" would have "A" as the receiver parameter even if a concrete type like "A" was specified @@ -228,7 +215,7 @@ internal class KClassImpl(override val jClass: Class) : KDeclaration } } - override val simpleName: String? get() = data().simpleName + override val simpleName: String? get() = ClassReference.getClassSimpleName(jClass) override val qualifiedName: String? get() = data().qualifiedName diff --git a/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/JsReflectionAPICallChecker.kt b/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/JsReflectionAPICallChecker.kt index 0b84ff4e31c..b0f54bb4526 100644 --- a/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/JsReflectionAPICallChecker.kt +++ b/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/JsReflectionAPICallChecker.kt @@ -20,18 +20,14 @@ import com.intellij.psi.PsiElement import org.jetbrains.kotlin.builtins.ReflectionTypes import org.jetbrains.kotlin.descriptors.CallableDescriptor import org.jetbrains.kotlin.descriptors.ClassDescriptor -import org.jetbrains.kotlin.descriptors.ModuleDescriptor -import org.jetbrains.kotlin.descriptors.NotFoundClasses import org.jetbrains.kotlin.diagnostics.Errors.UNSUPPORTED import org.jetbrains.kotlin.name.FqName -import org.jetbrains.kotlin.resolve.DescriptorUtils +import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.resolve.calls.checkers.AbstractReflectionApiCallChecker import org.jetbrains.kotlin.resolve.calls.checkers.CallCheckerContext import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe import org.jetbrains.kotlin.storage.StorageManager -import org.jetbrains.kotlin.storage.getValue -private val ALLOWED_KCLASS_MEMBERS = setOf("simpleName", "isInstance") private val ALLOWED_CLASSES = setOf( FqName("kotlin.reflect.KType"), FqName("kotlin.reflect.KTypeProjection"), @@ -40,11 +36,12 @@ private val ALLOWED_CLASSES = setOf( ) class JsReflectionAPICallChecker( - module: ModuleDescriptor, - private val reflectionTypes: ReflectionTypes, - notFoundClasses: NotFoundClasses, + reflectionTypes: ReflectionTypes, storageManager: StorageManager -) : AbstractReflectionApiCallChecker(module, notFoundClasses, storageManager) { +) : AbstractReflectionApiCallChecker(reflectionTypes, storageManager) { + override fun isAllowedKClassMember(name: Name): Boolean = + super.isAllowedKClassMember(name) || name.asString() == "isInstance" + override val isWholeReflectionApiAvailable: Boolean get() = false @@ -52,10 +49,6 @@ class JsReflectionAPICallChecker( context.trace.report(UNSUPPORTED.on(element, "This reflection API is not supported yet in JavaScript")) } - private val kClass by storageManager.createLazyValue { reflectionTypes.kClass } - override fun isAllowedReflectionApi(descriptor: CallableDescriptor, containingClass: ClassDescriptor): Boolean = - super.isAllowedReflectionApi(descriptor, containingClass) || - DescriptorUtils.isSubclass(containingClass, kClass) && descriptor.name.asString() in ALLOWED_KCLASS_MEMBERS || - containingClass.fqNameSafe in ALLOWED_CLASSES + super.isAllowedReflectionApi(descriptor, containingClass) || containingClass.fqNameSafe in ALLOWED_CLASSES } diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java index 4a244667089..46c2005d0dd 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java @@ -18054,11 +18054,6 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest { runTest("compiler/testData/codegen/box/reflection/classLiterals/annotationClassLiteral.kt"); } - @TestMetadata("builtinClassLiterals.kt") - public void testBuiltinClassLiterals() throws Exception { - runTest("compiler/testData/codegen/box/reflection/classLiterals/builtinClassLiterals.kt"); - } - @TestMetadata("genericClass.kt") public void testGenericClass() throws Exception { runTest("compiler/testData/codegen/box/reflection/classLiterals/genericClass.kt"); diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java index 64c3a895ce2..3db3cc5fa0f 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java @@ -19164,11 +19164,6 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { runTest("compiler/testData/codegen/box/reflection/classLiterals/annotationClassLiteral.kt"); } - @TestMetadata("builtinClassLiterals.kt") - public void testBuiltinClassLiterals() throws Exception { - runTest("compiler/testData/codegen/box/reflection/classLiterals/builtinClassLiterals.kt"); - } - @TestMetadata("genericClass.kt") public void testGenericClass() throws Exception { runTest("compiler/testData/codegen/box/reflection/classLiterals/genericClass.kt"); diff --git a/libraries/stdlib/jvm/runtime/kotlin/jvm/internal/ClassReference.kt b/libraries/stdlib/jvm/runtime/kotlin/jvm/internal/ClassReference.kt index bd967bf5a11..6ac4bf7819a 100644 --- a/libraries/stdlib/jvm/runtime/kotlin/jvm/internal/ClassReference.kt +++ b/libraries/stdlib/jvm/runtime/kotlin/jvm/internal/ClassReference.kt @@ -9,7 +9,7 @@ import kotlin.reflect.* public class ClassReference(override val jClass: Class<*>) : KClass, ClassBasedDeclarationContainer { override val simpleName: String? - get() = error() + get() = getClassSimpleName(jClass) override val qualifiedName: String? get() = error() @@ -86,4 +86,77 @@ public class ClassReference(override val jClass: Class<*>) : KClass, ClassB override fun toString() = jClass.toString() + Reflection.REFLECTION_NOT_AVAILABLE + + companion object { + private val primitiveFqNames = HashMap().apply { + put("boolean", "kotlin.Boolean") + put("char", "kotlin.Char") + put("byte", "kotlin.Byte") + put("short", "kotlin.Short") + put("int", "kotlin.Int") + put("float", "kotlin.Float") + put("long", "kotlin.Long") + put("double", "kotlin.Double") + } + + private val primitiveWrapperFqNames = HashMap().apply { + put("java.lang.Boolean", "kotlin.Boolean") + put("java.lang.Character", "kotlin.Char") + put("java.lang.Byte", "kotlin.Byte") + put("java.lang.Short", "kotlin.Short") + put("java.lang.Integer", "kotlin.Int") + put("java.lang.Float", "kotlin.Float") + put("java.lang.Long", "kotlin.Long") + put("java.lang.Double", "kotlin.Double") + } + + // See JavaToKotlinClassMap. + private val classFqNames = HashMap().apply { + put("java.lang.Object", "kotlin.Any") + put("java.lang.String", "kotlin.String") + put("java.lang.CharSequence", "kotlin.CharSequence") + put("java.lang.Throwable", "kotlin.Throwable") + put("java.lang.Cloneable", "kotlin.Cloneable") + put("java.lang.Number", "kotlin.Number") + put("java.lang.Comparable", "kotlin.Comparable") + put("java.lang.Enum", "kotlin.Enum") + put("java.lang.annotation.Annotation", "kotlin.Annotation") + put("java.lang.Iterable", "kotlin.collections.Iterable") + put("java.util.Iterator", "kotlin.collections.Iterator") + put("java.util.Collection", "kotlin.collections.Collection") + put("java.util.List", "kotlin.collections.List") + put("java.util.Set", "kotlin.collections.Set") + put("java.util.ListIterator", "kotlin.collections.ListIterator") + put("java.util.Map", "kotlin.collections.Map") + put("java.util.Map\$Entry", "kotlin.collections.Map.Entry") + put("kotlin.jvm.internal.StringCompanionObject", "kotlin.String.Companion") + put("kotlin.jvm.internal.EnumCompanionObject", "kotlin.Enum.Companion") + + putAll(primitiveFqNames) + putAll(primitiveWrapperFqNames) + primitiveFqNames.values.associateTo(this) { kotlinName -> + "kotlin.jvm.internal.${kotlinName.substringAfterLast('.')}CompanionObject" to "$kotlinName.Companion" + } + } + + private val simpleNames = classFqNames.mapValues { (_, fqName) -> fqName.substringAfterLast('.') } + + public fun getClassSimpleName(jClass: Class<*>): String? = when { + jClass.isAnonymousClass -> null + jClass.isLocalClass -> { + val name = jClass.simpleName + jClass.enclosingMethod?.let { method -> name.substringAfter(method.name + "$") } + ?: jClass.enclosingConstructor?.let { constructor -> name.substringAfter(constructor.name + "$") } + ?: name.substringAfter('$') + } + jClass.isArray -> { + val componentType = jClass.componentType + when { + componentType.isPrimitive -> simpleNames[componentType.name]?.plus("Array") + else -> null + } ?: "Array" + } + else -> simpleNames[jClass.name] ?: jClass.simpleName + } + } } diff --git a/libraries/tools/binary-compatibility-validator/reference-public-api/kotlin-stdlib-runtime-merged.txt b/libraries/tools/binary-compatibility-validator/reference-public-api/kotlin-stdlib-runtime-merged.txt index ce9ef01e313..54a31d8f977 100644 --- a/libraries/tools/binary-compatibility-validator/reference-public-api/kotlin-stdlib-runtime-merged.txt +++ b/libraries/tools/binary-compatibility-validator/reference-public-api/kotlin-stdlib-runtime-merged.txt @@ -3269,6 +3269,7 @@ public abstract interface class kotlin/jvm/internal/ClassBasedDeclarationContain } public final class kotlin/jvm/internal/ClassReference : kotlin/jvm/internal/ClassBasedDeclarationContainer, kotlin/reflect/KClass { + public static final field Companion Lkotlin/jvm/internal/ClassReference$Companion; public fun (Ljava/lang/Class;)V public fun equals (Ljava/lang/Object;)Z public fun getAnnotations ()Ljava/util/List; @@ -3295,6 +3296,10 @@ public final class kotlin/jvm/internal/ClassReference : kotlin/jvm/internal/Clas public fun toString ()Ljava/lang/String; } +public final class kotlin/jvm/internal/ClassReference$Companion { + public final fun getClassSimpleName (Ljava/lang/Class;)Ljava/lang/String; +} + public final class kotlin/jvm/internal/CollectionToArray { public static final fun toArray (Ljava/util/Collection;)[Ljava/lang/Object; public static final fun toArray (Ljava/util/Collection;[Ljava/lang/Object;)[Ljava/lang/Object;