diff --git a/compiler/testData/loadJava/compiledJava/EnumMembers.java b/compiler/testData/loadJava/compiledJava/EnumMembers.java new file mode 100644 index 00000000000..b86089dc270 --- /dev/null +++ b/compiler/testData/loadJava/compiledJava/EnumMembers.java @@ -0,0 +1,16 @@ +package test; + +public enum EnumMembers { + FIRST(true), + SECOND(false); + + public final boolean isFirst; + + private EnumMembers(boolean isFirst) { + this.isFirst = isFirst; + } + + public boolean first() { + return isFirst; + } +} diff --git a/compiler/testData/loadJava/compiledJava/EnumMembers.txt b/compiler/testData/loadJava/compiledJava/EnumMembers.txt new file mode 100644 index 00000000000..2466f8af994 --- /dev/null +++ b/compiler/testData/loadJava/compiledJava/EnumMembers.txt @@ -0,0 +1,47 @@ +package test + +public final enum class EnumMembers : jet.Enum { + private constructor EnumMembers(/*0*/ p0: jet.Boolean) + public final val isFirst: jet.Boolean + public open fun first(): jet.Boolean + public final override /*1*/ /*fake_override*/ fun name(): jet.String + public final override /*1*/ /*fake_override*/ fun ordinal(): jet.Int + + public class object { + private constructor () + public final /*synthesized*/ fun valueOf(/*0*/ value: jet.String): test.EnumMembers + public final /*synthesized*/ fun values(): jet.Array + + public enum entry FIRST : test.EnumMembers { + private constructor FIRST() + public final override /*1*/ /*fake_override*/ val isFirst: jet.Boolean + public open override /*1*/ /*fake_override*/ fun first(): jet.Boolean + public final override /*1*/ /*fake_override*/ fun name(): jet.String + public final override /*1*/ /*fake_override*/ fun ordinal(): jet.Int + + public class object : test.EnumMembers.FIRST { + private constructor () + public final override /*1*/ /*fake_override*/ val isFirst: jet.Boolean + public open override /*1*/ /*fake_override*/ fun first(): jet.Boolean + public final override /*1*/ /*fake_override*/ fun name(): jet.String + public final override /*1*/ /*fake_override*/ fun ordinal(): jet.Int + } + } + + public enum entry SECOND : test.EnumMembers { + private constructor SECOND() + public final override /*1*/ /*fake_override*/ val isFirst: jet.Boolean + public open override /*1*/ /*fake_override*/ fun first(): jet.Boolean + public final override /*1*/ /*fake_override*/ fun name(): jet.String + public final override /*1*/ /*fake_override*/ fun ordinal(): jet.Int + + public class object : test.EnumMembers.SECOND { + private constructor () + public final override /*1*/ /*fake_override*/ val isFirst: jet.Boolean + public open override /*1*/ /*fake_override*/ fun first(): jet.Boolean + public final override /*1*/ /*fake_override*/ fun name(): jet.String + public final override /*1*/ /*fake_override*/ fun ordinal(): jet.Int + } + } + } +} diff --git a/compiler/testData/loadJava/compiledJava/JavaEnum.java b/compiler/testData/loadJava/compiledJava/JavaEnum.java index d2ebd2b676e..adb6794406c 100644 --- a/compiler/testData/loadJava/compiledJava/JavaEnum.java +++ b/compiler/testData/loadJava/compiledJava/JavaEnum.java @@ -1,6 +1,5 @@ package test; -//TODO: move to LoadJavaTestGenerated when possible public enum JavaEnum { ENTRY, ANOTHER; diff --git a/compiler/testData/loadJava/compiledJava/JavaEnum.txt b/compiler/testData/loadJava/compiledJava/JavaEnum.txt index 028b99dc84c..7989fac475e 100644 --- a/compiler/testData/loadJava/compiledJava/JavaEnum.txt +++ b/compiler/testData/loadJava/compiledJava/JavaEnum.txt @@ -7,9 +7,31 @@ public final enum class JavaEnum : jet.Enum { public class object { private constructor () - public final val ANOTHER: test.JavaEnum - public final val ENTRY: test.JavaEnum public final /*synthesized*/ fun valueOf(/*0*/ value: jet.String): test.JavaEnum public final /*synthesized*/ fun values(): jet.Array + + public enum entry ANOTHER : test.JavaEnum { + private constructor ANOTHER() + public final override /*1*/ /*fake_override*/ fun name(): jet.String + public final override /*1*/ /*fake_override*/ fun ordinal(): jet.Int + + public class object : test.JavaEnum.ANOTHER { + private constructor () + public final override /*1*/ /*fake_override*/ fun name(): jet.String + public final override /*1*/ /*fake_override*/ fun ordinal(): jet.Int + } + } + + public enum entry ENTRY : test.JavaEnum { + private constructor ENTRY() + public final override /*1*/ /*fake_override*/ fun name(): jet.String + public final override /*1*/ /*fake_override*/ fun ordinal(): jet.Int + + public class object : test.JavaEnum.ENTRY { + private constructor () + public final override /*1*/ /*fake_override*/ fun name(): jet.String + public final override /*1*/ /*fake_override*/ fun ordinal(): jet.Int + } + } } } diff --git a/compiler/testData/loadJava/compiledJava/annotations/CustomAnnotation.txt b/compiler/testData/loadJava/compiledJava/annotations/CustomAnnotation.txt index d77f1c33000..f4abf6329e5 100644 --- a/compiler/testData/loadJava/compiledJava/annotations/CustomAnnotation.txt +++ b/compiler/testData/loadJava/compiledJava/annotations/CustomAnnotation.txt @@ -14,9 +14,20 @@ public trait CustomAnnotation : java.lang.Object { public class object { private constructor () - public final val ONE: test.CustomAnnotation.MyEnum public final /*synthesized*/ fun valueOf(/*0*/ value: jet.String): test.CustomAnnotation.MyEnum public final /*synthesized*/ fun values(): jet.Array + + public enum entry ONE : test.CustomAnnotation.MyEnum { + private constructor ONE() + public final override /*1*/ /*fake_override*/ fun name(): jet.String + public final override /*1*/ /*fake_override*/ fun ordinal(): jet.Int + + public class object : test.CustomAnnotation.MyEnum.ONE { + private constructor () + public final override /*1*/ /*fake_override*/ fun name(): jet.String + public final override /*1*/ /*fake_override*/ fun ordinal(): jet.Int + } + } } } diff --git a/compiler/testData/loadJava/compiledJava/static/Enum.txt b/compiler/testData/loadJava/compiledJava/static/Enum.txt index 2895a565277..c0e78b4076a 100644 --- a/compiler/testData/loadJava/compiledJava/static/Enum.txt +++ b/compiler/testData/loadJava/compiledJava/static/Enum.txt @@ -7,11 +7,44 @@ public final enum class Enum : jet.Enum { public class object { private constructor () - public final val A: test.Enum - public final val B: test.Enum - public final val C: test.Enum public final /*synthesized*/ fun valueOf(/*0*/ value: jet.String): test.Enum public final /*synthesized*/ fun values(): jet.Array + + public enum entry A : test.Enum { + private constructor A() + public final override /*1*/ /*fake_override*/ fun name(): jet.String + public final override /*1*/ /*fake_override*/ fun ordinal(): jet.Int + + public class object : test.Enum.A { + private constructor () + public final override /*1*/ /*fake_override*/ fun name(): jet.String + public final override /*1*/ /*fake_override*/ fun ordinal(): jet.Int + } + } + + public enum entry B : test.Enum { + private constructor B() + public final override /*1*/ /*fake_override*/ fun name(): jet.String + public final override /*1*/ /*fake_override*/ fun ordinal(): jet.Int + + public class object : test.Enum.B { + private constructor () + public final override /*1*/ /*fake_override*/ fun name(): jet.String + public final override /*1*/ /*fake_override*/ fun ordinal(): jet.Int + } + } + + public enum entry C : test.Enum { + private constructor C() + public final override /*1*/ /*fake_override*/ fun name(): jet.String + public final override /*1*/ /*fake_override*/ fun ordinal(): jet.Int + + public class object : test.Enum.C { + private constructor () + public final override /*1*/ /*fake_override*/ fun name(): jet.String + public final override /*1*/ /*fake_override*/ fun ordinal(): jet.Int + } + } } public open inner class Inner : java.lang.Object { diff --git a/compiler/testData/loadJava/compiledJava/static/StaticMembersInEnum.txt b/compiler/testData/loadJava/compiledJava/static/StaticMembersInEnum.txt index e8738b2689a..6a2bf22085f 100644 --- a/compiler/testData/loadJava/compiledJava/static/StaticMembersInEnum.txt +++ b/compiler/testData/loadJava/compiledJava/static/StaticMembersInEnum.txt @@ -7,9 +7,20 @@ public final enum class StaticMembersInEnum : jet.Enum public class object { private constructor () - public final val ENTRY: test.StaticMembersInEnum public final /*synthesized*/ fun valueOf(/*0*/ value: jet.String): test.StaticMembersInEnum public final /*synthesized*/ fun values(): jet.Array + + public enum entry ENTRY : test.StaticMembersInEnum { + private constructor ENTRY() + public final override /*1*/ /*fake_override*/ fun name(): jet.String + public final override /*1*/ /*fake_override*/ fun ordinal(): jet.Int + + public class object : test.StaticMembersInEnum.ENTRY { + private constructor () + public final override /*1*/ /*fake_override*/ fun name(): jet.String + public final override /*1*/ /*fake_override*/ fun ordinal(): jet.Int + } + } } } diff --git a/compiler/tests/org/jetbrains/jet/jvm/compiler/LoadJavaTestGenerated.java b/compiler/tests/org/jetbrains/jet/jvm/compiler/LoadJavaTestGenerated.java index 9bfc6455977..ddd3d99e896 100644 --- a/compiler/tests/org/jetbrains/jet/jvm/compiler/LoadJavaTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/jvm/compiler/LoadJavaTestGenerated.java @@ -1034,6 +1034,11 @@ public class LoadJavaTestGenerated extends AbstractLoadJavaTest { JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.GenerateTests", new File("compiler/testData/loadJava/compiledJava"), Pattern.compile("^(.+)\\.java$"), true); } + @TestMetadata("EnumMembers.java") + public void testEnumMembers() throws Exception { + doTestCompiledJava("compiler/testData/loadJava/compiledJava/EnumMembers.java"); + } + @TestMetadata("JavaEnum.java") public void testJavaEnum() throws Exception { doTestCompiledJava("compiler/testData/loadJava/compiledJava/JavaEnum.java"); diff --git a/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/java/descriptor/JavaPropertyDescriptorForObject.java b/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/java/descriptor/JavaPropertyDescriptorForObject.java deleted file mode 100644 index d0b3e4807be..00000000000 --- a/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/java/descriptor/JavaPropertyDescriptorForObject.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2010-2013 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.resolve.java.descriptor; - -import org.jetbrains.annotations.NotNull; -import org.jetbrains.jet.lang.descriptors.ClassDescriptor; -import org.jetbrains.jet.lang.descriptors.ClassOrNamespaceDescriptor; -import org.jetbrains.jet.lang.descriptors.Visibility; -import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor; -import org.jetbrains.jet.lang.descriptors.impl.PropertyDescriptorForObjectImpl; -import org.jetbrains.jet.lang.resolve.name.Name; - -import java.util.List; - -public class JavaPropertyDescriptorForObject extends PropertyDescriptorForObjectImpl implements JavaCallableMemberDescriptor { - public JavaPropertyDescriptorForObject( - @NotNull ClassOrNamespaceDescriptor containingDeclaration, - @NotNull List annotations, - @NotNull Visibility visibility, - @NotNull Name name, - @NotNull ClassDescriptor objectClass - ) { - super(containingDeclaration, annotations, visibility, name, objectClass); - } -} diff --git a/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/java/resolver/JavaPropertyResolver.java b/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/java/resolver/JavaPropertyResolver.java index 4aaae995288..39df71a2103 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/java/resolver/JavaPropertyResolver.java +++ b/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/java/resolver/JavaPropertyResolver.java @@ -18,22 +18,19 @@ package org.jetbrains.jet.lang.resolve.java.resolver; import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.lang.descriptors.*; -import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor; -import org.jetbrains.jet.lang.descriptors.impl.ClassDescriptorImpl; import org.jetbrains.jet.lang.descriptors.impl.PropertyDescriptorImpl; import org.jetbrains.jet.lang.resolve.DescriptorUtils; import org.jetbrains.jet.lang.resolve.java.descriptor.JavaPropertyDescriptor; -import org.jetbrains.jet.lang.resolve.java.descriptor.JavaPropertyDescriptorForObject; import org.jetbrains.jet.lang.resolve.java.scope.NamedMembers; import org.jetbrains.jet.lang.resolve.java.structure.JavaField; import org.jetbrains.jet.lang.resolve.name.Name; -import org.jetbrains.jet.lang.resolve.scopes.JetScope; import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.lang.types.TypeUtils; import javax.inject.Inject; import java.util.*; +import static org.jetbrains.jet.lang.resolve.DescriptorUtils.isEnumClassObject; import static org.jetbrains.jet.lang.resolve.java.resolver.DescriptorResolverUtils.resolveOverrides; public final class JavaPropertyResolver { @@ -70,6 +67,10 @@ public final class JavaPropertyResolver { @NotNull public Set resolveFieldGroup(@NotNull NamedMembers members, @NotNull ClassOrNamespaceDescriptor owner) { + if (isEnumClassObject(owner)) { + return Collections.emptySet(); + } + Name propertyName = members.getName(); List fields = members.getFields(); @@ -100,9 +101,12 @@ public final class JavaPropertyResolver { @NotNull private PropertyDescriptor resolveProperty(@NotNull ClassOrNamespaceDescriptor owner, @NotNull Name name, @NotNull JavaField field) { + assert !field.isEnumEntry() : "Enum entries are resolved into classes, not into properties: " + name; + boolean isVar = !field.isFinal(); - PropertyDescriptorImpl propertyDescriptor = createPropertyDescriptor(owner, name, field, isVar); + PropertyDescriptorImpl propertyDescriptor = + new JavaPropertyDescriptor(owner, annotationResolver.resolveAnnotations(field), field.getVisibility(), isVar, name); propertyDescriptor.initialize(null, null); TypeVariableResolver typeVariableResolver = @@ -129,31 +133,6 @@ public final class JavaPropertyResolver { return propertyDescriptor; } - @NotNull - private PropertyDescriptorImpl createPropertyDescriptor( - @NotNull ClassOrNamespaceDescriptor owner, - @NotNull Name propertyName, - @NotNull JavaField field, - boolean isVar - ) { - List annotations = annotationResolver.resolveAnnotations(field); - Visibility visibility = field.getVisibility(); - - if (field.isEnumEntry()) { - assert !isVar : "Enum entries should be immutable."; - assert DescriptorUtils.isEnumClassObject(owner) : "Enum entries should be put into class object of enum only: " + owner; - //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 - ClassDescriptorImpl dummyClassDescriptorForEnumEntryObject = - new ClassDescriptorImpl(owner, propertyName, Modality.FINAL, Collections.emptyList()); - dummyClassDescriptorForEnumEntryObject.initialize(JetScope.EMPTY, Collections.emptySet(), null); - return new JavaPropertyDescriptorForObject(owner, annotations, visibility, propertyName, - dummyClassDescriptorForEnumEntryObject); - } - - return new JavaPropertyDescriptor(owner, annotations, visibility, isVar, propertyName); - } - @NotNull private JetType getPropertyType(@NotNull JavaField field, @NotNull TypeVariableResolver typeVariableResolver) { JetType propertyType = typeTransformer.transformToType(field.getType(), typeVariableResolver); diff --git a/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/java/scope/JavaBaseScope.java b/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/java/scope/JavaBaseScope.java index 4bcb3c4b8ee..4e3cf6975bf 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/java/scope/JavaBaseScope.java +++ b/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/java/scope/JavaBaseScope.java @@ -39,8 +39,6 @@ public abstract class JavaBaseScope extends JetScopeImpl { private final Map> propertyDescriptors = new HashMap>(); @Nullable private Collection allDescriptors = null; - @Nullable - private Set objectDescriptors = null; @NotNull protected final ClassOrNamespaceDescriptor descriptor; @@ -125,17 +123,14 @@ public abstract class JavaBaseScope extends JetScopeImpl { protected Collection computeAllDescriptors() { Collection result = new HashSet(); result.addAll(computeFieldAndFunctionDescriptors()); - result.addAll(filterObjects(getInnerClasses(), false)); + result.addAll(getInnerClasses()); return result; } @NotNull @Override public Set getObjectDescriptors() { - if (objectDescriptors == null) { - objectDescriptors = new HashSet(filterObjects(getInnerClasses(), true)); - } - return objectDescriptors; + return Collections.emptySet(); } @NotNull @@ -162,17 +157,6 @@ public abstract class JavaBaseScope extends JetScopeImpl { return innerClasses; } - @NotNull - private static Collection filterObjects(@NotNull Collection classes, boolean objects) { - List result = new ArrayList(); - for (ClassDescriptor descriptor : classes) { - if (descriptor.getKind().isSingleton() == objects) { - result.add(descriptor); - } - } - return result; - } - @TestOnly @Override public void printScopeStructure(@NotNull Printer p) { diff --git a/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/java/scope/JavaClassMembersScope.java b/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/java/scope/JavaClassMembersScope.java index a3006eec599..be5a50fc7c9 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/java/scope/JavaClassMembersScope.java +++ b/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/java/scope/JavaClassMembersScope.java @@ -52,8 +52,13 @@ public abstract class JavaClassMembersScope extends JavaBaseScope { return memberResolver.resolveFunctionGroupForClass(members, descriptor); } - @NotNull - private Map getInnerClassesMap() { + @Override + public ClassDescriptor getObjectDescriptor(@NotNull Name name) { + return null; + } + + @Override + public ClassifierDescriptor getClassifier(@NotNull Name name) { if (innerClassesMap == null) { Collection innerClasses = getInnerClasses(); innerClassesMap = new HashMap(); @@ -61,24 +66,6 @@ public abstract class JavaClassMembersScope extends JavaBaseScope { innerClassesMap.put(innerClass.getName(), innerClass); } } - return innerClassesMap; - } - - @Override - public ClassDescriptor getObjectDescriptor(@NotNull Name name) { - ClassDescriptor innerClass = getInnerClassesMap().get(name); - if (innerClass != null && innerClass.getKind().isSingleton()) { - return innerClass; - } - return null; - } - - @Override - public ClassifierDescriptor getClassifier(@NotNull Name name) { - ClassDescriptor innerClass = getInnerClassesMap().get(name); - if (innerClass == null || innerClass.getKind().isSingleton()) { - return null; - } - return innerClass; + return innerClassesMap.get(name); } } diff --git a/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/java/scope/JavaEnumClassObjectScope.java b/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/java/scope/JavaEnumClassObjectScope.java index e4b3869930b..2476d369f4a 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/java/scope/JavaEnumClassObjectScope.java +++ b/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/java/scope/JavaEnumClassObjectScope.java @@ -16,14 +16,24 @@ package org.jetbrains.jet.lang.resolve.java.scope; +import jet.Function0; +import jet.Function1; +import kotlin.KotlinPackage; import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.lang.descriptors.ClassDescriptor; import org.jetbrains.jet.lang.descriptors.ClassOrNamespaceDescriptor; +import org.jetbrains.jet.lang.descriptors.impl.EnumEntrySyntheticClassDescriptor; import org.jetbrains.jet.lang.resolve.java.resolver.JavaMemberResolver; import org.jetbrains.jet.lang.resolve.java.structure.JavaClass; +import org.jetbrains.jet.lang.resolve.java.structure.JavaField; +import org.jetbrains.jet.lang.resolve.name.Name; +import org.jetbrains.jet.storage.LockBasedStorageManager; +import org.jetbrains.jet.storage.NotNullLazyValue; +import org.jetbrains.jet.storage.StorageManager; +import java.util.ArrayList; import java.util.Collection; -import java.util.Collections; +import java.util.List; public class JavaEnumClassObjectScope extends JavaClassMembersScope { public JavaEnumClassObjectScope( @@ -37,6 +47,34 @@ public class JavaEnumClassObjectScope extends JavaClassMembersScope { @NotNull @Override protected Collection computeInnerClasses() { - return Collections.emptyList(); + List result = new ArrayList(); + + final Collection enumNonStaticMembers = membersProvider.allMembers(); + + NotNullLazyValue> enumMemberNames = + LockBasedStorageManager.NO_LOCKS.createLazyValue(new Function0>() { + @Override + public Collection invoke() { + return KotlinPackage.map(enumNonStaticMembers, new Function1() { + @Override + public Name invoke(@NotNull NamedMembers members) { + return members.getName(); + } + }); + } + }); + + for (NamedMembers members : enumNonStaticMembers) { + for (JavaField field : members.getFields()) { + if (field.isEnumEntry()) { + EnumEntrySyntheticClassDescriptor enumEntry = EnumEntrySyntheticClassDescriptor + .create(LockBasedStorageManager.NO_LOCKS, (ClassDescriptor) descriptor, members.getName(), enumMemberNames); + result.add(enumEntry); + break; + } + } + } + + return result; } } diff --git a/core/descriptors/src/org/jetbrains/jet/lang/descriptors/impl/EnumEntrySyntheticClassDescriptor.java b/core/descriptors/src/org/jetbrains/jet/lang/descriptors/impl/EnumEntrySyntheticClassDescriptor.java new file mode 100644 index 00000000000..c43b611d392 --- /dev/null +++ b/core/descriptors/src/org/jetbrains/jet/lang/descriptors/impl/EnumEntrySyntheticClassDescriptor.java @@ -0,0 +1,271 @@ +/* + * Copyright 2010-2013 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 jet.Function0; +import jet.Function1; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.jet.lang.descriptors.*; +import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor; +import org.jetbrains.jet.lang.resolve.DescriptorFactory; +import org.jetbrains.jet.lang.resolve.OverridingUtil; +import org.jetbrains.jet.lang.resolve.name.Name; +import org.jetbrains.jet.lang.resolve.name.SpecialNames; +import org.jetbrains.jet.lang.resolve.scopes.JetScope; +import org.jetbrains.jet.lang.resolve.scopes.JetScopeImpl; +import org.jetbrains.jet.lang.types.JetType; +import org.jetbrains.jet.lang.types.TypeConstructor; +import org.jetbrains.jet.lang.types.TypeConstructorImpl; +import org.jetbrains.jet.storage.MemoizedFunctionToNotNull; +import org.jetbrains.jet.storage.NotNullLazyValue; +import org.jetbrains.jet.storage.StorageManager; +import org.jetbrains.jet.utils.Printer; + +import java.util.*; + +public class EnumEntrySyntheticClassDescriptor extends ClassDescriptorBase { + private final ClassKind kind; + private final TypeConstructor typeConstructor; + private final ConstructorDescriptor primaryConstructor; + private final JetScope scope; + private final EnumEntrySyntheticClassDescriptor classObjectDescriptor; + private final NotNullLazyValue> enumMemberNames; + + /** + * Creates and initializes descriptors for enum entry with the given name and its class object + * @param enumMemberNames needed for fake overrides resolution + */ + @NotNull + public static EnumEntrySyntheticClassDescriptor create( + @NotNull StorageManager storageManager, + @NotNull ClassDescriptor enumClassObject, + @NotNull Name name, + @NotNull NotNullLazyValue> enumMemberNames + ) { + JetType enumType = ((ClassDescriptor) enumClassObject.getContainingDeclaration()).getDefaultType(); + + return new EnumEntrySyntheticClassDescriptor(storageManager, enumClassObject, enumType, name, ClassKind.ENUM_ENTRY, + enumMemberNames); + } + + private EnumEntrySyntheticClassDescriptor( + @NotNull StorageManager storageManager, + @NotNull ClassDescriptor containingClass, + @NotNull JetType supertype, + @NotNull Name name, + @NotNull ClassKind kind, + @NotNull NotNullLazyValue> enumMemberNames + ) { + super(storageManager, containingClass, name); + this.kind = kind; + + this.typeConstructor = + new TypeConstructorImpl(this, getAnnotations(), true, "enum entry", Collections.emptyList(), + Collections.singleton(supertype)); + + this.scope = new EnumEntryScope(storageManager); + this.enumMemberNames = enumMemberNames; + + ConstructorDescriptorImpl primaryConstructor = DescriptorFactory.createPrimaryConstructorForObject(this); + primaryConstructor.setReturnType(getDefaultType()); + this.primaryConstructor = primaryConstructor; + + this.classObjectDescriptor = + kind == ClassKind.CLASS_OBJECT + ? null + : new EnumEntrySyntheticClassDescriptor(storageManager, this, getDefaultType(), SpecialNames.getClassObjectName(name), + ClassKind.CLASS_OBJECT, enumMemberNames); + } + + @NotNull + @Override + protected JetScope getScopeForMemberLookup() { + return scope; + } + + @NotNull + @Override + public Collection getConstructors() { + return Collections.singleton(primaryConstructor); + } + + @NotNull + @Override + public TypeConstructor getTypeConstructor() { + return typeConstructor; + } + + @Nullable + @Override + public ClassDescriptor getClassObjectDescriptor() { + return classObjectDescriptor; + } + + @NotNull + @Override + public ClassKind getKind() { + return kind; + } + + @NotNull + @Override + public Modality getModality() { + return Modality.FINAL; + } + + @NotNull + @Override + public Visibility getVisibility() { + return Visibilities.PUBLIC; + } + + @Override + public boolean isInner() { + return false; + } + + @Nullable + @Override + public ConstructorDescriptor getUnsubstitutedPrimaryConstructor() { + return primaryConstructor; + } + + @NotNull + @Override + public List getAnnotations() { + // TODO + return Collections.emptyList(); + } + + private class EnumEntryScope extends JetScopeImpl { + private final MemoizedFunctionToNotNull> functions; + private final MemoizedFunctionToNotNull> properties; + private final NotNullLazyValue> allDescriptors; + + public EnumEntryScope(@NotNull StorageManager storageManager) { + this.functions = storageManager.createMemoizedFunction(new Function1>() { + @Override + public Collection invoke(Name name) { + return computeFunctions(name); + } + }); + this.properties = storageManager.createMemoizedFunction(new Function1>() { + @Override + public Collection invoke(Name name) { + return computeProperties(name); + } + }); + this.allDescriptors = storageManager.createLazyValue(new Function0>() { + @Override + public Collection invoke() { + return computeAllDeclarations(); + } + }); + } + + @NotNull + @Override + @SuppressWarnings("unchecked") + public Collection getProperties(@NotNull Name name) { + return (Collection) properties.invoke(name); + } + + @NotNull + @SuppressWarnings("unchecked") + private Collection computeProperties(@NotNull Name name) { + return resolveFakeOverrides(name, (Collection) getSupertypeScope().getProperties(name)); + } + + @NotNull + @Override + public Collection getFunctions(@NotNull Name name) { + return functions.invoke(name); + } + + @NotNull + private Collection computeFunctions(@NotNull Name name) { + return resolveFakeOverrides(name, getSupertypeScope().getFunctions(name)); + } + + @NotNull + private JetScope getSupertypeScope() { + Collection supertype = getTypeConstructor().getSupertypes(); + assert supertype.size() == 1 : "Enum entry and its class object both should have exactly one supertype: " + supertype; + return supertype.iterator().next().getMemberScope(); + } + + @NotNull + private Collection resolveFakeOverrides( + @NotNull Name name, + @NotNull Collection fromSupertypes + ) { + final Set result = new HashSet(); + + OverridingUtil.generateOverridesInFunctionGroup( + name, fromSupertypes, Collections.emptySet(), EnumEntrySyntheticClassDescriptor.this, + new OverridingUtil.DescriptorSink() { + @Override + @SuppressWarnings("unchecked") + public void addToScope(@NotNull CallableMemberDescriptor fakeOverride) { + OverridingUtil.resolveUnknownVisibilityForMember(fakeOverride, new OverridingUtil.NotInferredVisibilitySink() { + @Override + public void cannotInferVisibility(@NotNull CallableMemberDescriptor descriptor) { + // Do nothing + } + }); + result.add((D) fakeOverride); + } + + @Override + public void conflict(@NotNull CallableMemberDescriptor fromSuper, @NotNull CallableMemberDescriptor fromCurrent) { + // Do nothing + } + } + ); + + return result; + } + + @NotNull + @Override + public DeclarationDescriptor getContainingDeclaration() { + return EnumEntrySyntheticClassDescriptor.this; + } + + @NotNull + @Override + public Collection getAllDescriptors() { + return allDescriptors.invoke(); + } + + @NotNull + private Collection computeAllDeclarations() { + Collection result = new HashSet(); + for (Name name : enumMemberNames.invoke()) { + result.addAll(getFunctions(name)); + result.addAll(getProperties(name)); + } + return result; + } + + @Override + public void printScopeStructure(@NotNull Printer p) { + p.println("enum entry scope for " + EnumEntrySyntheticClassDescriptor.this); + } + } +}