From e60cb5cdff4aa1308ca9f4ada3f92a14e3d197ab Mon Sep 17 00:00:00 2001 From: Maxim Medvedev Date: Wed, 8 Jun 2011 21:22:23 +0400 Subject: [PATCH] IDEA-70711 Irritating warnings when using named arguments for a generic Map parameter --- .../arguments/GrArgumentLabelImpl.java | 3 - .../statements/expressions/TypesUtil.java | 59 ++++++++++++++++--- .../groovy/lang/GroovyHighlightingTest.java | 4 ++ .../NativeMapAssignability.groovy | 5 ++ .../NumberDuplicatesInMaps.groovy | 2 +- 5 files changed, 61 insertions(+), 12 deletions(-) create mode 100644 plugins/groovy/testdata/highlighting/NativeMapAssignability.groovy diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/arguments/GrArgumentLabelImpl.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/arguments/GrArgumentLabelImpl.java index 599f27ec3236..7e9d5fc342d3 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/arguments/GrArgumentLabelImpl.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/arguments/GrArgumentLabelImpl.java @@ -155,9 +155,6 @@ public class GrArgumentLabelImpl extends GroovyPsiElementImpl implements GrArgum if (value instanceof String) { return (String)value; } - if (value instanceof Number) { - return value.toString(); - } } final IElementType elemType = element.getNode().getElementType(); 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 b1294e0a2007..6c5e36b20a6b 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 @@ -22,6 +22,7 @@ import com.intellij.psi.impl.PsiSubstitutorImpl; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.tree.IElementType; import com.intellij.psi.util.InheritanceUtil; +import com.intellij.psi.util.PsiUtil; import com.intellij.psi.util.TypeConversionUtil; import com.intellij.util.containers.ComparatorUtil; import com.intellij.util.containers.HashMap; @@ -38,6 +39,7 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrBinary import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression; import org.jetbrains.plugins.groovy.lang.psi.api.types.GrClosureSignature; import org.jetbrains.plugins.groovy.lang.psi.impl.GrClosureType; +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.impl.GroovyPsiManager; import org.jetbrains.plugins.groovy.lang.psi.impl.types.GrClosureSignatureImpl; @@ -283,14 +285,11 @@ public class TypesUtil { public static boolean isAssignableByMethodCallConversion(PsiType lType, PsiType rType, PsiManager manager, GlobalSearchScope scope) { if (lType == null || rType == null) return false; - if (rType instanceof GrTupleType) { - final GrTupleType tuple = (GrTupleType)rType; - if (tuple.getComponentTypes().length == 0) { - if (lType instanceof PsiArrayType || - InheritanceUtil.isInheritor(lType, JAVA_UTIL_LIST) || - InheritanceUtil.isInheritor(lType, JAVA_UTIL_SET)) { - return true; - } + if (rType instanceof GrTupleType && ((GrTupleType)rType).getComponentTypes().length == 0) { + if (lType instanceof PsiArrayType || + InheritanceUtil.isInheritor(lType, JAVA_UTIL_LIST) || + InheritanceUtil.isInheritor(lType, JAVA_UTIL_SET)) { + return true; } } @@ -318,10 +317,54 @@ public class TypesUtil { return true; } + if (rType instanceof GrMapType || rType instanceof GrTupleType) { + Boolean result = isAssignableForNativeTypes(lType, (PsiClassType)rType, manager, scope); + if (result != null) return result.booleanValue(); + } + return TypeConversionUtil.isAssignable(lType, rType); } + @Nullable + private static Boolean isAssignableForNativeTypes(PsiType lType, PsiClassType rType, PsiManager manager, GlobalSearchScope scope) { + if (!(lType instanceof PsiClassType)) return null; + final PsiClassType.ClassResolveResult leftResult = ((PsiClassType)lType).resolveGenerics(); + final PsiClassType.ClassResolveResult rightResult = rType.resolveGenerics(); + final PsiClass leftClass = leftResult.getElement(); + PsiClass rightClass = rightResult.getElement(); + if (rightClass == null || leftClass == null) return null; + + if (!InheritanceUtil.isInheritorOrSelf(rightClass, leftClass, true)) return Boolean.FALSE; + + PsiSubstitutor rightSubstitutor = rightResult.getSubstitutor(); + + if (!leftClass.hasTypeParameters()) return Boolean.TRUE; + PsiSubstitutor leftSubstitutor = leftResult.getSubstitutor(); + + if (!leftClass.getManager().areElementsEquivalent(leftClass, rightClass)) { + rightSubstitutor = TypeConversionUtil.getSuperClassSubstitutor(leftClass, rightClass, rightSubstitutor); + rightClass = leftClass; + } + else if (!rightClass.hasTypeParameters()) return Boolean.TRUE; + + Iterator li = PsiUtil.typeParametersIterator(leftClass); + Iterator ri = PsiUtil.typeParametersIterator(rightClass); + while (li.hasNext()) { + if (!ri.hasNext()) return Boolean.FALSE; + PsiTypeParameter lp = li.next(); + PsiTypeParameter rp = ri.next(); + final PsiType typeLeft = leftSubstitutor.substitute(lp); + if (typeLeft == null) continue; + final PsiType typeRight = rightSubstitutor.substituteWithBoundsPromotion(rp); + if (typeRight == null) { + return Boolean.TRUE; + } + if (!isAssignableByMethodCallConversion(typeLeft, typeRight, manager, scope)) return Boolean.FALSE; + } + return Boolean.TRUE; + } + public static boolean isNumericType(PsiType type) { if (type instanceof PsiClassType) { return TYPE_TO_RANK.contains(type.getCanonicalText()); diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovyHighlightingTest.java b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovyHighlightingTest.java index fa1112c49f61..be64439c4b1a 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovyHighlightingTest.java +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovyHighlightingTest.java @@ -420,4 +420,8 @@ public class GroovyHighlightingTest extends LightCodeInsightFixtureTestCase { public void testResultOfIncUsed() { doTest(new GroovyResultOfIncrementOrDecrementUsedInspection()); } + + public void testNativeMapAssignability() { + doTest(new GroovyAssignabilityCheckInspection()); + } } \ No newline at end of file diff --git a/plugins/groovy/testdata/highlighting/NativeMapAssignability.groovy b/plugins/groovy/testdata/highlighting/NativeMapAssignability.groovy new file mode 100644 index 000000000000..194dfd1d6bb4 --- /dev/null +++ b/plugins/groovy/testdata/highlighting/NativeMapAssignability.groovy @@ -0,0 +1,5 @@ +def foo(Map> m) {} + +foo(a:[b:'c']) +foo(a:'b') +foo(a:[(2):4]) \ No newline at end of file diff --git a/plugins/groovy/testdata/highlighting/NumberDuplicatesInMaps.groovy b/plugins/groovy/testdata/highlighting/NumberDuplicatesInMaps.groovy index 79850ae0531a..75b643b63990 100644 --- a/plugins/groovy/testdata/highlighting/NumberDuplicatesInMaps.groovy +++ b/plugins/groovy/testdata/highlighting/NumberDuplicatesInMaps.groovy @@ -1 +1 @@ -def map = [1:'d', (1):'sd'] \ No newline at end of file +def map = [1:'d', 1:'sd'] \ No newline at end of file