IDEA-55449 groovy: inspection: List assignment
authorMaxim Medvedev <maxim.medvedev@jetbrains.com>
Sat, 3 Jul 2010 10:21:27 +0000 (14:21 +0400)
committerMaxim Medvedev <maxim.medvedev@jetbrains.com>
Sat, 3 Jul 2010 10:22:09 +0000 (14:22 +0400)
plugins/groovy/src/META-INF/plugin.xml
plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrContainerTypeConverter.java [new file with mode: 0644]
plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/TypesUtil.java
plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovyHighlightingTest.java
plugins/groovy/testdata/highlighting/CollectionAssignments.groovy [new file with mode: 0644]

index 1931ece2bfdf4f8a2f60fb839ec9dc9eaea73b29..18d7de6eaea268a41909b7e4dca44b7311748fac 100644 (file)
@@ -71,6 +71,8 @@
     <variableEnhancer implementation="org.jetbrains.plugins.groovy.lang.psi.ClosureParameterEnhancer"/>
 
     <membersContributor implementation="org.jetbrains.plugins.groovy.gant.GantMemberContributor"/>
+
+    <typeConverter implementation="org.jetbrains.plugins.groovy.lang.psi.impl.GrContainerTypeConverter"/> 
   </extensions>
 
   <extensions defaultExtensionNs="com.intellij">
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
new file mode 100644 (file)
index 0000000..2fd193c
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2000-2010 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.plugins.groovy.lang.psi.impl;
+
+import com.intellij.psi.CommonClassNames;
+import com.intellij.psi.PsiArrayType;
+import com.intellij.psi.PsiType;
+import com.intellij.psi.util.InheritanceUtil;
+import com.intellij.psi.util.PsiUtil;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jetbrains.plugins.groovy.lang.psi.GrTypeConverter;
+import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement;
+import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil;
+
+/**
+ * @author Maxim.Medvedev
+ */
+public class GrContainerTypeConverter extends GrTypeConverter {
+  @Override
+  public Boolean isConvertible(@NotNull PsiType lType, @NotNull PsiType rType, @NotNull GroovyPsiElement context) {
+    if (!isCollectionOrArray(lType) || !isCollectionOrArray(rType)) return null;
+
+    final PsiType lComponentType = extractComponentType(lType);
+    final PsiType rComponentType = extractComponentType(rType);
+
+    if (lComponentType == null || rComponentType == null) return Boolean.TRUE;
+    if (TypesUtil.isAssignable(lComponentType, rComponentType, context)) return Boolean.TRUE;
+    return null;
+  }
+
+  @Nullable
+  private static PsiType extractComponentType(PsiType type) {
+    if (type instanceof PsiArrayType) return ((PsiArrayType)type).getComponentType();
+    return PsiUtil.substituteTypeParameter(type, CommonClassNames.JAVA_UTIL_COLLECTION, 0, false);
+  }
+
+  private static boolean isCollectionOrArray(PsiType type) {
+    return type instanceof PsiArrayType || InheritanceUtil.isInheritor(type, CommonClassNames.JAVA_UTIL_COLLECTION);
+  }
+}
index cb079e4992c07ca1158deb1409b6ec03d71a950f..f3d736fb87bc100710c88847e5a0d1a6934aa7a5 100644 (file)
@@ -233,6 +233,14 @@ public class TypesUtil {
   }
 
   public static boolean isAssignable(PsiType lType, PsiType rType, GroovyPsiElement context, boolean allowConversion) {
+    if (allowConversion && lType != null && rType != null) {
+      for (GrTypeConverter converter : GrTypeConverter.EP_NAME.getExtensions()) {
+        final Boolean result = converter.isConvertible(lType, rType, context);
+        if (result != null) {
+          return result;
+        }
+      }
+    }
     return (allowConversion && isAssignableByMethodCallConversion(lType, rType, context)) ||
            _isAssignable(lType, rType, context.getManager(), context.getResolveScope(), true);
   }
@@ -259,20 +267,7 @@ public class TypesUtil {
   }
 
   public static boolean isAssignableByMethodCallConversion(PsiType lType, PsiType rType, GroovyPsiElement context) {
-    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;
+    return isAssignableByMethodCallConversion(lType, rType, context.getManager(), context.getResolveScope());
   }
 
   public static boolean isAssignableByMethodCallConversion(PsiType lType, PsiType rType, PsiManager manager, GlobalSearchScope scope) {
index ccafebd38f7c9575cec82b6dd89c82f53ae38db3..95530e311aa96505dd85c389aaffc429acf99abf 100644 (file)
@@ -274,4 +274,8 @@ public class GroovyHighlightingTest extends LightCodeInsightFixtureTestCase {
   public void testInheritConstructorsAnnotation() throws Exception {
     doTest();
   }
+
+  public void testCollectionAssignments() throws Exception {
+    doTest(new GroovyAssignabilityCheckInspection());
+  }
 }
\ No newline at end of file
diff --git a/plugins/groovy/testdata/highlighting/CollectionAssignments.groovy b/plugins/groovy/testdata/highlighting/CollectionAssignments.groovy
new file mode 100644 (file)
index 0000000..6a16aad
--- /dev/null
@@ -0,0 +1,4 @@
+class Pair {}
+List<Pair> otherPairs = new ArrayList<Pair>();
+List<Pair> pairs = otherPairs.findAll({it != null})
+List<Date> pairs2 = <warning descr="Cannot assign 'Collection<Pair>' to 'List<Date>'">otherPairs.findAll({it != null})</warning> 
\ No newline at end of file