Do not use .kotlin_module files in reflection
Previously, we used a pretty roundabout way to load a MemberScope from a single file facade represented by KPackageImpl, which involved going through ModuleDescriptor, PackageFragmentProvider, PackagePartProvider etc. The only advantage of this approach was that it sort of works similarly as in the compiler, however mutable state in RuntimePackagePartProvider and the fact that .kotlin_module files were required for this to work diminished this advantage. In this change, we load MemberScope from a KPackageImpl pretty much directly, by using the existing method `DeserializedDescriptorResolver.createKotlinPackagePartScope` and caching the result in the new component PackagePartScopeCache. #KT-30344 Fixed
This commit is contained in:
@@ -16,10 +16,10 @@
|
||||
|
||||
package kotlin.reflect.jvm.internal
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.ConstructorDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||
import org.jetbrains.kotlin.load.java.lazy.descriptors.LazyJavaPackageFragment
|
||||
import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinaryPackageSourceElement
|
||||
import org.jetbrains.kotlin.metadata.ProtoBuf
|
||||
import org.jetbrains.kotlin.metadata.deserialization.TypeTable
|
||||
import org.jetbrains.kotlin.metadata.deserialization.getExtensionOrNull
|
||||
@@ -30,7 +30,6 @@ import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmProtoBufUtil
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.scopes.MemberScope
|
||||
import org.jetbrains.kotlin.serialization.deserialization.MemberDeserializer
|
||||
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedCallableMemberDescriptor
|
||||
import kotlin.reflect.KCallable
|
||||
import kotlin.reflect.jvm.internal.KDeclarationContainerImpl.MemberBelonginess.DECLARED
|
||||
import kotlin.reflect.jvm.internal.components.ReflectKotlinClass
|
||||
@@ -42,26 +41,24 @@ internal class KPackageImpl(
|
||||
) : KDeclarationContainerImpl() {
|
||||
private inner class Data : KDeclarationContainerImpl.Data() {
|
||||
private val kotlinClass: ReflectKotlinClass? by ReflectProperties.lazySoft {
|
||||
// TODO: do not read ReflectKotlinClass multiple times
|
||||
ReflectKotlinClass.create(jClass)
|
||||
}
|
||||
|
||||
val descriptor: PackageViewDescriptor by ReflectProperties.lazySoft {
|
||||
with(moduleData) {
|
||||
kotlinClass?.packageModuleName?.let(packagePartProvider::registerModule)
|
||||
module.getPackage(jClass.classId.packageFqName)
|
||||
}
|
||||
val scope: MemberScope by ReflectProperties.lazySoft {
|
||||
val klass = kotlinClass
|
||||
|
||||
if (klass != null)
|
||||
moduleData.packagePartScopeCache.getPackagePartScope(klass)
|
||||
else MemberScope.Empty
|
||||
}
|
||||
|
||||
val methodOwner: Class<*> by ReflectProperties.lazy {
|
||||
val multifileFacade: Class<*>? by ReflectProperties.lazy {
|
||||
val facadeName = kotlinClass?.classHeader?.multifileClassName
|
||||
// We need to check isNotEmpty because this is the value read from the annotation which cannot be null.
|
||||
// The default value for 'xs' is empty string, as declared in kotlin.Metadata
|
||||
if (facadeName != null && facadeName.isNotEmpty()) {
|
||||
if (facadeName != null && facadeName.isNotEmpty())
|
||||
jClass.classLoader.loadClass(facadeName.replace('/', '.'))
|
||||
} else {
|
||||
jClass
|
||||
}
|
||||
else null
|
||||
}
|
||||
|
||||
val metadata: Triple<JvmNameResolver, ProtoBuf.Package, JvmMetadataVersion>? by ReflectProperties.lazy {
|
||||
@@ -76,20 +73,15 @@ internal class KPackageImpl(
|
||||
}
|
||||
|
||||
val members: Collection<KCallableImpl<*>> by ReflectProperties.lazySoft {
|
||||
getMembers(scope, DECLARED).filter { member ->
|
||||
val callableDescriptor = member.descriptor as DeserializedCallableMemberDescriptor
|
||||
val packageFragment = callableDescriptor.containingDeclaration as PackageFragmentDescriptor
|
||||
val source = (packageFragment as? LazyJavaPackageFragment)?.source as? KotlinJvmBinaryPackageSourceElement
|
||||
(source?.getContainingBinaryClass(callableDescriptor) as? ReflectKotlinClass)?.klass == jClass
|
||||
}
|
||||
getMembers(scope, DECLARED)
|
||||
}
|
||||
}
|
||||
|
||||
private val data = ReflectProperties.lazy { Data() }
|
||||
|
||||
override val methodOwner: Class<*> get() = data().methodOwner
|
||||
override val methodOwner: Class<*> get() = data().multifileFacade ?: jClass
|
||||
|
||||
private val scope: MemberScope get() = data().descriptor.memberScope
|
||||
private val scope: MemberScope get() = data().scope
|
||||
|
||||
override val members: Collection<KCallable<*>> get() = data().members
|
||||
|
||||
@@ -119,8 +111,6 @@ internal class KPackageImpl(
|
||||
override fun hashCode(): Int =
|
||||
jClass.hashCode()
|
||||
|
||||
override fun toString(): String {
|
||||
val fqName = jClass.classId.packageFqName
|
||||
return "package " + (if (fqName.isRoot) "<default>" else fqName.asString())
|
||||
}
|
||||
override fun toString(): String =
|
||||
"file class ${jClass.classId.asSingleFqName()}"
|
||||
}
|
||||
|
||||
@@ -20,13 +20,12 @@ import org.jetbrains.kotlin.builtins.jvm.JavaToKotlinClassMap
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotated
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
|
||||
import org.jetbrains.kotlin.load.java.JvmAbi
|
||||
import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinarySourceElement
|
||||
import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader
|
||||
import org.jetbrains.kotlin.metadata.ProtoBuf
|
||||
import org.jetbrains.kotlin.metadata.deserialization.*
|
||||
import org.jetbrains.kotlin.metadata.jvm.JvmProtoBuf
|
||||
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmProtoBufUtil
|
||||
import org.jetbrains.kotlin.metadata.deserialization.BinaryVersion
|
||||
import org.jetbrains.kotlin.metadata.deserialization.NameResolver
|
||||
import org.jetbrains.kotlin.metadata.deserialization.TypeTable
|
||||
import org.jetbrains.kotlin.metadata.deserialization.VersionRequirementTable
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.protobuf.MessageLite
|
||||
@@ -169,27 +168,6 @@ internal fun Any?.asKPropertyImpl(): KPropertyImpl<*>? =
|
||||
internal fun Any?.asKCallableImpl(): KCallableImpl<*>? =
|
||||
this as? KCallableImpl<*> ?: asKFunctionImpl() ?: asKPropertyImpl()
|
||||
|
||||
internal val ReflectKotlinClass.packageModuleName: String?
|
||||
get() {
|
||||
val header = classHeader
|
||||
if (!header.metadataVersion.isCompatible()) return null
|
||||
|
||||
return when (header.kind) {
|
||||
KotlinClassHeader.Kind.FILE_FACADE, KotlinClassHeader.Kind.MULTIFILE_CLASS_PART -> {
|
||||
// TODO: avoid reading and parsing metadata twice (here and later in KPackageImpl#descriptor)
|
||||
val (nameResolver, proto) = JvmProtoBufUtil.readPackageDataFrom(header.data!!, header.strings!!)
|
||||
// If no packageModuleName extension is written, the name is assumed to be JvmAbi.DEFAULT_MODULE_NAME
|
||||
// (see JvmSerializerExtension.serializePackage)
|
||||
proto.getExtensionOrNull(JvmProtoBuf.packageModuleName)?.let(nameResolver::getString) ?: JvmAbi.DEFAULT_MODULE_NAME
|
||||
}
|
||||
KotlinClassHeader.Kind.MULTIFILE_CLASS -> {
|
||||
val partName = header.multifilePartNames.firstOrNull() ?: return null
|
||||
ReflectKotlinClass.create(klass.classLoader.loadClass(partName.replace('/', '.')))?.packageModuleName
|
||||
}
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
internal val CallableDescriptor.instanceReceiverParameter: ReceiverParameterDescriptor?
|
||||
get() =
|
||||
if (dispatchReceiverParameter != null) (containingDeclaration as ClassDescriptor).thisAsReceiverParameter
|
||||
|
||||
Reference in New Issue
Block a user