Collection.toString() should not throw if it contains itself
Merge-request: KT-MR-10591 Merged-by: Abduqodiri Qurbonzoda <abduqodiri.qurbonzoda@jetbrains.com>
This commit is contained in:
committed by
Space Team
parent
6fc02c3408
commit
f152fa537d
@@ -137,18 +137,3 @@ internal external fun arrayCopy(array: DoubleArray, fromIndex: Int, destination:
|
|||||||
@GCUnsafeCall("Kotlin_BooleanArray_copyImpl")
|
@GCUnsafeCall("Kotlin_BooleanArray_copyImpl")
|
||||||
internal external fun arrayCopy(array: BooleanArray, fromIndex: Int, destination: BooleanArray, toIndex: Int, count: Int)
|
internal external fun arrayCopy(array: BooleanArray, fromIndex: Int, destination: BooleanArray, toIndex: Int, count: Int)
|
||||||
|
|
||||||
|
|
||||||
internal fun <E> Collection<E>.collectionToString(): String {
|
|
||||||
val sb = StringBuilder(2 + size * 3)
|
|
||||||
sb.append("[")
|
|
||||||
var i = 0
|
|
||||||
val it = iterator()
|
|
||||||
while (it.hasNext()) {
|
|
||||||
if (i > 0) sb.append(", ")
|
|
||||||
val next = it.next()
|
|
||||||
if (next == this) sb.append("(this Collection)") else sb.append(next)
|
|
||||||
i++
|
|
||||||
}
|
|
||||||
sb.append("]")
|
|
||||||
return sb.toString()
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -174,7 +174,7 @@ internal class ListBuilder<E> private constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun toString(): String {
|
override fun toString(): String {
|
||||||
return array.subarrayContentToString(offset, length)
|
return array.subarrayContentToString(offset, length, this)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------- private ----------------------------
|
// ---------------------------- private ----------------------------
|
||||||
@@ -359,13 +359,18 @@ internal fun <E> arrayOfUninitializedElements(size: Int): Array<E> {
|
|||||||
return arrayOfNulls<Any?>(size) as Array<E>
|
return arrayOfNulls<Any?>(size) as Array<E>
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun <T> Array<out T>.subarrayContentToString(offset: Int, length: Int): String {
|
private fun <T> Array<out T>.subarrayContentToString(offset: Int, length: Int, thisCollection: Collection<T>): String {
|
||||||
val sb = StringBuilder(2 + length * 3)
|
val sb = StringBuilder(2 + length * 3)
|
||||||
sb.append("[")
|
sb.append("[")
|
||||||
var i = 0
|
var i = 0
|
||||||
while (i < length) {
|
while (i < length) {
|
||||||
if (i > 0) sb.append(", ")
|
if (i > 0) sb.append(", ")
|
||||||
sb.append(this[offset + i])
|
val nextElement = this[offset + i]
|
||||||
|
if (nextElement === thisCollection) {
|
||||||
|
sb.append("(this Collection)")
|
||||||
|
} else {
|
||||||
|
sb.append(nextElement)
|
||||||
|
}
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
sb.append("]")
|
sb.append("]")
|
||||||
|
|||||||
@@ -571,10 +571,10 @@ internal class MapBuilder<K, V> private constructor(
|
|||||||
if (index >= map.length) throw NoSuchElementException()
|
if (index >= map.length) throw NoSuchElementException()
|
||||||
lastIndex = index++
|
lastIndex = index++
|
||||||
val key = map.keysArray[lastIndex]
|
val key = map.keysArray[lastIndex]
|
||||||
if (key == map) sb.append("(this Map)") else sb.append(key)
|
if (key === map) sb.append("(this Map)") else sb.append(key)
|
||||||
sb.append('=')
|
sb.append('=')
|
||||||
val value = map.valuesArray!![lastIndex]
|
val value = map.valuesArray!![lastIndex]
|
||||||
if (value == map) sb.append("(this Map)") else sb.append(value)
|
if (value === map) sb.append("(this Map)") else sb.append(value)
|
||||||
initNext()
|
initNext()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -182,7 +182,7 @@ actual class ArrayList<E> private constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun toString(): String {
|
override fun toString(): String {
|
||||||
return backingArray.subarrayContentToString(offset, length)
|
return backingArray.subarrayContentToString(offset, length, this)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
|||||||
@@ -23,13 +23,18 @@ internal fun checkCopyOfRangeArguments(fromIndex: Int, toIndex: Int, size: Int)
|
|||||||
/**
|
/**
|
||||||
* Returns a string representation of the contents of the subarray of the specified array as if it is [List].
|
* Returns a string representation of the contents of the subarray of the specified array as if it is [List].
|
||||||
*/
|
*/
|
||||||
internal inline fun <T> Array<out T>.subarrayContentToString(offset: Int, length: Int): String {
|
internal inline fun <T> Array<out T>.subarrayContentToString(offset: Int, length: Int, thisCollection: Collection<T>): String {
|
||||||
val sb = StringBuilder(2 + length * 3)
|
val sb = StringBuilder(2 + length * 3)
|
||||||
sb.append("[")
|
sb.append("[")
|
||||||
var i = 0
|
var i = 0
|
||||||
while (i < length) {
|
while (i < length) {
|
||||||
if (i > 0) sb.append(", ")
|
if (i > 0) sb.append(", ")
|
||||||
sb.append(this[offset + i])
|
val nextElement = this[offset + i]
|
||||||
|
if (nextElement === thisCollection) {
|
||||||
|
sb.append("(this Collection)")
|
||||||
|
} else {
|
||||||
|
sb.append(nextElement)
|
||||||
|
}
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
sb.append("]")
|
sb.append("]")
|
||||||
|
|||||||
@@ -634,10 +634,10 @@ actual class HashMap<K, V> private constructor(
|
|||||||
if (index >= map.length) throw NoSuchElementException()
|
if (index >= map.length) throw NoSuchElementException()
|
||||||
lastIndex = index++
|
lastIndex = index++
|
||||||
val key = map.keysArray[lastIndex]
|
val key = map.keysArray[lastIndex]
|
||||||
if (key == map) sb.append("(this Map)") else sb.append(key)
|
if (key === map) sb.append("(this Map)") else sb.append(key)
|
||||||
sb.append('=')
|
sb.append('=')
|
||||||
val value = map.valuesArray!![lastIndex]
|
val value = map.valuesArray!![lastIndex]
|
||||||
if (value == map) sb.append("(this Map)") else sb.append(value)
|
if (value === map) sb.append("(this Map)") else sb.append(value)
|
||||||
initNext()
|
initNext()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,9 +5,7 @@
|
|||||||
|
|
||||||
package test.collections
|
package test.collections
|
||||||
|
|
||||||
import test.assertIsNegativeZero
|
import test.*
|
||||||
import test.assertIsPositiveZero
|
|
||||||
import test.assertStaticAndRuntimeTypeIs
|
|
||||||
import kotlin.test.*
|
import kotlin.test.*
|
||||||
import test.collections.behaviors.*
|
import test.collections.behaviors.*
|
||||||
import test.comparisons.STRING_CASE_INSENSITIVE_ORDER
|
import test.comparisons.STRING_CASE_INSENSITIVE_ORDER
|
||||||
@@ -1224,6 +1222,57 @@ class CollectionTest {
|
|||||||
assertEquals("[1, a, null, ${Long.MAX_VALUE.toString()}]", listOf(1, "a", null, Long.MAX_VALUE).toString())
|
assertEquals("[1, a, null, ${Long.MAX_VALUE.toString()}]", listOf(1, "a", null, Long.MAX_VALUE).toString())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test fun toStringContainingThis() = testExceptOn(TestPlatform.Js) {
|
||||||
|
// resulting string is platform-dependent, but shouldn't throw
|
||||||
|
arrayOf<Any>("a", "b", "c").apply { this[1] = this }.toString()
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
"[a, (this Collection), c]",
|
||||||
|
arrayListOf<Any>("a", "b", "c").apply { this[1] = this }.toString()
|
||||||
|
)
|
||||||
|
assertEquals(
|
||||||
|
"[a, (this Collection), c]",
|
||||||
|
buildList<Any> {
|
||||||
|
addAll(listOf("a", "b", "c"))
|
||||||
|
this[1] = this
|
||||||
|
}.toString()
|
||||||
|
)
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
"[a, (this Collection), c]",
|
||||||
|
linkedSetOf<Any>().apply {
|
||||||
|
add("a")
|
||||||
|
add(this)
|
||||||
|
add("c")
|
||||||
|
}.toString()
|
||||||
|
)
|
||||||
|
assertEquals(
|
||||||
|
"[a, (this Collection), c]",
|
||||||
|
buildSet<Any> {
|
||||||
|
add("a")
|
||||||
|
add(this)
|
||||||
|
add("c")
|
||||||
|
}.toString()
|
||||||
|
)
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
"{a=1, (this Map)=(this Map), c=3}",
|
||||||
|
linkedMapOf<Any, Any>().apply {
|
||||||
|
put("a", "1")
|
||||||
|
put(this, this)
|
||||||
|
put("c", "3")
|
||||||
|
}.toString()
|
||||||
|
)
|
||||||
|
assertEquals(
|
||||||
|
"{a=1, (this Map)=(this Map), c=3}",
|
||||||
|
buildMap<Any, Any> {
|
||||||
|
put("a", "1")
|
||||||
|
put(this, this)
|
||||||
|
put("c", "3")
|
||||||
|
}.toString()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
@Test fun randomAccess() {
|
@Test fun randomAccess() {
|
||||||
assertStaticAndRuntimeTypeIs<RandomAccess>(arrayListOf(1))
|
assertStaticAndRuntimeTypeIs<RandomAccess>(arrayListOf(1))
|
||||||
assertTrue(listOf(1, 2) is RandomAccess, "Default read-only list implementation is RandomAccess")
|
assertTrue(listOf(1, 2) is RandomAccess, "Default read-only list implementation is RandomAccess")
|
||||||
|
|||||||
Reference in New Issue
Block a user