IDEA-125900 (resolve of synthetic enum methods in class files fixed)

This commit is contained in:
Roman Shevchenko
2014-06-05 13:18:03 +04:00
parent bb35b2626c
commit 6396cd8927
6 changed files with 76 additions and 64 deletions
@@ -25,6 +25,7 @@ import com.intellij.pom.java.LanguageLevel;
import com.intellij.psi.*;
import com.intellij.psi.filters.OrFilter;
import com.intellij.psi.impl.compiled.ClsElementImpl;
import com.intellij.psi.impl.source.ClassInnerStuffCache;
import com.intellij.psi.impl.source.PsiImmediateClassType;
import com.intellij.psi.infos.MethodCandidateInfo;
import com.intellij.psi.scope.ElementClassFilter;
@@ -56,18 +57,15 @@ import java.util.*;
/**
* @author ik
* Date: 24.10.2003
* @since 24.10.2003
*/
public class PsiClassImplUtil {
private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.PsiClassImplUtil");
private static final Key<ParameterizedCachedValue<MembersMap, PsiClass>> MAP_IN_CLASS_KEY = Key.create("MAP_KEY");
private static final String VALUES_METHOD = "values";
private static final String VALUE_OF_METHOD = "valueOf";
private PsiClassImplUtil() {
}
public static void cacheEverything(PsiClass aClass) {
getValues(aClass).getValue(aClass);
}
private PsiClassImplUtil() { }
@NotNull
public static PsiField[] getAllFields(@NotNull PsiClass aClass) {
@@ -126,7 +124,7 @@ public class PsiClassImplUtil {
for (final PsiMethod method : methodsByName) {
final PsiClass superClass = method.getContainingClass();
final PsiSubstitutor substitutor;
if (checkBases && !aClass.equals(superClass)) {
if (checkBases && !aClass.equals(superClass) && superClass != null) {
substitutor = TypeConversionUtil.getSuperClassSubstitutor(superClass, aClass, PsiSubstitutor.EMPTY);
}
else {
@@ -425,6 +423,25 @@ public class PsiClassImplUtil {
}
}
public static boolean processDeclarationsInEnum(@NotNull PsiScopeProcessor processor,
@NotNull ResolveState state,
@NotNull ClassInnerStuffCache innerStuffCache) {
ElementClassHint classHint = processor.getHint(ElementClassHint.KEY);
if (classHint == null || classHint.shouldProcess(ElementClassHint.DeclarationKind.METHOD)) {
NameHint nameHint = processor.getHint(NameHint.KEY);
if ((nameHint == null || VALUES_METHOD.equals(nameHint.getName(state)))) {
PsiMethod method = innerStuffCache.getValuesMethod();
if (method != null && !processor.execute(method, ResolveState.initial())) return false;
}
if ((nameHint == null || VALUE_OF_METHOD.equals(nameHint.getName(state)))) {
PsiMethod method = innerStuffCache.getValueOfMethod();
if (method != null && !processor.execute(method, ResolveState.initial())) return false;
}
}
return true;
}
public static boolean processDeclarationsInClass(@NotNull PsiClass aClass,
@NotNull final PsiScopeProcessor processor,
@NotNull ResolveState state,
@@ -560,7 +577,7 @@ public class PsiClassImplUtil {
if (candidateMethod.isConstructor() != ((MethodResolverProcessor)processor).isConstructor()) continue;
}
final PsiClass containingClass = candidateMethod.getContainingClass();
if (visited != null && visited.contains(candidateMethod.getContainingClass())) {
if (containingClass == null || visited != null && visited.contains(containingClass)) {
continue;
}
@@ -448,6 +448,10 @@ public class ClsClassImpl extends ClsMemberImpl<PsiClassStub<?>> implements PsiE
@NotNull ResolveState state,
PsiElement lastParent,
@NotNull PsiElement place) {
if (isEnum()) {
if (!PsiClassImplUtil.processDeclarationsInEnum(processor, state, myInnersCache)) return false;
}
LanguageLevel level = processor instanceof MethodsProcessor ? ((MethodsProcessor)processor).getLanguageLevel() : PsiUtil.getLanguageLevel(place);
return PsiClassImplUtil.processDeclarationsInClass(this, processor, state, null, lastParent, place, level, false);
}
@@ -16,13 +16,11 @@
package com.intellij.psi.impl.source;
import com.intellij.openapi.util.SimpleModificationTracker;
import com.intellij.psi.ExternallyDefinedPsiElement;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiField;
import com.intellij.psi.PsiMethod;
import com.intellij.psi.*;
import com.intellij.psi.augment.PsiAugmentProvider;
import com.intellij.psi.impl.PsiClassImplUtil;
import com.intellij.psi.impl.PsiImplUtil;
import com.intellij.psi.impl.light.LightMethod;
import com.intellij.psi.util.CachedValueProvider;
import com.intellij.psi.util.CachedValuesManager;
import com.intellij.util.ArrayUtil;
@@ -139,6 +137,36 @@ public class ClassInnerStuffCache {
}
}
@Nullable
public PsiMethod getValuesMethod() {
return !myClass.isEnum() || myClass.getName() == null ? null : CachedValuesManager.getCachedValue(myClass, new CachedValueProvider<PsiMethod>() {
@Nullable
@Override
public Result<PsiMethod> compute() {
PsiElementFactory factory = JavaPsiFacade.getInstance(myClass.getProject()).getElementFactory();
String text = "public static " + myClass.getName() + "[] values() { }";
PsiMethod physicalMethod = factory.createMethodFromText(text, myClass);
PsiMethod method = new LightMethod(myClass.getManager(), physicalMethod, myClass);
return new Result<PsiMethod>(method, OUT_OF_CODE_BLOCK_MODIFICATION_COUNT, myTracker);
}
});
}
@Nullable
public PsiMethod getValueOfMethod() {
return !myClass.isEnum() || myClass.getName() == null ? null : CachedValuesManager.getCachedValue(myClass, new CachedValueProvider<PsiMethod>() {
@Nullable
@Override
public Result<PsiMethod> compute() {
PsiElementFactory factory = JavaPsiFacade.getInstance(myClass.getProject()).getElementFactory();
String text = "public static " + myClass.getName() + " valueOf(java.lang.String name) throws java.lang.IllegalArgumentException { }";
PsiMethod physicalMethod = factory.createMethodFromText(text, myClass);
PsiMethod method = new LightMethod(myClass.getManager(), physicalMethod, myClass);
return new Result<PsiMethod>(method, OUT_OF_CODE_BLOCK_MODIFICATION_COUNT, myTracker);
}
});
}
private PsiField[] getAllFields() {
List<PsiField> own = myClass.getOwnFields();
List<PsiField> ext = PsiAugmentProvider.collectAugments(myClass, PsiField.class);
@@ -23,17 +23,15 @@ import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.ui.Queryable;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.UserDataHolder;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.psi.*;
import com.intellij.psi.impl.*;
import com.intellij.psi.impl.java.stubs.JavaStubElementTypes;
import com.intellij.psi.impl.java.stubs.PsiClassStub;
import com.intellij.psi.impl.light.LightMethod;
import com.intellij.psi.impl.source.tree.ChildRole;
import com.intellij.psi.impl.source.tree.CompositeElement;
import com.intellij.psi.impl.source.tree.SharedImplUtil;
import com.intellij.psi.javadoc.PsiDocComment;
import com.intellij.psi.scope.ElementClassHint;
import com.intellij.psi.scope.NameHint;
import com.intellij.psi.scope.PsiScopeProcessor;
import com.intellij.psi.search.SearchScope;
import com.intellij.psi.stubs.IStubElementType;
@@ -42,7 +40,6 @@ import com.intellij.psi.stubs.StubElement;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -56,12 +53,7 @@ public class PsiClassImpl extends JavaStubPsiElement<PsiClassStub<?>> implements
private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.source.PsiClassImpl");
private final ClassInnerStuffCache myInnersCache = new ClassInnerStuffCache(this);
private volatile PsiMethod myValuesMethod;
private volatile PsiMethod myValueOfMethod;
private volatile String myCachedName;
@NonNls private static final String VALUES_METHOD = "values";
@NonNls private static final String VALUE_OF_METHOD = "valueOf";
public PsiClassImpl(final PsiClassStub stub) {
this(stub, JavaStubElementTypes.CLASS);
@@ -102,8 +94,6 @@ public class PsiClassImpl extends JavaStubPsiElement<PsiClassStub<?>> implements
private void dropCaches() {
myInnersCache.dropCaches();
myCachedName = null;
myValueOfMethod = null;
myValuesMethod = null;
}
@Override
@@ -494,30 +484,11 @@ public class PsiClassImpl extends JavaStubPsiElement<PsiClassStub<?>> implements
@Override
public boolean processDeclarations(@NotNull PsiScopeProcessor processor, @NotNull ResolveState state, PsiElement lastParent, @NotNull PsiElement place) {
if (isEnum()) {
String myName = getName();
if (myName != null) {
try {
final NameHint nameHint = processor.getHint(NameHint.KEY);
final ElementClassHint classHint = processor.getHint(ElementClassHint.KEY);
String nameToSearch = nameHint == null ? null : nameHint.getName(state);
if ((nameToSearch == null || VALUES_METHOD.equals(nameToSearch)) &&
(classHint == null || classHint.shouldProcess(ElementClassHint.DeclarationKind.METHOD))) {
PsiMethod method = getValuesMethod();
if (method != null && !processor.execute(method, ResolveState.initial())) return false;
}
if ((nameToSearch == null || VALUE_OF_METHOD.equals(nameToSearch)) &&
(classHint == null || classHint.shouldProcess(ElementClassHint.DeclarationKind.METHOD))) {
PsiMethod method = getValueOfMethod();
if (method != null && !processor.execute(method, ResolveState.initial())) return false;
}
}
catch (IncorrectOperationException e) {
LOG.error(e);
}
}
if (!PsiClassImplUtil.processDeclarationsInEnum(processor, state, myInnersCache)) return false;
}
return PsiClassImplUtil.processDeclarationsInClass(this, processor, state, null, lastParent, place, PsiUtil.getLanguageLevel(place), false);
LanguageLevel level = PsiUtil.getLanguageLevel(place);
return PsiClassImplUtil.processDeclarationsInClass(this, processor, state, null, lastParent, place, level, false);
}
@Override
@@ -706,23 +677,6 @@ public class PsiClassImpl extends JavaStubPsiElement<PsiClassStub<?>> implements
@Nullable
public PsiMethod getValuesMethod() {
PsiMethod method = myValuesMethod;
if (method == null && isEnum() && getName() != null) {
PsiElementFactory elementFactory = JavaPsiFacade.getInstance(getProject()).getElementFactory();
final PsiMethod valuesMethod = elementFactory.createMethodFromText("public static " + getName() + "[] values() {}", this);
myValuesMethod = method = new LightMethod(getManager(), valuesMethod, this);
}
return method;
}
@Nullable
public PsiMethod getValueOfMethod() {
PsiMethod method = myValueOfMethod;
if (method == null && isEnum() && getName() != null) {
PsiElementFactory elementFactory = JavaPsiFacade.getInstance(getProject()).getElementFactory();
final PsiMethod valuesMethod = elementFactory.createMethodFromText("public static " + getName() + " valueOf(String name) throws java.lang.IllegalArgumentException {}", this);
myValueOfMethod = method = new LightMethod(getManager(), valuesMethod, this);
}
return method;
return myInnersCache.getValuesMethod();
}
}
@@ -0,0 +1,8 @@
import java.lang.annotation.ElementType;
class EnumSynthetics {
void m() {
//ElementType[] values = ElementType.values();
ElementType type = ElementType.valueOf("TYPE");
}
}
@@ -62,6 +62,7 @@ public class LightAdvHighlightingJdk6Test extends LightDaemonAnalyzerTestCase {
public void testUnhandledExceptionsValueOf() { doTest(true, false); }
public void testUnsupportedFeatures7() { doTest(false, false); }
public void testEnumInitializers() { doTest(false, false); }
public void testEnumSynthetics() { doTest(false, false); }
public void testIDEA79251() { doTest(false, false); }
public void testAgentPremain() {
doTest(false, false);