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

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

There is a newer version: 2.1.0-Beta1
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.annotations.Annotated
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.load.java.JvmAbi
import org.jetbrains.kotlin.load.java.reflect.tryLoadClass
import org.jetbrains.kotlin.load.java.sources.JavaSourceElement
import org.jetbrains.kotlin.load.java.structure.reflect.ReflectJavaClass
import org.jetbrains.kotlin.load.java.structure.reflect.safeClassLoader
import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinarySourceElement
import org.jetbrains.kotlin.load.kotlin.reflect.ReflectKotlinClass
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.platform.JavaToKotlinClassMap
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.scopes.MemberScope
import org.jetbrains.kotlin.serialization.deserialization.findClassAcrossModuleDependencies
import kotlin.reflect.KCallable
import kotlin.reflect.KClass
import kotlin.reflect.KFunction
import kotlin.reflect.KotlinReflectionInternalError

internal class KClassImpl(override val jClass: Class) : KDeclarationContainerImpl(), KClass, KAnnotatedElementImpl {
    private val descriptor_ = ReflectProperties.lazySoft {
        val classId = classId

        val descriptor =
                if (classId.isLocal) moduleData.localClassResolver.resolveLocalClass(classId)
                else moduleData.module.findClassAcrossModuleDependencies(classId)

        descriptor ?: throw KotlinReflectionInternalError("Class not resolved: $jClass")
    }

    val descriptor: ClassDescriptor
        get() = descriptor_()

    override val annotated: Annotated get() = descriptor

    private val classId: ClassId get() = RuntimeTypeMapper.mapJvmClassToKotlinClassId(jClass)

    internal val memberScope: MemberScope get() = descriptor.defaultType.memberScope

    internal val staticScope: MemberScope get() = descriptor.staticScope

    override val members: Collection>
        get() = getMembers(memberScope, declaredOnly = false, nonExtensions = true, extensions = true)
                .plus(getMembers(staticScope, declaredOnly = false, nonExtensions = true, extensions = true))
                .toList()

    override val constructorDescriptors: Collection
        get() {
            val descriptor = descriptor
            if (descriptor.kind == ClassKind.CLASS || descriptor.kind == ClassKind.ENUM_CLASS) {
                return descriptor.constructors
            }
            return emptyList()
        }

    @Suppress("UNCHECKED_CAST")
    override fun getProperties(name: Name): Collection =
            (memberScope.getContributedVariables(name, NoLookupLocation.FROM_REFLECTION) +
             staticScope.getContributedVariables(name, NoLookupLocation.FROM_REFLECTION))

    override fun getFunctions(name: Name): Collection =
            memberScope.getContributedFunctions(name, NoLookupLocation.FROM_REFLECTION) +
            staticScope.getContributedFunctions(name, NoLookupLocation.FROM_REFLECTION)

    override val simpleName: String? get() {
        if (jClass.isAnonymousClass) return null

        val classId = classId
        return when {
            classId.isLocal -> calculateLocalClassName(jClass)
            else -> classId.shortClassName.asString()
        }
    }

    private fun calculateLocalClassName(jClass: Class<*>): String {
        val name = jClass.simpleName
        jClass.enclosingMethod?.let { method ->
            return name.substringAfter(method.name + "$")
        }
        jClass.enclosingConstructor?.let { constructor ->
            return name.substringAfter(constructor.name + "$")
        }
        return name.substringAfter('$')
    }

    override val qualifiedName: String? get() {
        if (jClass.isAnonymousClass) return null

        val classId = classId
        return when {
            classId.isLocal -> null
            else -> classId.asSingleFqName().asString()
        }
    }

    @Suppress("UNCHECKED_CAST")
    override val constructors: Collection>
        get() = constructorDescriptors.map {
            KFunctionImpl(this, it) as KFunction
        }

    override val nestedClasses: Collection>
        get() = descriptor.unsubstitutedInnerClassesScope.getContributedDescriptors().map { nestedClass ->
            val source = (nestedClass as DeclarationDescriptorWithSource).source
            when (source) {
                is KotlinJvmBinarySourceElement ->
                    (source.binaryClass as ReflectKotlinClass).klass
                is JavaSourceElement ->
                    (source.javaElement as ReflectJavaClass).element
                SourceElement.NO_SOURCE -> {
                    // If neither a Kotlin class nor a Java class, it must be a built-in
                    val classId = JavaToKotlinClassMap.INSTANCE.mapKotlinToJava(DescriptorUtils.getFqName(nestedClass))
                                  ?: throw KotlinReflectionInternalError("Class with no source must be a built-in: $nestedClass")
                    val packageName = classId.packageFqName.asString()
                    val className = classId.relativeClassName.asString().replace('.', '$')
                    // All pseudo-classes like String.Companion must be accessible from the current class loader
                    javaClass.safeClassLoader.tryLoadClass("$packageName.$className")
                }
                else -> throw KotlinReflectionInternalError("Unsupported class: $nestedClass (source = $source)")
            }
        }.filterNotNull().map { KClassImpl(it) }

    @Suppress("UNCHECKED_CAST")
    private val objectInstance_ = ReflectProperties.lazy {
        val descriptor = descriptor
        if (descriptor.kind != ClassKind.OBJECT) return@lazy null

        val field = if (descriptor.isCompanionObject) {
            jClass.enclosingClass.getDeclaredField(descriptor.name.asString())
        }
        else {
            jClass.getDeclaredField(JvmAbi.INSTANCE_FIELD)
        }
        field.get(null) as T
    }

    override val objectInstance: T?
        get() = objectInstance_()

    override fun equals(other: Any?): Boolean =
            other is KClassImpl<*> && jClass == other.jClass

    override fun hashCode(): Int =
            jClass.hashCode()

    override fun toString(): String {
        return "class " + classId.let { classId ->
            val packageFqName = classId.packageFqName
            val packagePrefix = if (packageFqName.isRoot) "" else packageFqName.asString() + "."
            val classSuffix = classId.relativeClassName.asString().replace('.', '$')
            packagePrefix + classSuffix
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy