IDEA-51686 Groovy syntax parser does not recognize that indexing using array returns a slice

This commit is contained in:
Maxim Medvedev
2010-07-29 16:03:30 +04:00
parent 1dc19a233a
commit dbcf1c6781
7 changed files with 34 additions and 24 deletions
@@ -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;
@@ -58,4 +58,5 @@ class GrCompletionTestWithLibrary extends GroovyCompletionTestBase {
public void testCategoryProperty() {doBasicTest()}
public void testMultipleCategories() {doBasicTest()}
public void testArrayLikeAccessForList() throws Throwable {doBasicTest(); }
}
@@ -96,10 +96,6 @@ public class GroovyCompletionTest extends GroovyCompletionTestBase {
doBasicTest();
}
public void testArrayLikeAccessForList() throws Throwable {
doBasicTest();
}
public void testArrayLikeAccessForMap() throws Throwable {
doBasicTest();
}
@@ -117,4 +117,9 @@ public class TypeInferenceTest extends GroovyResolveTestCase {
final GrReferenceExpression ref = (GrReferenceExpression)configureByFile("genericWildcard/A.groovy").getElement();
assertEquals("A<Base>", ref.getType().getCanonicalText());
}
public void testArrayLikeAccessWithIntSequence() {
final GrReferenceExpression ref = (GrReferenceExpression)configureByFile("arrayLikeAccessWithIntSequence/A.groovy").getElement();
assertEquals("java.util.List", ref.getType().getCanonicalText());
}
}
@@ -0,0 +1,4 @@
def foo = [1, 2, 5]
def list = foo[1, 2]
print l<ref>ist