Skip to content

Commit

Permalink
Resolve static enum members from compiled Java
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
udalov committed Mar 15, 2013
1 parent 6884413 commit 7368ca0
Show file tree
Hide file tree
Showing 8 changed files with 80 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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.*;
Expand All @@ -37,7 +36,9 @@
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");
Expand Down Expand Up @@ -148,4 +149,29 @@ public static AnnotationDescriptor getAnnotationDescriptorForJavaLangDeprecated(
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);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,10 @@ private SimpleFunctionDescriptor resolveMethodToFunctionDescriptor(
@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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -168,11 +168,6 @@ private JavaBaseScope doCreateNamespaceScope(
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;
}
Expand Down Expand Up @@ -219,7 +214,7 @@ private PsiClass getPsiClassForJavaPackageScope(@NotNull FqName packageFQN) {

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;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.*;
Expand Down Expand Up @@ -114,6 +115,10 @@ private Set<VariableDescriptor> resolveNamedGroupProperties(
continue;
}

if (!DescriptorResolverUtils.isCorrectOwnerForEnumMember(ownerDescriptor, propertyPsiData.getCharacteristicPsi())) {
continue;
}

propertiesFromCurrent.add(resolveProperty(ownerDescriptor, scopeData, propertyName, context, propertyPsiData));
}

Expand Down Expand Up @@ -181,7 +186,7 @@ private PropertyDescriptor resolveProperty(
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()),
Expand All @@ -196,6 +201,7 @@ private PropertyDescriptor resolveProperty(
// 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.<AnnotationDescriptor>emptyList(), Modality.FINAL, propertyName);
dummyClassDescriptorForEnumEntryObject.initialize(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,3 @@ public trait CustomAnnotation : java.lang.Object {
public constructor MyTest()
}
}

package CustomAnnotation {
}
Original file line number Diff line number Diff line change
@@ -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;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package test

public final enum class StaticMembersInEnum : jet.Enum<test.StaticMembersInEnum> {
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 <class-object-for-StaticMembersInEnum> {
private constructor <class-object-for-StaticMembersInEnum>()
public final val ENTRY : test.StaticMembersInEnum
public final fun valueOf(/*0*/ value : jet.String) : test.StaticMembersInEnum
public final fun values() : jet.Array<test.StaticMembersInEnum>
}
}

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
}
Original file line number Diff line number Diff line change
Expand Up @@ -1155,6 +1155,11 @@ public void testStaticFinal() throws Exception {
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() {
Expand Down

0 comments on commit 7368ca0

Please sign in to comment.