Skip to content

Commit 588a619

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

File tree

1 file changed

+60
-10
lines changed

1 file changed

+60
-10
lines changed

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

+60-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,64 @@ 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+
fun printPath(from: Any, to: Any) {
72+
val pathNodes = ArrayList<String>()
73+
val visited = newSetFromMap<Any>(IdentityHashMap())
74+
visited.add(from)
75+
if (findPath(from, to, visited, pathNodes)) {
76+
pathNodes.reverse()
77+
println(pathNodes.joinToString(" -> ", from.javaClass.simpleName + " -> ", "-> " + to.javaClass.simpleName))
78+
} else {
79+
println("Path from $from to $to not found")
80+
}
81+
}
82+
83+
private fun findPath(from: Any, to: Any, visited: MutableSet<Any>, pathNodes: MutableList<String>): Boolean {
84+
if (from === to) {
85+
return true
86+
}
87+
88+
val type = from.javaClass
89+
if (type.isArray) {
90+
if (type.componentType.isPrimitive) return false
91+
val array = from as Array<Any?>
92+
array.filterNotNull().forEach {
93+
if (findPath(it, to, visited, pathNodes)) {
94+
return true
95+
}
96+
}
97+
return false
98+
}
99+
100+
val fields = type.fields()
101+
fields.forEach {
102+
it.isAccessible = true
103+
val value = it.get(from) ?: return@forEach
104+
if (!visited.add(value)) return@forEach
105+
val found = findPath(value, to, visited, pathNodes)
106+
if (found) {
107+
pathNodes += from.javaClass.simpleName + ":" + it.name
108+
return true
109+
}
110+
}
111+
112+
return false
63113
}
64114
}

0 commit comments

Comments
 (0)