Fix version requirement serialization for nested classes
Use the version requierement table of the outer DescriptorSerializer instance when serializing metadata for a class. Pass parent serializer to DescriptorSerializer.create to make sure the correct table is used. Serialize nested classes before the outer class in JS and common code, to make sure requirements are not lost. Also, split VersionRequirementTest to JVM and JS #KT-25120 In Progress
This commit is contained in:
@@ -96,7 +96,7 @@ fun JavaClassDescriptor.convertToProto(): SerializedJavaClassWithSource {
|
||||
|
||||
val extension = JavaClassesSerializerExtension()
|
||||
val classProto = try {
|
||||
DescriptorSerializer.create(this, extension).classProto(this).build()
|
||||
DescriptorSerializer.create(this, extension, null).classProto(this).build()
|
||||
} catch (e: Exception) {
|
||||
throw IllegalStateException(
|
||||
"Error during writing proto for descriptor: ${DescriptorRenderer.DEBUG_TEXT.render(this)}\n" +
|
||||
|
||||
@@ -22,6 +22,7 @@ import org.jetbrains.kotlin.codegen.binding.CodegenBinding;
|
||||
import org.jetbrains.kotlin.codegen.binding.MutableClosure;
|
||||
import org.jetbrains.kotlin.codegen.context.*;
|
||||
import org.jetbrains.kotlin.codegen.extensions.ExpressionCodegenExtension;
|
||||
import org.jetbrains.kotlin.codegen.serialization.JvmSerializerExtension;
|
||||
import org.jetbrains.kotlin.codegen.signature.BothSignatureWriter;
|
||||
import org.jetbrains.kotlin.codegen.signature.JvmSignatureWriter;
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState;
|
||||
@@ -30,8 +31,11 @@ import org.jetbrains.kotlin.config.LanguageFeature;
|
||||
import org.jetbrains.kotlin.descriptors.*;
|
||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation;
|
||||
import org.jetbrains.kotlin.lexer.KtTokens;
|
||||
import org.jetbrains.kotlin.load.java.JvmAnnotationNames;
|
||||
import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor;
|
||||
import org.jetbrains.kotlin.load.kotlin.TypeMappingMode;
|
||||
import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader;
|
||||
import org.jetbrains.kotlin.metadata.ProtoBuf;
|
||||
import org.jetbrains.kotlin.name.ClassId;
|
||||
import org.jetbrains.kotlin.name.FqName;
|
||||
import org.jetbrains.kotlin.name.Name;
|
||||
@@ -52,6 +56,7 @@ import org.jetbrains.kotlin.resolve.scopes.MemberScope;
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ExtensionReceiver;
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitReceiver;
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue;
|
||||
import org.jetbrains.kotlin.serialization.DescriptorSerializer;
|
||||
import org.jetbrains.kotlin.types.KotlinType;
|
||||
import org.jetbrains.org.objectweb.asm.FieldVisitor;
|
||||
import org.jetbrains.org.objectweb.asm.Label;
|
||||
@@ -97,6 +102,8 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
||||
|
||||
private final List<Function2<ImplementationBodyCodegen, ClassBuilder, Unit>> additionalTasks = new ArrayList<>();
|
||||
|
||||
private final DescriptorSerializer serializer;
|
||||
|
||||
public ImplementationBodyCodegen(
|
||||
@NotNull KtPureClassOrObject aClass,
|
||||
@NotNull ClassContext context,
|
||||
@@ -108,7 +115,15 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
||||
super(aClass, context, v, state, parentCodegen);
|
||||
this.classAsmType = getObjectType(typeMapper.classInternalName(descriptor));
|
||||
this.isLocal = isLocal;
|
||||
delegationFieldsInfo = getDelegationFieldsInfo(myClass.getSuperTypeListEntries());
|
||||
this.delegationFieldsInfo = getDelegationFieldsInfo(myClass.getSuperTypeListEntries());
|
||||
|
||||
JvmSerializerExtension extension = new JvmSerializerExtension(v.getSerializationBindings(), state);
|
||||
this.serializer = DescriptorSerializer.create(
|
||||
descriptor, extension,
|
||||
parentCodegen instanceof ImplementationBodyCodegen
|
||||
? ((ImplementationBodyCodegen) parentCodegen).serializer
|
||||
: DescriptorSerializer.createTopLevel(extension)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -282,7 +297,12 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
||||
|
||||
@Override
|
||||
protected void generateKotlinMetadataAnnotation() {
|
||||
generateKotlinClassMetadataAnnotation(descriptor, false);
|
||||
ProtoBuf.Class classProto = serializer.classProto(descriptor).build();
|
||||
|
||||
WriteAnnotationUtilKt.writeKotlinMetadata(v, state, KotlinClassHeader.Kind.CLASS, 0, av -> {
|
||||
writeAnnotationData(av, serializer, classProto);
|
||||
return Unit.INSTANCE;
|
||||
});
|
||||
}
|
||||
|
||||
private void writeEnclosingMethod() {
|
||||
|
||||
@@ -7,7 +7,6 @@ package org.jetbrains.kotlin.codegen;
|
||||
|
||||
import com.intellij.openapi.progress.ProcessCanceledException;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import kotlin.Unit;
|
||||
import kotlin.jvm.functions.Function0;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -19,7 +18,6 @@ import org.jetbrains.kotlin.codegen.inline.DefaultSourceMapper;
|
||||
import org.jetbrains.kotlin.codegen.inline.NameGenerator;
|
||||
import org.jetbrains.kotlin.codegen.inline.ReifiedTypeParametersUsages;
|
||||
import org.jetbrains.kotlin.codegen.inline.SourceMapper;
|
||||
import org.jetbrains.kotlin.codegen.serialization.JvmSerializerExtension;
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState;
|
||||
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper;
|
||||
import org.jetbrains.kotlin.descriptors.*;
|
||||
@@ -29,9 +27,6 @@ import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl;
|
||||
import org.jetbrains.kotlin.fileClasses.JvmFileClassUtil;
|
||||
import org.jetbrains.kotlin.load.java.JavaVisibilities;
|
||||
import org.jetbrains.kotlin.load.java.JvmAbi;
|
||||
import org.jetbrains.kotlin.load.java.JvmAnnotationNames;
|
||||
import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader;
|
||||
import org.jetbrains.kotlin.metadata.ProtoBuf;
|
||||
import org.jetbrains.kotlin.name.Name;
|
||||
import org.jetbrains.kotlin.name.SpecialNames;
|
||||
import org.jetbrains.kotlin.psi.*;
|
||||
@@ -45,7 +40,6 @@ import org.jetbrains.kotlin.resolve.jvm.AsmTypes;
|
||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKt;
|
||||
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature;
|
||||
import org.jetbrains.kotlin.resolve.source.KotlinSourceElementKt;
|
||||
import org.jetbrains.kotlin.serialization.DescriptorSerializer;
|
||||
import org.jetbrains.kotlin.storage.LockBasedStorageManager;
|
||||
import org.jetbrains.kotlin.storage.NotNullLazyValue;
|
||||
import org.jetbrains.kotlin.types.ErrorUtils;
|
||||
@@ -62,7 +56,8 @@ import java.util.Collections;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
|
||||
import static org.jetbrains.kotlin.codegen.AsmUtil.*;
|
||||
import static org.jetbrains.kotlin.codegen.AsmUtil.calculateInnerClassAccessFlags;
|
||||
import static org.jetbrains.kotlin.codegen.AsmUtil.isPrimitive;
|
||||
import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.isNonDefaultInterfaceMember;
|
||||
import static org.jetbrains.kotlin.codegen.inline.InlineCodegenUtilsKt.getInlineName;
|
||||
import static org.jetbrains.kotlin.descriptors.CallableMemberDescriptor.Kind.SYNTHESIZED;
|
||||
@@ -914,20 +909,6 @@ public abstract class MemberCodegen<T extends KtPureElement/* TODO: & KtDeclarat
|
||||
return StackValue.onStack(callableMethod.getReturnType());
|
||||
}
|
||||
|
||||
protected void generateKotlinClassMetadataAnnotation(@NotNull ClassDescriptor descriptor, boolean isScript) {
|
||||
DescriptorSerializer serializer =
|
||||
DescriptorSerializer.create(descriptor, new JvmSerializerExtension(v.getSerializationBindings(), state));
|
||||
|
||||
ProtoBuf.Class classProto = serializer.classProto(descriptor).build();
|
||||
|
||||
int flags = isScript ? JvmAnnotationNames.METADATA_SCRIPT_FLAG : 0;
|
||||
|
||||
WriteAnnotationUtilKt.writeKotlinMetadata(v, state, KotlinClassHeader.Kind.CLASS, flags, av -> {
|
||||
writeAnnotationData(av, serializer, classProto);
|
||||
return Unit.INSTANCE;
|
||||
});
|
||||
}
|
||||
|
||||
public void generateAssertField() {
|
||||
if (jvmAssertFieldGenerated) return;
|
||||
AssertCodegenUtilKt.generateAssertionsDisabledFieldInitialization(this);
|
||||
|
||||
@@ -6,25 +6,31 @@
|
||||
package org.jetbrains.kotlin.codegen
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.codegen.AsmUtil.writeAnnotationData
|
||||
import org.jetbrains.kotlin.codegen.context.CodegenContext
|
||||
import org.jetbrains.kotlin.codegen.context.MethodContext
|
||||
import org.jetbrains.kotlin.codegen.context.ScriptContext
|
||||
import org.jetbrains.kotlin.codegen.serialization.JvmSerializerExtension
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ScriptDescriptor
|
||||
import org.jetbrains.kotlin.load.java.JvmAnnotationNames
|
||||
import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.*
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassNotAny
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassOrAny
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperInterfaces
|
||||
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
|
||||
import org.jetbrains.kotlin.resolve.jvm.AsmTypes.OBJECT_TYPE
|
||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
|
||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.*
|
||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin.Companion.NO_ORIGIN
|
||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.OtherOrigin
|
||||
import org.jetbrains.kotlin.serialization.DescriptorSerializer
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes.*
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
||||
|
||||
import org.jetbrains.kotlin.resolve.jvm.AsmTypes.OBJECT_TYPE
|
||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin.Companion.NO_ORIGIN
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes.*
|
||||
|
||||
class ScriptCodegen private constructor(
|
||||
private val scriptDeclaration: KtScript,
|
||||
state: GenerationState,
|
||||
@@ -64,7 +70,11 @@ class ScriptCodegen private constructor(
|
||||
override fun generateSyntheticPartsAfterBody() {}
|
||||
|
||||
override fun generateKotlinMetadataAnnotation() {
|
||||
generateKotlinClassMetadataAnnotation(scriptDescriptor, true)
|
||||
val serializer = DescriptorSerializer.create(scriptDescriptor, JvmSerializerExtension(v.serializationBindings, state), null)
|
||||
val classProto = serializer.classProto(scriptDescriptor).build()
|
||||
writeKotlinMetadata(v, state, KotlinClassHeader.Kind.CLASS, JvmAnnotationNames.METADATA_SCRIPT_FLAG) { av ->
|
||||
writeAnnotationData(av, serializer, classProto)
|
||||
}
|
||||
}
|
||||
|
||||
private fun genConstructor(
|
||||
|
||||
@@ -151,29 +151,29 @@ open class MetadataSerializer(private val dependOnOldBuiltIns: Boolean) {
|
||||
private val extension = createSerializerExtension()
|
||||
|
||||
fun run() {
|
||||
serializeClasses(classes)
|
||||
serializeMembers(members)
|
||||
val serializer = DescriptorSerializer.createTopLevel(extension)
|
||||
serializeClasses(classes, serializer)
|
||||
serializeMembers(members, serializer)
|
||||
serializeStringTable()
|
||||
serializeBuiltInsFile()
|
||||
}
|
||||
|
||||
private fun serializeClass(classDescriptor: ClassDescriptor) {
|
||||
val classProto = DescriptorSerializer.create(classDescriptor, extension).classProto(classDescriptor).build()
|
||||
proto.addClass_(classProto)
|
||||
|
||||
serializeClasses(classDescriptor.unsubstitutedInnerClassesScope.getContributedDescriptors(DescriptorKindFilter.CLASSIFIERS))
|
||||
}
|
||||
|
||||
private fun serializeClasses(classes: Collection<DeclarationDescriptor>) {
|
||||
private fun serializeClasses(classes: Collection<DeclarationDescriptor>, parentSerializer: DescriptorSerializer) {
|
||||
for (descriptor in DescriptorSerializer.sort(classes)) {
|
||||
if (descriptor is ClassDescriptor && descriptor.kind != ClassKind.ENUM_ENTRY) {
|
||||
serializeClass(descriptor)
|
||||
}
|
||||
if (descriptor !is ClassDescriptor || descriptor.kind == ClassKind.ENUM_ENTRY) continue
|
||||
|
||||
val serializer = DescriptorSerializer.create(descriptor, extension, parentSerializer)
|
||||
serializeClasses(
|
||||
descriptor.unsubstitutedInnerClassesScope.getContributedDescriptors(DescriptorKindFilter.CLASSIFIERS),
|
||||
serializer
|
||||
)
|
||||
|
||||
proto.addClass_(serializer.classProto(descriptor).build())
|
||||
}
|
||||
}
|
||||
|
||||
private fun serializeMembers(members: Collection<DeclarationDescriptor>) {
|
||||
proto.`package` = DescriptorSerializer.createTopLevel(extension).packagePartProto(packageFqName, members).build()
|
||||
private fun serializeMembers(members: Collection<DeclarationDescriptor>, serializer: DescriptorSerializer) {
|
||||
proto.`package` = serializer.packagePartProto(packageFqName, members).build()
|
||||
}
|
||||
|
||||
private fun serializeStringTable() {
|
||||
|
||||
+14
-10
@@ -20,7 +20,7 @@ import org.jetbrains.kotlin.metadata.serialization.MutableVersionRequirementTabl
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils.*
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils.isEnumEntry
|
||||
import org.jetbrains.kotlin.resolve.MemberComparator
|
||||
import org.jetbrains.kotlin.resolve.RequireKotlinNames
|
||||
import org.jetbrains.kotlin.resolve.calls.components.isActualParameterWithAnyExpectedDefault
|
||||
@@ -709,10 +709,14 @@ class DescriptorSerializer private constructor(
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun create(descriptor: ClassDescriptor, extension: SerializerExtension): DescriptorSerializer {
|
||||
fun create(
|
||||
descriptor: ClassDescriptor,
|
||||
extension: SerializerExtension,
|
||||
parentSerializer: DescriptorSerializer?
|
||||
): DescriptorSerializer {
|
||||
val container = descriptor.containingDeclaration
|
||||
val parentSerializer = if (container is ClassDescriptor)
|
||||
create(container, extension)
|
||||
val parent = if (container is ClassDescriptor)
|
||||
parentSerializer ?: create(container, extension, null)
|
||||
else
|
||||
createTopLevel(extension)
|
||||
|
||||
@@ -720,12 +724,12 @@ class DescriptorSerializer private constructor(
|
||||
// serializing outer classes before nested classes.
|
||||
// Otherwise our interner can get wrong ids because we may serialize classes in any order.
|
||||
val serializer = DescriptorSerializer(
|
||||
descriptor,
|
||||
Interner(parentSerializer.typeParameters),
|
||||
parentSerializer.extension,
|
||||
MutableTypeTable(),
|
||||
MutableVersionRequirementTable(),
|
||||
serializeTypeTableToFunction = false
|
||||
descriptor,
|
||||
Interner(parent.typeParameters),
|
||||
extension,
|
||||
MutableTypeTable(),
|
||||
if (container is ClassDescriptor) parent.versionRequirementTable else MutableVersionRequirementTable(),
|
||||
serializeTypeTableToFunction = false
|
||||
)
|
||||
for (typeParameter in descriptor.declaredTypeParameters) {
|
||||
serializer.typeParameters.intern(typeParameter)
|
||||
|
||||
+1
-3
@@ -3,9 +3,7 @@ suspend fun callRelease() {
|
||||
|
||||
C().dummy()
|
||||
|
||||
// TODO: This should be error
|
||||
WithNested.Nested().dummy()
|
||||
|
||||
// TODO: This should be error
|
||||
WithInner().Inner().dummy()
|
||||
}
|
||||
}
|
||||
|
||||
compiler/testData/compileKotlinAgainstCustomBinaries/releaseCoroutineCallFromExperimental/output.txt
Vendored
+6
@@ -4,4 +4,10 @@ compiler/testData/compileKotlinAgainstCustomBinaries/releaseCoroutineCallFromExp
|
||||
compiler/testData/compileKotlinAgainstCustomBinaries/releaseCoroutineCallFromExperimental/experimental.kt:4:9: error: 'dummy(): String' is only available since Kotlin 1.3 and cannot be used in Kotlin 1.2
|
||||
C().dummy()
|
||||
^
|
||||
compiler/testData/compileKotlinAgainstCustomBinaries/releaseCoroutineCallFromExperimental/experimental.kt:6:25: error: 'dummy(): String' is only available since Kotlin 1.3 and cannot be used in Kotlin 1.2
|
||||
WithNested.Nested().dummy()
|
||||
^
|
||||
compiler/testData/compileKotlinAgainstCustomBinaries/releaseCoroutineCallFromExperimental/experimental.kt:8:25: error: 'dummy(): String' is only available since Kotlin 1.3 and cannot be used in Kotlin 1.2
|
||||
WithInner().Inner().dummy()
|
||||
^
|
||||
COMPILATION_ERROR
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
@file:Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
|
||||
package test
|
||||
|
||||
import kotlin.internal.RequireKotlin
|
||||
|
||||
class Outer {
|
||||
inner class Inner {
|
||||
@RequireKotlin("1.1")
|
||||
inner class Deep @RequireKotlin("1.1") constructor() {
|
||||
@RequireKotlin("1.1")
|
||||
fun f() {}
|
||||
|
||||
@RequireKotlin("1.1")
|
||||
val x = ""
|
||||
|
||||
suspend fun s() {}
|
||||
}
|
||||
}
|
||||
|
||||
class Nested {
|
||||
@RequireKotlin("1.1")
|
||||
fun g() {}
|
||||
}
|
||||
|
||||
@RequireKotlin("1.1")
|
||||
companion object
|
||||
}
|
||||
|
||||
@RequireKotlin("1.1")
|
||||
fun topLevel() {}
|
||||
+34
-60
@@ -5,29 +5,22 @@
|
||||
|
||||
package org.jetbrains.kotlin.serialization
|
||||
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
|
||||
import org.jetbrains.kotlin.config.*
|
||||
import org.jetbrains.kotlin.config.LanguageVersion
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettingsImpl
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PackageViewDescriptor
|
||||
import org.jetbrains.kotlin.jvm.compiler.LoadDescriptorUtil
|
||||
import org.jetbrains.kotlin.metadata.ProtoBuf
|
||||
import org.jetbrains.kotlin.metadata.ProtoBuf.VersionRequirement.VersionKind.*
|
||||
import org.jetbrains.kotlin.metadata.deserialization.VersionRequirement
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.resolve.lazy.JvmResolveUtil
|
||||
import org.jetbrains.kotlin.resolve.scopes.getDescriptorsFiltered
|
||||
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedClassDescriptor
|
||||
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedMemberDescriptor
|
||||
import org.jetbrains.kotlin.test.ConfigurationKind
|
||||
import org.jetbrains.kotlin.test.KotlinTestUtils
|
||||
import org.jetbrains.kotlin.test.TestCaseWithTmpdir
|
||||
import org.jetbrains.kotlin.test.TestJdkKind
|
||||
import java.io.File
|
||||
|
||||
class VersionRequirementTest : TestCaseWithTmpdir() {
|
||||
abstract class AbstractVersionRequirementTest : TestCaseWithTmpdir() {
|
||||
fun doTest(
|
||||
expectedVersionRequirement: VersionRequirement.Version,
|
||||
expectedLevel: DeprecationLevel,
|
||||
@@ -37,47 +30,23 @@ class VersionRequirementTest : TestCaseWithTmpdir() {
|
||||
customLanguageVersion: LanguageVersion = LanguageVersionSettingsImpl.DEFAULT.languageVersion,
|
||||
fqNames: List<String>
|
||||
) {
|
||||
LoadDescriptorUtil.compileKotlinToDirAndGetModule(
|
||||
listOf(File("compiler/testData/versionRequirement/${getTestName(true)}.kt")), tmpdir,
|
||||
KotlinCoreEnvironment.createForTests(
|
||||
testRootDisposable,
|
||||
KotlinTestUtils.newConfiguration(ConfigurationKind.ALL, TestJdkKind.MOCK_JDK, tmpdir).apply {
|
||||
put(JVMConfigurationKeys.JVM_TARGET, JvmTarget.JVM_1_8)
|
||||
languageVersionSettings = LanguageVersionSettingsImpl(
|
||||
customLanguageVersion,
|
||||
ApiVersion.createByLanguageVersion(customLanguageVersion),
|
||||
mapOf(AnalysisFlag.jvmDefaultMode to JvmDefaultMode.ENABLE),
|
||||
emptyMap()
|
||||
)
|
||||
},
|
||||
EnvironmentConfigFiles.JVM_CONFIG_FILES
|
||||
)
|
||||
)
|
||||
compileFiles(listOf(File("compiler/testData/versionRequirement/${getTestName(true)}.kt")), tmpdir, customLanguageVersion)
|
||||
val module = loadModule(tmpdir)
|
||||
|
||||
val (_, module) = JvmResolveUtil.analyze(
|
||||
KotlinCoreEnvironment.createForTests(
|
||||
testRootDisposable,
|
||||
KotlinTestUtils.newConfiguration(ConfigurationKind.ALL, TestJdkKind.MOCK_JDK, tmpdir),
|
||||
EnvironmentConfigFiles.JVM_CONFIG_FILES
|
||||
)
|
||||
)
|
||||
for (fqName in fqNames) {
|
||||
val descriptor = module.findUnambiguousDescriptorByFqName(fqName)
|
||||
|
||||
fun check(descriptor: DeclarationDescriptor) {
|
||||
val requirement = when (descriptor) {
|
||||
is DeserializedMemberDescriptor -> descriptor.versionRequirement
|
||||
is DeserializedClassDescriptor -> descriptor.versionRequirement
|
||||
else -> throw AssertionError("Unknown descriptor: $descriptor")
|
||||
} ?: throw AssertionError("No VersionRequirement for $descriptor")
|
||||
|
||||
assertEquals(expectedVersionRequirement, requirement.version)
|
||||
assertEquals(expectedLevel, requirement.level)
|
||||
assertEquals(expectedMessage, requirement.message)
|
||||
assertEquals(expectedVersionKind, requirement.kind)
|
||||
assertEquals(expectedErrorCode, requirement.errorCode)
|
||||
}
|
||||
|
||||
for (fqName in fqNames) {
|
||||
check(module.findUnambiguousDescriptorByFqName(fqName))
|
||||
assertEquals("Incorrect version for $fqName", expectedVersionRequirement, requirement.version)
|
||||
assertEquals("Incorrect level for $fqName", expectedLevel, requirement.level)
|
||||
assertEquals("Incorrect message for $fqName", expectedMessage, requirement.message)
|
||||
assertEquals("Incorrect versionKind for $fqName", expectedVersionKind, requirement.kind)
|
||||
assertEquals("Incorrect errorCode for $fqName", expectedErrorCode, requirement.errorCode)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,9 +71,13 @@ class VersionRequirementTest : TestCaseWithTmpdir() {
|
||||
return descriptor
|
||||
}
|
||||
|
||||
protected abstract fun compileFiles(files: List<File>, outputDirectory: File, languageVersion: LanguageVersion)
|
||||
|
||||
protected abstract fun loadModule(directory: File): ModuleDescriptor
|
||||
|
||||
fun testSuspendFun() {
|
||||
doTest(
|
||||
VersionRequirement.Version(1, 1), DeprecationLevel.ERROR, null, LANGUAGE_VERSION, null,
|
||||
VersionRequirement.Version(1, 1), DeprecationLevel.ERROR, null, ProtoBuf.VersionRequirement.VersionKind.LANGUAGE_VERSION, null,
|
||||
fqNames = listOf(
|
||||
"test.topLevel",
|
||||
"test.Foo.member",
|
||||
@@ -118,7 +91,7 @@ class VersionRequirementTest : TestCaseWithTmpdir() {
|
||||
)
|
||||
|
||||
doTest(
|
||||
VersionRequirement.Version(1, 3), DeprecationLevel.ERROR, null, LANGUAGE_VERSION, null,
|
||||
VersionRequirement.Version(1, 3), DeprecationLevel.ERROR, null, ProtoBuf.VersionRequirement.VersionKind.LANGUAGE_VERSION, null,
|
||||
customLanguageVersion = LanguageVersion.KOTLIN_1_3,
|
||||
fqNames = listOf(
|
||||
"test.topLevel",
|
||||
@@ -135,7 +108,8 @@ class VersionRequirementTest : TestCaseWithTmpdir() {
|
||||
|
||||
fun testLanguageVersionViaAnnotation() {
|
||||
doTest(
|
||||
VersionRequirement.Version(1, 1), DeprecationLevel.WARNING, "message", LANGUAGE_VERSION, 42,
|
||||
VersionRequirement.Version(1, 1), DeprecationLevel.WARNING, "message",
|
||||
ProtoBuf.VersionRequirement.VersionKind.LANGUAGE_VERSION, 42,
|
||||
fqNames = listOf(
|
||||
"test.Klass",
|
||||
"test.Konstructor.<init>",
|
||||
@@ -148,7 +122,7 @@ class VersionRequirementTest : TestCaseWithTmpdir() {
|
||||
|
||||
fun testApiVersionViaAnnotation() {
|
||||
doTest(
|
||||
VersionRequirement.Version(1, 1), DeprecationLevel.WARNING, "message", API_VERSION, 42,
|
||||
VersionRequirement.Version(1, 1), DeprecationLevel.WARNING, "message", ProtoBuf.VersionRequirement.VersionKind.API_VERSION, 42,
|
||||
fqNames = listOf(
|
||||
"test.Klass",
|
||||
"test.Konstructor.<init>",
|
||||
@@ -161,7 +135,8 @@ class VersionRequirementTest : TestCaseWithTmpdir() {
|
||||
|
||||
fun testCompilerVersionViaAnnotation() {
|
||||
doTest(
|
||||
VersionRequirement.Version(1, 1), DeprecationLevel.WARNING, "message", COMPILER_VERSION, 42,
|
||||
VersionRequirement.Version(1, 1), DeprecationLevel.WARNING, "message",
|
||||
ProtoBuf.VersionRequirement.VersionKind.COMPILER_VERSION, 42,
|
||||
fqNames = listOf(
|
||||
"test.Klass",
|
||||
"test.Konstructor.<init>",
|
||||
@@ -174,25 +149,24 @@ class VersionRequirementTest : TestCaseWithTmpdir() {
|
||||
|
||||
fun testPatchVersion() {
|
||||
doTest(
|
||||
VersionRequirement.Version(1, 1, 50), DeprecationLevel.HIDDEN, null, LANGUAGE_VERSION, null,
|
||||
VersionRequirement.Version(1, 1, 50), DeprecationLevel.HIDDEN, null,
|
||||
ProtoBuf.VersionRequirement.VersionKind.LANGUAGE_VERSION, null,
|
||||
fqNames = listOf("test.Klass")
|
||||
)
|
||||
}
|
||||
|
||||
fun testJvmDefault() {
|
||||
fun testNestedClassMembers() {
|
||||
doTest(
|
||||
VersionRequirement.Version(1, 2, 40), DeprecationLevel.ERROR, null, COMPILER_VERSION, null,
|
||||
VersionRequirement.Version(1, 1), DeprecationLevel.ERROR, null, ProtoBuf.VersionRequirement.VersionKind.LANGUAGE_VERSION, null,
|
||||
fqNames = listOf(
|
||||
"test.Base",
|
||||
"test.Derived"
|
||||
"test.Outer.Inner.Deep",
|
||||
"test.Outer.Inner.Deep.<init>",
|
||||
"test.Outer.Inner.Deep.f",
|
||||
"test.Outer.Inner.Deep.x",
|
||||
"test.Outer.Inner.Deep.s",
|
||||
"test.Outer.Nested.g",
|
||||
"test.Outer.Companion"
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
fun testJvmFieldInInterfaceCompanion() {
|
||||
doTest(
|
||||
VersionRequirement.Version(1, 2, 70), DeprecationLevel.ERROR, null, COMPILER_VERSION, null,
|
||||
fqNames = listOf("test.Base.Companion.foo")
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright 2010-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.serialization
|
||||
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
|
||||
import org.jetbrains.kotlin.config.*
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.kotlin.jvm.compiler.LoadDescriptorUtil
|
||||
import org.jetbrains.kotlin.metadata.ProtoBuf
|
||||
import org.jetbrains.kotlin.metadata.ProtoBuf.VersionRequirement.VersionKind.COMPILER_VERSION
|
||||
import org.jetbrains.kotlin.metadata.deserialization.VersionRequirement
|
||||
import org.jetbrains.kotlin.resolve.lazy.JvmResolveUtil
|
||||
import org.jetbrains.kotlin.test.ConfigurationKind
|
||||
import org.jetbrains.kotlin.test.KotlinTestUtils
|
||||
import org.jetbrains.kotlin.test.TestJdkKind
|
||||
import java.io.File
|
||||
|
||||
class JvmVersionRequirementTest : AbstractVersionRequirementTest() {
|
||||
override fun compileFiles(files: List<File>, outputDirectory: File, languageVersion: LanguageVersion) {
|
||||
LoadDescriptorUtil.compileKotlinToDirAndGetModule(
|
||||
listOf(File("compiler/testData/versionRequirement/${getTestName(true)}.kt")), outputDirectory,
|
||||
KotlinCoreEnvironment.createForTests(
|
||||
testRootDisposable,
|
||||
KotlinTestUtils.newConfiguration(ConfigurationKind.ALL, TestJdkKind.MOCK_JDK, outputDirectory).apply {
|
||||
put(JVMConfigurationKeys.JVM_TARGET, JvmTarget.JVM_1_8)
|
||||
languageVersionSettings = LanguageVersionSettingsImpl(
|
||||
languageVersion,
|
||||
ApiVersion.createByLanguageVersion(languageVersion),
|
||||
mapOf(AnalysisFlag.jvmDefaultMode to JvmDefaultMode.ENABLE),
|
||||
emptyMap()
|
||||
)
|
||||
},
|
||||
EnvironmentConfigFiles.JVM_CONFIG_FILES
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
override fun loadModule(directory: File): ModuleDescriptor = JvmResolveUtil.analyze(
|
||||
KotlinCoreEnvironment.createForTests(
|
||||
testRootDisposable,
|
||||
KotlinTestUtils.newConfiguration(ConfigurationKind.ALL, TestJdkKind.MOCK_JDK, tmpdir),
|
||||
EnvironmentConfigFiles.JVM_CONFIG_FILES
|
||||
)
|
||||
).moduleDescriptor
|
||||
|
||||
fun testJvmDefault() {
|
||||
doTest(
|
||||
VersionRequirement.Version(1, 2, 40), DeprecationLevel.ERROR, null, COMPILER_VERSION, null,
|
||||
fqNames = listOf(
|
||||
"test.Base",
|
||||
"test.Derived"
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
fun testJvmFieldInInterfaceCompanion() {
|
||||
doTest(
|
||||
VersionRequirement.Version(1, 2, 70), DeprecationLevel.ERROR, null, COMPILER_VERSION, null,
|
||||
fqNames = listOf("test.Base.Companion.foo")
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.serialization.js
|
||||
|
||||
import org.jetbrains.kotlin.cli.common.output.outputUtils.writeAllTo
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
|
||||
import org.jetbrains.kotlin.config.ApiVersion
|
||||
import org.jetbrains.kotlin.config.LanguageVersion
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettingsImpl
|
||||
import org.jetbrains.kotlin.config.languageVersionSettings
|
||||
import org.jetbrains.kotlin.context.ContextForNewModule
|
||||
import org.jetbrains.kotlin.context.MutableModuleContext
|
||||
import org.jetbrains.kotlin.context.ProjectContext
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.kotlin.js.analyze.TopDownAnalyzerFacadeForJS
|
||||
import org.jetbrains.kotlin.js.config.JSConfigurationKeys
|
||||
import org.jetbrains.kotlin.js.config.JsConfig
|
||||
import org.jetbrains.kotlin.js.facade.K2JSTranslator
|
||||
import org.jetbrains.kotlin.js.facade.MainCallParameters
|
||||
import org.jetbrains.kotlin.js.facade.TranslationResult
|
||||
import org.jetbrains.kotlin.js.resolve.JsPlatform
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.BindingTraceContext
|
||||
import org.jetbrains.kotlin.serialization.AbstractVersionRequirementTest
|
||||
import org.jetbrains.kotlin.test.ConfigurationKind
|
||||
import org.jetbrains.kotlin.test.KotlinTestUtils
|
||||
import org.jetbrains.kotlin.test.TestJdkKind
|
||||
import java.io.File
|
||||
|
||||
class JsVersionRequirementTest : AbstractVersionRequirementTest() {
|
||||
override fun compileFiles(files: List<File>, outputDirectory: File, languageVersion: LanguageVersion) {
|
||||
val environment = createEnvironment(languageVersion)
|
||||
val ktFiles = files.map { file -> KotlinTestUtils.createFile(file.name, file.readText(), environment.project) }
|
||||
val trace = BindingTraceContext()
|
||||
val analysisResult = TopDownAnalyzerFacadeForJS.analyzeFilesWithGivenTrace(
|
||||
ktFiles, trace, createModule(environment), environment.configuration
|
||||
)
|
||||
|
||||
// There are INVISIBLE_REFERENCE errors on RequireKotlin and K2JSTranslator refuses to translate the code otherwise
|
||||
trace.clearDiagnostics()
|
||||
|
||||
val result = K2JSTranslator(JsConfig(environment.project, environment.configuration)).translate(
|
||||
object : JsConfig.Reporter() {}, ktFiles, MainCallParameters.noCall(), analysisResult
|
||||
) as TranslationResult.Success
|
||||
result.getOutputFiles(File(outputDirectory, "lib.js"), null, null).writeAllTo(outputDirectory)
|
||||
}
|
||||
|
||||
override fun loadModule(directory: File): ModuleDescriptor {
|
||||
val environment = createEnvironment(extraDependencies = listOf(File(directory, "lib.meta.js")))
|
||||
return TopDownAnalyzerFacadeForJS.analyzeFilesWithGivenTrace(
|
||||
emptyList(), BindingTraceContext(), createModule(environment), environment.configuration
|
||||
).moduleDescriptor
|
||||
}
|
||||
|
||||
private fun createEnvironment(
|
||||
languageVersion: LanguageVersion? = null,
|
||||
extraDependencies: List<File> = emptyList()
|
||||
): KotlinCoreEnvironment =
|
||||
KotlinCoreEnvironment.createForTests(
|
||||
testRootDisposable,
|
||||
KotlinTestUtils.newConfiguration(ConfigurationKind.ALL, TestJdkKind.MOCK_JDK).apply {
|
||||
put(JSConfigurationKeys.LIBRARIES, extraDependencies.map(File::getPath) + JsConfig.JS_STDLIB)
|
||||
put(JSConfigurationKeys.META_INFO, true)
|
||||
|
||||
if (languageVersion != null) {
|
||||
languageVersionSettings =
|
||||
LanguageVersionSettingsImpl(languageVersion, ApiVersion.createByLanguageVersion(languageVersion))
|
||||
}
|
||||
},
|
||||
EnvironmentConfigFiles.JS_CONFIG_FILES
|
||||
)
|
||||
|
||||
private fun createModule(environment: KotlinCoreEnvironment): MutableModuleContext {
|
||||
val config = JsConfig(environment.project, environment.configuration)
|
||||
return ContextForNewModule(ProjectContext(environment.project), Name.special("<test>"), JsPlatform.builtIns, null).apply {
|
||||
setDependencies(listOf(module) + config.moduleDescriptors + module.builtIns.builtInsModule)
|
||||
}
|
||||
}
|
||||
}
|
||||
+10
-15
@@ -192,29 +192,24 @@ object KotlinJavascriptSerializationUtil {
|
||||
|
||||
val classDescriptors = scope.filterIsInstance<ClassDescriptor>().sortedBy { it.fqNameSafe.asString() }
|
||||
|
||||
fun serializeClasses(descriptors: Collection<DeclarationDescriptor>) {
|
||||
fun serializeClass(classDescriptor: ClassDescriptor) {
|
||||
if (skip(classDescriptor)) return
|
||||
val classProto =
|
||||
DescriptorSerializer.create(classDescriptor, extension).classProto(classDescriptor).build()
|
||||
?: error("Class not serialized: $classDescriptor")
|
||||
builder.addClass_(classProto)
|
||||
serializeClasses(classDescriptor.unsubstitutedInnerClassesScope.getContributedDescriptors())
|
||||
}
|
||||
|
||||
fun serializeClasses(descriptors: Collection<DeclarationDescriptor>, parentSerializer: DescriptorSerializer) {
|
||||
for (descriptor in descriptors) {
|
||||
if (descriptor is ClassDescriptor) {
|
||||
serializeClass(descriptor)
|
||||
}
|
||||
if (descriptor !is ClassDescriptor || skip(descriptor)) continue
|
||||
|
||||
val serializer = DescriptorSerializer.create(descriptor, extension, parentSerializer)
|
||||
serializeClasses(descriptor.unsubstitutedInnerClassesScope.getContributedDescriptors(), serializer)
|
||||
val classProto = serializer.classProto(descriptor).build() ?: error("Class not serialized: $descriptor")
|
||||
builder.addClass_(classProto)
|
||||
}
|
||||
}
|
||||
|
||||
serializeClasses(classDescriptors)
|
||||
val serializer = DescriptorSerializer.createTopLevel(extension)
|
||||
serializeClasses(classDescriptors, serializer)
|
||||
|
||||
val stringTable = extension.stringTable
|
||||
|
||||
val members = scope.filterNot(skip)
|
||||
builder.`package` = DescriptorSerializer.createTopLevel(extension).packagePartProto(fqName, members).build()
|
||||
builder.`package` = serializer.packagePartProto(fqName, members).build()
|
||||
|
||||
builder.setExtension(
|
||||
JsProtoBuf.packageFragmentFiles,
|
||||
|
||||
Reference in New Issue
Block a user