find overloaded constructor usages in literals

This commit is contained in:
peter
2010-08-04 20:58:00 +01:00
parent dff00a0e7e
commit cbe8a8d06d
7 changed files with 110 additions and 50 deletions
@@ -36,7 +36,7 @@ public class ConstructorReferencesSearcher extends QueryExecutorBase<PsiReferenc
if (element instanceof PsiMethod) {
final PsiMethod method = (PsiMethod)element;
if (method.isConstructor()) {
GroovyConstructorUsagesSearcher.processConstructorUsages(method, queryParameters.getScope(), consumer, queryParameters.getOptimizer(), true);
GroovyConstructorUsagesSearcher.processConstructorUsages(method, queryParameters.getScope(), consumer, queryParameters.getOptimizer(), true, false);
}
}
}
@@ -80,10 +80,10 @@ public class GroovyConstructorUsagesSearcher extends QueryExecutorBase<PsiRefere
@Override
public void processQuery(MethodReferencesSearch.SearchParameters p, Processor<PsiReference> 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<PsiReference> consumer, final SearchRequestCollector collector, final boolean searchGppCalls) {
static void processConstructorUsages(final PsiMethod constructor, final SearchScope searchScope, final Processor<PsiReference> 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<PsiRefere
}
}
final LiteralConstructorSearcher literalProcessor = new LiteralConstructorSearcher(constructor, consumer);
final LiteralConstructorSearcher literalProcessor = new LiteralConstructorSearcher(constructor, consumer, includeOverloads);
final Processor<GrNewExpression> newExpressionProcessor = new Processor<GrNewExpression>() {
@Override
@@ -230,7 +230,7 @@ public class GroovyConstructorUsagesSearcher extends QueryExecutorBase<PsiRefere
}
};
if (currentTarget.isConstructor()) {
processConstructorUsages(currentTarget, gppScope, gppCallProcessor, originalCollector, false);
processConstructorUsages(currentTarget, gppScope, gppCallProcessor, originalCollector, false, false);
}
else {
MethodReferencesSearch.searchOptimized(currentTarget, gppScope, true, originalCollector, gppCallProcessor);
@@ -0,0 +1,53 @@
package org.jetbrains.plugins.groovy.findUsages;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.PsiClassType;
import com.intellij.psi.PsiReferenceBase;
import com.intellij.psi.PsiType;
import com.intellij.psi.ResolveResult;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.GrListOrMap;
import org.jetbrains.plugins.groovy.lang.psi.impl.GrMapType;
import org.jetbrains.plugins.groovy.lang.psi.impl.GrTupleType;
import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil;
/**
* @author peter
*/
public class LiteralConstructorReference extends PsiReferenceBase.Poly<GrListOrMap> {
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;
}
}
@@ -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<PsiReference> myConsumer;
private final boolean myIncludeOverloads;
public LiteralConstructorSearcher(PsiMethod constructor, Processor<PsiReference> consumer) {
public LiteralConstructorSearcher(PsiMethod constructor, Processor<PsiReference> consumer, boolean includeOverloads) {
myConstructor = constructor;
myConsumer = consumer;
myIncludeOverloads = includeOverloads;
}
private static boolean checkLiteralInstantiation(PsiMethod constructor,
Processor<PsiReference> 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);
}
}
@@ -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();
}
@@ -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<GrListOrMapImpl, PsiType> {
@Nullable
public PsiType fun(GrListOrMapImpl listOrMap) {
@@ -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())
}
}