All Downloads are FREE. Search and download functionalities are using the official Maven repository.

kotlin.reflect.jvm.internal.KDeclarationContainerImpl.kt Maven / Gradle / Ivy

There is a newer version: 2.1.0-RC
Show newest version
/*
 * Copyright 2010-2015 JetBrains s.r.o.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package kotlin.reflect.jvm.internal

import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.impl.DeclarationDescriptorVisitorEmptyBodies
import org.jetbrains.kotlin.load.java.JvmAbi
import org.jetbrains.kotlin.load.java.structure.reflect.createArrayType
import org.jetbrains.kotlin.load.java.structure.reflect.safeClassLoader
import org.jetbrains.kotlin.load.kotlin.reflect.RuntimeModuleData
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.scopes.MemberScope
import java.lang.reflect.Constructor
import java.lang.reflect.Field
import java.lang.reflect.Method
import kotlin.jvm.internal.ClassBasedDeclarationContainer
import kotlin.reflect.KCallable
import kotlin.reflect.KotlinReflectionInternalError

internal abstract class KDeclarationContainerImpl : ClassBasedDeclarationContainer {
    // Note: this is stored here on a soft reference to prevent GC from destroying the weak reference to it in the moduleByClassLoader cache
    private val moduleData_ = ReflectProperties.lazySoft {
        jClass.getOrCreateModule()
    }

    val moduleData: RuntimeModuleData
        get() = moduleData_()

    abstract val constructorDescriptors: Collection

    abstract fun getProperties(name: Name): Collection

    abstract fun getFunctions(name: Name): Collection

    fun getMembers(scope: MemberScope, declaredOnly: Boolean, nonExtensions: Boolean, extensions: Boolean): Sequence> {
        val visitor = object : DeclarationDescriptorVisitorEmptyBodies?, Unit>() {
            private fun skipCallable(descriptor: CallableMemberDescriptor): Boolean {
                if (declaredOnly && !descriptor.kind.isReal) return true

                val isExtension = descriptor.extensionReceiverParameter != null
                if (isExtension && !extensions) return true
                if (!isExtension && !nonExtensions) return true

                return false
            }

            override fun visitPropertyDescriptor(descriptor: PropertyDescriptor, data: Unit): KCallable<*>? {
                return if (skipCallable(descriptor)) null else createProperty(descriptor)
            }

            override fun visitFunctionDescriptor(descriptor: FunctionDescriptor, data: Unit): KCallable<*>? {
                return if (skipCallable(descriptor)) null else KFunctionImpl(this@KDeclarationContainerImpl, descriptor)
            }

            override fun visitConstructorDescriptor(descriptor: ConstructorDescriptor, data: Unit): KCallable<*>? {
                throw IllegalStateException("No constructors should appear in this scope: $descriptor")
            }
        }

        return scope.getContributedDescriptors().asSequence()
                .filter { descriptor ->
                    descriptor !is MemberDescriptor || descriptor.visibility != Visibilities.INVISIBLE_FAKE
                }
                .map { descriptor ->
                    descriptor.accept(visitor, Unit)
                }
                .filterNotNull()
    }

    private fun createProperty(descriptor: PropertyDescriptor): KPropertyImpl<*> {
        val receiverCount = (descriptor.dispatchReceiverParameter?.let { 1 } ?: 0) +
                            (descriptor.extensionReceiverParameter?.let { 1 } ?: 0)

        when {
            descriptor.isVar -> when (receiverCount) {
                0 -> return KMutableProperty0Impl(this, descriptor)
                1 -> return KMutableProperty1Impl(this, descriptor)
                2 -> return KMutableProperty2Impl(this, descriptor)
            }
            else -> when (receiverCount) {
                0 -> return KProperty0Impl(this, descriptor)
                1 -> return KProperty1Impl(this, descriptor)
                2 -> return KProperty2Impl(this, descriptor)
            }
        }

        throw KotlinReflectionInternalError("Unsupported property: $descriptor")
    }

    fun findPropertyDescriptor(name: String, signature: String): PropertyDescriptor {
        val properties = getProperties(Name.guess(name))
                .filter { descriptor ->
                    descriptor is PropertyDescriptor &&
                    RuntimeTypeMapper.mapPropertySignature(descriptor).asString() == signature
                }

        if (properties.size != 1) {
            val debugText = "'$name' (JVM signature: $signature)"
            throw KotlinReflectionInternalError(
                    if (properties.isEmpty()) "Property $debugText not resolved in $this"
                    else "${properties.size} properties $debugText resolved in $this: $properties"
            )
        }

        return properties.single()
    }

    fun findFunctionDescriptor(name: String, signature: String): FunctionDescriptor {
        val functions = (if (name == "") constructorDescriptors.toList() else getFunctions(Name.guess(name)))
                .filter { descriptor ->
                    RuntimeTypeMapper.mapSignature(descriptor).asString() == signature
                }

        if (functions.size != 1) {
            val debugText = "'$name' (JVM signature: $signature)"
            throw KotlinReflectionInternalError(
                    if (functions.isEmpty()) "Function $debugText not resolved in $this"
                    else "${functions.size} functions $debugText resolved in $this: $functions"
            )
        }

        return functions.single()
    }

    private fun Class<*>.tryGetMethod(name: String, parameterTypes: List>, declared: Boolean) =
            try {
                if (declared) getDeclaredMethod(name, *parameterTypes.toTypedArray())
                else getMethod(name, *parameterTypes.toTypedArray())
            }
            catch (e: NoSuchMethodException) {
                null
            }

    private fun Class<*>.tryGetConstructor(parameterTypes: List>, declared: Boolean) =
            try {
                if (declared) getDeclaredConstructor(*parameterTypes.toTypedArray())
                else getConstructor(*parameterTypes.toTypedArray())
            }
            catch (e: NoSuchMethodException) {
                null
            }

    // TODO: check resulting method's return type
    fun findMethodBySignature(name: String, desc: String, declared: Boolean): Method? {
        if (name == "") return null

        // Method for a top level function should be the one from the package facade.
        // This is likely to change after the package part reform.
        return jClass.tryGetMethod(name, loadParameterTypes(desc), declared)
    }

    fun findDefaultMethod(name: String, desc: String, isMember: Boolean, declared: Boolean): Method? {
        if (name == "") return null

        val parameterTypes = arrayListOf>()
        if (isMember) {
            parameterTypes.add(jClass)
        }
        addParametersAndMasks(parameterTypes, desc, false)

        return jClass.tryGetMethod(name + JvmAbi.DEFAULT_PARAMS_IMPL_SUFFIX, parameterTypes, declared)
    }

    fun findConstructorBySignature(desc: String, declared: Boolean): Constructor<*>? {
        return jClass.tryGetConstructor(loadParameterTypes(desc), declared)
    }

    fun findDefaultConstructor(desc: String, declared: Boolean): Constructor<*>? {
        val parameterTypes = arrayListOf>()
        addParametersAndMasks(parameterTypes, desc, true)

        return jClass.tryGetConstructor(parameterTypes, declared)
    }

    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 classLoader = jClass.safeClassLoader
        val result = arrayListOf>()

        var i = 1
        while (desc[i] != ')') {
            var arrayDimension = 0
            while (desc[i] == '[') {
                arrayDimension++
                i++
            }

            var type = when (desc[i++]) {
                'L' -> {
                    val semicolon = desc.indexOf(';', i)
                    val internalName = desc.substring(i, semicolon)
                    i = semicolon + 1
                    classLoader.loadClass(internalName.replace('/', '.'))
                }
                'V' -> Void.TYPE
                'Z' -> java.lang.Boolean.TYPE
                'C' -> java.lang.Character.TYPE
                'B' -> java.lang.Byte.TYPE
                'S' -> java.lang.Short.TYPE
                'I' -> java.lang.Integer.TYPE
                'F' -> java.lang.Float.TYPE
                'J' -> java.lang.Long.TYPE
                'D' -> java.lang.Double.TYPE
                else -> throw KotlinReflectionInternalError("Unknown type prefix in the method signature: $desc")
            }

            repeat(arrayDimension) {
                type = type.createArrayType()
            }

            result.add(type)
        }

        return result
    }

    // TODO: check resulting field's type
    fun findFieldBySignature(name: String, isCompanionOfClass: Boolean): Field? {
        val owner = if (isCompanionOfClass) jClass.enclosingClass else jClass

        return try {
            owner.getDeclaredField(name)
        }
        catch (e: NoSuchFieldException) {
            null
        }
    }

    companion object {
        private val DEFAULT_CONSTRUCTOR_MARKER = Class.forName("kotlin.jvm.internal.DefaultConstructorMarker")
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy