Metadata: 'non-stable parameter names' flag for callables
^KT-34602
This commit is contained in:
+4
-2
@@ -310,7 +310,8 @@ class FirElementSerializer private constructor(
|
||||
simpleFunction?.isTailRec == true,
|
||||
simpleFunction?.isExternal == true,
|
||||
simpleFunction?.isSuspend == true,
|
||||
simpleFunction?.isExpect == true
|
||||
simpleFunction?.isExpect == true,
|
||||
true // TODO: supply 'hasStableParameterNames' flag for metadata
|
||||
)
|
||||
if (flags != builder.flags) {
|
||||
builder.flags = flags
|
||||
@@ -439,7 +440,8 @@ class FirElementSerializer private constructor(
|
||||
val flags = Flags.getConstructorFlags(
|
||||
constructor.nonSourceAnnotations(session).isNotEmpty(),
|
||||
ProtoEnumFlags.visibility(normalizeVisibility(constructor)),
|
||||
!constructor.isPrimary
|
||||
!constructor.isPrimary,
|
||||
true // TODO: supply 'hasStableParameterNames' flag for metadata
|
||||
)
|
||||
if (flags != builder.flags) {
|
||||
builder.flags = flags
|
||||
|
||||
+3
-1
@@ -264,7 +264,9 @@ private class FirCallArgumentsProcessor(private val function: FirFunction<*>) {
|
||||
private val FirExpression.argumentName: Name?
|
||||
get() = (this as? FirNamedArgumentExpression)?.name
|
||||
|
||||
// TODO: handle java functions
|
||||
// TODO: handle functions with non-stable parameter names, see also
|
||||
// org.jetbrains.kotlin.fir.serialization.FirElementSerializer.functionProto
|
||||
// org.jetbrains.kotlin.fir.serialization.FirElementSerializer.constructorProto
|
||||
private val FirFunction<*>.hasStableParameterNames: Boolean
|
||||
get() = true
|
||||
}
|
||||
|
||||
+2
-2
@@ -74,10 +74,10 @@ inline class FunctionFlags(val flags: Long) {
|
||||
val modality = ProtoEnumFlags.modality(modality)
|
||||
val kind = if (isFakeOverride) ProtoBuf.MemberKind.FAKE_OVERRIDE else ProtoBuf.MemberKind.DECLARATION
|
||||
|
||||
|
||||
val flags = IrFlags.getFunctionFlags(
|
||||
hasAnnotation, visibility, modality, kind,
|
||||
isOperator, isInfix, isInline, isTailrec, isExternal, isSuspend, isExpect
|
||||
isOperator, isInfix, isInline, isTailrec, isExternal, isSuspend, isExpect,
|
||||
true // hasStableParameterNames does not make sense for Ir, just pass the default value
|
||||
)
|
||||
|
||||
return flags.toLong()
|
||||
|
||||
+11
-2
@@ -291,6 +291,14 @@ class DescriptorSerializer private constructor(
|
||||
else
|
||||
descriptor.visibility
|
||||
|
||||
private fun shouldSerializeHasStableParameterNames(descriptor: CallableMemberDescriptor): Boolean {
|
||||
return when {
|
||||
descriptor.hasStableParameterNames() -> true
|
||||
descriptor.kind == CallableMemberDescriptor.Kind.DELEGATION -> true // remove this line to fix KT-4758
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
fun functionProto(descriptor: FunctionDescriptor): ProtoBuf.Function.Builder? {
|
||||
if (!extension.shouldSerializeFunction(descriptor)) return null
|
||||
|
||||
@@ -304,7 +312,7 @@ class DescriptorSerializer private constructor(
|
||||
ProtoEnumFlags.modality(descriptor.modality),
|
||||
ProtoEnumFlags.memberKind(descriptor.kind),
|
||||
descriptor.isOperator, descriptor.isInfix, descriptor.isInline, descriptor.isTailrec, descriptor.isExternal,
|
||||
descriptor.isSuspend, descriptor.isExpect
|
||||
descriptor.isSuspend, descriptor.isExpect, shouldSerializeHasStableParameterNames(descriptor)
|
||||
)
|
||||
if (flags != builder.flags) {
|
||||
builder.flags = flags
|
||||
@@ -367,7 +375,8 @@ class DescriptorSerializer private constructor(
|
||||
val local = createChildSerializer(descriptor)
|
||||
|
||||
val flags = Flags.getConstructorFlags(
|
||||
hasAnnotations(descriptor), ProtoEnumFlags.visibility(normalizeVisibility(descriptor)), !descriptor.isPrimary
|
||||
hasAnnotations(descriptor), ProtoEnumFlags.visibility(normalizeVisibility(descriptor)), !descriptor.isPrimary,
|
||||
shouldSerializeHasStableParameterNames(descriptor)
|
||||
)
|
||||
if (flags != builder.flags) {
|
||||
builder.flags = flags
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
package library
|
||||
|
||||
fun foo(a: Int, b: String, c: Boolean) = Unit
|
||||
|
||||
class Foo(a: Int, b: String, c: Boolean) {
|
||||
constructor(a: Int, b: String, c: Boolean, d: Double) : this(a, b, c)
|
||||
|
||||
fun foo(a: Int, b: String, c: Boolean) = Unit
|
||||
|
||||
class Bar(a: Int, b: String, c: Boolean) {
|
||||
constructor(a: Int, b: String, c: Boolean, d: Double) : this(a, b, c)
|
||||
|
||||
fun bar(a: Int, b: String, c: Boolean) = Unit
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* 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.test
|
||||
|
||||
import com.intellij.openapi.util.Disposer
|
||||
import org.jetbrains.kotlin.analyzer.common.CommonResolverForModuleFactory
|
||||
import org.jetbrains.kotlin.backend.common.serialization.metadata.KlibMetadataMonolithicSerializer
|
||||
import org.jetbrains.kotlin.backend.common.serialization.metadata.KlibMetadataVersion
|
||||
import org.jetbrains.kotlin.builtins.DefaultBuiltIns
|
||||
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
|
||||
import org.jetbrains.kotlin.cli.common.config.addKotlinSourceRoots
|
||||
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
|
||||
import org.jetbrains.kotlin.config.CommonConfigurationKeys
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettingsImpl
|
||||
import org.jetbrains.kotlin.config.languageVersionSettings
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
|
||||
import org.jetbrains.kotlin.konan.util.KlibMetadataFactories
|
||||
import org.jetbrains.kotlin.library.*
|
||||
import org.jetbrains.kotlin.library.impl.BuiltInsPlatform
|
||||
import org.jetbrains.kotlin.library.impl.KotlinLibraryWriterImpl
|
||||
import org.jetbrains.kotlin.library.metadata.NativeTypeTransformer
|
||||
import org.jetbrains.kotlin.library.metadata.NullFlexibleTypeDeserializer
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.platform.CommonPlatforms
|
||||
import org.jetbrains.kotlin.storage.LockBasedStorageManager
|
||||
import org.jetbrains.kotlin.util.DummyLogger
|
||||
import java.io.File
|
||||
import org.jetbrains.kotlin.konan.file.File as KFile
|
||||
|
||||
object KlibTestUtil {
|
||||
fun compileCommonSourcesToKlib(sourceFiles: Collection<File>, libraryName: String, klibFile: File) {
|
||||
require(!Name.guessByFirstCharacter(libraryName).isSpecial) { "Invalid library name: $libraryName" }
|
||||
|
||||
val configuration = KotlinTestUtils.newConfiguration()
|
||||
configuration.put(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY, MessageCollector.NONE)
|
||||
configuration.put(CommonConfigurationKeys.MODULE_NAME, libraryName)
|
||||
configuration.addKotlinSourceRoots(sourceFiles.map { it.absolutePath })
|
||||
|
||||
val rootDisposable = Disposer.newDisposable()
|
||||
val module = try {
|
||||
val environment = KotlinCoreEnvironment.createForTests(
|
||||
parentDisposable = rootDisposable,
|
||||
initialConfiguration = configuration,
|
||||
extensionConfigs = EnvironmentConfigFiles.METADATA_CONFIG_FILES
|
||||
)
|
||||
|
||||
CommonResolverForModuleFactory.analyzeFiles(
|
||||
files = environment.getSourceFiles(),
|
||||
moduleName = Name.special("<$libraryName>"),
|
||||
dependOnBuiltIns = true,
|
||||
languageVersionSettings = environment.configuration.languageVersionSettings,
|
||||
targetPlatform = CommonPlatforms.defaultCommonPlatform
|
||||
) { content ->
|
||||
environment.createPackagePartProvider(content.moduleContentScope)
|
||||
}.moduleDescriptor
|
||||
} finally {
|
||||
Disposer.dispose(rootDisposable)
|
||||
}
|
||||
|
||||
serializeCommonModuleToKlib(module, libraryName, klibFile)
|
||||
}
|
||||
|
||||
fun serializeCommonModuleToKlib(module: ModuleDescriptor, libraryName: String, klibFile: File) {
|
||||
require(klibFile.extension == KLIB_FILE_EXTENSION) { "KLIB file must have $KLIB_FILE_EXTENSION extension" }
|
||||
|
||||
val serializer = KlibMetadataMonolithicSerializer(
|
||||
languageVersionSettings = LanguageVersionSettingsImpl.DEFAULT,
|
||||
metadataVersion = KlibMetadataVersion.INSTANCE,
|
||||
skipExpects = false
|
||||
)
|
||||
|
||||
val serializedMetadata = serializer.serializeModule(module)
|
||||
|
||||
val library = KotlinLibraryWriterImpl(
|
||||
libDir = KFile(klibFile.path.removeSuffix(KLIB_FILE_EXTENSION_WITH_DOT)),
|
||||
moduleName = libraryName,
|
||||
versions = KotlinLibraryVersioning(
|
||||
libraryVersion = null,
|
||||
compilerVersion = null,
|
||||
abiVersion = null,
|
||||
metadataVersion = KlibMetadataVersion.INSTANCE.toString(),
|
||||
irVersion = null
|
||||
),
|
||||
builtInsPlatform = BuiltInsPlatform.COMMON,
|
||||
nativeTargets = emptyList(),
|
||||
nopack = false,
|
||||
shortName = libraryName
|
||||
)
|
||||
|
||||
library.addMetadata(serializedMetadata)
|
||||
library.commit()
|
||||
}
|
||||
|
||||
fun deserializeKlibToCommonModule(klibFile: File): ModuleDescriptorImpl {
|
||||
val library = resolveSingleFileKlib(
|
||||
libraryFile = KFile(klibFile.path),
|
||||
logger = DummyLogger,
|
||||
strategy = ToolingSingleFileKlibResolveStrategy
|
||||
)
|
||||
|
||||
val metadataFactories = KlibMetadataFactories({ DefaultBuiltIns.Instance }, NullFlexibleTypeDeserializer, NativeTypeTransformer())
|
||||
|
||||
val module = metadataFactories.DefaultDeserializedDescriptorFactory.createDescriptor(
|
||||
library = library,
|
||||
languageVersionSettings = LanguageVersionSettingsImpl.DEFAULT,
|
||||
storageManager = LockBasedStorageManager.NO_LOCKS,
|
||||
builtIns = DefaultBuiltIns.Instance,
|
||||
packageAccessHandler = null
|
||||
)
|
||||
module.setDependencies(listOf(DefaultBuiltIns.Instance.builtInsModule, module))
|
||||
|
||||
return module
|
||||
}
|
||||
}
|
||||
+105
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* 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
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.impl.FunctionDescriptorImpl
|
||||
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
||||
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
|
||||
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter.Companion.CLASSIFIERS_MASK
|
||||
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter.Companion.FUNCTIONS_MASK
|
||||
import org.jetbrains.kotlin.resolve.scopes.MemberScope
|
||||
import org.jetbrains.kotlin.test.KlibTestUtil
|
||||
import org.jetbrains.kotlin.test.TestCaseWithTmpdir
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.assertedCast
|
||||
import org.jetbrains.kotlin.utils.alwaysTrue
|
||||
import java.io.File
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
class NonStableParameterNamesSerializationTest : TestCaseWithTmpdir() {
|
||||
fun testNonStableParameterNames() {
|
||||
val originalKlibName = File(SOURCE_FILE).nameWithoutExtension
|
||||
val originalKlibFile = File(tmpdir, "$originalKlibName.klib")
|
||||
KlibTestUtil.compileCommonSourcesToKlib(listOf(File(SOURCE_FILE)), originalKlibName, originalKlibFile)
|
||||
|
||||
val originalModule = KlibTestUtil.deserializeKlibToCommonModule(originalKlibFile)
|
||||
val originalCallables = collectCallablesForPatch(originalModule)
|
||||
|
||||
assertTrue { originalCallables.isNotEmpty() }
|
||||
assertTrue { originalCallables.all { it.hasStableParameterNames() } }
|
||||
|
||||
originalCallables.forEach { it.setHasStableParameterNames(false) }
|
||||
|
||||
val patchedKlibName = "${originalKlibFile.nameWithoutExtension}-patched"
|
||||
val patchedKlibFile = originalKlibFile.resolveSibling("$patchedKlibName.klib")
|
||||
KlibTestUtil.serializeCommonModuleToKlib(originalModule, patchedKlibName, patchedKlibFile)
|
||||
|
||||
val patchedModule = KlibTestUtil.deserializeKlibToCommonModule(patchedKlibFile)
|
||||
val patchedCallables = collectCallablesForPatch(patchedModule)
|
||||
|
||||
assertEquals(expected = originalCallables.size, actual = patchedCallables.size)
|
||||
assertEquals(expected = originalCallables.map { it.signature }.toSet(), actual = patchedCallables.map { it.signature }.toSet())
|
||||
assertTrue { patchedCallables.all { !it.hasStableParameterNames() } }
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val SOURCE_FILE = "compiler/testData/serialization/nonStableParameterNames/test.kt"
|
||||
|
||||
private fun collectCallablesForPatch(module: ModuleDescriptorImpl): List<FunctionDescriptorImpl> {
|
||||
fun DeclarationDescriptor.castToFunctionImpl(): FunctionDescriptorImpl =
|
||||
assertedCast { "Not an instance of ${FunctionDescriptorImpl::class.java}: ${this::class.java}, $this" }
|
||||
|
||||
val result = mutableListOf<FunctionDescriptorImpl>()
|
||||
|
||||
fun recurse(memberScope: MemberScope) {
|
||||
memberScope
|
||||
.getContributedDescriptors(DescriptorKindFilter(FUNCTIONS_MASK or CLASSIFIERS_MASK))
|
||||
.forEach { descriptor ->
|
||||
when (descriptor) {
|
||||
is SimpleFunctionDescriptor -> {
|
||||
if (descriptor.kind != CallableMemberDescriptor.Kind.FAKE_OVERRIDE)
|
||||
result += descriptor.castToFunctionImpl()
|
||||
}
|
||||
is ClassDescriptor -> {
|
||||
descriptor.constructors.mapTo(result) { it.castToFunctionImpl() }
|
||||
recurse(descriptor.unsubstitutedMemberScope)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val packageFragmentProvider = module.packageFragmentProviderForModuleContentWithoutDependencies
|
||||
|
||||
fun recurse(packageFqName: FqName) {
|
||||
packageFragmentProvider
|
||||
.getPackageFragments(packageFqName)
|
||||
.forEach { packageFragment ->
|
||||
recurse(packageFragment.getMemberScope())
|
||||
}
|
||||
|
||||
packageFragmentProvider
|
||||
.getSubPackagesOf(packageFqName, alwaysTrue())
|
||||
.toSet()
|
||||
.forEach { recurse(it) }
|
||||
}
|
||||
|
||||
recurse(FqName.ROOT)
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
private val FunctionDescriptorImpl.signature: String
|
||||
get() = buildString {
|
||||
append(fqNameSafe)
|
||||
append('(')
|
||||
valueParameters.joinTo(this, ",") { it.type.constructor.declarationDescriptor?.fqNameSafe?.asString().orEmpty() }
|
||||
append(')')
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -15,7 +15,7 @@ class KlibMetadataVersion(vararg numbers: Int) : BinaryVersion(*numbers) {
|
||||
|
||||
companion object {
|
||||
@JvmField
|
||||
val INSTANCE = KlibMetadataVersion(1, 4, 0)
|
||||
val INSTANCE = KlibMetadataVersion(1, 4, 1)
|
||||
|
||||
@JvmField
|
||||
val INVALID_VERSION = KlibMetadataVersion()
|
||||
|
||||
+5
@@ -272,6 +272,7 @@ class MemberDeserializer(private val c: DeserializationContext) {
|
||||
ProtoEnumFlags.memberKind(Flags.MEMBER_KIND.get(flags)), proto, c.nameResolver, c.typeTable, versionRequirementTable,
|
||||
c.containerSource
|
||||
)
|
||||
|
||||
val local = c.childContext(function, proto.typeParameterList)
|
||||
|
||||
function.initializeWithCoroutinesExperimentalityStatus(
|
||||
@@ -294,6 +295,7 @@ class MemberDeserializer(private val c: DeserializationContext) {
|
||||
function.isTailrec = Flags.IS_TAILREC.get(flags)
|
||||
function.isSuspend = Flags.IS_SUSPEND.get(flags)
|
||||
function.isExpect = Flags.IS_EXPECT_FUNCTION.get(flags)
|
||||
function.setHasStableParameterNames(!Flags.IS_FUNCTION_WITH_NON_STABLE_PARAMETER_NAMES.get(flags))
|
||||
|
||||
val mapValueForContract =
|
||||
c.components.contractDeserializer.deserializeContractFromFunction(proto, function, c.typeTable, local.typeDeserializer)
|
||||
@@ -337,6 +339,7 @@ class MemberDeserializer(private val c: DeserializationContext) {
|
||||
isPrimary, CallableMemberDescriptor.Kind.DECLARATION, proto, c.nameResolver, c.typeTable, c.versionRequirementTable,
|
||||
c.containerSource
|
||||
)
|
||||
|
||||
val local = c.childContext(descriptor, listOf())
|
||||
descriptor.initialize(
|
||||
local.memberDeserializer.valueParameters(proto.valueParameterList, proto, AnnotatedCallableKind.FUNCTION),
|
||||
@@ -344,6 +347,8 @@ class MemberDeserializer(private val c: DeserializationContext) {
|
||||
)
|
||||
descriptor.returnType = classDescriptor.defaultType
|
||||
|
||||
descriptor.setHasStableParameterNames(!Flags.IS_CONSTRUCTOR_WITH_NON_STABLE_PARAMETER_NAMES.get(proto.flags))
|
||||
|
||||
val doesClassContainIncompatibility =
|
||||
(c.containingDeclaration as? DeserializedClassDescriptor)
|
||||
?.c?.typeDeserializer?.experimentalSuspendFunctionTypeEncountered == true
|
||||
|
||||
+5
-1
@@ -120,6 +120,7 @@ class DeserializedSimpleFunctionDescriptor(
|
||||
newOwner, original as SimpleFunctionDescriptor?, annotations, newName ?: name, kind,
|
||||
proto, nameResolver, typeTable, versionRequirementTable, containerSource, source
|
||||
).also {
|
||||
it.setHasStableParameterNames(hasStableParameterNames())
|
||||
it.coroutinesExperimentalCompatibilityMode = coroutinesExperimentalCompatibilityMode
|
||||
}
|
||||
}
|
||||
@@ -209,7 +210,10 @@ class DeserializedClassConstructorDescriptor(
|
||||
return DeserializedClassConstructorDescriptor(
|
||||
newOwner as ClassDescriptor, original as ConstructorDescriptor?, annotations, isPrimary, kind,
|
||||
proto, nameResolver, typeTable, versionRequirementTable, containerSource, source
|
||||
).also { it.coroutinesExperimentalCompatibilityMode = coroutinesExperimentalCompatibilityMode }
|
||||
).also {
|
||||
it.setHasStableParameterNames(hasStableParameterNames())
|
||||
it.coroutinesExperimentalCompatibilityMode = coroutinesExperimentalCompatibilityMode
|
||||
}
|
||||
}
|
||||
|
||||
override fun isExternal(): Boolean = false
|
||||
|
||||
+1
-1
@@ -26,7 +26,7 @@ class JvmMetadataVersion(versionArray: IntArray, val isStrictSemantics: Boolean)
|
||||
|
||||
companion object {
|
||||
@JvmField
|
||||
val INSTANCE = JvmMetadataVersion(1, 4, 0)
|
||||
val INSTANCE = JvmMetadataVersion(1, 4, 1)
|
||||
|
||||
@JvmField
|
||||
val INVALID_VERSION = JvmMetadataVersion()
|
||||
|
||||
@@ -270,6 +270,7 @@ message Constructor {
|
||||
hasAnnotations
|
||||
Visibility
|
||||
isSecondary
|
||||
hasNonStableParameterNames
|
||||
*/
|
||||
optional int32 flags = 1 [default = 6 /* public constructor, no annotations */];
|
||||
|
||||
@@ -294,6 +295,7 @@ message Function {
|
||||
isExternal
|
||||
isSuspend
|
||||
isExpect
|
||||
hasNonStableParameterNames
|
||||
*/
|
||||
optional int32 flags = 9 [default = 6 /* public final function, no annotations */];
|
||||
optional int32 old_flags = 1 [default = 6];
|
||||
|
||||
@@ -35,6 +35,7 @@ public class Flags {
|
||||
// Constructors
|
||||
|
||||
public static final BooleanFlagField IS_SECONDARY = FlagField.booleanAfter(VISIBILITY);
|
||||
public static final BooleanFlagField IS_CONSTRUCTOR_WITH_NON_STABLE_PARAMETER_NAMES = FlagField.booleanAfter(IS_SECONDARY);
|
||||
|
||||
// Callables
|
||||
|
||||
@@ -49,6 +50,7 @@ public class Flags {
|
||||
public static final BooleanFlagField IS_EXTERNAL_FUNCTION = FlagField.booleanAfter(IS_TAILREC);
|
||||
public static final BooleanFlagField IS_SUSPEND = FlagField.booleanAfter(IS_EXTERNAL_FUNCTION);
|
||||
public static final BooleanFlagField IS_EXPECT_FUNCTION = FlagField.booleanAfter(IS_SUSPEND);
|
||||
public static final BooleanFlagField IS_FUNCTION_WITH_NON_STABLE_PARAMETER_NAMES = FlagField.booleanAfter(IS_EXPECT_FUNCTION);
|
||||
|
||||
// Properties
|
||||
|
||||
@@ -115,11 +117,13 @@ public class Flags {
|
||||
public static int getConstructorFlags(
|
||||
boolean hasAnnotations,
|
||||
@NotNull ProtoBuf.Visibility visibility,
|
||||
boolean isSecondary
|
||||
boolean isSecondary,
|
||||
boolean hasStableParameterNames
|
||||
) {
|
||||
return HAS_ANNOTATIONS.toFlags(hasAnnotations)
|
||||
| VISIBILITY.toFlags(visibility)
|
||||
| IS_SECONDARY.toFlags(isSecondary)
|
||||
| IS_CONSTRUCTOR_WITH_NON_STABLE_PARAMETER_NAMES.toFlags(!hasStableParameterNames)
|
||||
;
|
||||
}
|
||||
|
||||
@@ -134,7 +138,8 @@ public class Flags {
|
||||
boolean isTailrec,
|
||||
boolean isExternal,
|
||||
boolean isSuspend,
|
||||
boolean isExpect
|
||||
boolean isExpect,
|
||||
boolean hasStableParameterNames
|
||||
) {
|
||||
return HAS_ANNOTATIONS.toFlags(hasAnnotations)
|
||||
| VISIBILITY.toFlags(visibility)
|
||||
@@ -147,6 +152,7 @@ public class Flags {
|
||||
| IS_EXTERNAL_FUNCTION.toFlags(isExternal)
|
||||
| IS_SUSPEND.toFlags(isSuspend)
|
||||
| IS_EXPECT_FUNCTION.toFlags(isExpect)
|
||||
| IS_FUNCTION_WITH_NON_STABLE_PARAMETER_NAMES.toFlags(!hasStableParameterNames)
|
||||
;
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ import kotlinx.metadata.*
|
||||
import kotlinx.metadata.jvm.*
|
||||
import org.jetbrains.org.objectweb.asm.ClassWriter
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.*
|
||||
import org.junit.Test
|
||||
import java.net.URLClassLoader
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
@@ -169,4 +169,38 @@ class MetadataSmokeTest {
|
||||
) as KotlinClassMetadata.SyntheticClass
|
||||
metadata.accept(KmLambda())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun unstableParameterNames() {
|
||||
@Suppress("unused")
|
||||
class Test(a: String, b: Int, c: Boolean) {
|
||||
fun foo(a: String, b: Int, c: Boolean) = Unit
|
||||
}
|
||||
|
||||
val classWithStableParameterNames =
|
||||
(KotlinClassMetadata.read(Test::class.java.readMetadata()) as KotlinClassMetadata.Class).toKmClass()
|
||||
|
||||
classWithStableParameterNames.constructors.forEach { assertFalse(Flag.Constructor.HAS_NON_STABLE_PARAMETER_NAMES(it.flags)) }
|
||||
classWithStableParameterNames.functions.forEach { assertFalse(Flag.Function.HAS_NON_STABLE_PARAMETER_NAMES(it.flags)) }
|
||||
|
||||
val newMetadata = KotlinClassMetadata.Class.Writer().let { writer ->
|
||||
KmClass().apply {
|
||||
classWithStableParameterNames.accept(
|
||||
object : KmClassVisitor(this) {
|
||||
override fun visitConstructor(flags: Flags) =
|
||||
super.visitConstructor(flags + flagsOf(Flag.Constructor.HAS_NON_STABLE_PARAMETER_NAMES))
|
||||
|
||||
override fun visitFunction(flags: Flags, name: String) =
|
||||
super.visitFunction(flags + flagsOf(Flag.Function.HAS_NON_STABLE_PARAMETER_NAMES), name)
|
||||
}
|
||||
)
|
||||
}.accept(writer)
|
||||
writer.write()
|
||||
}
|
||||
|
||||
val classWithUnstableParameterNames = newMetadata.toKmClass()
|
||||
|
||||
classWithUnstableParameterNames.constructors.forEach { assertTrue(Flag.Constructor.HAS_NON_STABLE_PARAMETER_NAMES(it.flags)) }
|
||||
classWithUnstableParameterNames.functions.forEach { assertTrue(Flag.Function.HAS_NON_STABLE_PARAMETER_NAMES(it.flags)) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -224,6 +224,12 @@ class Flag(private val offset: Int, private val bitWidth: Int, private val value
|
||||
*/
|
||||
@JvmField
|
||||
val IS_PRIMARY = Flag(F.IS_SECONDARY, 0)
|
||||
|
||||
/**
|
||||
* Signifies that the corresponding constructor has non-stable parameter names, i.e. cannot be called with named arguments.
|
||||
*/
|
||||
@JvmField
|
||||
val HAS_NON_STABLE_PARAMETER_NAMES = Flag(F.IS_CONSTRUCTOR_WITH_NON_STABLE_PARAMETER_NAMES)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -302,6 +308,12 @@ class Flag(private val offset: Int, private val bitWidth: Int, private val value
|
||||
*/
|
||||
@JvmField
|
||||
val IS_EXPECT = Flag(F.IS_EXPECT_FUNCTION)
|
||||
|
||||
/**
|
||||
* Signifies that the corresponding function has non-stable parameter names, i.e. cannot be called with named arguments.
|
||||
*/
|
||||
@JvmField
|
||||
val HAS_NON_STABLE_PARAMETER_NAMES = Flag(F.IS_FUNCTION_WITH_NON_STABLE_PARAMETER_NAMES)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -958,7 +958,8 @@ private val CLASS_FLAGS_MAP = COMMON_FLAGS_MAP + mapOf(
|
||||
)
|
||||
|
||||
private val CONSTRUCTOR_FLAGS_MAP = VISIBILITY_FLAGS_MAP + mapOf(
|
||||
Flag.Constructor.IS_PRIMARY to "/* primary */"
|
||||
Flag.Constructor.IS_PRIMARY to "/* primary */",
|
||||
Flag.Constructor.HAS_NON_STABLE_PARAMETER_NAMES to "/* non-stable parameter names */"
|
||||
)
|
||||
|
||||
private val FUNCTION_FLAGS_MAP = COMMON_FLAGS_MAP + mapOf(
|
||||
@@ -973,7 +974,9 @@ private val FUNCTION_FLAGS_MAP = COMMON_FLAGS_MAP + mapOf(
|
||||
Flag.Function.IS_TAILREC to "tailrec",
|
||||
Flag.Function.IS_EXTERNAL to "external",
|
||||
Flag.Function.IS_SUSPEND to "suspend",
|
||||
Flag.Function.IS_EXPECT to "expect"
|
||||
Flag.Function.IS_EXPECT to "expect",
|
||||
|
||||
Flag.Function.HAS_NON_STABLE_PARAMETER_NAMES to "/* non-stable parameter names */"
|
||||
)
|
||||
|
||||
private val PROPERTY_FLAGS_MAP = COMMON_FLAGS_MAP + mapOf(
|
||||
|
||||
Reference in New Issue
Block a user