assignability to primitive: check type parameter bounds if applicable (IDEA-155551)
authorAnna.Kozlova <anna.kozlova@jetbrains.com>
Wed, 4 May 2016 09:01:58 +0000 (11:01 +0200)
committerAnna.Kozlova <anna.kozlova@jetbrains.com>
Wed, 4 May 2016 09:09:25 +0000 (11:09 +0200)
java/java-psi-api/src/com/intellij/psi/util/TypeConversionUtil.java
java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/UnboxingFromTypeParameter.java [new file with mode: 0644]
java/java-tests/testSrc/com/intellij/codeInsight/daemon/GenericsHighlightingTest.java

index 8ccab9517a7b9ec7543778cc8d64a7eaa844f405..99e2a24aa5fc3d51dbe8214d85588cd3350d0057 100644 (file)
@@ -33,10 +33,7 @@ import org.jetbrains.annotations.NonNls;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Set;
+import java.util.*;
 
 import static com.intellij.psi.CommonClassNames.JAVA_LANG_STRING;
 
@@ -839,7 +836,7 @@ public class TypeConversionUtil {
       return false; // must be TypeCook's PsiTypeVariable
     }
     if (left instanceof PsiPrimitiveType) {
-      return isUnboxable((PsiPrimitiveType)left, (PsiClassType)right);
+      return isUnboxable((PsiPrimitiveType)left, (PsiClassType)right, new HashSet<PsiClassType>());
     }
     final PsiClassType.ClassResolveResult leftResult = PsiUtil.resolveGenericsClassInType(left);
     final PsiClassType.ClassResolveResult rightResult = PsiUtil.resolveGenericsClassInType(right);
@@ -880,7 +877,20 @@ public class TypeConversionUtil {
     return isAssignable(wildcardType.getExtendsBound(), right);
   }
 
-  private static boolean isUnboxable(@NotNull PsiPrimitiveType left, @NotNull PsiClassType right) {
+  private static boolean isUnboxable(@NotNull PsiPrimitiveType left, @NotNull PsiClassType right, @NotNull Set<PsiClassType> types) {
+    if (!right.getLanguageLevel().isAtLeast(LanguageLevel.JDK_1_5)) return false;
+    final PsiClass psiClass = right.resolve();
+    if (psiClass == null) return false;
+
+    if (psiClass instanceof PsiTypeParameter) {
+      for (PsiClassType bound : psiClass.getExtendsListTypes()) {
+        if (types.add(bound) && isUnboxable(left, bound, types)) {
+          return true;
+        }
+      }
+      return false;
+    }
+
     final PsiPrimitiveType rightUnboxedType = PsiPrimitiveType.getUnboxedType(right);
     return rightUnboxedType != null && isAssignable(left, rightUnboxedType);
   }
diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/UnboxingFromTypeParameter.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/UnboxingFromTypeParameter.java
new file mode 100644 (file)
index 0000000..b757661
--- /dev/null
@@ -0,0 +1,7 @@
+class Test {
+  <T extends S, S extends Long, K extends Long & Runnable> void method1(T param, S param1, K param2) {
+    long l = param;
+    long l1 = param1;
+    long l2 = param2;
+  }
+}
\ No newline at end of file
index 90a76764c9c0234f1065733b4b40d58b87524569..2b10c698a0c45345bd0ff16a20a1f5a07865829d 100644 (file)
@@ -575,6 +575,10 @@ public class GenericsHighlightingTest extends LightDaemonAnalyzerTestCase {
     doTest(LanguageLevel.JDK_1_7, JavaSdkVersion.JDK_1_7, false);
   }
 
+  public void testUnboxingFromTypeParameter() throws Exception {
+    doTest(LanguageLevel.JDK_1_7, JavaSdkVersion.JDK_1_7, false);
+  }
+
   public void testLeastUpperBoundWithRecursiveTypes() throws Exception {
     final PsiManager manager = getPsiManager();
     final GlobalSearchScope scope = GlobalSearchScope.allScope(getProject());