From cbe8a8d06d17e04ef9b043cfd1f8a53ce33ce630 Mon Sep 17 00:00:00 2001 From: peter Date: Wed, 4 Aug 2010 20:58:00 +0100 Subject: [PATCH] find overloaded constructor usages in literals --- .../ConstructorReferencesSearcher.java | 2 +- .../GroovyConstructorUsagesSearcher.java | 8 +-- .../LiteralConstructorReference.java | 53 ++++++++++++++++ .../LiteralConstructorSearcher.java | 63 ++++++------------- .../lang/psi/api/auxiliary/GrListOrMap.java | 4 ++ .../psi/impl/auxiliary/GrListOrMapImpl.java | 11 ++++ .../lang/LiteralConstructorUsagesTest.groovy | 19 +++++- 7 files changed, 110 insertions(+), 50 deletions(-) create mode 100644 plugins/groovy/src/org/jetbrains/plugins/groovy/findUsages/LiteralConstructorReference.java diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/findUsages/ConstructorReferencesSearcher.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/findUsages/ConstructorReferencesSearcher.java index 1e8ee89c70ff..beab58cf4968 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/findUsages/ConstructorReferencesSearcher.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/findUsages/ConstructorReferencesSearcher.java @@ -36,7 +36,7 @@ public class ConstructorReferencesSearcher extends QueryExecutorBase consumer) { - processConstructorUsages(p.getMethod(), p.getScope(), consumer, p.getOptimizer(), true); + processConstructorUsages(p.getMethod(), p.getScope(), consumer, p.getOptimizer(), true, !p.isStrictSignatureSearch()); } - static void processConstructorUsages(final PsiMethod constructor, final SearchScope searchScope, final Processor consumer, final SearchRequestCollector collector, final boolean searchGppCalls) { + static void processConstructorUsages(final PsiMethod constructor, final SearchScope searchScope, final Processor consumer, final SearchRequestCollector collector, final boolean searchGppCalls, final boolean includeOverloads) { if (!constructor.isConstructor()) return; SearchScope onlyGroovy = PsiUtil.restrictScopeToGroovyFiles(searchScope); @@ -103,7 +103,7 @@ public class GroovyConstructorUsagesSearcher extends QueryExecutorBase newExpressionProcessor = new Processor() { @Override @@ -230,7 +230,7 @@ public class GroovyConstructorUsagesSearcher extends QueryExecutorBase { + private final PsiClassType myConstructedClass; + + public LiteralConstructorReference(@NotNull GrListOrMap element, @NotNull PsiClassType constructedClassType) { + super(element, TextRange.from(0, 1), false); + myConstructedClass = constructedClassType; + } + + @Nullable + private PsiType[] argTypes() { + final GrListOrMap literal = getElement(); + final PsiType listType = literal.getType(); + if (listType instanceof GrTupleType) { + return ((GrTupleType)listType).getComponentTypes(); + } + else if (listType instanceof GrMapType && ((GrMapType)listType).getValueType("super") == null) { + return PsiType.EMPTY_ARRAY; + } + return null; + } + + @NotNull + @Override + public ResolveResult[] multiResolve(boolean incompleteCode) { + final PsiType[] psiTypes = argTypes(); + if (psiTypes == null) return ResolveResult.EMPTY_ARRAY; + + return PsiUtil.getConstructorCandidates(myConstructedClass, psiTypes, getElement()); + } + + @NotNull + @Override + public Object[] getVariants() { + return EMPTY_ARRAY; + } +} diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/findUsages/LiteralConstructorSearcher.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/findUsages/LiteralConstructorSearcher.java index 470b6a2625b2..5cf0ef6ddf39 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/findUsages/LiteralConstructorSearcher.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/findUsages/LiteralConstructorSearcher.java @@ -1,14 +1,13 @@ package org.jetbrains.plugins.groovy.findUsages; -import com.intellij.openapi.util.TextRange; -import com.intellij.psi.*; +import com.intellij.psi.PsiClassType; +import com.intellij.psi.PsiMethod; +import com.intellij.psi.PsiReference; +import com.intellij.util.ObjectUtils; import com.intellij.util.Processor; -import org.jetbrains.plugins.groovy.gpp.GppReferenceContributor; +import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.GrListOrMap; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentLabel; import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrNamedArgument; -import org.jetbrains.plugins.groovy.lang.psi.impl.GrMapType; -import org.jetbrains.plugins.groovy.lang.psi.impl.GrTupleType; /** * @author peter @@ -16,53 +15,29 @@ import org.jetbrains.plugins.groovy.lang.psi.impl.GrTupleType; public class LiteralConstructorSearcher { private final PsiMethod myConstructor; private final Processor myConsumer; + private final boolean myIncludeOverloads; - public LiteralConstructorSearcher(PsiMethod constructor, Processor consumer) { + public LiteralConstructorSearcher(PsiMethod constructor, Processor consumer, boolean includeOverloads) { myConstructor = constructor; myConsumer = consumer; + myIncludeOverloads = includeOverloads; } - private static boolean checkLiteralInstantiation(PsiMethod constructor, - Processor consumer, - GrListOrMap literal, - PsiClassType expectedType) { - final PsiType listType = literal.getType(); - if (listType instanceof GrTupleType) { - if (GppReferenceContributor.isConstructorCall(expectedType, ((GrTupleType)listType).getComponentTypes(), constructor, literal)) { - return consumer.process(PsiReferenceBase.createSelfReference(literal, TextRange.from(0, literal.getTextLength()), constructor)); + public boolean processLiteral(GrListOrMap literal, PsiClassType expectedType) { + if (literal.isMap()) { + final GrNamedArgument argument = literal.findNamedArgument("super"); + if (argument != null) { + return processConstructorReference(ObjectUtils.assertNotNull(argument.getLabel()).getReference()); } } - else if (listType instanceof GrMapType) { - final PsiType constructorArgs = ((GrMapType)listType).getValueType("super"); - if (constructorArgs == null) { - if (constructor.getParameterList().getParametersCount() == 0) { - if (!consumer.process(PsiReferenceBase.createSelfReference(literal, TextRange.from(0, literal.getTextLength()), constructor))) { - return false; - } - } - return true; - } - for (GrNamedArgument argument : literal.getNamedArguments()) { - final GrArgumentLabel label = argument.getLabel(); - if (label != null && "super".equals(label.getName())) { - final PsiReference reference = label.getReference(); - if (reference != null && reference.isReferenceTo(constructor)) { - return consumer.process(reference); - } - return true; - } - } + return processConstructorReference(new LiteralConstructorReference(literal, expectedType)); + } - //no 'super', only default constructor applicable - if (constructor.getParameterList().getParametersCount() == 0) { - return consumer.process(PsiReferenceBase.createSelfReference(literal, TextRange.from(0, literal.getTextLength()), constructor)); - } - } + private boolean processConstructorReference(@Nullable PsiReference reference) { + if (reference != null && (myIncludeOverloads || reference.isReferenceTo(myConstructor))) { + return myConsumer.process(reference); + } return true; } - - public boolean processLiteral(GrListOrMap list, PsiClassType expectedType) { - return checkLiteralInstantiation(myConstructor, myConsumer, list, expectedType); - } } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/api/auxiliary/GrListOrMap.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/api/auxiliary/GrListOrMap.java index d69643b07845..4df2e4b140c4 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/api/auxiliary/GrListOrMap.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/api/auxiliary/GrListOrMap.java @@ -22,6 +22,7 @@ import com.intellij.openapi.util.UserDataHolderEx; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiArrayInitializerMemberValue; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrNamedArgument; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression; @@ -42,5 +43,8 @@ public interface GrListOrMap extends UserDataHolderEx, Cloneable, Iconable, PsiE @NotNull GrNamedArgument[] getNamedArguments(); + @Nullable + GrNamedArgument findNamedArgument(@NotNull String label); + boolean isMap(); } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/auxiliary/GrListOrMapImpl.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/auxiliary/GrListOrMapImpl.java index e1e3d6d9d631..77c33eb34ab6 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/auxiliary/GrListOrMapImpl.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/auxiliary/GrListOrMapImpl.java @@ -92,6 +92,17 @@ public class GrListOrMapImpl extends GrExpressionImpl implements GrListOrMap { return findChildrenByClass(GrNamedArgument.class); } + @Override + public GrNamedArgument findNamedArgument(@NotNull String labelName) { + for (GrNamedArgument argument : getNamedArguments()) { + final GrArgumentLabel label = argument.getLabel(); + if (label != null && labelName.equals(label.getName())) { + return argument; + } + } + return null; + } + private static class MyTypesCalculator implements Function { @Nullable public PsiType fun(GrListOrMapImpl listOrMap) { diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/LiteralConstructorUsagesTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/LiteralConstructorUsagesTest.groovy index 4faa4cb1b0b3..3e97b48a842c 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/LiteralConstructorUsagesTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/LiteralConstructorUsagesTest.groovy @@ -1,7 +1,8 @@ package org.jetbrains.plugins.groovy.lang -import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase +import com.intellij.psi.search.searches.MethodReferencesSearch import com.intellij.psi.search.searches.ReferencesSearch +import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase /** * @author peter @@ -160,4 +161,20 @@ class LiteralConstructorUsagesTest extends LightCodeInsightFixtureTestCase { assertEquals(2, ReferencesSearch.search(foo.constructors[1]).findAll().size()) } + public void testOverloadedConstructorUsages() throws Exception { + def foo = myFixture.addClass(""" + class Foo { + Foo() {} + Foo(int a) {} + } + """) + + myFixture.addFileToProject "a.gpp", """ + Foo b = [] + Foo b1 = [2] + """ + assertEquals(2, MethodReferencesSearch.search(foo.constructors[0], false).findAll().size()) + assertEquals(2, MethodReferencesSearch.search(foo.constructors[1], false).findAll().size()) + } + }