Skip to content

Commit 018a578

Browse files
committed
Add debug utility to find a path to the target object
1 parent 066d2f5 commit 018a578

File tree

1 file changed

+61
-10
lines changed

1 file changed

+61
-10
lines changed

kotlinx-coroutines-core/jvm/test/FieldWalker.kt

+61-10
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ package kotlinx.coroutines
77
import java.lang.reflect.*
88
import java.util.*
99
import java.util.Collections.*
10+
import kotlin.collections.ArrayList
1011

1112
object FieldWalker {
1213

@@ -22,12 +23,6 @@ object FieldWalker {
2223
val element = stack.removeLast()
2324
val type = element.javaClass
2425
type.visit(element, result, stack)
25-
26-
var superclass = type.superclass
27-
while (superclass != Any::class.java && superclass != null) {
28-
superclass.visit(element, result, stack)
29-
superclass = superclass.superclass
30-
}
3126
}
3227
return result
3328
}
@@ -56,9 +51,65 @@ object FieldWalker {
5651
}
5752
}
5853

59-
private fun Class<*>.fields() = declaredFields.filter {
60-
!it.type.isPrimitive
61-
&& !Modifier.isStatic(it.modifiers)
62-
&& !(it.type.isArray && it.type.componentType.isPrimitive)
54+
private fun Class<*>.fields(): List<Field> {
55+
val result = ArrayList<Field>()
56+
var type = this
57+
while (type != Any::class.java) {
58+
val fields = type.declaredFields.filter {
59+
!it.type.isPrimitive
60+
&& !Modifier.isStatic(it.modifiers)
61+
&& !(it.type.isArray && it.type.componentType.isPrimitive)
62+
}
63+
result.addAll(fields)
64+
type = type.superclass
65+
}
66+
67+
return result
68+
}
69+
70+
// Debugging-only
71+
@Suppress("UNUSED")
72+
fun printPath(from: Any, to: Any) {
73+
val pathNodes = ArrayList<String>()
74+
val visited = newSetFromMap<Any>(IdentityHashMap())
75+
visited.add(from)
76+
if (findPath(from, to, visited, pathNodes)) {
77+
pathNodes.reverse()
78+
println(pathNodes.joinToString(" -> ", from.javaClass.simpleName + " -> ", "-> " + to.javaClass.simpleName))
79+
} else {
80+
println("Path from $from to $to not found")
81+
}
82+
}
83+
84+
private fun findPath(from: Any, to: Any, visited: MutableSet<Any>, pathNodes: MutableList<String>): Boolean {
85+
if (from === to) {
86+
return true
87+
}
88+
89+
val type = from.javaClass
90+
if (type.isArray) {
91+
if (type.componentType.isPrimitive) return false
92+
val array = from as Array<Any?>
93+
array.filterNotNull().forEach {
94+
if (findPath(it, to, visited, pathNodes)) {
95+
return true
96+
}
97+
}
98+
return false
99+
}
100+
101+
val fields = type.fields()
102+
fields.forEach {
103+
it.isAccessible = true
104+
val value = it.get(from) ?: return@forEach
105+
if (!visited.add(value)) return@forEach
106+
val found = findPath(value, to, visited, pathNodes)
107+
if (found) {
108+
pathNodes += from.javaClass.simpleName + ":" + it.name
109+
return true
110+
}
111+
}
112+
113+
return false
63114
}
64115
}

0 commit comments

Comments
 (0)