Serialize metadata for Cloneable and discard it during deserialization

#KT-16358 Fixed
This commit is contained in:
Alexander Udalov
2017-02-15 12:07:55 +03:00
parent 46bd64f59a
commit bae955aafd
8 changed files with 67 additions and 8 deletions
@@ -18,6 +18,8 @@ package org.jetbrains.kotlin.serialization.builtins
import com.intellij.openapi.util.Disposer
import org.jetbrains.kotlin.builtins.BuiltInSerializerProtocol
import org.jetbrains.kotlin.builtins.JvmBuiltInClassDescriptorFactory
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
import org.jetbrains.kotlin.cli.common.messages.*
import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles
@@ -26,12 +28,16 @@ import org.jetbrains.kotlin.cli.jvm.config.addJvmClasspathRoots
import org.jetbrains.kotlin.config.CommonConfigurationKeys
import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.config.addKotlinSourceRoots
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.descriptors.impl.EmptyPackageFragmentDescriptor
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
import org.jetbrains.kotlin.serialization.MetadataSerializer
import org.jetbrains.kotlin.storage.LockBasedStorageManager
import java.io.File
class BuiltInsSerializer(dependOnOldBuiltIns: Boolean) : MetadataSerializer(dependOnOldBuiltIns) {
@@ -88,11 +94,21 @@ class BuiltInsSerializer(dependOnOldBuiltIns: Boolean) : MetadataSerializer(depe
fqName ->
val packageView = module.getPackage(fqName)
PackageSerializer(
packageView.memberScope.getContributedDescriptors(DescriptorKindFilter.CLASSIFIERS),
packageView.memberScope.getContributedDescriptors(DescriptorKindFilter.CLASSIFIERS) + createCloneable(module),
packageView.fragments.flatMap { fragment -> DescriptorUtils.getAllDescriptors(fragment.getMemberScope()) },
packageView.fqName,
File(destDir, BuiltInSerializerProtocol.getBuiltInsFilePath(packageView.fqName))
).run()
}
}
// Serialize metadata for kotlin.Cloneable manually for compatibility with kotlin-reflect 1.0 which expects this metadata to be there.
// Since Kotlin 1.1, we always discard this class during deserialization (see ClassDeserializer.kt).
private fun createCloneable(module: ModuleDescriptor): ClassDescriptor {
val factory = JvmBuiltInClassDescriptorFactory(LockBasedStorageManager.NO_LOCKS, module) {
EmptyPackageFragmentDescriptor(module, KotlinBuiltIns.BUILT_INS_PACKAGE_FQ_NAME)
}
return factory.createClass(ClassId.topLevel(KotlinBuiltIns.FQ_NAMES.cloneable.toSafe()))
?: error("Could not create kotlin.Cloneable in $module")
}
}
@@ -0,0 +1,3 @@
import kotlin.<!UNRESOLVED_REFERENCE!>Cloneable<!>
fun cloneable(): <!UNRESOLVED_REFERENCE!>Cloneable<!> = intArrayOf(42)
@@ -0,0 +1,3 @@
package
public fun cloneable(): [ERROR : Cloneable]
@@ -369,6 +369,21 @@ public class DiagnosticsTestWithJsStdLibGenerated extends AbstractDiagnosticsTes
}
}
@TestMetadata("compiler/testData/diagnostics/testsWithJsStdLib/jvmDeclarations")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class JvmDeclarations extends AbstractDiagnosticsTestWithJsStdLib {
public void testAllFilesPresentInJvmDeclarations() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/diagnostics/testsWithJsStdLib/jvmDeclarations"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
}
@TestMetadata("cloneable.kt")
public void testCloneable() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithJsStdLib/jvmDeclarations/cloneable.kt");
doTest(fileName);
}
}
@TestMetadata("compiler/testData/diagnostics/testsWithJsStdLib/module")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
@@ -27,11 +27,14 @@ import org.jetbrains.kotlin.storage.getValue
class JvmBuiltInClassDescriptorFactory(
storageManager: StorageManager,
private val moduleDescriptor: ModuleDescriptor
private val moduleDescriptor: ModuleDescriptor,
private val computeContainingDeclaration: (ModuleDescriptor) -> DeclarationDescriptor = { module ->
module.getPackage(KOTLIN_FQ_NAME).fragments.filterIsInstance<BuiltInsPackageFragment>().first()
}
) : ClassDescriptorFactory {
private val cloneable by storageManager.createLazyValue {
ClassDescriptorImpl(
moduleDescriptor.getPackage(KOTLIN_FQ_NAME).fragments.filterIsInstance<BuiltInsPackageFragment>().first(),
computeContainingDeclaration(moduleDescriptor),
CLONEABLE_NAME, Modality.ABSTRACT, ClassKind.INTERFACE, listOf(moduleDescriptor.builtIns.anyType),
SourceElement.NO_SOURCE, /* isExternal = */ false
).apply {
@@ -38,9 +38,7 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe
import org.jetbrains.kotlin.resolve.jvm.JvmPrimitiveType
import org.jetbrains.kotlin.resolve.scopes.MemberScope
import org.jetbrains.kotlin.serialization.deserialization.AdditionalClassPartsProvider
import org.jetbrains.kotlin.serialization.deserialization.PLATFORM_DEPENDENT_ANNOTATION_FQ_NAME
import org.jetbrains.kotlin.serialization.deserialization.PlatformDependentDeclarationFilter
import org.jetbrains.kotlin.serialization.deserialization.*
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedClassDescriptor
import org.jetbrains.kotlin.storage.LockBasedStorageManager
import org.jetbrains.kotlin.storage.StorageManager
@@ -66,7 +64,10 @@ open class JvmBuiltInsSettings(
private val mockSerializableType = storageManager.createMockJavaIoSerializableType()
private val cloneableType by storageManager.createLazyValue {
moduleDescriptor.builtIns.getBuiltInClassByName(JvmBuiltInClassDescriptorFactory.CLONEABLE_CLASS_ID.shortClassName).defaultType
ownerModuleDescriptor.findNonGenericClassAcrossDependencies(
JvmBuiltInClassDescriptorFactory.CLONEABLE_CLASS_ID,
NotFoundClasses(storageManager, ownerModuleDescriptor)
).defaultType
}
private val javaAnalogueClassesWithCustomSupertypeCache = storageManager.createCacheWithNotNullValues<FqName, ClassDescriptor>()
@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.builtins
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.serialization.builtins.BuiltInsProtoBuf
import org.jetbrains.kotlin.serialization.deserialization.ClassDeserializer
import org.jetbrains.kotlin.serialization.deserialization.DeserializedPackageFragment
import org.jetbrains.kotlin.serialization.deserialization.NameResolverImpl
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedPackageMemberScope
@@ -53,6 +54,8 @@ class BuiltInsPackageFragment(
override fun computeMemberScope() =
DeserializedPackageMemberScope(
this, proto.`package`, nameResolver, containerSource = null, components = components,
classNames = { classDataFinder.allClassIds.filter { classId -> !classId.isNestedClass }.map { it.shortClassName } }
classNames = { classDataFinder.allClassIds.filter { classId ->
!classId.isNestedClass && classId !in ClassDeserializer.BLACK_LIST
}.map { it.shortClassName } }
)
}
@@ -16,6 +16,7 @@
package org.jetbrains.kotlin.serialization.deserialization
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.serialization.ClassDataWithSource
@@ -36,6 +37,8 @@ class ClassDeserializer(private val components: DeserializationComponents) {
for (factory in components.fictitiousClassDescriptorFactories) {
factory.createClass(classId)?.let { return it }
}
if (classId in BLACK_LIST) return null
val (classData, sourceElement) = key.classDataWithSource
?: components.classDataFinder.findClassData(classId)
?: return null
@@ -76,4 +79,16 @@ class ClassDeserializer(private val components: DeserializationComponents) {
override fun hashCode() = classId.hashCode()
}
companion object {
/**
* FQ names of classes that should be ignored during deserialization.
*
* We ignore kotlin.Cloneable because since Kotlin 1.1, the descriptor for it is created via JvmBuiltInClassDescriptorFactory,
* but the metadata is still serialized for kotlin-reflect 1.0 to work (see BuiltInsSerializer.kt).
*/
val BLACK_LIST = setOf(
ClassId.topLevel(KotlinBuiltIns.FQ_NAMES.cloneable.toSafe())
)
}
}