From 7368ca09b98336fa122c9b8f12db842c61b53785 Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Thu, 14 Mar 2013 18:52:14 +0400 Subject: [PATCH] Resolve static enum members from compiled Java For static members, a corresponding package is now created for every enum, as it's done for every other class. All static members of enum classes are resolved into the package, EXCEPT its enum entries, valueOf() and values() methods, which are put into the enum's class descriptor. --- .../resolve/java/DescriptorResolverUtils.java | 32 +++++++++++++++++-- .../java/resolver/JavaFunctionResolver.java | 4 +++ .../java/resolver/JavaNamespaceResolver.java | 7 +--- .../java/resolver/JavaPropertyResolver.java | 8 ++++- .../annotations/CustomAnnotation.txt | 3 -- .../static/StaticMembersInEnum.java | 12 +++++++ .../static/StaticMembersInEnum.txt | 22 +++++++++++++ .../jvm/compiler/LoadJavaTestGenerated.java | 5 +++ 8 files changed, 80 insertions(+), 13 deletions(-) create mode 100644 compiler/testData/loadJava/compiledJava/static/StaticMembersInEnum.java create mode 100644 compiler/testData/loadJava/compiledJava/static/StaticMembersInEnum.txt 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() {