Support enums in Java code

This commit is contained in:
Andrey Breslav
2013-11-07 17:51:04 +04:00
parent 6ff2d68206
commit b1c4665246
4 changed files with 99 additions and 51 deletions
@@ -28,6 +28,12 @@ import org.jetbrains.jet.lang.resolve.java.structure.JavaMethod
import org.jetbrains.jet.lang.descriptors.SimpleFunctionDescriptor
import org.jetbrains.jet.lang.types.TypeUtils
import org.jetbrains.jet.lang.resolve.java.descriptor.JavaClassDescriptor
import org.jetbrains.kotlin.util.iif
import org.jetbrains.jet.lang.resolve.java.descriptor.JavaEnumClassObjectDescriptor
import org.jetbrains.jet.lang.descriptors.Modality
import org.jetbrains.jet.lang.resolve.scopes.WritableScopeImpl
import org.jetbrains.jet.lang.resolve.scopes.RedeclarationHandler
import org.jetbrains.jet.lang.resolve.scopes.WritableScope
class LazyJavaClassDescriptor(
private val c: LazyJavaResolverContextWithTypes,
@@ -62,12 +68,31 @@ class LazyJavaClassDescriptor(
override fun getUnsubstitutedPrimaryConstructor(): ConstructorDescriptor? = null
private val _classObjectDescriptor = c.storageManager.createNullableLazyValue {
if (jClass.isEnum()) {
val classObject = JavaEnumClassObjectDescriptor(this)
classObject.setModality(Modality.FINAL)
classObject.setVisibility(jClass.getVisibility())
classObject.setTypeParameterDescriptors(Collections.emptyList<TypeParameterDescriptor>())
classObject.createTypeConstructor()
val scope = LazyJavaClassMemberScope(innerC, classObject, jClass, enumClassObject = true)
val writableScope = WritableScopeImpl(scope, classObject, RedeclarationHandler.THROW_EXCEPTION, "Enum class object scope")
writableScope.changeLockLevel(WritableScope.LockLevel.BOTH)
classObject.setScopeForMemberLookup(writableScope)
JavaClassResolver.createEnumSyntheticMethods(classObject, this.getDefaultType())
classObject
}
else null
}
override fun getClassObjectDescriptor(): ClassDescriptor? = _classObjectDescriptor()
override fun getClassObjectType(): JetType? = getClassObjectDescriptor()?.let { d -> d.getDefaultType() }
override fun getConstructors() = _scopeForMemberLookup._constructors()
override fun getClassObjectType(): JetType? = null
override fun getClassObjectDescriptor(): ClassDescriptor? = null
private val _annotations = c.storageManager.createLazyValue { c.resolveAnnotations(jClass.getAnnotations()) }
override fun getAnnotations(): List<AnnotationDescriptor> = _annotations()
@@ -17,49 +17,38 @@
package org.jetbrains.jet.lang.resolve.java.lazy.descriptors
import org.jetbrains.jet.lang.descriptors.*
import org.jetbrains.jet.storage.NotNullLazyValue
import org.jetbrains.jet.lang.resolve.name.LabelName
import org.jetbrains.jet.lang.resolve.name.Name
import org.jetbrains.jet.lang.resolve.scopes.JetScope
import org.jetbrains.jet.utils.emptyList
import org.jetbrains.jet.lang.resolve.java.structure.JavaClass
import org.jetbrains.jet.lang.resolve.java.structure.JavaMethod
import org.jetbrains.jet.lang.resolve.java.structure.JavaField
import org.jetbrains.jet.lang.resolve.java.lazy.LazyJavaResolverContextWithTypes
import org.jetbrains.jet.lang.resolve.java.descriptor.JavaMethodDescriptor
import org.jetbrains.jet.lang.resolve.DescriptorUtils
import org.jetbrains.jet.lang.resolve.java.lazy.child
import org.jetbrains.jet.lang.descriptors.impl.ValueParameterDescriptorImpl
import org.jetbrains.jet.lang.resolve.java.lazy.resolveAnnotations
import org.jetbrains.jet.lang.resolve.java.structure.JavaArrayType
import org.jetbrains.jet.lang.resolve.java.resolver.TypeUsage
import org.jetbrains.jet.lang.types.TypeUtils
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns
import org.jetbrains.jet.lang.resolve.java.lazy.hasNotNullAnnotation
import org.jetbrains.jet.lang.resolve.java.lazy.types.LazyJavaTypeAttributes
import org.jetbrains.jet.lang.resolve.java.lazy.hasMutableAnnotation
import org.jetbrains.kotlin.util.iif
import org.jetbrains.jet.lang.resolve.java.lazy.hasReadOnlyAnnotation
import org.jetbrains.jet.utils.valuesToMap
import org.jetbrains.jet.lang.resolve.java.structure.JavaValueParameter
import org.jetbrains.jet.lang.descriptors.impl.ConstructorDescriptorImpl
import java.util.Collections
import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor
import org.jetbrains.jet.lang.resolve.java.resolver.JavaConstructorResolver
import org.jetbrains.jet.utils.*
import java.util.ArrayList
import org.jetbrains.jet.lang.resolve.java.lazy.types.toAttributes
import org.jetbrains.jet.lang.types.JetType
import org.jetbrains.jet.lang.resolve.java.resolver.DescriptorResolverUtils
import org.jetbrains.jet.lang.resolve.java.structure.JavaMember
import org.jetbrains.jet.lang.resolve.DescriptorUtils
import org.jetbrains.jet.lang.descriptors.impl.EnumEntrySyntheticClassDescriptor
import org.jetbrains.jet.storage.get
public class LazyJavaClassMemberScope(
c: LazyJavaResolverContextWithTypes,
containingDeclaration: LazyJavaClassDescriptor,
private val jClass: JavaClass
containingDeclaration: ClassDescriptor,
private val jClass: JavaClass,
private val enumClassObject: Boolean = false
) : LazyJavaMemberScope(c, containingDeclaration) {
override fun computeMemberIndex(): MemberIndex = object : ClassMemberIndex(jClass, { m -> !m.isStatic() }) {
// For SAM-constructors
override fun getAllMetodNames(): Collection<Name> = super.getAllMetodNames() + getAllClassNames()
override fun computeMemberIndex(): MemberIndex {
return object : ClassMemberIndex(jClass, { !enumClassObject && !it.isStatic() }) {
// For SAM-constructors
override fun getAllMetodNames(): Collection<Name> = super.getAllMetodNames() + getAllClassNames()
}
}
internal val _constructors = c.storageManager.createLazyValue {
@@ -165,10 +154,10 @@ public class LazyJavaClassMemberScope(
if (jNestedClass == null)
null
else
LazyJavaClassDescriptor(c, getContainingDeclaration(), getContainingDeclaration().fqName.child(name), jNestedClass)
LazyJavaClassDescriptor(c, getContainingDeclaration(), jNestedClass.getFqName()!!, jNestedClass)
}
override fun getClassifier(name: Name): ClassifierDescriptor? = nestedClasses(name)
override fun getClassifier(name: Name): ClassifierDescriptor? = if (enumClassObject) null else nestedClasses(name)
override fun getAllClassNames(): Collection<Name> = nestedClassIndex().keySet()
override fun addExtraDescriptors(result: MutableCollection<in DeclarationDescriptor>) {
@@ -179,8 +168,8 @@ public class LazyJavaClassMemberScope(
override fun getImplicitReceiversHierarchy(): List<ReceiverParameterDescriptor> = listOf()
override fun getContainingDeclaration(): LazyJavaClassDescriptor {
return super.getContainingDeclaration() as LazyJavaClassDescriptor
override fun getContainingDeclaration(): ClassDescriptor {
return super.getContainingDeclaration() as ClassDescriptor
}
// namespaces should be resolved elsewhere
@@ -41,6 +41,8 @@ import org.jetbrains.annotations.TestOnly
import org.jetbrains.jet.utils.Printer
import org.jetbrains.jet.lang.resolve.java.resolver.ExternalSignatureResolver
import org.jetbrains.jet.lang.resolve.java.sam.SingleAbstractMethodUtils
import org.jetbrains.jet.lang.resolve.java.descriptor.JavaPropertyDescriptorForObject
import org.jetbrains.jet.lang.descriptors.impl.ClassDescriptorImpl
public abstract class LazyJavaMemberScope(
protected val c: LazyJavaResolverContextWithTypes,
@@ -67,15 +69,19 @@ public abstract class LazyJavaMemberScope(
(name: Name): Collection<FunctionDescriptor>
->
val methods = memberIndex().findMethodsByName(name)
val functions = LinkedHashSet(methods.flatMap {
m ->
val function = resolveMethodToFunctionDescriptor(m, true)
val samAdapter = JavaFunctionResolver.resolveSamAdapter(function)
if (samAdapter != null)
listOf(function, samAdapter)
else
listOf(function)
})
val functions = LinkedHashSet(
methods.iterator()
// values() and valueOf() are added manually, see LazyJavaClassDescriptor::getClassObjectDescriptor()
.filter{ m -> !DescriptorResolverUtils.shouldBeInEnumClassObject(m) }
.flatMap {
m ->
val function = resolveMethodToFunctionDescriptor(m, true)
val samAdapter = JavaFunctionResolver.resolveSamAdapter(function)
if (samAdapter != null)
listOf(function, samAdapter).iterator()
else
listOf(function).iterator()
}.toList())
if (_containingDeclaration is NamespaceDescriptor) {
val klass = JavaFunctionResolver.findClassInNamespace(_containingDeclaration, name);
@@ -211,7 +217,9 @@ public abstract class LazyJavaMemberScope(
val field = memberIndex().findFieldByName(name)
if (field != null) {
properties.add(resolveProperty(field))
if (DescriptorResolverUtils.shouldBeInEnumClassObject(field) == DescriptorUtils.isEnumClassObject(_containingDeclaration)) {
properties.add(resolveProperty(field))
}
}
if (_containingDeclaration is ClassDescriptor) {
@@ -227,13 +235,7 @@ public abstract class LazyJavaMemberScope(
private fun resolveProperty(field: JavaField): PropertyDescriptor {
val isVar = !field.isFinal()
val propertyDescriptor = JavaPropertyDescriptor(
getContainingDeclaration(),
c.resolveAnnotations(field.getAnnotations()),
field.getVisibility(),
isVar,
field.getName()
)
val propertyDescriptor = createPropertyDescriptor(field)
propertyDescriptor.initialize(null, null)
val propertyType = getPropertyType(field)
@@ -250,6 +252,38 @@ public abstract class LazyJavaMemberScope(
return propertyDescriptor
}
private fun createPropertyDescriptor(field: JavaField): PropertyDescriptorImpl {
val isVar = !field.isFinal()
val visibility = field.getVisibility()
val annotations = c.resolveAnnotations(field.getAnnotations())
val propertyName = field.getName()
if (field.isEnumEntry()) {
assert(!isVar, "Enum entries should be immutable.")
assert(DescriptorUtils.isEnumClassObject(_containingDeclaration), "Enum entries should be put into class object of enum only: " + _containingDeclaration)
//TODO: this is a hack to indicate that this enum entry is an object
// class descriptor for enum entries is not used by backends so for now this should be safe to use
val dummyClassDescriptorForEnumEntryObject = ClassDescriptorImpl(_containingDeclaration, Collections.emptyList(), Modality.FINAL, propertyName)
dummyClassDescriptorForEnumEntryObject.initialize(
true,
Collections.emptyList(),
Collections.emptyList(),
JetScope.EMPTY,
Collections.emptySet(),
null,
false)
return JavaPropertyDescriptorForObject(
_containingDeclaration as ClassDescriptor,
annotations,
visibility,
propertyName,
dummyClassDescriptorForEnumEntryObject
)
}
return JavaPropertyDescriptor(_containingDeclaration, annotations, visibility, isVar, propertyName)
}
private fun getPropertyType(field: JavaField): JetType {
// Fields do not have their own generic parameters
val propertyType = c.typeResolver.transformJavaType(field.getType(), LazyJavaTypeAttributes(c, field, TypeUsage.MEMBER_SIGNATURE_INVARIANT))
@@ -305,7 +305,7 @@ public final class JavaClassResolver {
}
@NotNull
private static FqNameUnsafe getFqNameForClassObject(@NotNull JavaClass javaClass) {
public static FqNameUnsafe getFqNameForClassObject(@NotNull JavaClass javaClass) {
FqName fqName = javaClass.getFqName();
assert fqName != null : "Reading java class with no qualified name";
return fqName.toUnsafe().child(getClassObjectName(javaClass.getName()));
@@ -414,7 +414,7 @@ public final class JavaClassResolver {
return javaClass.getOuterClass() != null && !javaClass.isStatic();
}
private static void createEnumSyntheticMethods(@NotNull JavaEnumClassObjectDescriptor classObject, @NotNull JetType enumType) {
public static void createEnumSyntheticMethods(@NotNull JavaEnumClassObjectDescriptor classObject, @NotNull JetType enumType) {
JetType valuesReturnType = KotlinBuiltIns.getInstance().getArrayType(enumType);
SimpleFunctionDescriptor valuesMethod = DescriptorFactory.createEnumClassObjectValuesMethod(classObject, valuesReturnType);
classObject.getBuilder().addFunctionDescriptor(valuesMethod);