From 2b161581ca4c8ec300347e5d5113c8a8edb041f0 Mon Sep 17 00:00:00 2001 From: Dmitriy Dolovov Date: Tue, 8 Jun 2021 09:35:28 +0300 Subject: [PATCH] K/N: Use class FQN in default toString() implementation ^KT-47167 --- .../backend.native/tests/build.gradle | 4 +++ .../tests/runtime/basic/tostring4.kt | 33 +++++++++++++++++++ .../runtime/src/main/kotlin/kotlin/Any.kt | 4 +-- .../kotlin/native/internal/KClassImpl.kt | 18 +++++----- 4 files changed, 49 insertions(+), 10 deletions(-) create mode 100644 kotlin-native/backend.native/tests/runtime/basic/tostring4.kt diff --git a/kotlin-native/backend.native/tests/build.gradle b/kotlin-native/backend.native/tests/build.gradle index 292973db597..26186dbeedd 100644 --- a/kotlin-native/backend.native/tests/build.gradle +++ b/kotlin-native/backend.native/tests/build.gradle @@ -816,6 +816,10 @@ task tostring3(type: KonanLocalTest) { source = "runtime/basic/tostring3.kt" } +task tostring4(type: KonanLocalTest) { + source = "runtime/basic/tostring4.kt" +} + task empty_substring(type: KonanLocalTest) { goldValue = "\n" source = "runtime/basic/empty_substring.kt" diff --git a/kotlin-native/backend.native/tests/runtime/basic/tostring4.kt b/kotlin-native/backend.native/tests/runtime/basic/tostring4.kt new file mode 100644 index 00000000000..7e1978a16c7 --- /dev/null +++ b/kotlin-native/backend.native/tests/runtime/basic/tostring4.kt @@ -0,0 +1,33 @@ +/* + * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the LICENSE file. + */ + +package runtime.basic.tostring4 + +import kotlin.test.* + +class TopLevel + +@Test fun runTest() { + assertEquals("runtime.basic.tostring4.TopLevel", TopLevel().toStringWithoutHashCode()) + + class Local1 + assertEquals("runtime.basic.tostring4.runTest\$Local1", Local1().toStringWithoutHashCode()) + + assertEquals("runtime.basic.tostring4.runTest\$1", object {}.toStringWithoutHashCode()) + + fun localFun() { + class Local2 + assertEquals("runtime.basic.tostring4.runTest\$localFun\$Local2", Local2().toStringWithoutHashCode()) + + assertEquals("runtime.basic.tostring4.runTest\$localFun\$1", object {}.toStringWithoutHashCode()) + } + localFun() +} + +private fun Any.toStringWithoutHashCode(): String { + val string = toString() + assertEquals(1, string.count { it == '@' }, "Invalid toString() value: $string") + return string.substringBefore('@') +} diff --git a/kotlin-native/runtime/src/main/kotlin/kotlin/Any.kt b/kotlin-native/runtime/src/main/kotlin/kotlin/Any.kt index 6e09de81f04..d25340fa004 100644 --- a/kotlin-native/runtime/src/main/kotlin/kotlin/Any.kt +++ b/kotlin-native/runtime/src/main/kotlin/kotlin/Any.kt @@ -6,6 +6,7 @@ package kotlin import kotlin.native.identityHashCode +import kotlin.native.internal.fullName import kotlin.native.internal.ExportTypeInfo import kotlin.native.internal.GCUnsafeCall @@ -41,8 +42,7 @@ public open class Any { * Returns a string representation of the object. */ public open fun toString(): String { - val kClass = this::class - val className = kClass.qualifiedName ?: kClass.simpleName ?: "" + val className = this::class.fullName ?: "" // TODO: consider using [identityHashCode]. val unsignedHashCode = this.hashCode().toLong() and 0xffffffffL val hashCodeStr = unsignedHashCode.toString(16) diff --git a/kotlin-native/runtime/src/main/kotlin/kotlin/native/internal/KClassImpl.kt b/kotlin-native/runtime/src/main/kotlin/kotlin/native/internal/KClassImpl.kt index 61e90e03779..4486f41e69e 100644 --- a/kotlin-native/runtime/src/main/kotlin/kotlin/native/internal/KClassImpl.kt +++ b/kotlin-native/runtime/src/main/kotlin/kotlin/native/internal/KClassImpl.kt @@ -27,20 +27,22 @@ internal class KClassImpl(private val typeInfo: NativePtr) : KClass override fun hashCode(): Int = typeInfo.hashCode() - override fun toString(): String { - val relativeName = getRelativeName(typeInfo, false) - val visibleName = if (relativeName != null) { - val packageName = getPackageName(typeInfo, false)!! - if (packageName.isEmpty()) relativeName else "$packageName.$relativeName" - } else "" + override fun toString(): String = "class ${fullName ?: ""}" - return "class $visibleName" - } + internal val fullName: String? + get() { + val relativeName = getRelativeName(typeInfo, false) ?: return null + val packageName = getPackageName(typeInfo, false)!! + return if (packageName.isEmpty()) relativeName else "$packageName.$relativeName" + } internal fun findAssociatedObjectImpl(key: KClassImpl<*>): Any? = findAssociatedObjectImpl(this.typeInfo, key.typeInfo) } +internal val KClass<*>.fullName: String? + get() = (this as? KClassImpl<*>)?.fullName + @PublishedApi internal fun KClass<*>.findAssociatedObject(key: KClass<*>): Any? = if (this is KClassImpl<*> && key is KClassImpl<*>) {