aboutsummaryrefslogtreecommitdiff
path: root/integration/src/main/kotlin/org/jetbrains/dokka/ReflectDsl.kt
blob: 1984a3e5a57aed3f67491da78b033cb272f2c0b2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
package org.jetbrains.dokka

import kotlin.reflect.*
import kotlin.reflect.full.memberFunctions
import kotlin.reflect.full.memberProperties
import kotlin.reflect.jvm.isAccessible

object ReflectDsl {

    class CallOrPropAccess(private val receiver: Any?,
                           private val clz: KClass<*>,
                           private val selector: String) {

        @Suppress("UNCHECKED_CAST")
        operator fun <T : Any?> invoke(vararg a: Any?): T {
            return func!!.call(receiver, *a) as T
        }

        operator fun get(s: String): CallOrPropAccess {
            return v<Any?>()!![s]
        }

        val func: KFunction<*>? by lazy { clz.memberFunctions.find { it.name == selector } }
        val prop: KProperty<*>? by lazy { clz.memberProperties.find { it.name == selector } }

        fun takeIfIsFunc(): CallOrPropAccess? = if (func != null) this else null

        fun takeIfIsProp(): CallOrPropAccess? = if (prop != null) this else null

        @Suppress("UNCHECKED_CAST")
        fun <T : Any?> v(): T {
            val prop = prop!!
            return try {
                prop.getter.apply { isAccessible = true }.call(receiver) as T
            } catch (e: KotlinNullPointerException) {
                // Hack around kotlin-reflect bug KT-18480
                val jclass = clz.java
                val customGetterName = prop.getter.name
                val getterName = if (customGetterName.startsWith("<")) "get" + prop.name.capitalize() else customGetterName
                val getter = jclass.getDeclaredMethod(getterName)
                getter.isAccessible = true

                getter.invoke(receiver) as T

            }
        }

        @Suppress("UNCHECKED_CAST")
        fun v(x: Any?) {
            (prop as KMutableProperty).setter.apply { isAccessible = true }.call(receiver, x)
        }


    }

    operator fun Any.get(s: String): CallOrPropAccess {
        val clz = this.javaClass.kotlin
        return CallOrPropAccess(this, clz, s)
    }

    operator fun Any.get(s: String, clz: Class<*>): CallOrPropAccess {
        val kclz = clz.kotlin
        return CallOrPropAccess(this, kclz, s)
    }

    operator fun Any.get(s: String, clz: KClass<*>): CallOrPropAccess {
        return CallOrPropAccess(this, clz, s)
    }

    inline infix fun Any.isInstance(clz: Class<*>?): Boolean = clz != null && clz.isAssignableFrom(this.javaClass)
    inline infix fun Any.isNotInstance(clz: Class<*>?): Boolean = !(this isInstance clz)
}