From 8c2baf0704aaeca3fba9828f87b9ffbf344b848c Mon Sep 17 00:00:00 2001 From: Ilya Muradyan Date: Wed, 17 Jun 2020 15:33:48 +0300 Subject: [PATCH] Add missing definitelyDoesNotContainName methods --- .../extensions/SyntheticResolveExtension.kt | 15 ++++++++ .../lazy/descriptors/LazyClassMemberScope.kt | 37 ++++++++++++++++++- .../kotlin/resolve/scopes/MemberScope.kt | 2 + .../SerializationResolveExtension.kt | 4 ++ ...lizationPluginDiagnosticTestGenerated.java | 5 +++ .../testData/diagnostics/LazyRecursionBug.kt | 9 +++++ .../testData/diagnostics/LazyRecursionBug.txt | 21 +++++++++++ .../SerializationIDEResolveExtension.kt | 6 +++ 8 files changed, 97 insertions(+), 2 deletions(-) create mode 100644 plugins/kotlin-serialization/kotlin-serialization-compiler/testData/diagnostics/LazyRecursionBug.kt create mode 100644 plugins/kotlin-serialization/kotlin-serialization-compiler/testData/diagnostics/LazyRecursionBug.txt diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/extensions/SyntheticResolveExtension.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/extensions/SyntheticResolveExtension.kt index c60958e919d..921ea5cee20 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/extensions/SyntheticResolveExtension.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/extensions/SyntheticResolveExtension.kt @@ -26,6 +26,7 @@ import org.jetbrains.kotlin.resolve.lazy.declarations.ClassMemberDeclarationProv import org.jetbrains.kotlin.resolve.lazy.declarations.PackageMemberDeclarationProvider import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult +import org.jetbrains.kotlin.utils.addToStdlib.flatMapToNullable import java.util.* //---------------------------------------------------------------- @@ -43,6 +44,13 @@ interface SyntheticResolveExtension { override fun getSyntheticNestedClassNames(thisDescriptor: ClassDescriptor): List = instances.flatMap { withLinkageErrorLogger(it) { getSyntheticNestedClassNames(thisDescriptor) } } + override fun getPossibleSyntheticNestedClassNames(thisDescriptor: ClassDescriptor): List? = + instances.flatMapToNullable(ArrayList()) { + withLinkageErrorLogger(it) { + getPossibleSyntheticNestedClassNames(thisDescriptor) + } + } + override fun getSyntheticFunctionNames(thisDescriptor: ClassDescriptor): List = instances.flatMap { withLinkageErrorLogger(it) { getSyntheticFunctionNames(thisDescriptor) } } @@ -136,6 +144,13 @@ interface SyntheticResolveExtension { fun getSyntheticNestedClassNames(thisDescriptor: ClassDescriptor): List = emptyList() + /** + * This method should return either superset of what [getSyntheticNestedClassNames] returns, + * or null in case it needs to run resolution and inference and/or it is very costly. + * Override this method if resolution started to fail with recursion. + */ + fun getPossibleSyntheticNestedClassNames(thisDescriptor: ClassDescriptor): List? = getSyntheticNestedClassNames(thisDescriptor) + fun addSyntheticSupertypes(thisDescriptor: ClassDescriptor, supertypes: MutableList) {} fun generateSyntheticClasses( diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/descriptors/LazyClassMemberScope.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/descriptors/LazyClassMemberScope.kt index 83f47863ba1..006b1b63d3f 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/descriptors/LazyClassMemberScope.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/descriptors/LazyClassMemberScope.kt @@ -44,6 +44,7 @@ import org.jetbrains.kotlin.storage.getValue import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.checker.KotlinTypeRefiner import org.jetbrains.kotlin.types.refinement.TypeRefinement +import org.jetbrains.kotlin.utils.addToStdlib.flatMapToNullable import java.util.* open class LazyClassMemberScope( @@ -102,7 +103,7 @@ open class LazyClassMemberScope( } private val _variableNames: MutableSet - by lazy(LazyThreadSafetyMode.PUBLICATION) { + by storageManager.createLazyValue { mutableSetOf().apply { addAll(declarationProvider.getDeclarationNames()) supertypes.flatMapTo(this) { @@ -112,9 +113,10 @@ open class LazyClassMemberScope( } private val _functionNames: MutableSet - by lazy(LazyThreadSafetyMode.PUBLICATION) { + by storageManager.createLazyValue { mutableSetOf().apply { addAll(declarationProvider.getDeclarationNames()) + addAll(c.syntheticResolveExtension.getSyntheticFunctionNames(thisDescriptor)) supertypes.flatMapTo(this) { it.memberScope.getFunctionNames() } @@ -123,6 +125,32 @@ open class LazyClassMemberScope( } } + private val _classifierNames: Set? + by storageManager.createNullableLazyValue { + mutableSetOf().apply { + supertypes.flatMapToNullable(this) { + it.memberScope.getClassifierNames() + } ?: return@createNullableLazyValue null + + addAll(declarationProvider.getDeclarationNames()) + with(c.syntheticResolveExtension) { + getPossibleSyntheticNestedClassNames(thisDescriptor)?.let { addAll(it) } ?: return@createNullableLazyValue null + getSyntheticCompanionObjectNameIfNeeded(thisDescriptor)?.let { add(it) } + } + } + } + + private val _allNames: Set? + by storageManager.createNullableLazyValue { + val classifiers = getClassifierNames() ?: return@createNullableLazyValue null + + mutableSetOf().apply { + addAll(getVariableNames()) + addAll(getFunctionNames()) + addAll(classifiers) + } + } + private fun getDataClassRelatedFunctionNames(): Collection { val declarations = mutableListOf() addDataClassMethods(declarations, NoLookupLocation.WHEN_GET_ALL_DESCRIPTORS) @@ -131,6 +159,11 @@ open class LazyClassMemberScope( override fun getVariableNames() = _variableNames override fun getFunctionNames() = _functionNames + override fun getClassifierNames() = _classifierNames + + override fun definitelyDoesNotContainName(name: Name): Boolean { + return _allNames?.let { name !in it } ?: false + } private interface MemberExtractor { fun extract(extractFrom: KotlinType, name: Name): Collection diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/MemberScope.kt b/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/MemberScope.kt index 59a3c6f9eff..bd8224e80ed 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/MemberScope.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/MemberScope.kt @@ -46,6 +46,8 @@ interface MemberScope : ResolutionScope { p.println("Empty member scope") } + override fun definitelyDoesNotContainName(name: Name): Boolean = true + override fun getFunctionNames() = emptySet() override fun getVariableNames() = emptySet() override fun getClassifierNames() = emptySet() diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/extensions/SerializationResolveExtension.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/extensions/SerializationResolveExtension.kt index 238c843fc6b..908fe46921b 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/extensions/SerializationResolveExtension.kt +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/extensions/SerializationResolveExtension.kt @@ -42,6 +42,10 @@ open class SerializationResolveExtension : SyntheticResolveExtension { else -> listOf() } + override fun getPossibleSyntheticNestedClassNames(thisDescriptor: ClassDescriptor): List? { + return listOf(SerialEntityNames.IMPL_NAME, SerialEntityNames.SERIALIZER_CLASS_NAME) + } + override fun getSyntheticFunctionNames(thisDescriptor: ClassDescriptor): List = when { thisDescriptor.isSerializableObject || thisDescriptor.isCompanionObject && getSerializableClassDescriptorByCompanion(thisDescriptor) != null -> listOf(SerialEntityNames.SERIALIZER_PROVIDER_NAME) diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/test/org/jetbrains/kotlinx/serialization/SerializationPluginDiagnosticTestGenerated.java b/plugins/kotlin-serialization/kotlin-serialization-compiler/test/org/jetbrains/kotlinx/serialization/SerializationPluginDiagnosticTestGenerated.java index a69024d04ee..2a07c127c73 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-compiler/test/org/jetbrains/kotlinx/serialization/SerializationPluginDiagnosticTestGenerated.java +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/test/org/jetbrains/kotlinx/serialization/SerializationPluginDiagnosticTestGenerated.java @@ -33,6 +33,11 @@ public class SerializationPluginDiagnosticTestGenerated extends AbstractSerializ runTest("plugins/kotlin-serialization/kotlin-serialization-compiler/testData/diagnostics/DuplicateSerialName.kt"); } + @TestMetadata("LazyRecursionBug.kt") + public void testLazyRecursionBug() throws Exception { + runTest("plugins/kotlin-serialization/kotlin-serialization-compiler/testData/diagnostics/LazyRecursionBug.kt"); + } + @TestMetadata("NoSuitableCtorInParent.kt") public void testNoSuitableCtorInParent() throws Exception { runTest("plugins/kotlin-serialization/kotlin-serialization-compiler/testData/diagnostics/NoSuitableCtorInParent.kt"); diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/testData/diagnostics/LazyRecursionBug.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/testData/diagnostics/LazyRecursionBug.kt new file mode 100644 index 00000000000..d2455d7f342 --- /dev/null +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/testData/diagnostics/LazyRecursionBug.kt @@ -0,0 +1,9 @@ +// This test enshures that analysis ends up without compiler exceptions + +import kotlinx.serialization.* + +@Serializable +class Digest() { + @Serializer(forClass = Digest::class) + companion object : KSerializer {} +} diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/testData/diagnostics/LazyRecursionBug.txt b/plugins/kotlin-serialization/kotlin-serialization-compiler/testData/diagnostics/LazyRecursionBug.txt new file mode 100644 index 00000000000..65fe78e46e7 --- /dev/null +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/testData/diagnostics/LazyRecursionBug.txt @@ -0,0 +1,21 @@ +package + +@kotlinx.serialization.Serializable public final class Digest { + public constructor Digest() + @kotlin.Deprecated(level = DeprecationLevel.HIDDEN, message = "This synthesized declaration should not be used directly", replaceWith = kotlin.ReplaceWith(expression = "", imports = {})) public /*synthesized*/ constructor Digest(/*0*/ seen1: kotlin.Int, /*1*/ serializationConstructorMarker: kotlinx.serialization.SerializationConstructorMarker?) + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + + @kotlinx.serialization.Serializer(forClass = Digest::class) public companion object Companion : kotlinx.serialization.KSerializer { + private constructor Companion() + public open override /*1*/ /*synthesized*/ val descriptor: kotlinx.serialization.SerialDescriptor + public open override /*1*/ /*synthesized*/ fun deserialize(/*0*/ decoder: kotlinx.serialization.Decoder): Digest + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + @kotlin.Deprecated(level = DeprecationLevel.ERROR, message = "Patch function is deprecated for removal since this functionality is no longer supported by serializer.Some formats may provide implementation-specific patching in their Decoders.") public open override /*1*/ /*fake_override*/ fun patch(/*0*/ decoder: kotlinx.serialization.Decoder, /*1*/ old: Digest): Digest + public open override /*1*/ /*synthesized*/ fun serialize(/*0*/ encoder: kotlinx.serialization.Encoder, /*1*/ value: Digest): kotlin.Unit + public final /*synthesized*/ fun serializer(): kotlinx.serialization.KSerializer + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } +} diff --git a/plugins/kotlin-serialization/kotlin-serialization-ide/src/org/jetbrains/kotlinx/serialization/compiler/extensions/SerializationIDEResolveExtension.kt b/plugins/kotlin-serialization/kotlin-serialization-ide/src/org/jetbrains/kotlinx/serialization/compiler/extensions/SerializationIDEResolveExtension.kt index ec37aac0aae..22ef130ca82 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-ide/src/org/jetbrains/kotlinx/serialization/compiler/extensions/SerializationIDEResolveExtension.kt +++ b/plugins/kotlin-serialization/kotlin-serialization-ide/src/org/jetbrains/kotlinx/serialization/compiler/extensions/SerializationIDEResolveExtension.kt @@ -21,6 +21,12 @@ class SerializationIDEResolveExtension : SerializationResolveExtension() { override fun getSyntheticNestedClassNames(thisDescriptor: ClassDescriptor): List = getIfEnabledOn(thisDescriptor) { super.getSyntheticNestedClassNames(thisDescriptor) } ?: emptyList() + override fun getPossibleSyntheticNestedClassNames(thisDescriptor: ClassDescriptor): List? { + val enabled = getIfEnabledOn(thisDescriptor) { true } ?: false + return if (enabled) super.getPossibleSyntheticNestedClassNames(thisDescriptor) + else emptyList() + } + override fun getSyntheticFunctionNames(thisDescriptor: ClassDescriptor): List = getIfEnabledOn(thisDescriptor) { super.getSyntheticFunctionNames(thisDescriptor) } ?: emptyList()