diff --git a/plugins/groovy/groovypp/src/org/jetbrains/plugins/groovy/gpp/GppTypeConverter.java b/plugins/groovy/groovypp/src/org/jetbrains/plugins/groovy/gpp/GppTypeConverter.java index 0ebb8448b4db..64ba6c939cad 100644 --- a/plugins/groovy/groovypp/src/org/jetbrains/plugins/groovy/gpp/GppTypeConverter.java +++ b/plugins/groovy/groovypp/src/org/jetbrains/plugins/groovy/gpp/GppTypeConverter.java @@ -44,18 +44,17 @@ public class GppTypeConverter extends GrTypeConverter { @Override public Boolean isConvertible(@NotNull PsiType lType, @NotNull PsiType rType, @NotNull GroovyPsiElement context) { if (rType instanceof GrTupleType) { - final PsiType type = PsiUtil.extractIterableTypeParameter(lType, false); - if (type == null || TypesUtil.isAssignable(type, ((GrTupleType)rType).getParameters()[0], context)) { - final PsiType[] componentTypes = ((GrTupleType)rType).getComponentTypes(); + final GrTupleType tupleType = (GrTupleType)rType; - final PsiType expectedComponent = PsiUtil.extractIterableTypeParameter(lType, false); - if (expectedComponent != null && hasDefaultConstructor(lType)) { - return true; - } + final PsiType expectedComponent = PsiUtil.extractIterableTypeParameter(lType, false); + if (expectedComponent != null && + isMethodCallConversion(context) && TypesUtil.isAssignable(expectedComponent, tupleType.getParameters()[0], context) && + hasDefaultConstructor(lType)) { + return true; + } - if (lType instanceof PsiClassType && hasConstructor((PsiClassType)lType, componentTypes, context)) { - return true; - } + if (lType instanceof PsiClassType && hasConstructor((PsiClassType)lType, tupleType.getComponentTypes(), context)) { + return true; } } else if (rType instanceof GrMapType) { diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionContributor.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionContributor.java index 6b32b8c7ac69..639b59d79656 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionContributor.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionContributor.java @@ -261,7 +261,7 @@ public class GroovyCompletionContributor extends CompletionContributor { } else if (call instanceof GrCallExpression) { GrCallExpression constructorCall = (GrCallExpression)call; - ContainerUtil.addAll(results, constructorCall.getMethodVariants()); + ContainerUtil.addAll(results, constructorCall.getMethodVariants(null)); final PsiType type = ((GrCallExpression)call).getType(); if (type instanceof PsiClassType) { final PsiClass psiClass = ((PsiClassType)type).resolve(); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/GrTypeConverter.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/GrTypeConverter.java index 3fdc0239b076..4f3b20e1ed4f 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/GrTypeConverter.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/GrTypeConverter.java @@ -5,6 +5,7 @@ import com.intellij.psi.PsiElement; import com.intellij.psi.PsiType; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrMethodCall; /** * @author peter @@ -12,7 +13,11 @@ import org.jetbrains.annotations.Nullable; public abstract class GrTypeConverter { public static final ExtensionPointName EP_NAME = ExtensionPointName.create("org.intellij.groovy.typeConverter"); + protected static boolean isMethodCallConversion(GroovyPsiElement context) { + return context.getParent() instanceof GrMethodCall; + } + @Nullable public abstract Boolean isConvertible(@NotNull PsiType lType, @NotNull PsiType rType, @NotNull GroovyPsiElement context); -} \ No newline at end of file +} diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/api/statements/expressions/path/GrCallExpression.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/api/statements/expressions/path/GrCallExpression.java index 84cf9d13c549..48aeb07117d5 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/api/statements/expressions/path/GrCallExpression.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/api/statements/expressions/path/GrCallExpression.java @@ -43,7 +43,7 @@ public interface GrCallExpression extends GrExpression, GrCall { PsiMethod resolveMethod(); @NotNull - GroovyResolveResult[] getMethodVariants(); + GroovyResolveResult[] getMethodVariants(@Nullable GrExpression upToArgument); //PsiElement addNamedArgument(GrNamedArgument argument); } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/expectedTypes/GroovyExpectedTypesProvider.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/expectedTypes/GroovyExpectedTypesProvider.java index a382c23d87e6..a37a96beddbd 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/expectedTypes/GroovyExpectedTypesProvider.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/expectedTypes/GroovyExpectedTypesProvider.java @@ -127,7 +127,7 @@ public class GroovyExpectedTypesProvider { final int closureIndex = closureArgs.indexOf(myExpression); if (closureIndex >= 0) { List constraints = new ArrayList(); - for (GroovyResolveResult variant : methodCall.getMethodVariants()) { + for (GroovyResolveResult variant : ResolveUtil.getMethodVariants(myExpression)) { PsiParameter[] parameters = getCallParameters(variant); if (parameters == null || parameters.length == 0) continue; diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrContainerTypeConverter.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrContainerTypeConverter.java index 2fd193c1203a..a243ff54012b 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrContainerTypeConverter.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrContainerTypeConverter.java @@ -32,6 +32,10 @@ import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUt public class GrContainerTypeConverter extends GrTypeConverter { @Override public Boolean isConvertible(@NotNull PsiType lType, @NotNull PsiType rType, @NotNull GroovyPsiElement context) { + if (isMethodCallConversion(context)) { + return null; + } + if (!isCollectionOrArray(lType) || !isCollectionOrArray(rType)) return null; final PsiType lComponentType = extractComponentType(lType); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrMapType.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrMapType.java index 7f0c4391bbf4..2a45e985ae61 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrMapType.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrMapType.java @@ -115,7 +115,9 @@ public class GrMapType extends GrLiteralClassType { for (Pair entry : myOtherEntries) { components.add(getInternalCanonicalText(entry.first) + ":" + getInternalCanonicalText(entry.second)); } - return "[" + StringUtil.join(components, ", ") + "]"; + boolean tooMany = components.size() > 2; + final List theFirst = components.subList(0, Math.min(2, components.size())); + return "[" + StringUtil.join(theFirst, ", ") + (tooMany ? ",..." : "") + "]"; } public boolean isValid() { diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrTupleType.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrTupleType.java index 13fc908f461e..8dd75907f1ad 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrTupleType.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrTupleType.java @@ -59,6 +59,11 @@ public class GrTupleType extends GrLiteralClassType { StringBuilder builder = new StringBuilder(); builder.append("["); for (int i = 0; i < myComponentTypes.length; i++) { + if (i >= 2) { + builder.append(",..."); + break; + } + if (i > 0) builder.append(", "); builder.append(getInternalCanonicalText(myComponentTypes[i])); } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrNewExpressionImpl.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrNewExpressionImpl.java index d3726e2b1077..b79ecbde0668 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrNewExpressionImpl.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrNewExpressionImpl.java @@ -42,7 +42,6 @@ import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil; import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; /** @@ -183,7 +182,7 @@ public class GrNewExpressionImpl extends GrCallExpressionImpl implements GrNewEx } @NotNull - public GroovyResolveResult[] getMethodVariants() { + public GroovyResolveResult[] getMethodVariants(@Nullable GrExpression upToArgument) { final GrCodeReferenceElement referenceElement = getReferenceElement(); if (referenceElement == null) return GroovyResolveResult.EMPTY_ARRAY; final GroovyResolveResult[] classResults = referenceElement.multiResolve(false); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrReferenceExpressionImpl.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrReferenceExpressionImpl.java index b62e74f3c2af..16311308b982 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrReferenceExpressionImpl.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrReferenceExpressionImpl.java @@ -28,7 +28,10 @@ import com.intellij.psi.tree.IElementType; import com.intellij.psi.util.PropertyUtil; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.TypeConversionUtil; -import com.intellij.util.*; +import com.intellij.util.ArrayUtil; +import com.intellij.util.Consumer; +import com.intellij.util.Function; +import com.intellij.util.IncorrectOperationException; import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -61,7 +64,6 @@ import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil; import org.jetbrains.plugins.groovy.lang.resolve.processors.*; import java.util.ArrayList; -import java.util.Arrays; import java.util.EnumSet; import java.util.List; @@ -413,7 +415,7 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl implements Kind kind = refExpr.getKind(); if (incompleteCode) { ResolverProcessor processor = CompletionProcessor.createRefSameNameProcessor(refExpr, name); - resolveImpl(refExpr, processor); + refExpr.resolveImpl(processor); GroovyResolveResult[] propertyCandidates = processor.getCandidates(); if (propertyCandidates.length > 0) return propertyCandidates; } @@ -436,7 +438,7 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl implements GroovyResolveResult[] classCandidates = GroovyResolveResult.EMPTY_ARRAY; if (!hasAt) { ResolverProcessor classProcessor = new ClassResolverProcessor(refExpr.getReferenceName(), refExpr, kinds); - resolveImpl(refExpr, classProcessor); + refExpr.resolveImpl(classProcessor); classCandidates = classProcessor.getCandidates(); for (GroovyResolveResult classCandidate : classCandidates) { final PsiElement element = classCandidate.getElement(); @@ -447,7 +449,7 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl implements } ResolverProcessor processor = new PropertyResolverProcessor(name, refExpr); - resolveImpl(refExpr, processor); + refExpr.resolveImpl(processor); final GroovyResolveResult[] fieldCandidates = processor.getCandidates(); if (refExpr.hasAt()) { @@ -471,7 +473,7 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl implements List accessorResults = new ArrayList(); for (String getterName : names) { AccessorResolverProcessor accessorResolver = new AccessorResolverProcessor(getterName, refExpr, !isLValue); - resolveImpl(refExpr, accessorResolver); + refExpr.resolveImpl(accessorResolver); final GroovyResolveResult[] candidates = accessorResolver.getCandidates(); //can be only one candidate if (candidates.length == 1 && candidates[0].isStaticsOK()) { return candidates; @@ -488,18 +490,15 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl implements private static GroovyResolveResult[] resolveMethodOrProperty(GrReferenceExpressionImpl refExpr, String name) { final PsiType[] argTypes = PsiUtil.getArgumentTypes(refExpr, false); - PsiType thisType = getThisType(refExpr); - - MethodResolverProcessor methodResolver = - new MethodResolverProcessor(name, refExpr, false, thisType, argTypes, refExpr.getTypeArguments()); - resolveImpl(refExpr, methodResolver); + MethodResolverProcessor methodResolver = refExpr.runMethodResolverProcessor(argTypes, false); + assert methodResolver != null; if (methodResolver.hasApplicableCandidates()) return methodResolver.getCandidates(); final String[] names = GroovyPropertyUtils.suggestGettersName(name); List list = new ArrayList(); for (String getterName : names) { AccessorResolverProcessor getterResolver = new AccessorResolverProcessor(getterName, refExpr, true); - resolveImpl(refExpr, getterResolver); + refExpr.resolveImpl(getterResolver); final GroovyResolveResult[] candidates = getterResolver.getCandidates(); //can be only one candidate if (candidates.length == 1 && candidates[0].isStaticsOK()) { refExpr.putUserData(IS_RESOLVED_TO_GETTER, true); @@ -511,7 +510,7 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl implements } PropertyResolverProcessor propertyResolver = new PropertyResolverProcessor(name, refExpr); - resolveImpl(refExpr, propertyResolver); + refExpr.resolveImpl(propertyResolver); if (propertyResolver.hasCandidates()) return propertyResolver.getCandidates(); if (methodResolver.hasCandidates()) { @@ -525,144 +524,158 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl implements return GroovyResolveResult.EMPTY_ARRAY; } + } - private static void resolveImpl(GrReferenceExpressionImpl refExpr, ResolverProcessor processor) { - GrExpression qualifier = refExpr.getQualifierExpression(); - if (qualifier == null) { - ResolveUtil.treeWalkUp(refExpr, processor, true); - if (!processor.hasCandidates()) { - qualifier = PsiImplUtil.getRuntimeQualifier(refExpr); - if (qualifier != null) { - processQualifier(refExpr, processor, qualifier); - } + private void resolveImpl(ResolverProcessor processor) { + GrExpression qualifier = getQualifierExpression(); + if (qualifier == null) { + ResolveUtil.treeWalkUp(this, processor, true); + if (!processor.hasCandidates()) { + qualifier = PsiImplUtil.getRuntimeQualifier(this); + if (qualifier != null) { + processQualifier(processor, qualifier); } + } + } else { + if (getDotTokenType() != GroovyTokenTypes.mSPREAD_DOT) { + processQualifier(processor, qualifier); } else { - if (refExpr.getDotTokenType() != GroovyTokenTypes.mSPREAD_DOT) { - processQualifier(refExpr, processor, qualifier); - } else { - processQualifierForSpreadDot(refExpr, processor, qualifier); - } - - if (qualifier instanceof GrReferenceExpression && "class".equals(((GrReferenceExpression)qualifier).getReferenceName())) { - processIfJavaLangClass(refExpr, processor, qualifier.getType()); - } else if (qualifier instanceof GrThisReferenceExpression) { - processIfJavaLangClass(refExpr, processor, qualifier.getType()); - } - } - } - - private static void processIfJavaLangClass(GrReferenceExpressionImpl refExpr, ResolverProcessor processor, PsiType type) { - if (type instanceof PsiClassType) { - final PsiClass psiClass = ((PsiClassType)type).resolve(); - if (psiClass != null && CommonClassNames.JAVA_LANG_CLASS.equals(psiClass.getQualifiedName())) { - final PsiType[] params = ((PsiClassType)type).getParameters(); - if (params.length == 1) { - processClassQualifierType(refExpr, processor, params[0]); - } - } - } - } - - private static void processQualifierForSpreadDot(GrReferenceExpressionImpl refExpr, ResolverProcessor processor, GrExpression qualifier) { - PsiType qualifierType = qualifier.getType(); - if (qualifierType instanceof PsiClassType) { - PsiClassType.ClassResolveResult result = ((PsiClassType) qualifierType).resolveGenerics(); - PsiClass clazz = result.getElement(); - if (clazz != null) { - PsiClass listClass = ResolveUtil.findListClass(refExpr.getManager(), refExpr.getResolveScope()); - if (listClass != null && listClass.getTypeParameters().length == 1) { - PsiSubstitutor substitutor = TypeConversionUtil.getClassSubstitutor(listClass, clazz, result.getSubstitutor()); - if (substitutor != null) { - PsiType componentType = substitutor.substitute(listClass.getTypeParameters()[0]); - if (componentType != null) { - processClassQualifierType(refExpr, processor, componentType); - } - } - } - } - } else if (qualifierType instanceof PsiArrayType) { - processClassQualifierType(refExpr, processor, ((PsiArrayType) qualifierType).getComponentType()); - } - } - - private static void processQualifier(GrReferenceExpressionImpl refExpr, ResolverProcessor processor, GrExpression qualifier) { - PsiType qualifierType = qualifier.getType(); - if (qualifierType == null) { - if (qualifier instanceof GrReferenceExpression) { - PsiElement resolved = ((GrReferenceExpression) qualifier).resolve(); - if (resolved instanceof PsiPackage) { - if (!resolved.processDeclarations(processor, ResolveState.initial(), null, refExpr)) //noinspection UnnecessaryReturnStatement - return; - } - else { - qualifierType = JavaPsiFacade.getInstance(refExpr.getProject()).getElementFactory() - .createTypeByFQClassName(CommonClassNames.JAVA_LANG_OBJECT, refExpr.getResolveScope()); - processClassQualifierType(refExpr, processor, qualifierType); - } - } - } else { - if (qualifierType instanceof PsiIntersectionType) { - for (PsiType conjunct : ((PsiIntersectionType) qualifierType).getConjuncts()) { - processClassQualifierType(refExpr, processor, conjunct); - } - } else { - processClassQualifierType(refExpr, processor, qualifierType); - if (qualifier instanceof GrReferenceExpression) { - PsiElement resolved = ((GrReferenceExpression) qualifier).resolve(); - if (resolved instanceof PsiClass) { //omitted .class - PsiClass javaLangClass = PsiUtil.getJavaLangClass(resolved, refExpr.getResolveScope()); - if (javaLangClass != null) { - ResolveState state = ResolveState.initial(); - PsiTypeParameter[] typeParameters = javaLangClass.getTypeParameters(); - PsiSubstitutor substitutor = state.get(PsiSubstitutor.KEY); - if (substitutor == null) substitutor = PsiSubstitutor.EMPTY; - if (typeParameters.length == 1) { - substitutor = substitutor.put(typeParameters[0], qualifierType); - state = state.put(PsiSubstitutor.KEY, substitutor); - } - if (!javaLangClass.processDeclarations(processor, state, null, refExpr)) return; - PsiType javaLangClassType = JavaPsiFacade.getInstance(refExpr.getProject()).getElementFactory().createType(javaLangClass, substitutor); - ResolveUtil.processNonCodeMethods(javaLangClassType, processor, refExpr, false); - } - } - } - } - } - } - - private static void processClassQualifierType(GrReferenceExpressionImpl refExpr, ResolverProcessor processor, PsiType qualifierType) { - Project project = refExpr.getProject(); - if (qualifierType instanceof PsiClassType) { - PsiClassType.ClassResolveResult qualifierResult = ((PsiClassType) qualifierType).resolveGenerics(); - PsiClass qualifierClass = qualifierResult.getElement(); - if (qualifierClass != null) { - if (!qualifierClass.processDeclarations(processor, - ResolveState.initial().put(PsiSubstitutor.KEY, qualifierResult.getSubstitutor()), null, refExpr)) - return; - } - if (!ResolveUtil.processCategoryMembers(refExpr, processor)) return; - } else if (qualifierType instanceof PsiArrayType) { - final GrTypeDefinition arrayClass = GroovyPsiManager.getInstance(project).getArrayClass(); - if (!arrayClass.processDeclarations(processor, ResolveState.initial(), null, refExpr)) return; - } else if (qualifierType instanceof PsiIntersectionType) { - for (PsiType conjunct : ((PsiIntersectionType) qualifierType).getConjuncts()) { - processClassQualifierType(refExpr, processor, conjunct); - } - return; + processQualifierForSpreadDot(processor, qualifier); } - ResolveUtil.processNonCodeMethods(qualifierType, processor, refExpr, false); + if (qualifier instanceof GrReferenceExpression && "class".equals(((GrReferenceExpression)qualifier).getReferenceName())) { + processIfJavaLangClass(processor, qualifier.getType()); + } else if (qualifier instanceof GrThisReferenceExpression) { + processIfJavaLangClass(processor, qualifier.getType()); + } } } - private static PsiType getThisType(GrReferenceExpression refExpr) { - GrExpression qualifier = refExpr.getQualifierExpression(); + private void processIfJavaLangClass(ResolverProcessor processor, PsiType type) { + if (type instanceof PsiClassType) { + final PsiClass psiClass = ((PsiClassType)type).resolve(); + if (psiClass != null && CommonClassNames.JAVA_LANG_CLASS.equals(psiClass.getQualifiedName())) { + final PsiType[] params = ((PsiClassType)type).getParameters(); + if (params.length == 1) { + processClassQualifierType(processor, params[0]); + } + } + } + } + + private void processQualifierForSpreadDot(ResolverProcessor processor, GrExpression qualifier) { + PsiType qualifierType = qualifier.getType(); + if (qualifierType instanceof PsiClassType) { + PsiClassType.ClassResolveResult result = ((PsiClassType) qualifierType).resolveGenerics(); + PsiClass clazz = result.getElement(); + if (clazz != null) { + PsiClass listClass = ResolveUtil.findListClass(getManager(), getResolveScope()); + if (listClass != null && listClass.getTypeParameters().length == 1) { + PsiSubstitutor substitutor = TypeConversionUtil.getClassSubstitutor(listClass, clazz, result.getSubstitutor()); + if (substitutor != null) { + PsiType componentType = substitutor.substitute(listClass.getTypeParameters()[0]); + if (componentType != null) { + processClassQualifierType(processor, componentType); + } + } + } + } + } else if (qualifierType instanceof PsiArrayType) { + processClassQualifierType(processor, ((PsiArrayType) qualifierType).getComponentType()); + } + } + + private void processQualifier(ResolverProcessor processor, GrExpression qualifier) { + PsiType qualifierType = qualifier.getType(); + if (qualifierType == null) { + if (qualifier instanceof GrReferenceExpression) { + PsiElement resolved = ((GrReferenceExpression) qualifier).resolve(); + if (resolved instanceof PsiPackage) { + if (!resolved.processDeclarations(processor, ResolveState.initial(), null, this)) //noinspection UnnecessaryReturnStatement + return; + } + else { + qualifierType = JavaPsiFacade.getInstance(getProject()).getElementFactory() + .createTypeByFQClassName(CommonClassNames.JAVA_LANG_OBJECT, getResolveScope()); + processClassQualifierType(processor, qualifierType); + } + } + } else { + if (qualifierType instanceof PsiIntersectionType) { + for (PsiType conjunct : ((PsiIntersectionType) qualifierType).getConjuncts()) { + processClassQualifierType(processor, conjunct); + } + } else { + processClassQualifierType(processor, qualifierType); + if (qualifier instanceof GrReferenceExpression) { + PsiElement resolved = ((GrReferenceExpression) qualifier).resolve(); + if (resolved instanceof PsiClass) { //omitted .class + PsiClass javaLangClass = PsiUtil.getJavaLangClass(resolved, getResolveScope()); + if (javaLangClass != null) { + ResolveState state = ResolveState.initial(); + PsiTypeParameter[] typeParameters = javaLangClass.getTypeParameters(); + PsiSubstitutor substitutor = state.get(PsiSubstitutor.KEY); + if (substitutor == null) substitutor = PsiSubstitutor.EMPTY; + if (typeParameters.length == 1) { + substitutor = substitutor.put(typeParameters[0], qualifierType); + state = state.put(PsiSubstitutor.KEY, substitutor); + } + if (!javaLangClass.processDeclarations(processor, state, null, this)) return; + PsiType javaLangClassType = JavaPsiFacade.getInstance(getProject()).getElementFactory().createType(javaLangClass, substitutor); + ResolveUtil.processNonCodeMethods(javaLangClassType, processor, this, false); + } + } + } + } + } + } + + private void processClassQualifierType(ResolverProcessor processor, PsiType qualifierType) { + Project project = getProject(); + if (qualifierType instanceof PsiClassType) { + PsiClassType.ClassResolveResult qualifierResult = ((PsiClassType) qualifierType).resolveGenerics(); + PsiClass qualifierClass = qualifierResult.getElement(); + if (qualifierClass != null) { + if (!qualifierClass.processDeclarations(processor, + ResolveState.initial().put(PsiSubstitutor.KEY, qualifierResult.getSubstitutor()), null, this)) + return; + } + if (!ResolveUtil.processCategoryMembers(this, processor)) return; + } else if (qualifierType instanceof PsiArrayType) { + final GrTypeDefinition arrayClass = GroovyPsiManager.getInstance(project).getArrayClass(); + if (!arrayClass.processDeclarations(processor, ResolveState.initial(), null, this)) return; + } else if (qualifierType instanceof PsiIntersectionType) { + for (PsiType conjunct : ((PsiIntersectionType) qualifierType).getConjuncts()) { + processClassQualifierType(processor, conjunct); + } + return; + } + + ResolveUtil.processNonCodeMethods(qualifierType, processor, this, false); + } + + @Nullable + public MethodResolverProcessor runMethodResolverProcessor(PsiType[] argTypes, final boolean allVariants) { + final String name = getReferenceName(); + if (name == null) { + return null; + } + + PsiType thisType = getThisType(); + + MethodResolverProcessor methodResolver = new MethodResolverProcessor(name, this, false, thisType, argTypes, getTypeArguments(), allVariants); + resolveImpl(methodResolver); + return methodResolver; + } + + private PsiType getThisType() { + GrExpression qualifier = getQualifierExpression(); if (qualifier != null) { PsiType qType = qualifier.getType(); if (qType != null) return qType; } - return TypesUtil.getJavaLangObject(refExpr); + return TypesUtil.getJavaLangObject(this); } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/TypesUtil.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/TypesUtil.java index f3d736fb87bc..26a0d6868e64 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/TypesUtil.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/TypesUtil.java @@ -233,6 +233,23 @@ public class TypesUtil { } public static boolean isAssignable(PsiType lType, PsiType rType, GroovyPsiElement context, boolean allowConversion) { + if (rType instanceof PsiIntersectionType) { + for (PsiType child : ((PsiIntersectionType)rType).getConjuncts()) { + if (isAssignable(lType, child, context, allowConversion)) { + return true; + } + } + return false; + } + if (lType instanceof PsiIntersectionType) { + for (PsiType child : ((PsiIntersectionType)lType).getConjuncts()) { + if (!isAssignable(child, rType, context, allowConversion)) { + return false; + } + } + return true; + } + if (allowConversion && lType != null && rType != null) { for (GrTypeConverter converter : GrTypeConverter.EP_NAME.getExtensions()) { final Boolean result = converter.isConvertible(lType, rType, context); @@ -267,7 +284,20 @@ public class TypesUtil { } public static boolean isAssignableByMethodCallConversion(PsiType lType, PsiType rType, GroovyPsiElement context) { - return isAssignableByMethodCallConversion(lType, rType, context.getManager(), context.getResolveScope()); + if (lType == null || rType == null) return false; + + if (isAssignableByMethodCallConversion(lType, rType, context.getManager(), context.getResolveScope())) { + return true; + } + + for (GrTypeConverter converter : GrTypeConverter.EP_NAME.getExtensions()) { + final Boolean result = converter.isConvertible(lType, rType, context); + if (result != null) { + return result; + } + } + + return false; } public static boolean isAssignableByMethodCallConversion(PsiType lType, PsiType rType, PsiManager manager, GlobalSearchScope scope) { diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/path/GrMethodCallExpressionImpl.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/path/GrMethodCallExpressionImpl.java index 720b0dcc0cd0..5a7033e7aefc 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/path/GrMethodCallExpressionImpl.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/path/GrMethodCallExpressionImpl.java @@ -41,9 +41,9 @@ import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.GrRefer import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil; import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil; import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil; +import org.jetbrains.plugins.groovy.lang.resolve.processors.MethodResolverProcessor; import java.util.ArrayList; -import java.util.Arrays; /** * @author ilyas @@ -187,21 +187,17 @@ public class GrMethodCallExpressionImpl extends GrCallExpressionImpl implements } @NotNull - public GroovyResolveResult[] getMethodVariants() { + public GroovyResolveResult[] getMethodVariants(@Nullable GrExpression upToArgument) { final GrExpression invoked = getInvokedExpression(); - if (!(invoked instanceof GrReferenceExpression)) return GroovyResolveResult.EMPTY_ARRAY; - final ArrayList res = new ArrayList(); + if (!(invoked instanceof GrReferenceExpressionImpl)) return GroovyResolveResult.EMPTY_ARRAY; - for (PsiReference ref : invoked.getReferences()) { - if (ref instanceof PsiPolyVariantReference) { - for (ResolveResult result : ((PsiPolyVariantReference)ref).multiResolve(true)) { - if (result instanceof GroovyResolveResult) { - res.add((GroovyResolveResult)result); - } - } - } + final PsiType[] partialArgs = PsiUtil.getArgumentTypes(invoked, false, upToArgument); + final MethodResolverProcessor processor = ((GrReferenceExpressionImpl)invoked).runMethodResolverProcessor(partialArgs, true); + if (processor != null) { + return processor.getCandidates(); } - return res.toArray(new GroovyResolveResult[res.size()]); + + return GroovyResolveResult.EMPTY_ARRAY; } } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/patterns/GroovyExpressionPattern.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/patterns/GroovyExpressionPattern.java index 2f6af4b020c7..67b76bf82b5b 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/patterns/GroovyExpressionPattern.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/patterns/GroovyExpressionPattern.java @@ -42,7 +42,7 @@ public class GroovyExpressionPattern method) { return new GroovyMethodCallPattern().and(this).with(new PatternCondition("methodCall") { public boolean accepts(@NotNull GrCallExpression callExpression, ProcessingContext context) { - final GroovyResolveResult[] results = callExpression.getMethodVariants(); + final GroovyResolveResult[] results = callExpression.getMethodVariants(null); for (GroovyResolveResult result : results) { if (method.getCondition().accepts(result.getElement(), context)) { return true; @@ -72,4 +72,4 @@ public class GroovyExpressionPattern result = new ArrayList(); @@ -193,6 +197,9 @@ public class PsiUtil { } else { result.add(type); } + if (stopAt == expression) { + return result.toArray(new PsiType[result.size()]); + } } GrClosableBlock[] closures = call.getClosureArguments(); @@ -201,6 +208,9 @@ public class PsiUtil { if (closureType != null) { result.add(closureType); } + if (stopAt == closure) { + break; + } } return result.toArray(new PsiType[result.size()]); @@ -224,6 +234,9 @@ public class PsiUtil { } else { result.add(type); } + if (stopAt == expression) { + break; + } } return result.toArray(new PsiType[result.size()]); @@ -245,6 +258,10 @@ public class PsiUtil { else { result.add(argType); } + if (stopAt == arg) { + break; + } + } return result.toArray(new PsiType[result.size()]); } else if (parent instanceof GrConstructorInvocation || parent instanceof GrEnumConstant) { @@ -264,6 +281,10 @@ public class PsiUtil { } else { result.add(type); } + if (stopAt == expression) { + break; + } + } return result.toArray(new PsiType[result.size()]); @@ -603,7 +624,7 @@ public class PsiUtil { } public static boolean isRawMethodCall(GrMethodCallExpression call) { - final GroovyResolveResult[] resolveResults = call.getMethodVariants(); + final GroovyResolveResult[] resolveResults = call.getMethodVariants(null); if (resolveResults.length == 0) return false; final PsiElement element = resolveResults[0].getElement(); if (element instanceof PsiMethod) { diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/resolve/ResolveUtil.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/resolve/ResolveUtil.java index 080c3de1fe9f..49a3ed5858e7 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/resolve/ResolveUtil.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/resolve/ResolveUtil.java @@ -444,7 +444,7 @@ public class ResolveUtil { final PsiElement parent = place.getParent(); GroovyResolveResult[] variants = GroovyResolveResult.EMPTY_ARRAY; if (parent instanceof GrCallExpression) { - variants = ((GrCallExpression) parent).getMethodVariants(); + variants = ((GrCallExpression) parent).getMethodVariants(place instanceof GrExpression ? (GrExpression)place : null); } else if (parent instanceof GrConstructorInvocation) { final PsiClass clazz = ((GrConstructorInvocation) parent).getDelegatedClass(); if (clazz != null) { diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/resolve/processors/MethodResolverProcessor.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/resolve/processors/MethodResolverProcessor.java index 901e599a4eef..3e225918b136 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/resolve/processors/MethodResolverProcessor.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/resolve/processors/MethodResolverProcessor.java @@ -50,6 +50,7 @@ public class MethodResolverProcessor extends ResolverProcessor { @Nullable private final PsiType[] myArgumentTypes; private final PsiType[] myTypeArguments; + private final boolean myAllVariants; private final Set myInapplicableCandidates = new LinkedHashSet(); private final boolean myIsConstructor; @@ -57,11 +58,15 @@ public class MethodResolverProcessor extends ResolverProcessor { private boolean myStopExecuting = false; public MethodResolverProcessor(String name, GroovyPsiElement place, boolean isConstructor, PsiType thisType, @Nullable PsiType[] argumentTypes, PsiType[] typeArguments) { + this(name, place, isConstructor, thisType, argumentTypes, typeArguments, false); + } + public MethodResolverProcessor(String name, GroovyPsiElement place, boolean isConstructor, PsiType thisType, @Nullable PsiType[] argumentTypes, PsiType[] typeArguments, boolean allVariants) { super(name, EnumSet.of(ResolveKind.METHOD, ResolveKind.PROPERTY), place, PsiType.EMPTY_ARRAY); myIsConstructor = isConstructor; myThisType = thisType; myArgumentTypes = argumentTypes; myTypeArguments = typeArguments; + myAllVariants = allVariants; } public boolean execute(PsiElement element, ResolveState state) { @@ -78,7 +83,7 @@ public class MethodResolverProcessor extends ResolverProcessor { boolean isAccessible = isAccessible(method); GroovyPsiElement fileResolveContext = state.get(RESOLVE_CONTEXT); boolean isStaticsOK = isStaticsOK(method, fileResolveContext); - if (PsiUtil.isApplicable(myArgumentTypes, method, substitutor, fileResolveContext instanceof GrMethodCallExpression, (GroovyPsiElement)myPlace) && isStaticsOK) { + if (!myAllVariants && PsiUtil.isApplicable(myArgumentTypes, method, substitutor, fileResolveContext instanceof GrMethodCallExpression, (GroovyPsiElement)myPlace) && isStaticsOK) { myCandidates.add(new GroovyResolveResultImpl(method, fileResolveContext, substitutor, isAccessible, isStaticsOK)); } else { myInapplicableCandidates.add(new GroovyResolveResultImpl(method, fileResolveContext, substitutor, isAccessible, isStaticsOK)); @@ -213,6 +218,10 @@ public class MethodResolverProcessor extends ResolverProcessor { @NotNull public GroovyResolveResult[] getCandidates() { + if (myAllVariants) { + return myInapplicableCandidates.toArray(new GroovyResolveResult[myInapplicableCandidates.size()]); + } + if (!myCandidates.isEmpty()) { return filterCandidates(); } diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GppFunctionalTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GppFunctionalTest.groovy index 6c26a5010bc4..345efb7e3450 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GppFunctionalTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GppFunctionalTest.groovy @@ -36,17 +36,17 @@ class GppFunctionalTest extends LightCodeInsightFixtureTestCase { super.setUp() } - public void _testCastListToIterable() throws Exception { + public void testCastListToIterable() throws Exception { myFixture.addClass("class X extends java.util.ArrayList {}") testAssignability """ X ints = [239, 4.2d] """ } - public void _testCastListToAnything() throws Exception { + public void testCastListToAnything() throws Exception { testAssignability """ File f1 = ['path'] -File f2 = ['path', 2, true, 42] +File f2 = ['path', 2, true, 42] """ } @@ -323,7 +323,7 @@ class BarImpl extends Bar {} return myFixture.file.findReferenceAt(myFixture.editor.caretModel.offset).resolve() } - public void _testMethodTypeParameterInference() throws Exception { + public void testMethodTypeParameterInference() throws Exception { configureScript """ @Typed package aaa @@ -334,7 +334,7 @@ r.apply { it.intVi } assertSameElements myFixture.getLookupElementStrings(), "intValue" } - public void _testMethodTypeParameterInference2() throws Exception { + public void testMethodTypeParameterInference2() throws Exception { configureScript """ @Typed package aaa @@ -385,4 +385,4 @@ class GppProjectDescriptor extends DefaultLightProjectDescriptor { modifiableModel.addRoot(JarFileSystem.instance.refreshAndFindFileByPath(TestUtils.mockGroovy1_7LibraryName + "!/"), OrderRootType.CLASSES); modifiableModel.commit(); } -} \ No newline at end of file +} diff --git a/plugins/groovy/testdata/highlighting/SignatureIsNotApplicableToList.groovy b/plugins/groovy/testdata/highlighting/SignatureIsNotApplicableToList.groovy index be1878b6974d..f0b8f175ba66 100644 --- a/plugins/groovy/testdata/highlighting/SignatureIsNotApplicableToList.groovy +++ b/plugins/groovy/testdata/highlighting/SignatureIsNotApplicableToList.groovy @@ -1,3 +1,3 @@ def foo(int... i) {} def list = [1, 2, 3] -foo(list) \ No newline at end of file +foo(list) \ No newline at end of file