diff --git a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/DescriptorByIdSignatureFinder.kt b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/DescriptorByIdSignatureFinder.kt index 6459e47d8dc..b5f2fe9715d 100644 --- a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/DescriptorByIdSignatureFinder.kt +++ b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/DescriptorByIdSignatureFinder.kt @@ -7,9 +7,13 @@ package org.jetbrains.kotlin.backend.common.serialization import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl +import org.jetbrains.kotlin.incremental.components.NoLookupLocation import org.jetbrains.kotlin.ir.util.IdSignature import org.jetbrains.kotlin.ir.util.KotlinMangler -import org.jetbrains.kotlin.resolve.scopes.getDescriptorsFiltered +import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.resolve.scopes.MemberScope +import org.jetbrains.kotlin.utils.addIfNotNull class DescriptorByIdSignatureFinder( private val moduleDescriptor: ModuleDescriptor, @@ -35,11 +39,12 @@ class DescriptorByIdSignatureFinder( MODULE_ONLY } - fun findDescriptorBySignature(signature: IdSignature): DeclarationDescriptor? = when (signature) { - is IdSignature.AccessorSignature -> findDescriptorForAccessorSignature(signature) - is IdSignature.PublicSignature -> findDescriptorForPublicSignature(signature) - else -> error("only PublicSignature or AccessorSignature should reach this point, got $signature") - } + fun findDescriptorBySignature(signature: IdSignature): DeclarationDescriptor? = + when (signature) { + is IdSignature.AccessorSignature -> findDescriptorForAccessorSignature(signature) + is IdSignature.PublicSignature -> findDescriptorForPublicSignature(signature) + else -> error("only PublicSignature or AccessorSignature should reach this point, got $signature") + } private fun findDescriptorForAccessorSignature(signature: IdSignature.AccessorSignature): DeclarationDescriptor? { val propertyDescriptor = findDescriptorBySignature(signature.propertySignature) as? PropertyDescriptor @@ -48,37 +53,77 @@ class DescriptorByIdSignatureFinder( return propertyDescriptor.accessors.singleOrNull { it.name.asString() == shortName } } - private fun performLookup(signature: IdSignature.PublicSignature): Collection { - val declarationName = signature.firstNameSegment + private fun isConstructorName(n: Name) = n.isSpecial && n.asString() == "" + + private fun MemberScope.loadDescriptors(name: String, isLeaf: Boolean): Collection { + val descriptorName = Name.guessByFirstCharacter(name) + val classifier = getContributedClassifier(descriptorName, NoLookupLocation.FROM_BACKEND) + if (!isLeaf) { + return listOfNotNull(classifier) + } + + val result = mutableListOf() + classifier?.let { result.add(it) } + + result.addAll(getContributedFunctions(descriptorName, NoLookupLocation.FROM_BACKEND)) + result.addAll(getContributedVariables(descriptorName, NoLookupLocation.FROM_BACKEND)) + + return result + } + + private fun performLookup(nameSegments: List, packageFqName: FqName): Collection { + val declarationName = nameSegments[0] + val isLeaf = nameSegments.size == 1 return when (lookupMode) { LookupMode.MODULE_WITH_DEPENDENCIES -> { moduleDescriptor - .getPackage(signature.packageFqName()) - .memberScope - .getContributedDescriptors { name -> name.asString() == declarationName } + .getPackage(packageFqName) + .memberScope.loadDescriptors(declarationName, isLeaf) } LookupMode.MODULE_ONLY -> { (moduleDescriptor as ModuleDescriptorImpl) .packageFragmentProviderForModuleContentWithoutDependencies - .getPackageFragments(signature.packageFqName()) - .map { it.getMemberScope() } - .flatMap { it.getContributedDescriptors { name -> name.asString() == declarationName } } + .getPackageFragments(packageFqName) + .flatMap { it.getMemberScope().loadDescriptors(declarationName, isLeaf) } } } } private fun findDescriptorForPublicSignature(signature: IdSignature.PublicSignature): DeclarationDescriptor? { - val toplevelDescriptors = performLookup(signature) + val nameSegments = signature.nameSegments + val toplevelDescriptors = performLookup(nameSegments, signature.packageFqName()) .ifEmpty { return null } - val candidates = signature.nameSegments.drop(1).fold(toplevelDescriptors) { acc, current -> - acc.flatMap { container -> + + var acc = toplevelDescriptors + val lastIndex = nameSegments.lastIndex + + // The code bellow could look tricky because of it is bottle neck so here is put some attempt including + // 1. Minimize amount of descriptors is loaded on each step + // 2. Reduce memory pollution + for (i in 1 until nameSegments.size) { + val current = Name.guessByFirstCharacter(nameSegments[i]) + acc = acc.flatMap { container -> val classDescriptor = container as? ClassDescriptor ?: return@flatMap emptyList() - classDescriptor.constructors.filter { it.name.asString() == current } + - classDescriptor.unsubstitutedMemberScope.getDescriptorsFiltered { name -> name.asString() == current } + - // Static scope is required only for Enum.values() and Enum.valueOf(). - classDescriptor.staticScope.getDescriptorsFiltered { name -> name.asString() == current } + val isLeaf = i == lastIndex + val memberScope = classDescriptor.unsubstitutedMemberScope + + val classifier = memberScope.getContributedClassifier(current, NoLookupLocation.FROM_BACKEND) + if (!isLeaf) { + classifier?.let { listOf(it) } ?: emptyList() + } else { + mutableListOf().apply { + addIfNotNull(classifier) + if (signature.id != null) { + if (isConstructorName(current)) addAll(classDescriptor.constructors) + addAll(memberScope.getContributedFunctions(current, NoLookupLocation.FROM_BACKEND)) + addAll(memberScope.getContributedVariables(current, NoLookupLocation.FROM_BACKEND)) + addAll(classDescriptor.staticScope.getContributedDescriptors { it == current }) + } + } + } } } + val candidates = acc return when (candidates.size) { 1 -> candidates.first()