From 7aa7ab5e909d3c7585a72cdf855e91469c3891c4 Mon Sep 17 00:00:00 2001 From: Maxim Medvedev Date: Thu, 23 Sep 2010 14:25:03 +0400 Subject: [PATCH] IDEA-57503 Criteria builder calls reported as syntax errors in static methods (Idea X) --- .../groovy/annotator/GroovyAnnotator.java | 2 ++ .../groovy/lang/psi/impl/PsiImplUtil.java | 3 ++ .../GrReferenceExpressionImpl.java | 29 ++++++++++--------- .../plugins/groovy/lang/psi/util/PsiUtil.java | 17 +++++++---- .../resolve/processors/ResolverProcessor.java | 2 +- .../lang/resolve/GroovyResolveTestCase.java | 7 +++++ .../lang/resolve/ResolveMethodTest.groovy | 5 ---- .../lang/resolve/ResolvePropertyTest.groovy | 13 +++++++++ .../A.groovy | 18 ++++++++++++ .../fieldAccessInStaticContext/A.groovy | 7 +++++ 10 files changed, 78 insertions(+), 25 deletions(-) create mode 100644 plugins/groovy/testdata/resolve/property/fieldAccessInClosureVsStaticContext/A.groovy create mode 100644 plugins/groovy/testdata/resolve/property/fieldAccessInStaticContext/A.groovy diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/GroovyAnnotator.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/GroovyAnnotator.java index 47a0bc941793..2e9818ab9c05 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/GroovyAnnotator.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/GroovyAnnotator.java @@ -178,6 +178,8 @@ public class GroovyAnnotator extends GroovyElementVisitor implements Annotator { registerAccessFix(annotation, referenceExpression, ((PsiMember)resolved)); } } + + //todo uncomment when correct isStatic() is working if (!resolveResult.isStaticsOK() && resolved instanceof PsiModifierListOwner) { if (!((PsiModifierListOwner)resolved).hasModifierProperty(GrModifier.STATIC)) { Annotation annotation = myHolder.createInfoAnnotation(referenceExpression, diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/PsiImplUtil.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/PsiImplUtil.java index 23a3fd0794f6..aa6bd389309f 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/PsiImplUtil.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/PsiImplUtil.java @@ -37,6 +37,7 @@ import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult; import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrStatement; import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariable; import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariableDeclaration; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentList; import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.*; import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod; @@ -137,6 +138,7 @@ public class PsiImplUtil { GrClosableBlock closure = PsiTreeUtil.getParentOfType(refExpr, GrClosableBlock.class); while (closure != null) { PsiElement parent = closure.getParent(); + if (parent instanceof GrArgumentList) parent = parent.getParent(); if (parent instanceof GrMethodCall) { GrExpression funExpr = ((GrMethodCall)parent).getInvokedExpression(); if (funExpr instanceof GrReferenceExpression) { @@ -326,6 +328,7 @@ public class PsiImplUtil { method.hasModifierProperty(PsiModifier.STATIC); } + @Nullable public static PsiMethod resolveMethod(GrMethodCall expression) { final GrExpression methodExpr = expression.getInvokedExpression(); if (methodExpr instanceof GrReferenceExpression) { 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 52e164b58347..4a13b7b1a805 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 @@ -42,6 +42,7 @@ import org.jetbrains.plugins.groovy.lang.lexer.TokenSets; import org.jetbrains.plugins.groovy.lang.parser.GroovyElementTypes; import org.jetbrains.plugins.groovy.lang.psi.GroovyElementVisitor; import org.jetbrains.plugins.groovy.lang.psi.GroovyFile; +import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement; import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElementFactory; import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult; import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrField; @@ -580,20 +581,20 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl implements } if (qualifier instanceof GrReferenceExpression && "class".equals(((GrReferenceExpression)qualifier).getReferenceName())) { - processIfJavaLangClass(processor, qualifier.getType()); + processIfJavaLangClass(processor, qualifier.getType(), qualifier); } else if (qualifier instanceof GrThisReferenceExpression) { - processIfJavaLangClass(processor, qualifier.getType()); + processIfJavaLangClass(processor, qualifier.getType(), qualifier); } } } - private void processIfJavaLangClass(ResolverProcessor processor, PsiType type) { + private void processIfJavaLangClass(ResolverProcessor processor, PsiType type, GroovyPsiElement resolveContext) { if (type instanceof PsiClassType) { final PsiClass psiClass = ((PsiClassType)type).resolve(); if (psiClass != null && CommonClassNames.JAVA_LANG_CLASS.equals(psiClass.getQualifiedName())) { final PsiType[] params = ((PsiClassType)type).getParameters(); if (params.length == 1) { - processClassQualifierType(processor, params[0]); + processClassQualifierType(processor, params[0], resolveContext); } } } @@ -611,13 +612,13 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl implements if (substitutor != null) { PsiType componentType = substitutor.substitute(listClass.getTypeParameters()[0]); if (componentType != null) { - processClassQualifierType(processor, componentType); + processClassQualifierType(processor, componentType, qualifier); } } } } } else if (qualifierType instanceof PsiArrayType) { - processClassQualifierType(processor, ((PsiArrayType) qualifierType).getComponentType()); + processClassQualifierType(processor, ((PsiArrayType) qualifierType).getComponentType(), qualifier); } } @@ -627,22 +628,22 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl implements if (qualifier instanceof GrReferenceExpression) { PsiElement resolved = ((GrReferenceExpression) qualifier).resolve(); if (resolved instanceof PsiPackage) { - if (!resolved.processDeclarations(processor, ResolveState.initial(), null, this)) //noinspection UnnecessaryReturnStatement + if (!resolved.processDeclarations(processor, ResolveState.initial().put(ResolverProcessor.RESOLVE_CONTEXT, qualifier), null, this)) //noinspection UnnecessaryReturnStatement return; } else { qualifierType = JavaPsiFacade.getInstance(getProject()).getElementFactory() .createTypeByFQClassName(CommonClassNames.JAVA_LANG_OBJECT, getResolveScope()); - processClassQualifierType(processor, qualifierType); + processClassQualifierType(processor, qualifierType, qualifier); } } } else { if (qualifierType instanceof PsiIntersectionType) { for (PsiType conjunct : ((PsiIntersectionType) qualifierType).getConjuncts()) { - processClassQualifierType(processor, conjunct); + processClassQualifierType(processor, conjunct, qualifier); } } else { - processClassQualifierType(processor, qualifierType); + processClassQualifierType(processor, qualifierType, qualifier); if (qualifier instanceof GrReferenceExpression) { PsiElement resolved = ((GrReferenceExpression) qualifier).resolve(); if (resolved instanceof PsiClass) { //omitted .class @@ -666,14 +667,14 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl implements } } - private void processClassQualifierType(ResolverProcessor processor, PsiType qualifierType) { + private void processClassQualifierType(ResolverProcessor processor, PsiType qualifierType, GroovyPsiElement resolveContext) { Project project = getProject(); if (qualifierType instanceof PsiClassType) { PsiClassType.ClassResolveResult qualifierResult = ((PsiClassType) qualifierType).resolveGenerics(); PsiClass qualifierClass = qualifierResult.getElement(); if (qualifierClass != null) { - if (!qualifierClass.processDeclarations(processor, - ResolveState.initial().put(PsiSubstitutor.KEY, qualifierResult.getSubstitutor()), null, this)) + if (!qualifierClass.processDeclarations(processor, ResolveState.initial().put(PsiSubstitutor.KEY, qualifierResult.getSubstitutor()) + .put(ResolverProcessor.RESOLVE_CONTEXT, resolveContext), null, this)) return; } if (!ResolveUtil.processCategoryMembers(this, processor)) return; @@ -682,7 +683,7 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl implements if (!arrayClass.processDeclarations(processor, ResolveState.initial(), null, this)) return; } else if (qualifierType instanceof PsiIntersectionType) { for (PsiType conjunct : ((PsiIntersectionType) qualifierType).getConjuncts()) { - processClassQualifierType(processor, conjunct); + processClassQualifierType(processor, conjunct, resolveContext); } return; } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/util/PsiUtil.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/util/PsiUtil.java index ad875ae90601..01a1db3548de 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/util/PsiUtil.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/util/PsiUtil.java @@ -53,7 +53,6 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgument import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrNamedArgument; import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.*; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.literals.GrLiteral; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.path.GrCallExpression; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.path.GrIndexProperty; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.path.GrMethodCallExpression; @@ -68,7 +67,6 @@ import org.jetbrains.plugins.groovy.lang.psi.impl.GrClosureType; import org.jetbrains.plugins.groovy.lang.psi.impl.GrMapType; import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyResolveResultImpl; import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil; -import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.literals.GrLiteralImpl; import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GroovyScriptClass; import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.JavaIdentifier; import org.jetbrains.plugins.groovy.lang.psi.impl.types.GrClosureSignatureUtil; @@ -384,6 +382,10 @@ public class PsiUtil { } public static boolean isStaticsOK(PsiModifierListOwner owner, PsiElement place) { + return isStaticsOK(owner, place, owner); + } + + public static boolean isStaticsOK(PsiModifierListOwner owner, PsiElement place, PsiElement resolveContext) { if (owner instanceof PsiMember) { if (place instanceof GrReferenceExpression) { GrExpression qualifier = ((GrReferenceExpression)place).getQualifierExpression(); @@ -459,9 +461,14 @@ public class PsiUtil { if (((PsiMember)owner).getContainingClass() == null) return true; if (owner instanceof GrVariable && !(owner instanceof GrField)) return true; if (owner.hasModifierProperty(GrModifier.STATIC)) return true; - final GrMember placeOwner = PsiTreeUtil.getParentOfType(place, GrMember.class); - if (placeOwner == null) return true; - return !placeOwner.hasModifierProperty(GrModifier.STATIC); + + PsiElement stopAt = resolveContext != null ? PsiTreeUtil.findCommonParent(place, resolveContext) : null; + while (place != null && place != stopAt && !(place instanceof GrMember)) { + if (place instanceof PsiFile) break; + place = place.getParent(); + } + if (place == null || place instanceof PsiFile || place == stopAt) return true; + return !((GrMember)place).hasModifierProperty(GrModifier.STATIC); } } } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/resolve/processors/ResolverProcessor.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/resolve/processors/ResolverProcessor.java index 04b3c87891b4..e97b6b99507b 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/resolve/processors/ResolverProcessor.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/resolve/processors/ResolverProcessor.java @@ -109,7 +109,7 @@ public class ResolverProcessor implements PsiScopeProcessor, NameHint, ClassHint if (resolveContext instanceof GrImportStatement) return true; if (element instanceof PsiModifierListOwner) { - return PsiUtil.isStaticsOK((PsiModifierListOwner) element, myPlace); + return PsiUtil.isStaticsOK((PsiModifierListOwner) element, myPlace, resolveContext); } return true; } diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/GroovyResolveTestCase.java b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/GroovyResolveTestCase.java index 41e10dc025d6..2bc8a7de78d6 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/GroovyResolveTestCase.java +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/GroovyResolveTestCase.java @@ -19,6 +19,7 @@ package org.jetbrains.plugins.groovy.lang.resolve; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VfsUtil; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.psi.PsiElement; import com.intellij.psi.PsiReference; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.Nullable; @@ -74,4 +75,10 @@ public abstract class GroovyResolveTestCase extends LightGroovyTestCase { return configureByFile(filePath, null); } + @Nullable + protected PsiElement resolve(String fileName) { + PsiReference ref = configureByFile(getTestName(true) + "/" + fileName); + return ref.resolve(); + } + } diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolveMethodTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolveMethodTest.groovy index 8796885064e1..29819b9553b0 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolveMethodTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolveMethodTest.groovy @@ -602,11 +602,6 @@ class Zoo { assertInstanceOf resolved, GrVariable } - private PsiElement resolve(String fileName) { - PsiReference ref = configureByFile("${getTestName(true)}/$fileName"); - ref.resolve() - } - public void testCommandExpressionStatement1() { PsiElement method = resolve("A.groovy") assertInstanceOf method, GrMethod diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolvePropertyTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolvePropertyTest.groovy index a1fef2e7d82e..f823bd06134c 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolvePropertyTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolvePropertyTest.groovy @@ -581,4 +581,17 @@ setFoo(2) PsiElement resolved = ref.resolve() assertInstanceOf resolved, PsiField } + + public void testFieldAccessInStaticContext() { + def ref = configureByFile("fieldAccessInStaticContext/A.groovy") + def resolveResult = ref.advancedResolve() + assertTrue !resolveResult.staticsOK + } + + public void testFieldAccessInClosureVsStaticContext() { + def ref = configureByFile("fieldAccessInClosureVsStaticContext/A.groovy") + def resolveResult = ref.advancedResolve() + assertTrue resolveResult.staticsOK + } + } \ No newline at end of file diff --git a/plugins/groovy/testdata/resolve/property/fieldAccessInClosureVsStaticContext/A.groovy b/plugins/groovy/testdata/resolve/property/fieldAccessInClosureVsStaticContext/A.groovy new file mode 100644 index 000000000000..4a426f878a87 --- /dev/null +++ b/plugins/groovy/testdata/resolve/property/fieldAccessInClosureVsStaticContext/A.groovy @@ -0,0 +1,18 @@ +class MyDom { + + static void main(String[] args) { + new Foo().foo({ + print bar + }); + } +} + + +class Foo { + def bar = 2 + + def foo(Closure c) { + c.delegate = this + c.call() + } +} diff --git a/plugins/groovy/testdata/resolve/property/fieldAccessInStaticContext/A.groovy b/plugins/groovy/testdata/resolve/property/fieldAccessInStaticContext/A.groovy new file mode 100644 index 000000000000..2375c037f73d --- /dev/null +++ b/plugins/groovy/testdata/resolve/property/fieldAccessInStaticContext/A.groovy @@ -0,0 +1,7 @@ +class Foo { + def field = 2 + + static def foo() { + print field + } +} \ No newline at end of file