From a57110b5862925fb43b89531feb91623df57523f Mon Sep 17 00:00:00 2001 From: peter Date: Thu, 29 Jul 2010 21:37:42 +0100 Subject: [PATCH] search for map constructors now --- .../GroovyConstructorUsagesSearcher.java | 104 +++++++++++++----- .../lang/LiteralConstructorUsagesTest.groovy | 38 +++++++ 2 files changed, 117 insertions(+), 25 deletions(-) diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/findUsages/GroovyConstructorUsagesSearcher.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/findUsages/GroovyConstructorUsagesSearcher.java index 852872969121..493de46d9ddd 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/findUsages/GroovyConstructorUsagesSearcher.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/findUsages/GroovyConstructorUsagesSearcher.java @@ -53,7 +53,9 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrConstructorInvocat 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.GrArgumentLabel; import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentList; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrNamedArgument; import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrOpenBlock; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.*; import org.jetbrains.plugins.groovy.lang.psi.api.statements.params.GrParameter; @@ -65,6 +67,7 @@ import org.jetbrains.plugins.groovy.lang.psi.api.types.GrCodeReferenceElement; import org.jetbrains.plugins.groovy.lang.psi.api.types.GrTypeElement; import org.jetbrains.plugins.groovy.lang.psi.controlFlow.Instruction; import org.jetbrains.plugins.groovy.lang.psi.expectedTypes.GroovyExpectedTypesProvider; +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; @@ -112,12 +115,10 @@ public class GroovyConstructorUsagesSearcher extends QueryExecutorBase newExpressionProcessor = new Processor() { @Override public boolean process(GrNewExpression grNewExpression) { @@ -129,7 +130,7 @@ public class GroovyConstructorUsagesSearcher extends QueryExecutorBase newExpressionProcessor, final PairProcessor literalProcessor) { final Set processedMethods = new ConcurrentHashSet(); @@ -164,7 +164,7 @@ public class GroovyConstructorUsagesSearcher extends QueryExecutorBase literalProcessor) { final SearchScope gppScope = getGppScope(targetClass.getProject()).intersectWith(scope); final ReadActionProcessor gppCallProcessor = new ReadActionProcessor() { @@ -214,7 +213,7 @@ public class GroovyConstructorUsagesSearcher extends QueryExecutorBase newExpressionProcessor, - final boolean mapsNeeded, - final PairProcessor literalProcessor) { + boolean usualCallsOnly, + final Processor newExpressionProcessor, + final PairProcessor literalProcessor) { PsiElement parent = element.getParent(); if (parent instanceof GrAnonymousClassDefinition) { @@ -280,7 +278,7 @@ public class GroovyConstructorUsagesSearcher extends QueryExecutorBase literalProcessor, boolean mapsNeeded) { + private static boolean checkLiteralInstantiation(GrExpression expression, + final GrTypeElement typeElement, + final PairProcessor literalProcessor) { - if (expression instanceof GrListOrMap && mapsNeeded == ((GrListOrMap)expression).isMap()) { + if (expression instanceof GrListOrMap) { final PsiType expectedType = typeElement.getType(); if (expectedType instanceof PsiClassType) { return literalProcessor.process((GrListOrMap)expression, (PsiClassType)expectedType); @@ -355,23 +355,77 @@ public class GroovyConstructorUsagesSearcher extends QueryExecutorBase consumer, - GrListOrMap list, + GrListOrMap literal, PsiClassType expectedType) { - final PsiType listType = list.getType(); + final PsiType listType = literal.getType(); if (listType instanceof GrTupleType) { - for (GroovyResolveResult candidate : PsiUtil.getConstructorCandidates(expectedType, ((GrTupleType)listType).getComponentTypes(), list)) { - if (constructor.getManager().areElementsEquivalent(candidate.getElement(), constructor)) { - if (!consumer.process(PsiReferenceBase.createSelfReference(list, TextRange.from(0, list.getTextLength()), constructor))) { + if (isConstructorCall(expectedType, ((GrTupleType)listType).getComponentTypes(), constructor, literal)) { + return consumer.process(PsiReferenceBase.createSelfReference(literal, TextRange.from(0, literal.getTextLength()), constructor)); + } + } + 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())) { + if (mayInvokeConstructor(expectedType, constructor, argument.getExpression())) { + return consumer.process(PsiReferenceBase.createSelfReference(label, TextRange.from(0, label.getTextLength()), constructor)); + } + return true; + } + } + + //no 'super', only default constructor applicable + if (constructor.getParameterList().getParametersCount() == 0) { + return consumer.process(PsiReferenceBase.createSelfReference(literal, TextRange.from(0, literal.getTextLength()), constructor)); } } return true; } + private static boolean mayInvokeConstructor(PsiClassType expectedType, PsiMethod constructor, GrExpression args) { + if (args == null) { + return true; + } + + final PsiType type = args.getType(); + if (type == null) { + return true; + } + + if (type instanceof GrTupleType) { + if (!isConstructorCall(expectedType, ((GrTupleType)type).getComponentTypes(), constructor, args)) { + return false; + } + } else if (!isConstructorCall(expectedType, new PsiType[]{type}, constructor, args)) { + return false; + } + return true; + } + + private static boolean isConstructorCall(PsiClassType expectedType, + PsiType[] argTypes, + PsiMethod constructor, + GroovyPsiElement context) { + for (GroovyResolveResult candidate : PsiUtil.getConstructorCandidates(expectedType, argTypes, context)) { + if (constructor.getManager().areElementsEquivalent(candidate.getElement(), constructor)) { + return true; + } + } + return false; + } + private static boolean processConstructors(final PsiMethod searchedConstructor, final Processor consumer, final PsiClass clazz, final boolean processThisRefs) { final PsiMethod[] constructors = clazz.getConstructors(); 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 00432a8cb4d0..ee34be8156ac 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/LiteralConstructorUsagesTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/LiteralConstructorUsagesTest.groovy @@ -48,6 +48,26 @@ class LiteralConstructorUsagesTest extends LightCodeInsightFixtureTestCase { assertOneElement(ReferencesSearch.search(foo.constructors[0]).findAll()) } + public void testMap_AsCast() throws Exception { + def foo = myFixture.addClass("""class Foo { + Foo() {} + } +}""") + myFixture.addFileToProject "a.groovy", "def x = [:] as Foo" + assertOneElement(ReferencesSearch.search(foo.constructors[0]).findAll()) + } + + public void testMapSuper_AsCast() throws Exception { + def foo = myFixture.addClass("""class Foo { + Foo(int a) {} + } +}""") + myFixture.addFileToProject "a.gpp", "def x = ['super':[2]] as Foo" + myFixture.addFileToProject "c.gpp", "def x = [super:2] as Foo" + + assertEquals(2, ReferencesSearch.search(foo.constructors[0]).findAll().size()) + } + public void testList_GppMethodCall() throws Exception { //------------------------declarations def foo = myFixture.addClass(""" @@ -100,4 +120,22 @@ class LiteralConstructorUsagesTest extends LightCodeInsightFixtureTestCase { assertEquals(3, ReferencesSearch.search(foo.constructors[0]).findAll().size()) } + public void testMap_GppOverloads() throws Exception { + def foo = myFixture.addClass(""" + class Foo { + Foo() {} + Foo(int a) {} + } + """) + + myFixture.addClass(""" + class Bar { + static void foo(Foo f1, Foo f2) {} + } + """) + myFixture.addFileToProject "a.gpp", "Bar.foo([:], [super:2])" + assertEquals(1, ReferencesSearch.search(foo.constructors[0]).findAll().size()) + assertEquals(1, ReferencesSearch.search(foo.constructors[1]).findAll().size()) + } + }