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.
This commit is contained in:
+29
-3
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
+4
@@ -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;
|
||||
|
||||
+1
-6
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
+7
-1
@@ -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.<AnnotationDescriptor>emptyList(), Modality.FINAL, propertyName);
|
||||
dummyClassDescriptorForEnumEntryObject.initialize(
|
||||
|
||||
@@ -24,6 +24,3 @@ public trait CustomAnnotation : java.lang.Object {
|
||||
public constructor MyTest()
|
||||
}
|
||||
}
|
||||
|
||||
package CustomAnnotation {
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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() {
|
||||
|
||||
Reference in New Issue
Block a user