kotlinx.reflect.lite.descriptors.impl.ClassBasedDeclarationContainerDescriptorImpl.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of kotlinx.reflect.lite Show documentation
Show all versions of kotlinx.reflect.lite Show documentation
Experimental lightweight library that replaces existing 'kotlin-reflect' implementation
The newest version!
/*
* Copyright 2016-2022 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
// Most logic copied from: https://github.com/JetBrains/kotlin/blob/master/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KDeclarationContainerImpl.kt
package kotlinx.reflect.lite.descriptors.impl
import kotlinx.reflect.lite.builtins.*
import kotlinx.reflect.lite.descriptors.*
import kotlinx.reflect.lite.impl.*
import kotlinx.reflect.lite.impl.KotlinReflectionInternalError
import kotlinx.reflect.lite.misc.*
import java.lang.reflect.*
internal abstract class ClassBasedDeclarationContainerDescriptorImpl(
override val jClass: Class<*>
) : ClassBasedDeclarationContainerDescriptor {
protected open val methodOwner: Class<*> by lazy {
jClass.wrapperByPrimitive ?: jClass
}
override val module by lazy {
ModuleDescriptorImpl(jClass.safeClassLoader)
}
abstract val memberScope: MemberScope
abstract val staticScope: MemberScope
private val declaredNonStaticMembers: Collection> by lazy {
getMembers(memberScope, MemberBelonginess.DECLARED)
}
private val declaredStaticMembers: Collection> by lazy {
getMembers(staticScope, MemberBelonginess.DECLARED)
}
private val inheritedNonStaticMembers: Collection> by lazy {
getMembers(memberScope, MemberBelonginess.INHERITED)
}
private val inheritedStaticMembers: Collection> by lazy {
getMembers(staticScope, MemberBelonginess.INHERITED)
}
private val allNonStaticMembers: Collection> by lazy {
declaredNonStaticMembers + inheritedNonStaticMembers
}
private val allStaticMembers: Collection> by lazy {
declaredStaticMembers + inheritedStaticMembers
}
override val declaredMembers: Collection> by lazy {
declaredNonStaticMembers + declaredStaticMembers
}
override val allMembers: Collection> by lazy {
allNonStaticMembers + allStaticMembers
}
private fun getMembers(scope: MemberScope, belonginess: MemberBelonginess): Collection> =
(scope.functions + scope.properties).mapNotNull { descriptor ->
if (belonginess.accept(descriptor)) createKCallable(descriptor) else null
}.toList()
protected enum class MemberBelonginess {
DECLARED,
INHERITED;
fun accept(member: CallableDescriptor): Boolean =
member.isReal == (this == DECLARED)
}
private fun Class<*>.lookupMethod(
name: String, parameterTypes: Array>, returnType: Class<*>, isStaticDefault: Boolean
): Method? {
// Static "$default" method in any class takes an instance of that class as the first parameter.
if (isStaticDefault) {
parameterTypes[0] = this
}
tryGetMethod(name, parameterTypes, returnType)?.let { return it }
superclass?.lookupMethod(name, parameterTypes, returnType, isStaticDefault)?.let { return it }
// TODO: avoid exponential complexity here
for (superInterface in interfaces) {
superInterface.lookupMethod(name, parameterTypes, returnType, isStaticDefault)?.let { return it }
// Static "$default" methods should be looked up in each DefaultImpls class, see KT-33430
if (isStaticDefault) {
val defaultImpls = superInterface.safeClassLoader.tryLoadClass(superInterface.name + JvmAbi.DEFAULT_IMPLS_SUFFIX)
if (defaultImpls != null) {
parameterTypes[0] = superInterface
defaultImpls.tryGetMethod(name, parameterTypes, returnType)?.let { return it }
}
}
}
return null
}
private fun Class<*>.tryGetMethod(name: String, parameterTypes: Array>, returnType: Class<*>): Method? =
try {
val result = getDeclaredMethod(name, *parameterTypes)
if (result.returnType == returnType) result
else {
// If we've found a method with an unexpected return type, it's likely that there are several methods in this class
// with the given parameter types and Java reflection API has returned not the one we're looking for.
// Falling back to enumerating all methods in the class in this (rather rare) case.
// Example: class A(val x: Int) { fun getX(): String = ... }
declaredMethods.firstOrNull { method ->
method.name == name && method.returnType == returnType && method.parameterTypes.contentEquals(parameterTypes)
}
}
} catch (e: NoSuchMethodException) {
null
}
private fun Class<*>.tryGetConstructor(parameterTypes: List>): Constructor<*>? =
try {
getDeclaredConstructor(*parameterTypes.toTypedArray())
} catch (e: NoSuchMethodException) {
null
}
override fun findMethodBySignature(name: String, desc: String): Method? {
if (name == "") return null
val parameterTypes = loadParameterTypes(desc).toTypedArray()
val returnType = loadReturnType(desc)
methodOwner.lookupMethod(name, parameterTypes, returnType, false)?.let { return it }
// Methods from java.lang.Object (equals, hashCode, toString) cannot be found in the interface via
// Class.getMethod/getDeclaredMethod, so for interfaces, we also look in java.lang.Object.
if (methodOwner.isInterface) {
Any::class.java.lookupMethod(name, parameterTypes, returnType, false)?.let { return it }
}
return null
}
override fun findDefaultMethod(name: String, desc: String, isMember: Boolean): Method? {
if (name == "") return null
val parameterTypes = arrayListOf>()
if (isMember) {
// Note that this value is replaced inside the lookupMethod call below, for each class/interface in the hierarchy.
parameterTypes.add(jClass)
}
addParametersAndMasks(parameterTypes, desc, false)
return methodOwner.lookupMethod(
name + JvmAbi.DEFAULT_PARAMS_IMPL_SUFFIX, parameterTypes.toTypedArray(), loadReturnType(desc), isStaticDefault = isMember
)
}
override fun findConstructorBySignature(desc: String): Constructor<*>? =
jClass.tryGetConstructor(loadParameterTypes(desc))
override fun findDefaultConstructor(desc: String): Constructor<*>? =
jClass.tryGetConstructor(arrayListOf>().also { parameterTypes ->
addParametersAndMasks(parameterTypes, desc, true)
})
private fun addParametersAndMasks(result: MutableList>, desc: String, isConstructor: Boolean) {
val valueParameters = loadParameterTypes(desc)
result.addAll(valueParameters)
repeat((valueParameters.size + Integer.SIZE - 1) / Integer.SIZE) {
result.add(Integer.TYPE)
}
result.add(if (isConstructor) DEFAULT_CONSTRUCTOR_MARKER else Any::class.java)
}
private fun loadParameterTypes(desc: String): List> {
val result = arrayListOf>()
var begin = 1
while (desc[begin] != ')') {
var end = begin
while (desc[end] == '[') end++
@Suppress("SpellCheckingInspection")
when (desc[end]) {
in "VZCBSIFJD" -> end++
'L' -> end = desc.indexOf(';', begin) + 1
else -> throw KotlinReflectionInternalError("Unknown type prefix in the method signature: $desc")
}
result.add(parseType(desc, begin, end))
begin = end
}
return result
}
private fun parseType(desc: String, begin: Int, end: Int): Class<*> =
when (desc[begin]) {
'L' -> jClass.safeClassLoader.loadClass(desc.substring(begin + 1, end - 1).replace('/', '.'))
'[' -> parseType(desc, begin + 1, end).createArrayType()
'V' -> Void.TYPE
'Z' -> Boolean::class.java
'C' -> Char::class.java
'B' -> Byte::class.java
'S' -> Short::class.java
'I' -> Int::class.java
'F' -> Float::class.java
'J' -> Long::class.java
'D' -> Double::class.java
else -> throw KotlinReflectionInternalError("Unknown type prefix in the method signature: $desc")
}
private fun loadReturnType(desc: String): Class<*> =
parseType(desc, desc.indexOf(')') + 1, desc.length)
companion object {
private val DEFAULT_CONSTRUCTOR_MARKER = Class.forName("kotlin.jvm.internal.DefaultConstructorMarker")
}
override fun equals(other: Any?): Boolean {
return other is ClassBasedDeclarationContainerDescriptor && jClass == other.jClass
}
override fun hashCode(): Int = jClass.hashCode()
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy