From 3ba0a4231d88aa6201262f53e37181f98d2e1785 Mon Sep 17 00:00:00 2001 From: peter Date: Mon, 30 Jan 2012 18:01:36 +0100 Subject: [PATCH] don't error-highlight groovy builder members as unresolved --- .../GroovyUnresolvedAccessInspection.java | 71 ++++++++++++++++++- .../groovy/lang/GroovyHighlightingTest.groovy | 4 ++ .../BuilderMembersAreNotUnresolved.groovy | 22 ++++++ 3 files changed, 94 insertions(+), 3 deletions(-) create mode 100644 plugins/groovy/testdata/highlighting/BuilderMembersAreNotUnresolved.groovy diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/untypedUnresolvedAccess/GroovyUnresolvedAccessInspection.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/untypedUnresolvedAccess/GroovyUnresolvedAccessInspection.java index 91260b7fc7ea..9b661072510b 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/untypedUnresolvedAccess/GroovyUnresolvedAccessInspection.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/untypedUnresolvedAccess/GroovyUnresolvedAccessInspection.java @@ -16,19 +16,24 @@ package org.jetbrains.plugins.groovy.codeInspection.untypedUnresolvedAccess; -import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiPackage; +import com.intellij.psi.*; +import com.intellij.util.containers.CollectionFactory; import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.NotNull; import org.jetbrains.plugins.groovy.annotator.GroovyAnnotator; import org.jetbrains.plugins.groovy.codeInspection.BaseInspection; import org.jetbrains.plugins.groovy.codeInspection.BaseInspectionVisitor; -import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult; +import org.jetbrains.plugins.groovy.gpp.GppTypeConverter; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrCall; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression; +import org.jetbrains.plugins.groovy.lang.psi.util.GroovyCommonClassNames; +import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil; import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil; +import java.util.Iterator; +import java.util.List; + import static org.jetbrains.plugins.groovy.annotator.GroovyAnnotator.isDeclarationAssignment; /** @@ -72,10 +77,70 @@ public class GroovyUnresolvedAccessInspection extends BaseInspection { if (!(parent instanceof GrCall) && ResolveUtil.isKeyOfMap(refExpr)) return; // It's a key of map. if (!GroovyAnnotator.shouldHighlightAsUnresolved(refExpr)) return; + + if (qualifier != null && isBuilderInvocation(refExpr)) return; PsiElement refNameElement = refExpr.getReferenceNameElement(); registerError(refNameElement == null ? refExpr : refNameElement); } } + private static boolean isBuilderInvocation(@NotNull GrReferenceExpression refExpr) { + GrExpression qualifier = refExpr.getQualifier(); + PsiType type = qualifier == null ? null : qualifier.getType(); + if (type instanceof PsiClassType) { + PsiClass target = ((PsiClassType)type).resolve(); + if (target != null) { + for (PsiMethod method : findBuilderMetaMethods(refExpr, target)) { + PsiClass containingClass = method.getContainingClass(); + if (containingClass != null && + method.getParameterList().getParameters()[0].getType().equalsToText(CommonClassNames.JAVA_LANG_STRING)) { + String qname = containingClass.getQualifiedName(); + if (!GroovyCommonClassNames.GROOVY_OBJECT.equals(qname) && !GroovyCommonClassNames.GROOVY_OBJECT_SUPPORT.equals(qname)) { + return true; + } + } + } + } + } + + return false; + } + + private static List findBuilderMetaMethods(GrReferenceExpression refExpr, PsiClass target) { + boolean gpp = GppTypeConverter.hasTypedContext(target) && GppTypeConverter.hasTypedContext(refExpr); + if (refExpr.getParent() instanceof GrCall) { + List toSearch = + CollectionFactory.arrayList(target.findMethodsByName(gpp ? "invokeUnresolvedMethod" : "invokeMethod", true)); + for (Iterator iterator = toSearch.iterator(); iterator.hasNext(); ) { + PsiMethod method = iterator.next(); + if (!gpp && + (method.getParameterList().getParametersCount() != 2 || method.getParameterList().getParameters()[1].getType() + .equalsToText(CommonClassNames.JAVA_LANG_OBJECT + "[]"))) { + iterator.remove(); + } + } + return toSearch; + } + + if (PsiUtil.isLValue(refExpr)) { + List toSearch = CollectionFactory.arrayList(target.findMethodsByName(gpp ? "setUnresolvedProperty" : "setProperty", true)); + for (Iterator iterator = toSearch.iterator(); iterator.hasNext(); ) { + PsiMethod method = iterator.next(); + if (method.getParameterList().getParametersCount() != 2 || (!gpp && !method.getParameterList().getParameters()[1].getType() + .equalsToText(CommonClassNames.JAVA_LANG_OBJECT))) { + iterator.remove(); + } + } + return toSearch; + } + + List toSearch = CollectionFactory.arrayList(target.findMethodsByName(gpp ? "getUnresolvedProperty" : "getProperty", true)); + for (Iterator iterator = toSearch.iterator(); iterator.hasNext(); ) { + if (iterator.next().getParameterList().getParametersCount() != 1) { + iterator.remove(); + } + } + return toSearch; + } } diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovyHighlightingTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovyHighlightingTest.groovy index 76bf926f58e9..e72b91eb44d6 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovyHighlightingTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovyHighlightingTest.groovy @@ -452,6 +452,10 @@ public class GroovyHighlightingTest extends LightCodeInsightFixtureTestCase { doTest(new GroovyAssignabilityCheckInspection(), new GroovyUnresolvedAccessInspection()); } + public void testBuilderMembersAreNotUnresolved() throws Exception { + doTest(new GroovyUnresolvedAccessInspection()); + } + public void testUnknownVarInArgList() { doTest(new GroovyAssignabilityCheckInspection()); } diff --git a/plugins/groovy/testdata/highlighting/BuilderMembersAreNotUnresolved.groovy b/plugins/groovy/testdata/highlighting/BuilderMembersAreNotUnresolved.groovy new file mode 100644 index 000000000000..300b84e61fce --- /dev/null +++ b/plugins/groovy/testdata/highlighting/BuilderMembersAreNotUnresolved.groovy @@ -0,0 +1,22 @@ +class MyBuilder { + @Override + Object getProperty(String property) { + return super.getProperty(property) + } + + @Override + Object invokeMethod(String name, Object args) { + return super.invokeMethod(name, args) + } + + @Override + void setProperty(String property, Object newValue) { + super.setProperty(property, newValue) + } +} + +def b = new MyBuilder() +println b.foo +println new Object().foo +b.foo = 2 +b.bar() \ No newline at end of file