functional type: find common super type of intersection type's conjuncts (IDEA-144145)
authorAnna Kozlova <anna.kozlova@jetbrains.com>
Thu, 20 Aug 2015 13:05:47 +0000 (15:05 +0200)
committerAnna Kozlova <anna.kozlova@jetbrains.com>
Thu, 20 Aug 2015 14:01:58 +0000 (16:01 +0200)
java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/LambdaHighlightingUtil.java
java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/functionalInterface/IntersectionTypeWithSameBaseInterfaceInConjuncts.java [new file with mode: 0644]
java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/FunctionalInterfaceTest.java

index fbd6edb1907bff0dcda63661bb3b5f84e5155c4d..c2dd86e7d813eb7757012e8c5df218236d1fa3e1 100644 (file)
@@ -17,6 +17,7 @@ package com.intellij.codeInsight.daemon.impl.analysis;
 
 import com.intellij.codeInsight.daemon.impl.HighlightInfo;
 import com.intellij.codeInsight.daemon.impl.HighlightInfoType;
+import com.intellij.openapi.diagnostic.Logger;
 import com.intellij.psi.*;
 import com.intellij.psi.util.MethodSignature;
 import com.intellij.psi.util.PsiTypesUtil;
@@ -25,12 +26,16 @@ import com.intellij.psi.util.TypeConversionUtil;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
+import java.util.HashSet;
 import java.util.List;
+import java.util.Set;
 
 /**
  * User: anna
  */
 public class LambdaHighlightingUtil {
+  private static final Logger LOG = Logger.getInstance("#" + LambdaHighlightingUtil.class.getName());
+
   @Nullable
   public static String checkInterfaceFunctional(@NotNull PsiClass psiClass) {
     return checkInterfaceFunctional(psiClass, "Target type of a lambda conversion must be an interface");
@@ -90,14 +95,16 @@ public class LambdaHighlightingUtil {
   @Nullable
   public static String checkInterfaceFunctional(PsiType functionalInterfaceType) {
     if (functionalInterfaceType instanceof PsiIntersectionType) {
-      int count = 0;
+      final Set<MethodSignature> signatures = new HashSet<MethodSignature>();
       for (PsiType type : ((PsiIntersectionType)functionalInterfaceType).getConjuncts()) {
         if (checkInterfaceFunctional(type) == null) {
-          count++;
+          final MethodSignature signature = LambdaUtil.getFunction(PsiUtil.resolveClassInType(type));
+          LOG.assertTrue(signature != null, type.getCanonicalText());
+          signatures.add(signature);
         }
       }
 
-      if (count > 1) {
+      if (signatures.size() > 1) {
         return "Multiple non-overriding abstract methods found in " + functionalInterfaceType.getPresentableText();
       }
       return null;
diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/functionalInterface/IntersectionTypeWithSameBaseInterfaceInConjuncts.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/functionalInterface/IntersectionTypeWithSameBaseInterfaceInConjuncts.java
new file mode 100644 (file)
index 0000000..fae246a
--- /dev/null
@@ -0,0 +1,12 @@
+interface Z {
+  void m();
+}
+
+interface X extends Z {}
+interface Y extends Z {}
+
+class Test {
+  {
+    ((X & <caret>Y) () -> {}).m();
+  }
+}
\ No newline at end of file
index b09f4d7e2a7737d4ab503307271c1ae167e02773..a8501fd81660a27a683753778503ab42057b48c6 100644 (file)
@@ -18,7 +18,11 @@ package com.intellij.codeInsight.daemon.lambda;
 import com.intellij.codeInsight.daemon.LightDaemonAnalyzerTestCase;
 import com.intellij.codeInsight.daemon.impl.analysis.LambdaHighlightingUtil;
 import com.intellij.psi.PsiClass;
+import com.intellij.psi.PsiType;
+import com.intellij.psi.PsiTypeCastExpression;
+import com.intellij.psi.PsiTypeElement;
 import com.intellij.psi.search.GlobalSearchScope;
+import com.intellij.psi.util.PsiTreeUtil;
 import org.jetbrains.annotations.NonNls;
 import org.jetbrains.annotations.Nullable;
 
@@ -86,4 +90,17 @@ public class FunctionalInterfaceTest extends LightDaemonAnalyzerTestCase {
   public void testAbstractClass() throws Exception {
     doTestFunctionalInterface("Target type of a lambda conversion must be an interface");
   }
+
+  public void testIntersectionTypeWithSameBaseInterfaceInConjuncts() throws Exception {
+    String filePath = BASE_PATH + "/" + getTestName(false) + ".java";
+    configureByFile(filePath);
+    final PsiTypeCastExpression castExpression =
+      PsiTreeUtil.getParentOfType(getFile().findElementAt(getEditor().getCaretModel().getOffset()), PsiTypeCastExpression.class);
+    assertNotNull(castExpression);
+    final PsiTypeElement castTypeElement = castExpression.getCastType();
+    assertNotNull(castTypeElement);
+    final PsiType type = castTypeElement.getType();
+    final String errorMessage = LambdaHighlightingUtil.checkInterfaceFunctional(type);
+    assertEquals(null, errorMessage);
+  }
 }