From e11c89c26992ae070db31692bccdf03dd71dde23 Mon Sep 17 00:00:00 2001 From: Maxim Medvedev Date: Sat, 29 May 2010 14:20:10 +0400 Subject: [PATCH] IDEA-53871: Reference to inner enum incorrectly resolved as property reference --- .../GrReferenceExpressionImpl.java | 160 ++++++++++-------- .../groovy/lang/resolve/ResolveClassTest.java | 6 + .../resolve/class/enumVsProperty/Test.groovy | 11 ++ 3 files changed, 105 insertions(+), 72 deletions(-) create mode 100644 plugins/groovy/testdata/resolve/class/enumVsProperty/Test.groovy diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrReferenceExpressionImpl.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrReferenceExpressionImpl.java index 87cd4b948bd2..bce292db98c4 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrReferenceExpressionImpl.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrReferenceExpressionImpl.java @@ -428,84 +428,100 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl implements if (propertyCandidates.length > 0) return propertyCandidates; } - if (kind == Kind.METHOD_OR_PROPERTY) { - final PsiType[] argTypes = PsiUtil.getArgumentTypes(refExpr, false); - PsiType thisType = getThisType(refExpr); - - MethodResolverProcessor methodResolver = - new MethodResolverProcessor(name, refExpr, false, thisType, argTypes, refExpr.getTypeArguments()); - resolveImpl(refExpr, methodResolver); - if (methodResolver.hasApplicableCandidates()) return methodResolver.getCandidates(); - - final String[] names = GroovyPropertyUtils.suggestGettersName(name); - List list = new ArrayList(); - for (String getterName : names) { - AccessorResolverProcessor getterResolver = new AccessorResolverProcessor(getterName, refExpr, true); - resolveImpl(refExpr, getterResolver); - final GroovyResolveResult[] candidates = getterResolver.getCandidates(); //can be only one candidate - if (candidates.length == 1 && candidates[0].isStaticsOK()) { - refExpr.putUserData(IS_RESOLVED_TO_GETTER, true); - return candidates; - } - else { - list.addAll(Arrays.asList(candidates)); - } - } - - PropertyResolverProcessor propertyResolver = new PropertyResolverProcessor(name, refExpr); - resolveImpl(refExpr, propertyResolver); - if (propertyResolver.hasCandidates()) return propertyResolver.getCandidates(); - - if (methodResolver.hasCandidates()) { - return methodResolver.getCandidates(); - } - else if (list.size() > 0) { - refExpr.putUserData(IS_RESOLVED_TO_GETTER, true); - return list.toArray(new GroovyResolveResult[list.size()]); - } - - return GroovyResolveResult.EMPTY_ARRAY; + switch (kind) { + case METHOD_OR_PROPERTY: + return resolveMethodOrProperty(refExpr, name); + case TYPE_OR_PROPERTY: + return resolveTypeOrProperty(refExpr, name); + default: + return GroovyResolveResult.EMPTY_ARRAY; } - else if (kind == Kind.TYPE_OR_PROPERTY) { - ResolverProcessor processor = new PropertyResolverProcessor(name, refExpr); - resolveImpl(refExpr, processor); - final GroovyResolveResult[] fieldCandidates = processor.getCandidates(); + } - //if reference expression is in class we need to return field instead of accessor method - for (GroovyResolveResult candidate : fieldCandidates) { - final PsiElement element = candidate.getElement(); - if (element instanceof PsiField) { - final PsiClass containingClass = ((PsiField)element).getContainingClass(); - if (containingClass != null && PsiTreeUtil.isAncestor(containingClass, refExpr, true)) return fieldCandidates; - } else { - return fieldCandidates; - } + private static GroovyResolveResult[] resolveTypeOrProperty(GrReferenceExpressionImpl refExpr, String name) { + EnumSet kinds = refExpr.getParent() instanceof GrReferenceExpression + ? EnumSet.of(ClassHint.ResolveKind.CLASS, ClassHint.ResolveKind.PACKAGE) + : EnumSet.of(ClassHint.ResolveKind.CLASS); + ResolverProcessor classProcessor = new ClassResolverProcessor(refExpr.getReferenceName(), refExpr, kinds); + resolveImpl(refExpr, classProcessor); + final GroovyResolveResult[] classCandidates = classProcessor.getCandidates(); + for (GroovyResolveResult classCandidate : classCandidates) { + final PsiElement element = classCandidate.getElement(); + if (element instanceof PsiClass && ((PsiClass)element).isEnum()) { + return classCandidates; } + } - final boolean isLValue = PsiUtil.isLValue(refExpr); - String[] names; - names = isLValue ? GroovyPropertyUtils.suggestSettersName(name) : GroovyPropertyUtils.suggestGettersName(name); - List accessorResults = new ArrayList(); - for (String getterName : names) { - AccessorResolverProcessor accessorResolver = new AccessorResolverProcessor(getterName, refExpr, !isLValue); - resolveImpl(refExpr, accessorResolver); - final GroovyResolveResult[] candidates = accessorResolver.getCandidates(); //can be only one candidate - if (candidates.length == 1 && candidates[0].isStaticsOK()) { - return candidates; - } - else { - accessorResults.addAll(Arrays.asList(candidates)); - } + ResolverProcessor processor = new PropertyResolverProcessor(name, refExpr); + resolveImpl(refExpr, processor); + final GroovyResolveResult[] fieldCandidates = processor.getCandidates(); + + //if reference expression is in class we need to return field instead of accessor method + for (GroovyResolveResult candidate : fieldCandidates) { + final PsiElement element = candidate.getElement(); + if (element instanceof PsiField) { + final PsiClass containingClass = ((PsiField)element).getContainingClass(); + if (containingClass != null && PsiTreeUtil.isAncestor(containingClass, refExpr, true)) return fieldCandidates; + } else { + return fieldCandidates; } - if (fieldCandidates.length > 0) return fieldCandidates; - if (accessorResults.size() > 0) return new GroovyResolveResult[]{accessorResults.get(0)}; + } - EnumSet kinds = refExpr.getParent() instanceof GrReferenceExpression - ? EnumSet.of(ClassHint.ResolveKind.CLASS, ClassHint.ResolveKind.PACKAGE) - : EnumSet.of(ClassHint.ResolveKind.CLASS); - ResolverProcessor classProcessor = new ClassResolverProcessor(refExpr.getReferenceName(), refExpr, kinds); - resolveImpl(refExpr, classProcessor); - return classProcessor.getCandidates(); + final boolean isLValue = PsiUtil.isLValue(refExpr); + String[] names; + names = isLValue ? GroovyPropertyUtils.suggestSettersName(name) : GroovyPropertyUtils.suggestGettersName(name); + List accessorResults = new ArrayList(); + for (String getterName : names) { + AccessorResolverProcessor accessorResolver = new AccessorResolverProcessor(getterName, refExpr, !isLValue); + resolveImpl(refExpr, accessorResolver); + final GroovyResolveResult[] candidates = accessorResolver.getCandidates(); //can be only one candidate + if (candidates.length == 1 && candidates[0].isStaticsOK()) { + return candidates; + } + else { + accessorResults.addAll(Arrays.asList(candidates)); + } + } + if (fieldCandidates.length > 0) return fieldCandidates; + if (accessorResults.size() > 0) return new GroovyResolveResult[]{accessorResults.get(0)}; + + return classCandidates; + } + + private static GroovyResolveResult[] resolveMethodOrProperty(GrReferenceExpressionImpl refExpr, String name) { + final PsiType[] argTypes = PsiUtil.getArgumentTypes(refExpr, false); + PsiType thisType = getThisType(refExpr); + + MethodResolverProcessor methodResolver = + new MethodResolverProcessor(name, refExpr, false, thisType, argTypes, refExpr.getTypeArguments()); + resolveImpl(refExpr, methodResolver); + if (methodResolver.hasApplicableCandidates()) return methodResolver.getCandidates(); + + final String[] names = GroovyPropertyUtils.suggestGettersName(name); + List list = new ArrayList(); + for (String getterName : names) { + AccessorResolverProcessor getterResolver = new AccessorResolverProcessor(getterName, refExpr, true); + resolveImpl(refExpr, getterResolver); + final GroovyResolveResult[] candidates = getterResolver.getCandidates(); //can be only one candidate + if (candidates.length == 1 && candidates[0].isStaticsOK()) { + refExpr.putUserData(IS_RESOLVED_TO_GETTER, true); + return candidates; + } + else { + list.addAll(Arrays.asList(candidates)); + } + } + + PropertyResolverProcessor propertyResolver = new PropertyResolverProcessor(name, refExpr); + resolveImpl(refExpr, propertyResolver); + if (propertyResolver.hasCandidates()) return propertyResolver.getCandidates(); + + if (methodResolver.hasCandidates()) { + return methodResolver.getCandidates(); + } + else if (list.size() > 0) { + refExpr.putUserData(IS_RESOLVED_TO_GETTER, true); + return list.toArray(new GroovyResolveResult[list.size()]); } return GroovyResolveResult.EMPTY_ARRAY; diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolveClassTest.java b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolveClassTest.java index 6bdf94400435..8b3d682e5549 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolveClassTest.java +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolveClassTest.java @@ -120,6 +120,12 @@ public class ResolveClassTest extends GroovyResolveTestCase { assertInstanceOf(resolved, PsiClass.class); } + public void testEnumVsProperty() throws Exception { + PsiReference ref = configureByFile("enumVsProperty/Test.groovy"); + final PsiElement resolved = ref.resolve(); + assertInstanceOf(resolved, PsiClass.class); + } + private void doTest() throws Exception { doTest(getTestName(true) + "/" + getTestName(false) + ".groovy"); } diff --git a/plugins/groovy/testdata/resolve/class/enumVsProperty/Test.groovy b/plugins/groovy/testdata/resolve/class/enumVsProperty/Test.groovy new file mode 100644 index 000000000000..e2224bc33b60 --- /dev/null +++ b/plugins/groovy/testdata/resolve/class/enumVsProperty/Test.groovy @@ -0,0 +1,11 @@ +class X { + def Foo + + enum Foo { + a, b, c + } + + def foo() { + print Foo.a + } +} \ No newline at end of file