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
|
package org.jetbrains.kotlin.builtins
|
||||||
|
|
||||||
import org.jetbrains.kotlin.serialization.deserialization.DeserializedPackageFragment
|
|
||||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.serialization.ProtoBuf
|
import org.jetbrains.kotlin.serialization.ProtoBuf
|
||||||
import org.jetbrains.kotlin.serialization.builtins.BuiltInsProtoBuf
|
import org.jetbrains.kotlin.serialization.builtins.BuiltInsProtoBuf
|
||||||
|
import org.jetbrains.kotlin.serialization.deserialization.DeserializedPackageFragment
|
||||||
import org.jetbrains.kotlin.storage.StorageManager
|
import org.jetbrains.kotlin.storage.StorageManager
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
|
|
||||||
@@ -32,7 +32,7 @@ public class BuiltinsPackageFragment(
|
|||||||
loadResource: (path: String) -> InputStream?
|
loadResource: (path: String) -> InputStream?
|
||||||
) : DeserializedPackageFragment(fqName, storageManager, module, BuiltInsSerializedResourcePaths, loadResource) {
|
) : 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()
|
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 classData = key.classData ?: components.classDataFinder.findClassData(classId) ?: return null
|
||||||
val outerContext = if (classId.isNestedClass()) {
|
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 {
|
else {
|
||||||
val fragments = components.packageFragmentProvider.getPackageFragments(classId.getPackageFqName())
|
val fragments = components.packageFragmentProvider.getPackageFragments(classId.getPackageFqName())
|
||||||
assert(fragments.size() == 1) { "There should be exactly one package: $fragments, class id is $classId" }
|
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())
|
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.descriptors.impl.PackageFragmentDescriptorImpl
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.resolve.scopes.JetScope
|
|
||||||
import org.jetbrains.kotlin.serialization.ProtoBuf
|
import org.jetbrains.kotlin.serialization.ProtoBuf
|
||||||
import org.jetbrains.kotlin.serialization.SerializedResourcePaths
|
import org.jetbrains.kotlin.serialization.SerializedResourcePaths
|
||||||
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedPackageMemberScope
|
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.StorageManager
|
||||||
|
import org.jetbrains.kotlin.storage.get
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import kotlin.properties.Delegates
|
import kotlin.properties.Delegates
|
||||||
@@ -50,16 +49,20 @@ public abstract class DeserializedPackageFragment(
|
|||||||
this.components = components
|
this.components = components
|
||||||
}
|
}
|
||||||
|
|
||||||
private val memberScopeLazyValue: NotNullLazyValue<JetScope> = storageManager.createLazyValue {
|
internal val deserializedMemberScope by storageManager.createLazyValue {
|
||||||
val packageStream = loadResourceSure(serializedResourcePaths.getPackageFilePath(fqName))
|
val packageStream = loadResourceSure(serializedResourcePaths.getPackageFilePath(fqName))
|
||||||
val packageProto = ProtoBuf.Package.parseFrom(packageStream, serializedResourcePaths.EXTENSION_REGISTRY)
|
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 =
|
protected fun loadResourceSure(path: String): InputStream =
|
||||||
loadResource(path) ?: throw IllegalStateException("Resource not found in classpath: $path")
|
loadResource(path) ?: throw IllegalStateException("Resource not found in classpath: $path")
|
||||||
}
|
}
|
||||||
|
|||||||
+7
-16
@@ -16,7 +16,6 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.serialization.deserialization
|
package org.jetbrains.kotlin.serialization.deserialization
|
||||||
|
|
||||||
import org.jetbrains.kotlin.serialization.deserialization.DeserializedPackageFragment
|
|
||||||
import org.jetbrains.kotlin.descriptors.PackageFragmentProvider
|
import org.jetbrains.kotlin.descriptors.PackageFragmentProvider
|
||||||
import org.jetbrains.kotlin.name.ClassId
|
import org.jetbrains.kotlin.name.ClassId
|
||||||
import org.jetbrains.kotlin.serialization.ClassData
|
import org.jetbrains.kotlin.serialization.ClassData
|
||||||
@@ -30,22 +29,14 @@ public open class ResourceLoadingClassDataFinder(
|
|||||||
private val loadResource: (path: String) -> InputStream?
|
private val loadResource: (path: String) -> InputStream?
|
||||||
) : ClassDataFinder {
|
) : ClassDataFinder {
|
||||||
override fun findClassData(classId: ClassId): ClassData? {
|
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 stream = loadResource(serializedResourcePaths.getClassMetadataPath(classId)) ?: return null
|
||||||
|
|
||||||
val classProto = ProtoBuf.Class.parseFrom(stream, serializedResourcePaths.EXTENSION_REGISTRY)
|
return ClassData(
|
||||||
val nameResolver =
|
packageFragment.nameResolver,
|
||||||
(packageFragment as? DeserializedPackageFragment ?: error("Not a deserialized package fragment: $packageFragment")).nameResolver
|
ProtoBuf.Class.parseFrom(stream, serializedResourcePaths.EXTENSION_REGISTRY)
|
||||||
|
)
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-2
@@ -139,6 +139,10 @@ public class DeserializedClassDescriptor(
|
|||||||
return supertypes
|
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 toString() = "deserialized class ${getName().toString()}" // not using descriptor render to preserve laziness
|
||||||
|
|
||||||
override fun getSource() = SourceElement.NO_SOURCE
|
override fun getSource() = SourceElement.NO_SOURCE
|
||||||
@@ -241,9 +245,9 @@ public class DeserializedClassDescriptor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private inner class NestedClassDescriptors {
|
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 ->
|
name ->
|
||||||
if (name in nestedClassNames) {
|
if (name in nestedClassNames) {
|
||||||
c.components.deserializeClass(classId.createNestedClassId(name))
|
c.components.deserializeClass(classId.createNestedClassId(name))
|
||||||
|
|||||||
+7
-5
@@ -16,16 +16,17 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.serialization.deserialization.descriptors
|
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.DeclarationDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor
|
import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.ReceiverParameterDescriptor
|
import org.jetbrains.kotlin.descriptors.ReceiverParameterDescriptor
|
||||||
import org.jetbrains.kotlin.name.ClassId
|
import org.jetbrains.kotlin.name.ClassId
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
|
||||||
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
|
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.serialization.deserialization.NameResolver
|
||||||
|
import org.jetbrains.kotlin.storage.get
|
||||||
|
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||||
|
|
||||||
public open class DeserializedPackageMemberScope(
|
public open class DeserializedPackageMemberScope(
|
||||||
packageDescriptor: PackageFragmentDescriptor,
|
packageDescriptor: PackageFragmentDescriptor,
|
||||||
@@ -36,7 +37,8 @@ public open class DeserializedPackageMemberScope(
|
|||||||
) : DeserializedMemberScope(components.createContext(packageDescriptor, nameResolver), proto.getMemberList()) {
|
) : DeserializedMemberScope(components.createContext(packageDescriptor, nameResolver), proto.getMemberList()) {
|
||||||
|
|
||||||
private val packageFqName = packageDescriptor.fqName
|
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)
|
override fun getDescriptors(kindFilter: DescriptorKindFilter, nameFilter: (Name) -> Boolean)
|
||||||
= computeDescriptors(kindFilter, nameFilter)
|
= computeDescriptors(kindFilter, nameFilter)
|
||||||
@@ -44,7 +46,7 @@ public open class DeserializedPackageMemberScope(
|
|||||||
override fun getClassDescriptor(name: Name) = c.components.deserializeClass(ClassId(packageFqName, name))
|
override fun getClassDescriptor(name: Name) = c.components.deserializeClass(ClassId(packageFqName, name))
|
||||||
|
|
||||||
override fun addClassDescriptors(result: MutableCollection<DeclarationDescriptor>, nameFilter: (Name) -> Boolean) {
|
override fun addClassDescriptors(result: MutableCollection<DeclarationDescriptor>, nameFilter: (Name) -> Boolean) {
|
||||||
for (className in classNames()) {
|
for (className in classNames) {
|
||||||
if (nameFilter(className)) {
|
if (nameFilter(className)) {
|
||||||
result.addIfNotNull(getClassDescriptor(className))
|
result.addIfNotNull(getClassDescriptor(className))
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -16,11 +16,11 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.serialization.js
|
package org.jetbrains.kotlin.serialization.js
|
||||||
|
|
||||||
import org.jetbrains.kotlin.serialization.deserialization.DeserializedPackageFragment
|
|
||||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.serialization.ProtoBuf
|
import org.jetbrains.kotlin.serialization.ProtoBuf
|
||||||
|
import org.jetbrains.kotlin.serialization.deserialization.DeserializedPackageFragment
|
||||||
import org.jetbrains.kotlin.storage.StorageManager
|
import org.jetbrains.kotlin.storage.StorageManager
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
|
|
||||||
@@ -31,7 +31,7 @@ public class KotlinJavascriptPackageFragment(
|
|||||||
loadResource: (path: String) -> InputStream?
|
loadResource: (path: String) -> InputStream?
|
||||||
) : DeserializedPackageFragment(fqName, storageManager, module, KotlinJavascriptSerializedResourcePaths, loadResource) {
|
) : 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 classesStream = loadResourceSure(KotlinJavascriptSerializedResourcePaths.getClassesInPackageFilePath(fqName))
|
||||||
val classesProto = JsProtoBuf.Classes.parseFrom(classesStream, serializedResourcePaths.EXTENSION_REGISTRY)
|
val classesProto = JsProtoBuf.Classes.parseFrom(classesStream, serializedResourcePaths.EXTENSION_REGISTRY)
|
||||||
return classesProto.getClassNameList()?.map { id -> nameResolver.getName(id) } ?: listOf()
|
return classesProto.getClassNameList()?.map { id -> nameResolver.getName(id) } ?: listOf()
|
||||||
|
|||||||
Reference in New Issue
Block a user