From dbcf1c6781fc3e80e918675f7e52f4d704471372 Mon Sep 17 00:00:00 2001 From: Maxim Medvedev Date: Thu, 29 Jul 2010 16:03:30 +0400 Subject: [PATCH] IDEA-51686 Groovy syntax parser does not recognize that indexing using array returns a slice --- .../expressions/path/GrIndexPropertyImpl.java | 44 ++++++++++--------- .../groovy/GrCompletionTestWithLibrary.groovy | 1 + .../plugins/groovy/GroovyCompletionTest.java | 4 -- .../lang/resolve/TypeInferenceTest.java | 5 +++ .../ArrayLikeAccessForList.groovy | 0 .../ArrayLikeAccessForList_after.groovy | 0 .../arrayLikeAccessWithIntSequence/A.groovy | 4 ++ 7 files changed, 34 insertions(+), 24 deletions(-) rename plugins/groovy/testdata/groovy/{completion => completionWithLibrary}/ArrayLikeAccessForList.groovy (100%) rename plugins/groovy/testdata/groovy/{completion => completionWithLibrary}/ArrayLikeAccessForList_after.groovy (100%) create mode 100644 plugins/groovy/testdata/resolve/inference/arrayLikeAccessWithIntSequence/A.groovy diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/path/GrIndexPropertyImpl.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/path/GrIndexPropertyImpl.java index e30d24327ee4..4bf6c6faf70f 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/path/GrIndexPropertyImpl.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/path/GrIndexPropertyImpl.java @@ -19,18 +19,19 @@ package org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.path; import com.intellij.lang.ASTNode; import com.intellij.psi.*; import com.intellij.psi.util.InheritanceUtil; -import com.intellij.psi.util.PsiUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.plugins.groovy.lang.psi.GroovyElementVisitor; import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult; import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentList; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.path.GrIndexProperty; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrGdkMethod; import org.jetbrains.plugins.groovy.lang.psi.impl.GrTupleType; import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.GrExpressionImpl; import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil; +import static com.intellij.psi.util.PsiUtil.substituteTypeParameter; +import static org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil.getSmartReturnType; + /** * @author ilyas */ @@ -74,38 +75,41 @@ public class GrIndexPropertyImpl extends GrExpressionImpl implements GrIndexProp argTypes[i] = argType; } - if (thisType instanceof GrTupleType) { + if (thisType instanceof GrTupleType && + argTypes.length == 1 && + TypesUtil.isAssignable(PsiType.INT, argTypes[0], getManager(), getResolveScope())) { PsiType[] types = ((GrTupleType)thisType).getParameters(); return types.length == 1 ? types[0] : null; } PsiType overloadedOperatorType = null; - final GroovyResolveResult[] candidates = TypesUtil.getOverloadedOperatorCandidates(thisType, "getAt", this, argTypes); + GroovyResolveResult[] candidates = TypesUtil.getOverloadedOperatorCandidates(thisType, "getAt", this, argTypes); + if (candidates.length != 1) { + candidates = TypesUtil.getOverloadedOperatorCandidates(thisType, "getAt", this, new PsiType[]{ + new GrTupleType(argTypes, JavaPsiFacade.getInstance(getProject()), getResolveScope())}); + } if (candidates.length == 1) { final PsiElement element = candidates[0].getElement(); if (element instanceof PsiMethod) { - overloadedOperatorType = candidates[0].getSubstitutor().substitute(org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil.getSmartReturnType((PsiMethod)element)); - if (overloadedOperatorType != null && !(element instanceof GrGdkMethod)) { //gdk 'getAt' methods don't have information about type parameters - return overloadedOperatorType; - } + overloadedOperatorType = candidates[0].getSubstitutor().substitute(getSmartReturnType((PsiMethod)element)); } } - if (thisType instanceof PsiArrayType) { - PsiType componentType = ((PsiArrayType)thisType).getComponentType(); - return TypesUtil.boxPrimitiveType(componentType, getManager(), getResolveScope()); + PsiType componentType = null; + if (thisType instanceof PsiArrayType && + argTypes.length == 1 && + TypesUtil.isAssignable(PsiType.INT, argTypes[0], getManager(), getResolveScope())) { + componentType = TypesUtil.boxPrimitiveType(((PsiArrayType)thisType).getComponentType(), getManager(), getResolveScope()); + } + else if (InheritanceUtil.isInheritor(thisType, CommonClassNames.JAVA_UTIL_MAP) && argTypes.length == 1) { + componentType = substituteTypeParameter(thisType, CommonClassNames.JAVA_UTIL_MAP, 1, true); } - if (InheritanceUtil.isInheritor(thisType, CommonClassNames.JAVA_UTIL_LIST)) { - PsiType iterType = PsiUtil.extractIterableTypeParameter(thisType, true); - if (iterType != null) return iterType; + if (overloadedOperatorType != null && + (componentType == null || !TypesUtil.isAssignable(overloadedOperatorType, componentType, getManager(), getResolveScope()))) { + return overloadedOperatorType; } - - if (InheritanceUtil.isInheritor(thisType, CommonClassNames.JAVA_UTIL_MAP)) { - return PsiUtil.substituteTypeParameter(thisType, CommonClassNames.JAVA_UTIL_MAP, 1, true); - } - - return overloadedOperatorType; + return componentType; } } return null; diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/GrCompletionTestWithLibrary.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/GrCompletionTestWithLibrary.groovy index 967dcc8d2b23..2297b11c51b9 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/GrCompletionTestWithLibrary.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/GrCompletionTestWithLibrary.groovy @@ -58,4 +58,5 @@ class GrCompletionTestWithLibrary extends GroovyCompletionTestBase { public void testCategoryProperty() {doBasicTest()} public void testMultipleCategories() {doBasicTest()} + public void testArrayLikeAccessForList() throws Throwable {doBasicTest(); } } diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/GroovyCompletionTest.java b/plugins/groovy/test/org/jetbrains/plugins/groovy/GroovyCompletionTest.java index cbcb20662b39..db2e370bec05 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/GroovyCompletionTest.java +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/GroovyCompletionTest.java @@ -96,10 +96,6 @@ public class GroovyCompletionTest extends GroovyCompletionTestBase { doBasicTest(); } - public void testArrayLikeAccessForList() throws Throwable { - doBasicTest(); - } - public void testArrayLikeAccessForMap() throws Throwable { doBasicTest(); } diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/TypeInferenceTest.java b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/TypeInferenceTest.java index 65d2d74e5b97..bfe4adfa098a 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/TypeInferenceTest.java +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/TypeInferenceTest.java @@ -117,4 +117,9 @@ public class TypeInferenceTest extends GroovyResolveTestCase { final GrReferenceExpression ref = (GrReferenceExpression)configureByFile("genericWildcard/A.groovy").getElement(); assertEquals("A", ref.getType().getCanonicalText()); } + + public void testArrayLikeAccessWithIntSequence() { + final GrReferenceExpression ref = (GrReferenceExpression)configureByFile("arrayLikeAccessWithIntSequence/A.groovy").getElement(); + assertEquals("java.util.List", ref.getType().getCanonicalText()); + } } diff --git a/plugins/groovy/testdata/groovy/completion/ArrayLikeAccessForList.groovy b/plugins/groovy/testdata/groovy/completionWithLibrary/ArrayLikeAccessForList.groovy similarity index 100% rename from plugins/groovy/testdata/groovy/completion/ArrayLikeAccessForList.groovy rename to plugins/groovy/testdata/groovy/completionWithLibrary/ArrayLikeAccessForList.groovy diff --git a/plugins/groovy/testdata/groovy/completion/ArrayLikeAccessForList_after.groovy b/plugins/groovy/testdata/groovy/completionWithLibrary/ArrayLikeAccessForList_after.groovy similarity index 100% rename from plugins/groovy/testdata/groovy/completion/ArrayLikeAccessForList_after.groovy rename to plugins/groovy/testdata/groovy/completionWithLibrary/ArrayLikeAccessForList_after.groovy diff --git a/plugins/groovy/testdata/resolve/inference/arrayLikeAccessWithIntSequence/A.groovy b/plugins/groovy/testdata/resolve/inference/arrayLikeAccessWithIntSequence/A.groovy new file mode 100644 index 000000000000..d176af95fc38 --- /dev/null +++ b/plugins/groovy/testdata/resolve/inference/arrayLikeAccessWithIntSequence/A.groovy @@ -0,0 +1,4 @@ +def foo = [1, 2, 5] +def list = foo[1, 2] + +print list \ No newline at end of file