Don't load irrelevant classes by accident, if resource happens to exist
Check with the containing class or package first, don't load the class if the container doesn't know about it. This also makes the workaround for case-insensitive file systems unnecessary
This commit is contained in:
@@ -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<Name> {
|
||||
protected override fun loadClassNames(packageProto: ProtoBuf.Package): Collection<Name> {
|
||||
return packageProto.getExtension(BuiltInsProtoBuf.className)?.map { id -> nameResolver.getName(id) } ?: listOf()
|
||||
}
|
||||
}
|
||||
|
||||
+14
-2
@@ -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())
|
||||
|
||||
+10
-7
@@ -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<JetScope> = 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<Name>
|
||||
internal fun hasTopLevelClass(name: Name): Boolean {
|
||||
return name in getMemberScope().classNames
|
||||
}
|
||||
|
||||
protected abstract fun loadClassNames(packageProto: ProtoBuf.Package): Collection<Name>
|
||||
|
||||
protected fun loadResourceSure(path: String): InputStream =
|
||||
loadResource(path) ?: throw IllegalStateException("Resource not found in classpath: $path")
|
||||
}
|
||||
}
|
||||
|
||||
+7
-16
@@ -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)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+6
-2
@@ -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<Name, ClassDescriptor> {
|
||||
internal val findNestedClass = c.storageManager.createMemoizedFunctionWithNullableValues<Name, ClassDescriptor> {
|
||||
name ->
|
||||
if (name in nestedClassNames) {
|
||||
c.components.deserializeClass(classId.createNestedClassId(name))
|
||||
|
||||
+7
-5
@@ -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<DeclarationDescriptor>, nameFilter: (Name) -> Boolean) {
|
||||
for (className in classNames()) {
|
||||
for (className in classNames) {
|
||||
if (nameFilter(className)) {
|
||||
result.addIfNotNull(getClassDescriptor(className))
|
||||
}
|
||||
|
||||
+2
-2
@@ -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<Name> {
|
||||
protected override fun loadClassNames(packageProto: ProtoBuf.Package): Collection<Name> {
|
||||
val classesStream = loadResourceSure(KotlinJavascriptSerializedResourcePaths.getClassesInPackageFilePath(fqName))
|
||||
val classesProto = JsProtoBuf.Classes.parseFrom(classesStream, serializedResourcePaths.EXTENSION_REGISTRY)
|
||||
return classesProto.getClassNameList()?.map { id -> nameResolver.getName(id) } ?: listOf()
|
||||
|
||||
Reference in New Issue
Block a user