diff --git a/core/descriptors/src/org/jetbrains/kotlin/builtins/BuiltinsPackageFragment.kt b/core/descriptors/src/org/jetbrains/kotlin/builtins/BuiltinsPackageFragment.kt index 4d25cb09c4d..d745744f919 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/builtins/BuiltinsPackageFragment.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/builtins/BuiltinsPackageFragment.kt @@ -16,12 +16,12 @@ package org.jetbrains.kotlin.builtins -import org.jetbrains.kotlin.serialization.deserialization.DeserializedPackageFragment import org.jetbrains.kotlin.descriptors.ModuleDescriptor import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.serialization.ProtoBuf import org.jetbrains.kotlin.serialization.builtins.BuiltInsProtoBuf +import org.jetbrains.kotlin.serialization.deserialization.DeserializedPackageFragment import org.jetbrains.kotlin.storage.StorageManager import java.io.InputStream @@ -32,7 +32,7 @@ public class BuiltinsPackageFragment( loadResource: (path: String) -> InputStream? ) : DeserializedPackageFragment(fqName, storageManager, module, BuiltInsSerializedResourcePaths, loadResource) { - protected override fun loadClassNames(fqName: FqName, packageProto: ProtoBuf.Package): Collection { + protected override fun loadClassNames(packageProto: ProtoBuf.Package): Collection { return packageProto.getExtension(BuiltInsProtoBuf.className)?.map { id -> nameResolver.getName(id) } ?: listOf() } } diff --git a/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/ClassDeserializer.kt b/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/ClassDeserializer.kt index f26af6d8b5b..22e680678a8 100644 --- a/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/ClassDeserializer.kt +++ b/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/ClassDeserializer.kt @@ -35,12 +35,24 @@ public class ClassDeserializer(private val components: DeserializationComponents val classData = key.classData ?: components.classDataFinder.findClassData(classId) ?: return null val outerContext = if (classId.isNestedClass()) { - (deserializeClass(classId.getOuterClassId()) as? DeserializedClassDescriptor)?.c ?: return null + val outerClass = deserializeClass(classId.getOuterClassId()) as? DeserializedClassDescriptor ?: return null + + // Find the outer class first and check if he knows anything about the nested class we're looking for + if (!outerClass.hasNestedClass(classId.getShortClassName())) return null + + outerClass.c } else { val fragments = components.packageFragmentProvider.getPackageFragments(classId.getPackageFqName()) assert(fragments.size() == 1) { "There should be exactly one package: $fragments, class id is $classId" } - components.createContext(fragments.single(), classData.getNameResolver()) + + val fragment = fragments.single() + if (fragment is DeserializedPackageFragment) { + // Similarly, verify that the containing package has information about this class + if (!fragment.hasTopLevelClass(classId.getShortClassName())) return null + } + + components.createContext(fragment, classData.getNameResolver()) } return DeserializedClassDescriptor(outerContext, classData.getClassProto(), classData.getNameResolver()) diff --git a/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/DeserializedPackageFragment.kt b/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/DeserializedPackageFragment.kt index 2dc100d084d..2f404139dd2 100644 --- a/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/DeserializedPackageFragment.kt +++ b/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/DeserializedPackageFragment.kt @@ -20,12 +20,11 @@ import org.jetbrains.kotlin.descriptors.ModuleDescriptor import org.jetbrains.kotlin.descriptors.impl.PackageFragmentDescriptorImpl import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name -import org.jetbrains.kotlin.resolve.scopes.JetScope import org.jetbrains.kotlin.serialization.ProtoBuf import org.jetbrains.kotlin.serialization.SerializedResourcePaths import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedPackageMemberScope -import org.jetbrains.kotlin.storage.NotNullLazyValue import org.jetbrains.kotlin.storage.StorageManager +import org.jetbrains.kotlin.storage.get import java.io.InputStream import javax.inject.Inject import kotlin.properties.Delegates @@ -50,16 +49,20 @@ public abstract class DeserializedPackageFragment( this.components = components } - private val memberScopeLazyValue: NotNullLazyValue = storageManager.createLazyValue { + internal val deserializedMemberScope by storageManager.createLazyValue { val packageStream = loadResourceSure(serializedResourcePaths.getPackageFilePath(fqName)) val packageProto = ProtoBuf.Package.parseFrom(packageStream, serializedResourcePaths.EXTENSION_REGISTRY) - DeserializedPackageMemberScope(this, packageProto, nameResolver, components, classNames = { loadClassNames(fqName, packageProto) }) + DeserializedPackageMemberScope(this, packageProto, nameResolver, components, classNames = { loadClassNames(packageProto) }) } - override fun getMemberScope() = memberScopeLazyValue() + override fun getMemberScope() = deserializedMemberScope - protected abstract fun loadClassNames(fqName: FqName, packageProto: ProtoBuf.Package): Collection + internal fun hasTopLevelClass(name: Name): Boolean { + return name in getMemberScope().classNames + } + + protected abstract fun loadClassNames(packageProto: ProtoBuf.Package): Collection protected fun loadResourceSure(path: String): InputStream = loadResource(path) ?: throw IllegalStateException("Resource not found in classpath: $path") -} \ No newline at end of file +} diff --git a/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/ResourceLoadingClassDataFinder.kt b/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/ResourceLoadingClassDataFinder.kt index d689f211a2c..03b86ee84d5 100644 --- a/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/ResourceLoadingClassDataFinder.kt +++ b/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/ResourceLoadingClassDataFinder.kt @@ -16,7 +16,6 @@ package org.jetbrains.kotlin.serialization.deserialization -import org.jetbrains.kotlin.serialization.deserialization.DeserializedPackageFragment import org.jetbrains.kotlin.descriptors.PackageFragmentProvider import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.serialization.ClassData @@ -30,22 +29,14 @@ public open class ResourceLoadingClassDataFinder( private val loadResource: (path: String) -> InputStream? ) : ClassDataFinder { override fun findClassData(classId: ClassId): ClassData? { - val packageFragment = packageFragmentProvider.getPackageFragments(classId.getPackageFqName()).singleOrNull() ?: return null + val packageFragment = packageFragmentProvider.getPackageFragments(classId.getPackageFqName()).singleOrNull() + as? DeserializedPackageFragment ?: return null val stream = loadResource(serializedResourcePaths.getClassMetadataPath(classId)) ?: return null - val classProto = ProtoBuf.Class.parseFrom(stream, serializedResourcePaths.EXTENSION_REGISTRY) - val nameResolver = - (packageFragment as? DeserializedPackageFragment ?: error("Not a deserialized package fragment: $packageFragment")).nameResolver - - val expectedShortName = classId.getShortClassName() - val actualShortName = nameResolver.getClassId(classProto.getFqName()).getShortClassName() - if (!actualShortName.isSpecial() && actualShortName != expectedShortName) { - // Workaround for case-insensitive file systems, - // otherwise we'd find "Collection" for "collection" etc - return null - } - - return ClassData(nameResolver, classProto) + return ClassData( + packageFragment.nameResolver, + ProtoBuf.Class.parseFrom(stream, serializedResourcePaths.EXTENSION_REGISTRY) + ) } -} \ No newline at end of file +} diff --git a/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/descriptors/DeserializedClassDescriptor.kt b/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/descriptors/DeserializedClassDescriptor.kt index ae5ee0bfc77..1244c3f7e11 100644 --- a/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/descriptors/DeserializedClassDescriptor.kt +++ b/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/descriptors/DeserializedClassDescriptor.kt @@ -139,6 +139,10 @@ public class DeserializedClassDescriptor( return supertypes } + internal fun hasNestedClass(name: Name): Boolean { + return name in nestedClasses.nestedClassNames + } + override fun toString() = "deserialized class ${getName().toString()}" // not using descriptor render to preserve laziness override fun getSource() = SourceElement.NO_SOURCE @@ -241,9 +245,9 @@ public class DeserializedClassDescriptor( } private inner class NestedClassDescriptors { - private val nestedClassNames = nestedClassNames() + internal val nestedClassNames = nestedClassNames() - val findNestedClass = c.storageManager.createMemoizedFunctionWithNullableValues { + internal val findNestedClass = c.storageManager.createMemoizedFunctionWithNullableValues { name -> if (name in nestedClassNames) { c.components.deserializeClass(classId.createNestedClassId(name)) diff --git a/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/descriptors/DeserializedPackageMemberScope.kt b/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/descriptors/DeserializedPackageMemberScope.kt index 9a98d7e8cd8..55c647defef 100644 --- a/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/descriptors/DeserializedPackageMemberScope.kt +++ b/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/descriptors/DeserializedPackageMemberScope.kt @@ -16,16 +16,17 @@ package org.jetbrains.kotlin.serialization.deserialization.descriptors -import org.jetbrains.kotlin.serialization.ProtoBuf -import org.jetbrains.kotlin.serialization.deserialization.DeserializationComponents import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor import org.jetbrains.kotlin.descriptors.ReceiverParameterDescriptor import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.Name -import org.jetbrains.kotlin.utils.addIfNotNull import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter +import org.jetbrains.kotlin.serialization.ProtoBuf +import org.jetbrains.kotlin.serialization.deserialization.DeserializationComponents import org.jetbrains.kotlin.serialization.deserialization.NameResolver +import org.jetbrains.kotlin.storage.get +import org.jetbrains.kotlin.utils.addIfNotNull public open class DeserializedPackageMemberScope( packageDescriptor: PackageFragmentDescriptor, @@ -36,7 +37,8 @@ public open class DeserializedPackageMemberScope( ) : DeserializedMemberScope(components.createContext(packageDescriptor, nameResolver), proto.getMemberList()) { private val packageFqName = packageDescriptor.fqName - private val classNames = c.storageManager.createLazyValue(classNames) + + internal val classNames by c.storageManager.createLazyValue { classNames().toSet() } override fun getDescriptors(kindFilter: DescriptorKindFilter, nameFilter: (Name) -> Boolean) = computeDescriptors(kindFilter, nameFilter) @@ -44,7 +46,7 @@ public open class DeserializedPackageMemberScope( override fun getClassDescriptor(name: Name) = c.components.deserializeClass(ClassId(packageFqName, name)) override fun addClassDescriptors(result: MutableCollection, nameFilter: (Name) -> Boolean) { - for (className in classNames()) { + for (className in classNames) { if (nameFilter(className)) { result.addIfNotNull(getClassDescriptor(className)) } diff --git a/js/js.serializer/src/org/jetbrains/kotlin/serialization/js/KotlinJavascriptPackageFragment.kt b/js/js.serializer/src/org/jetbrains/kotlin/serialization/js/KotlinJavascriptPackageFragment.kt index 9f71c3f853e..8c619cd1772 100644 --- a/js/js.serializer/src/org/jetbrains/kotlin/serialization/js/KotlinJavascriptPackageFragment.kt +++ b/js/js.serializer/src/org/jetbrains/kotlin/serialization/js/KotlinJavascriptPackageFragment.kt @@ -16,11 +16,11 @@ package org.jetbrains.kotlin.serialization.js -import org.jetbrains.kotlin.serialization.deserialization.DeserializedPackageFragment import org.jetbrains.kotlin.descriptors.ModuleDescriptor import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.serialization.ProtoBuf +import org.jetbrains.kotlin.serialization.deserialization.DeserializedPackageFragment import org.jetbrains.kotlin.storage.StorageManager import java.io.InputStream @@ -31,7 +31,7 @@ public class KotlinJavascriptPackageFragment( loadResource: (path: String) -> InputStream? ) : DeserializedPackageFragment(fqName, storageManager, module, KotlinJavascriptSerializedResourcePaths, loadResource) { - protected override fun loadClassNames(fqName: FqName, packageProto: ProtoBuf.Package): Collection { + protected override fun loadClassNames(packageProto: ProtoBuf.Package): Collection { val classesStream = loadResourceSure(KotlinJavascriptSerializedResourcePaths.getClassesInPackageFilePath(fqName)) val classesProto = JsProtoBuf.Classes.parseFrom(classesStream, serializedResourcePaths.EXTENSION_REGISTRY) return classesProto.getClassNameList()?.map { id -> nameResolver.getName(id) } ?: listOf()