diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/DescriptorResolverUtils.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/DescriptorResolverUtils.java index eb7a79acdf3..0e907bc8a67 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/DescriptorResolverUtils.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/DescriptorResolverUtils.java @@ -16,9 +16,8 @@ package org.jetbrains.jet.lang.resolve.java; -import com.intellij.psi.PsiClass; -import com.intellij.psi.PsiModifier; -import com.intellij.psi.PsiModifierListOwner; +import com.intellij.psi.*; +import com.intellij.psi.util.PsiFormatUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.*; @@ -37,7 +36,9 @@ import java.util.Collection; import java.util.Collections; import java.util.List; +import static com.intellij.psi.util.PsiFormatUtilBase.*; import static org.jetbrains.jet.lang.resolve.DescriptorUtils.getClassObjectName; +import static org.jetbrains.jet.lang.resolve.DescriptorUtils.isEnumClassObject; public final class DescriptorResolverUtils { public static final FqName OBJECT_FQ_NAME = new FqName("java.lang.Object"); @@ -148,4 +149,29 @@ public final class DescriptorResolverUtils { annotationDescriptor.setValueArgument(value, new StringValue("Deprecated in Java")); return annotationDescriptor; } + + /** + * @return true if {@code member} is a static member of enum class, which is to be put into its class object (and not into the + * corresponding package). This applies to enum entries, values() and valueOf(String) methods + */ + public static boolean shouldBeInEnumClassObject(@NotNull PsiMember member) { + PsiClass psiClass = member.getContainingClass(); + if (psiClass == null || !psiClass.isEnum()) return false; + + if (member instanceof PsiEnumConstant) return true; + + if (!(member instanceof PsiMethod)) return false; + String signature = PsiFormatUtil.formatMethod((PsiMethod) member, + PsiSubstitutor.EMPTY, SHOW_NAME | SHOW_PARAMETERS, SHOW_TYPE | SHOW_FQ_CLASS_NAMES); + + return "values()".equals(signature) || + "valueOf(java.lang.String)".equals(signature); + } + + public static boolean isCorrectOwnerForEnumMember( + @NotNull ClassOrNamespaceDescriptor ownerDescriptor, + @NotNull PsiMember member + ) { + return isEnumClassObject(ownerDescriptor) == shouldBeInEnumClassObject(member); + } } diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/resolver/JavaFunctionResolver.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/resolver/JavaFunctionResolver.java index 1bdedd22b37..5912a57ed03 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/resolver/JavaFunctionResolver.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/resolver/JavaFunctionResolver.java @@ -94,6 +94,10 @@ public final class JavaFunctionResolver { @NotNull PsiClass psiClass, PsiMethodWrapper method, @NotNull PsiDeclarationProvider scopeData, @NotNull ClassOrNamespaceDescriptor ownerDescriptor ) { + if (!DescriptorResolverUtils.isCorrectOwnerForEnumMember(ownerDescriptor, method.getPsiMember())) { + return null; + } + PsiType returnPsiType = method.getReturnType(); if (returnPsiType == null) { return null; diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/resolver/JavaNamespaceResolver.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/resolver/JavaNamespaceResolver.java index a064c1a70bd..d8b3794a54c 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/resolver/JavaNamespaceResolver.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/resolver/JavaNamespaceResolver.java @@ -168,11 +168,6 @@ public final class JavaNamespaceResolver { if (psiClass == null) { return null; } - if (psiClass.isEnum()) { - // NOTE: we don't want to create namespace for enum classes because we put - // static members of enum class into class object descriptor - return null; - } if (DescriptorResolverUtils.isKotlinClass(psiClass)) { return null; } @@ -219,7 +214,7 @@ public final class JavaNamespaceResolver { private static boolean hasStaticMembers(@NotNull PsiClass psiClass) { for (PsiMember member : ContainerUtil.concat(psiClass.getMethods(), psiClass.getFields())) { - if (member.hasModifierProperty(PsiModifier.STATIC)) { + if (member.hasModifierProperty(PsiModifier.STATIC) && !DescriptorResolverUtils.shouldBeInEnumClassObject(member)) { return true; } } diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/resolver/JavaPropertyResolver.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/resolver/JavaPropertyResolver.java index d03280f96f3..0a22af77cea 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/resolver/JavaPropertyResolver.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/resolver/JavaPropertyResolver.java @@ -17,6 +17,7 @@ package org.jetbrains.jet.lang.resolve.java.resolver; import com.google.common.collect.Sets; +import com.intellij.psi.PsiEnumConstant; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.*; @@ -114,6 +115,10 @@ public final class JavaPropertyResolver { continue; } + if (!DescriptorResolverUtils.isCorrectOwnerForEnumMember(ownerDescriptor, propertyPsiData.getCharacteristicPsi())) { + continue; + } + propertiesFromCurrent.add(resolveProperty(ownerDescriptor, scopeData, propertyName, context, propertyPsiData)); } @@ -181,7 +186,7 @@ public final class JavaPropertyResolver { kind = DescriptorKindUtils.flagsToKind(methodAnnotation.kind()); } - boolean isEnumEntry = DescriptorUtils.isEnumClassObject(owner); + boolean isEnumEntry = psiData.getCharacteristicPsi() instanceof PsiEnumConstant; PropertyDescriptorImpl propertyDescriptor = new PropertyDescriptorImpl( owner, annotationResolver.resolveAnnotations(psiData.getCharacteristicPsi()), @@ -196,6 +201,7 @@ public final class JavaPropertyResolver { // class descriptor for enum entries is not used by backends so for now this should be safe to use // remove this when JavaDescriptorResolver gets rewritten if (isEnumEntry) { + assert DescriptorUtils.isEnumClassObject(owner) : "Enum entries should be put into class object of enum only: " + owner; ClassDescriptorImpl dummyClassDescriptorForEnumEntryObject = new ClassDescriptorImpl(owner, Collections.emptyList(), Modality.FINAL, propertyName); dummyClassDescriptorForEnumEntryObject.initialize( diff --git a/compiler/testData/loadJava/compiledJava/annotations/CustomAnnotation.txt b/compiler/testData/loadJava/compiledJava/annotations/CustomAnnotation.txt index dd91e4eac62..9f53dd51cd5 100644 --- a/compiler/testData/loadJava/compiledJava/annotations/CustomAnnotation.txt +++ b/compiler/testData/loadJava/compiledJava/annotations/CustomAnnotation.txt @@ -24,6 +24,3 @@ public trait CustomAnnotation : java.lang.Object { public constructor MyTest() } } - -package CustomAnnotation { -} diff --git a/compiler/testData/loadJava/compiledJava/static/StaticMembersInEnum.java b/compiler/testData/loadJava/compiledJava/static/StaticMembersInEnum.java new file mode 100644 index 00000000000..f10f2256b94 --- /dev/null +++ b/compiler/testData/loadJava/compiledJava/static/StaticMembersInEnum.java @@ -0,0 +1,12 @@ +package test; + +public enum StaticMembersInEnum { + ENTRY; + + public static void foo() { } + public static void values(int x) { } + public static void valueOf(int x) { } + + public static int STATIC_FIELD = 42; + public static final StaticMembersInEnum CONSTANT = ENTRY; +} diff --git a/compiler/testData/loadJava/compiledJava/static/StaticMembersInEnum.txt b/compiler/testData/loadJava/compiledJava/static/StaticMembersInEnum.txt new file mode 100644 index 00000000000..0e87d4436a4 --- /dev/null +++ b/compiler/testData/loadJava/compiledJava/static/StaticMembersInEnum.txt @@ -0,0 +1,22 @@ +package test + +public final enum class StaticMembersInEnum : jet.Enum { + private constructor StaticMembersInEnum() + 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 val ENTRY : test.StaticMembersInEnum + public final fun valueOf(/*0*/ value : jet.String) : test.StaticMembersInEnum + public final fun values() : jet.Array + } +} + +package StaticMembersInEnum { + public val CONSTANT : test.StaticMembersInEnum + public var STATIC_FIELD : jet.Int + public open fun foo() : Unit + public open fun valueOf(/*0*/ p0 : jet.Int) : Unit + public open fun values(/*0*/ p0 : jet.Int) : Unit +} diff --git a/compiler/tests/org/jetbrains/jet/jvm/compiler/LoadJavaTestGenerated.java b/compiler/tests/org/jetbrains/jet/jvm/compiler/LoadJavaTestGenerated.java index 98b0db83cf8..84ef06611da 100644 --- a/compiler/tests/org/jetbrains/jet/jvm/compiler/LoadJavaTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/jvm/compiler/LoadJavaTestGenerated.java @@ -1155,6 +1155,11 @@ public class LoadJavaTestGenerated extends AbstractLoadJavaTest { doTestCompiledJava("compiler/testData/loadJava/compiledJava/static/StaticFinal.java"); } + @TestMetadata("StaticMembersInEnum.java") + public void testStaticMembersInEnum() throws Exception { + doTestCompiledJava("compiler/testData/loadJava/compiledJava/static/StaticMembersInEnum.java"); + } + } public static Test innerSuite() {