K1: add support for Enum.entries synthetic property (see KT-48872)

#KT-53270 Fixed
This commit is contained in:
Mikhail Glukhikh
2022-07-25 11:40:32 +02:00
committed by Space
parent c0f81cbc45
commit 12e8b1d844
13 changed files with 247 additions and 62 deletions
@@ -22,16 +22,16 @@ import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.descriptors.annotations.Annotations;
import org.jetbrains.kotlin.descriptors.impl.*;
import org.jetbrains.kotlin.name.Name;
import org.jetbrains.kotlin.name.StandardClassIds;
import org.jetbrains.kotlin.resolve.scopes.receivers.ContextClassReceiver;
import org.jetbrains.kotlin.resolve.scopes.receivers.ContextReceiver;
import org.jetbrains.kotlin.resolve.scopes.receivers.ExtensionReceiver;
import org.jetbrains.kotlin.types.KotlinType;
import org.jetbrains.kotlin.types.Variance;
import org.jetbrains.kotlin.types.*;
import java.util.Collections;
import static org.jetbrains.kotlin.builtins.StandardNames.ENUM_VALUES;
import static org.jetbrains.kotlin.builtins.StandardNames.ENUM_VALUE_OF;
import static org.jetbrains.kotlin.builtins.StandardNames.*;
import static org.jetbrains.kotlin.resolve.DescriptorUtils.getContainingModule;
import static org.jetbrains.kotlin.resolve.DescriptorUtils.getDefaultConstructorVisibility;
import static org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt.getBuiltIns;
@@ -172,6 +172,36 @@ public class DescriptorFactory {
Modality.FINAL, DescriptorVisibilities.PUBLIC);
}
@Nullable
public static PropertyDescriptor createEnumEntriesProperty(@NotNull ClassDescriptor enumClass) {
ClassDescriptor enumEntriesClass = FindClassInModuleKt.findClassAcrossModuleDependencies(getContainingModule(enumClass),
StandardClassIds.INSTANCE.getEnumEntries());
if (enumEntriesClass == null) {
return null;
}
PropertyDescriptorImpl entries =
PropertyDescriptorImpl.create(enumClass, Annotations.Companion.getEMPTY(), Modality.FINAL, DescriptorVisibilities.PUBLIC,
/* isVar = */ false, ENUM_ENTRIES, CallableMemberDescriptor.Kind.SYNTHESIZED,
enumClass.getSource(), /* lateinit = */ false, /* isConst = */ false, /* isExpect = */ false,
/* isActual = */ false, /* isExternal = */ false, /* isDelegated = */ false);
PropertyGetterDescriptorImpl getter = new PropertyGetterDescriptorImpl(
entries, Annotations.Companion.getEMPTY(), Modality.FINAL, DescriptorVisibilities.PUBLIC, /* isDefault = */ false,
/* isExternal = */ false, /* isInline = */ false, CallableMemberDescriptor.Kind.SYNTHESIZED,
/* original = */ null, enumClass.getSource()
);
entries.initialize(getter, /* setter = */ null);
entries.setType(
KotlinTypeFactory.simpleType(TypeAttributes.Companion.getEmpty(),
enumEntriesClass.getTypeConstructor(),
Collections.singletonList(new TypeProjectionImpl(enumClass.getDefaultType())),
/* isNullable = */ false),
Collections.<TypeParameterDescriptor>emptyList(), null, null,
Collections.<ReceiverParameterDescriptor>emptyList())
;
getter.initialize(entries.getReturnType());
return entries;
}
public static boolean isEnumValuesMethod(@NotNull FunctionDescriptor descriptor) {
return descriptor.getName().equals(ENUM_VALUES) && isEnumSpecialMethod(descriptor);
}
@@ -70,6 +70,9 @@ fun MemberScope.computeAllNames() = getClassifierNames()?.let { classifierNames
inline fun MemberScope.findFirstFunction(name: String, predicate: (CallableMemberDescriptor) -> Boolean) =
getContributedFunctions(Name.identifier(name), NoLookupLocation.FROM_BACKEND).first(predicate)
inline fun MemberScope.findFirstVariable(name: String, predicate: (CallableMemberDescriptor) -> Boolean) =
getContributedVariables(Name.identifier(name), NoLookupLocation.FROM_BACKEND).firstOrNull(predicate)
fun Iterable<MemberScope>.flatMapClassifierNamesOrNull(): MutableSet<Name>? =
flatMapToNullable(hashSetOf(), MemberScope::getClassifierNames)
@@ -18,11 +18,11 @@ package org.jetbrains.kotlin.resolve.scopes
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor
import org.jetbrains.kotlin.incremental.components.LookupLocation
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.DescriptorFactory.createEnumValueOfMethod
import org.jetbrains.kotlin.resolve.DescriptorFactory.createEnumValuesMethod
import org.jetbrains.kotlin.resolve.DescriptorFactory.*
import org.jetbrains.kotlin.storage.StorageManager
import org.jetbrains.kotlin.storage.getValue
import org.jetbrains.kotlin.utils.Printer
@@ -30,8 +30,9 @@ import org.jetbrains.kotlin.utils.SmartList
// We don't need to track lookups here since this scope used only for introduce special Enum class members
class StaticScopeForKotlinEnum(
storageManager: StorageManager,
private val containingClass: ClassDescriptor
storageManager: StorageManager,
private val containingClass: ClassDescriptor,
private val supportEnumEntries: Boolean
) : MemberScopeImpl() {
init {
assert(containingClass.kind == ClassKind.ENUM_CLASS) { "Class should be an enum: $containingClass" }
@@ -43,11 +44,18 @@ class StaticScopeForKotlinEnum(
listOf(createEnumValueOfMethod(containingClass), createEnumValuesMethod(containingClass))
}
override fun getContributedDescriptors(kindFilter: DescriptorKindFilter, nameFilter: (Name) -> Boolean) = functions
private val properties: List<PropertyDescriptor> by storageManager.createLazyValue {
if (supportEnumEntries) listOfNotNull(createEnumEntriesProperty(containingClass)) else emptyList()
}
override fun getContributedDescriptors(kindFilter: DescriptorKindFilter, nameFilter: (Name) -> Boolean) = functions + properties
override fun getContributedFunctions(name: Name, location: LookupLocation) =
functions.filterTo(SmartList()) { it.name == name }
override fun getContributedVariables(name: Name, location: LookupLocation): Collection<PropertyDescriptor> =
properties.filterTo(SmartList()) { it.name == name }
override fun printScopeStructure(p: Printer) {
p.println("Static scope for $containingClass")
}
@@ -36,5 +36,8 @@ interface DeserializationConfiguration {
val preserveDeclarationsOrdering: Boolean
get() = false
val supportEnumEntries: Boolean
get() = false
object Default : DeserializationConfiguration
}
@@ -52,7 +52,12 @@ class DeserializedClassDescriptor(
VersionRequirementTable.create(classProto.versionRequirementTable), metadataVersion
)
private val staticScope = if (kind == ClassKind.ENUM_CLASS) StaticScopeForKotlinEnum(c.storageManager, this) else MemberScope.Empty
private val staticScope =
if (kind == ClassKind.ENUM_CLASS)
StaticScopeForKotlinEnum(c.storageManager, this, c.components.configuration.supportEnumEntries)
else
MemberScope.Empty
private val typeConstructor = DeserializedClassTypeConstructor()
private val memberScopeHolder =