Drop enum class object hack

Place valueOf() and values() into the static scope of the corresponding enum
class

 #KT-5580 Fixed
 #KT-2410 Fixed
This commit is contained in:
Alexander Udalov
2014-09-05 13:39:33 +04:00
parent bb54825fac
commit b52f337f7f
43 changed files with 299 additions and 352 deletions
@@ -39,7 +39,6 @@ import org.jetbrains.jet.lang.descriptors.annotations.Annotations
import java.util.ArrayList
import org.jetbrains.jet.lang.types.checker.JetTypeChecker
import org.jetbrains.jet.lang.types.AbstractClassTypeConstructor
import org.jetbrains.jet.lang.descriptors.impl.EnumClassObjectDescriptor
class LazyJavaClassDescriptor(
private val outerC: LazyJavaResolverContextWithTypes,
@@ -88,14 +87,7 @@ class LazyJavaClassDescriptor(
override fun getUnsubstitutedPrimaryConstructor(): ConstructorDescriptor? = null
private val _classObjectDescriptor = c.storageManager.createNullableLazyValue {
if (jClass.isEnum()) {
EnumClassObjectDescriptor(c.storageManager, this)
}
else null
}
override fun getClassObjectDescriptor(): ClassDescriptor? = _classObjectDescriptor()
override fun getClassObjectDescriptor(): ClassDescriptor? = null
override fun getClassObjectType(): JetType? = getClassObjectDescriptor()?.let { d -> d.getDefaultType() }
override fun getConstructors() = _scopeForMemberLookup._constructors()
@@ -87,6 +87,8 @@ public class LazyJavaClassMemberScope(
c.errorReporter))
}
override fun computeAdditionalFunctions(name: Name) = listOf<SimpleFunctionDescriptor>()
private fun getPropertiesFromSupertypes(name: Name, descriptor: ClassDescriptor): Set<PropertyDescriptor> {
return descriptor.getTypeConstructor().getSupertypes().flatMap {
it.getMemberScope().getProperties(name).map { p -> p as PropertyDescriptor }
@@ -38,7 +38,6 @@ import org.jetbrains.jet.lang.resolve.java.lazy.hasMutableAnnotation
import org.jetbrains.jet.lang.resolve.java.lazy.hasReadOnlyAnnotation
import org.jetbrains.jet.lang.resolve.java.structure.JavaValueParameter
import java.util.ArrayList
import org.jetbrains.jet.lang.resolve.java.resolver.DescriptorResolverUtils
import java.util.LinkedHashSet
import org.jetbrains.jet.lang.types.JetType
import org.jetbrains.jet.lang.resolve.java.descriptor.JavaPropertyDescriptor
@@ -72,23 +71,25 @@ public abstract class LazyJavaMemberScope(
protected abstract fun getExpectedThisObject(): ReceiverParameterDescriptor?
protected abstract fun computeAdditionalFunctions(name: Name): Collection<SimpleFunctionDescriptor>
private val _functions = c.storageManager.createMemoizedFunction {
(name: Name): Collection<FunctionDescriptor>
->
(name: Name): Collection<FunctionDescriptor> ->
val methods = memberIndex().findMethodsByName(name)
val functions = LinkedHashSet<SimpleFunctionDescriptor>(
methods.stream()
// values() and valueOf() are added manually, see LazyJavaClassDescriptor::getClassObjectDescriptor()
.filter{ m -> !DescriptorResolverUtils.shouldBeInEnumClassObject(m) }
.flatMap {
m ->
val function = resolveMethodToFunctionDescriptor(m, true)
val samAdapter = resolveSamAdapter(function)
if (samAdapter != null)
listOf(function, samAdapter).stream()
else
listOf(function).stream()
}.toList())
.flatMap {
m ->
val function = resolveMethodToFunctionDescriptor(m, true)
val samAdapter = resolveSamAdapter(function)
if (samAdapter != null)
listOf(function, samAdapter).stream()
else
listOf(function).stream()
}
.plus(computeAdditionalFunctions(name))
.toList()
)
computeNonDeclaredFunctions(functions, name)
@@ -36,6 +36,7 @@ import org.jetbrains.jet.lang.resolve.java.lazy.descriptors.LazyJavaMemberScope.
import org.jetbrains.jet.lang.resolve.java.descriptor.SamConstructorDescriptor
import org.jetbrains.jet.lang.resolve.name.SpecialNames
import org.jetbrains.jet.lang.resolve.kotlin.KotlinJvmBinaryClass
import org.jetbrains.jet.lang.resolve.DescriptorFactory.*
public abstract class LazyJavaStaticScope(
c: LazyJavaResolverContext,
@@ -131,6 +132,8 @@ public class LazyPackageFragmentScopeForJavaPackage(
override fun computeMemberIndex(): MemberIndex = computeMemberIndexForSamConstructors(EMPTY_MEMBER_INDEX)
override fun computeAdditionalFunctions(name: Name) = listOf<SimpleFunctionDescriptor>()
override fun getAllClassNames(): Collection<Name> {
return jPackage.getClasses().stream()
.filter { c -> c.getOriginKind() != JavaClass.OriginKind.KOTLIN_LIGHT_CLASS }
@@ -165,6 +168,21 @@ public class LazyJavaStaticClassScope(
override fun computeMemberIndex(): MemberIndex = computeMemberIndexForSamConstructors(ClassMemberIndex(jClass, { m -> m.isStatic() }))
override fun getAllFunctionNames(): Collection<Name> {
if (jClass.isEnum()) {
return super.getAllFunctionNames() + listOf(Name.identifier("valueOf"), Name.identifier("values"))
}
return super.getAllFunctionNames()
}
override fun computeAdditionalFunctions(name: Name): Collection<SimpleFunctionDescriptor> {
if (jClass.isEnum()) {
if (name.asString() == "valueOf") return listOf(createEnumValueOfMethod(getContainingDeclaration()))
if (name.asString() == "values") return listOf(createEnumValuesMethod(getContainingDeclaration()))
}
return listOf()
}
override fun getAllClassNames(): Collection<Name> = listOf()
override fun getClassifier(name: Name): ClassifierDescriptor? = null
@@ -87,23 +87,6 @@ public final class DescriptorResolverUtils {
return null;
}
/**
* @return true if {@code method} is a static method of enum class, which is to be put into its class object (and not into the
* corresponding package). This applies to values() and valueOf(String) methods
*/
public static boolean shouldBeInEnumClassObject(@NotNull JavaMethod method) {
if (!method.getContainingClass().isEnum()) return false;
String name = method.getName().asString();
if (name.equals("values")) {
return method.getValueParameters().isEmpty();
}
else if (name.equals("valueOf")) {
return isMethodWithOneParameterWithFqName(method, "java.lang.String");
}
return false;
}
public static boolean isObjectMethodInInterface(@NotNull JavaMember member) {
return member.getContainingClass().isInterface() && member instanceof JavaMethod && isObjectMethod((JavaMethod) member);
}
@@ -1,140 +0,0 @@
/*
* Copyright 2010-2014 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.jet.lang.descriptors.impl
import org.jetbrains.jet.storage.StorageManager
import org.jetbrains.jet.lang.descriptors.*
import org.jetbrains.jet.lang.descriptors.CallableMemberDescriptor.Kind.SYNTHESIZED
import org.jetbrains.jet.lang.descriptors.annotations.Annotations
import org.jetbrains.jet.lang.resolve.name.SpecialNames
import org.jetbrains.jet.lang.resolve.scopes.JetScope
import org.jetbrains.jet.lang.resolve.DescriptorUtils
import org.jetbrains.jet.lang.resolve.DescriptorFactory
import org.jetbrains.jet.lang.types.TypeConstructor
import org.jetbrains.jet.lang.types.TypeConstructorImpl
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns
import org.jetbrains.jet.lang.resolve.OverridingUtil
import org.jetbrains.jet.lang.types.DelegatingType
import org.jetbrains.jet.lang.types.JetType
import org.jetbrains.jet.lang.resolve.name.Name
import org.jetbrains.jet.lang.resolve.scopes.JetScopeImpl
import org.jetbrains.jet.utils.Printer
import java.util.ArrayList
import kotlin.properties.Delegates
import org.jetbrains.jet.lang.resolve.scopes.StaticScopeForKotlinClass
public class EnumClassObjectDescriptor(
storageManager: StorageManager,
enumClass: ClassDescriptor
) : ClassDescriptorBase(storageManager, enumClass, SpecialNames.getClassObjectName(enumClass.getName()), SourceElement.NO_SOURCE) {
private val primaryConstructor = DescriptorFactory.createPrimaryConstructorForObject(this, SourceElement.NO_SOURCE)
;{
primaryConstructor.setReturnType(object : DelegatingType() {
override fun getDelegate() = getDefaultType()
})
}
private val _typeConstructor = TypeConstructorImpl.createForClass(this, getAnnotations(), true, getName().asString(),
listOf(), listOf(KotlinBuiltIns.getInstance().getAnyType()))
private val scope = EnumClassObjectScope()
private val staticScope = StaticScopeForKotlinClass(this)
override fun getScopeForMemberLookup(): JetScope = scope
override fun getStaticScope(): JetScope = staticScope
override fun getClassObjectDescriptor(): ClassDescriptor? = null
override fun getConstructors(): List<ConstructorDescriptor> = listOf(primaryConstructor)
override fun getUnsubstitutedPrimaryConstructor(): ConstructorDescriptor = primaryConstructor
override fun getTypeConstructor(): TypeConstructor = _typeConstructor
override fun getKind(): ClassKind = ClassKind.CLASS_OBJECT
override fun getModality(): Modality = Modality.FINAL
override fun getVisibility(): Visibility = DescriptorUtils.getSyntheticClassObjectVisibility()
override fun isInner(): Boolean = false
override fun getAnnotations(): Annotations = Annotations.EMPTY
private inner class EnumClassObjectScope : JetScopeImpl() {
private val enumClassObject: EnumClassObjectDescriptor
get() = this@EnumClassObjectDescriptor
private val functions: List<FunctionDescriptor> by Delegates.lazy {
val result = ArrayList<FunctionDescriptor>(5)
val enumType = object : DelegatingType() {
override fun getDelegate() = (enumClassObject.getContainingDeclaration() as ClassDescriptor).getDefaultType()
}
result.add(createEnumClassObjectValuesMethod(enumType))
result.add(createEnumClassObjectValueOfMethod(enumType))
val sink = object : OverridingUtil.DescriptorSink {
override fun addToScope(fakeOverride: CallableMemberDescriptor) {
OverridingUtil.resolveUnknownVisibilityForMember(fakeOverride, null)
result.add(fakeOverride as FunctionDescriptor)
}
override fun conflict(fromSuper: CallableMemberDescriptor, fromCurrent: CallableMemberDescriptor) {
throw IllegalStateException("Conflict on enum class object override: $fromSuper vs $fromCurrent")
}
}
val superScope = KotlinBuiltIns.getInstance().getAnyType().getMemberScope()
for (descriptor in superScope.getAllDescriptors()) {
if (descriptor is FunctionDescriptor) {
val name = descriptor.getName()
OverridingUtil.generateOverridesInFunctionGroup(name, superScope.getFunctions(name), setOf(), enumClassObject, sink)
}
}
result
}
private fun createEnumClassObjectValuesMethod(enumType: JetType): SimpleFunctionDescriptor {
val enumArrayType = KotlinBuiltIns.getInstance().getArrayType(enumType)
val values = SimpleFunctionDescriptorImpl.create(enumClassObject, Annotations.EMPTY, Name.identifier("values"), SYNTHESIZED, SourceElement.NO_SOURCE)
return values.initialize(null, getThisAsReceiverParameter(), listOf(), listOf(), enumArrayType, Modality.FINAL, Visibilities.PUBLIC)
}
private fun createEnumClassObjectValueOfMethod(enumType: JetType): SimpleFunctionDescriptor {
val values = SimpleFunctionDescriptorImpl.create(enumClassObject, Annotations.EMPTY, Name.identifier("valueOf"), SYNTHESIZED, SourceElement.NO_SOURCE)
val parameter = ValueParameterDescriptorImpl(values, null, 0, Annotations.EMPTY, Name.identifier("value"),
KotlinBuiltIns.getInstance().getStringType(), false, null, SourceElement.NO_SOURCE)
return values.initialize(null, getThisAsReceiverParameter(), listOf(), listOf(parameter), enumType, Modality.FINAL, Visibilities.PUBLIC)
}
override fun getFunctions(name: Name) = functions.filter { it.getName() == name }
override fun getAllDescriptors() = functions
override fun printScopeStructure(p: Printer) {
p.println("enum class object scope for $enumClassObject")
}
override fun getContainingDeclaration(): ClassDescriptor = enumClassObject
}
}
@@ -20,12 +20,11 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.descriptors.annotations.Annotations;
import org.jetbrains.jet.lang.descriptors.impl.ConstructorDescriptorImpl;
import org.jetbrains.jet.lang.descriptors.impl.PropertyGetterDescriptorImpl;
import org.jetbrains.jet.lang.descriptors.impl.PropertySetterDescriptorImpl;
import org.jetbrains.jet.lang.descriptors.impl.ReceiverParameterDescriptorImpl;
import org.jetbrains.jet.lang.descriptors.impl.*;
import org.jetbrains.jet.lang.resolve.name.Name;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ExtensionReceiver;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
import java.util.Collections;
@@ -83,6 +82,31 @@ public class DescriptorFactory {
return constructor instanceof DefaultConstructorDescriptor;
}
@NotNull
public static SimpleFunctionDescriptor createEnumValuesMethod(@NotNull ClassDescriptor enumClass) {
SimpleFunctionDescriptorImpl values =
SimpleFunctionDescriptorImpl.create(enumClass, Annotations.EMPTY, Name.identifier("values"),
CallableMemberDescriptor.Kind.SYNTHESIZED, SourceElement.NO_SOURCE);
return values.initialize(null, NO_RECEIVER_PARAMETER, Collections.<TypeParameterDescriptor>emptyList(),
Collections.<ValueParameterDescriptor>emptyList(),
KotlinBuiltIns.getInstance().getArrayType(enumClass.getDefaultType()), Modality.FINAL,
Visibilities.PUBLIC);
}
@NotNull
public static SimpleFunctionDescriptor createEnumValueOfMethod(@NotNull ClassDescriptor enumClass) {
SimpleFunctionDescriptorImpl valueOf =
SimpleFunctionDescriptorImpl.create(enumClass, Annotations.EMPTY, Name.identifier("valueOf"),
CallableMemberDescriptor.Kind.SYNTHESIZED, SourceElement.NO_SOURCE);
ValueParameterDescriptor parameterDescriptor = new ValueParameterDescriptorImpl(
valueOf, null, 0, Annotations.EMPTY, Name.identifier("value"), KotlinBuiltIns.getInstance().getStringType(), false, null,
SourceElement.NO_SOURCE
);
return valueOf.initialize(null, NO_RECEIVER_PARAMETER, Collections.<TypeParameterDescriptor>emptyList(),
Collections.singletonList(parameterDescriptor), enumClass.getDefaultType(), Modality.FINAL,
Visibilities.PUBLIC);
}
@Nullable
public static ReceiverParameterDescriptor createReceiverParameterForCallable(
@NotNull CallableDescriptor owner,
@@ -299,13 +299,7 @@ public class DescriptorUtils {
}
public static boolean isSyntheticClassObject(@NotNull DeclarationDescriptor descriptor) {
if (isClassObject(descriptor)) {
DeclarationDescriptor containing = descriptor.getContainingDeclaration();
if (containing != null) {
return isEnumClass(containing) || isObject(containing) || isEnumEntry(containing);
}
}
return false;
return isClassObject(descriptor) && isSingleton(descriptor.getContainingDeclaration());
}
@NotNull
@@ -16,21 +16,16 @@
package org.jetbrains.jet.lang.resolve.descriptorUtil
import org.jetbrains.jet.lang.descriptors.ClassDescriptor
import org.jetbrains.jet.lang.descriptors.ClassKind.ENUM_ENTRY
import org.jetbrains.jet.lang.descriptors.ClassKind.ENUM_CLASS
import org.jetbrains.jet.lang.descriptors.ClassKind.OBJECT
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor
import org.jetbrains.jet.lang.descriptors.ConstructorDescriptor
import org.jetbrains.jet.lang.descriptors.*
import org.jetbrains.jet.lang.resolve.DescriptorUtils
import org.jetbrains.jet.lang.descriptors.ClassKind.*
public fun ClassDescriptor.getClassObjectReferenceTarget(): ClassDescriptor {
val classObjectDescriptor = getClassObjectDescriptor()
return if (classObjectDescriptor == null || hasSyntheticClassObject()) this else classObjectDescriptor
}
public fun ClassDescriptor.hasSyntheticClassObject(): Boolean = getKind() in setOf(ENUM_ENTRY, ENUM_CLASS, OBJECT)
public fun ClassDescriptor.hasSyntheticClassObject(): Boolean = getKind() in setOf(ENUM_ENTRY, OBJECT)
public fun DeclarationDescriptor.getImportableDescriptor(): DeclarationDescriptor =
if (this is ConstructorDescriptor || DescriptorUtils.isClassObject(this)) getContainingDeclaration()!! else this
@@ -19,20 +19,33 @@ package org.jetbrains.jet.lang.resolve.scopes
import org.jetbrains.jet.lang.resolve.name.Name
import org.jetbrains.jet.lang.descriptors.*
import org.jetbrains.jet.utils.Printer
import java.util.ArrayList
import kotlin.properties.Delegates
import org.jetbrains.jet.lang.resolve.DescriptorFactory.*
public class StaticScopeForKotlinClass(
private val containingClass: ClassDescriptor
) : JetScope {
override fun getClassifier(name: Name) = null // TODO
override fun getAllDescriptors() = listOf<DeclarationDescriptor>() // TODO
private val functions: List<FunctionDescriptor> by Delegates.lazy {
if (containingClass.getKind() != ClassKind.ENUM_CLASS) {
listOf<FunctionDescriptor>()
}
else {
listOf(createEnumValueOfMethod(containingClass), createEnumValuesMethod(containingClass))
}
}
override fun getOwnDeclaredDescriptors() = listOf<DeclarationDescriptor>() // TODO
override fun getAllDescriptors() = functions
override fun getOwnDeclaredDescriptors() = functions
override fun getFunctions(name: Name) = functions.filterTo(ArrayList<FunctionDescriptor>(2)) { it.getName() == name }
override fun getPackage(name: Name) = null
override fun getProperties(name: Name) = listOf<VariableDescriptor>()
override fun getLocalVariable(name: Name) = null
override fun getFunctions(name: Name) = listOf<FunctionDescriptor>()
override fun getContainingDeclaration() = containingClass
override fun getDeclarationsByLabel(labelName: Name) = listOf<DeclarationDescriptor>()
override fun getImplicitReceiversHierarchy() = listOf<ReceiverParameterDescriptor>()
@@ -30,7 +30,6 @@ import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.descriptors.annotations.Annotations;
import org.jetbrains.jet.lang.descriptors.impl.AbstractClassDescriptor;
import org.jetbrains.jet.lang.descriptors.impl.ConstructorDescriptorImpl;
import org.jetbrains.jet.lang.descriptors.impl.EnumClassObjectDescriptor;
import org.jetbrains.jet.lang.descriptors.impl.EnumEntrySyntheticClassDescriptor;
import org.jetbrains.jet.lang.resolve.DescriptorFactory;
import org.jetbrains.jet.lang.resolve.OverridingUtil;
@@ -238,10 +237,6 @@ public class DeserializedClassDescriptor extends AbstractClassDescriptor impleme
return null;
}
if (getKind() == ClassKind.ENUM_CLASS) {
return new EnumClassObjectDescriptor(context.getStorageManager(), this);
}
if (getKind() == ClassKind.OBJECT) {
ProtoBuf.Class.ClassObject classObjectProto = classProto.getClassObject();
if (!classObjectProto.hasData()) {