fix intersection types in receiver position (IDEA-144472)
authorAnna Kozlova <anna.kozlova@jetbrains.com>
Mon, 31 Aug 2015 13:20:21 +0000 (16:20 +0300)
committerAnna Kozlova <anna.kozlova@jetbrains.com>
Mon, 31 Aug 2015 16:09:52 +0000 (19:09 +0300)
java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceSession.java
java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/PsiMethodReferenceCompatibilityConstraint.java
java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/methodRef/IntersectionTypesInReceiverPosition.java [new file with mode: 0644]
java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/MethodRefHighlightingTest.java

index b0ed00a69e25c10bca1a473d8b200752d59ecf1f..fbfe8c1160d657d80ef1b7fd9968ec4486d38ab1 100644 (file)
@@ -1290,10 +1290,9 @@ public class InferenceSession {
       // the type to search is the result of capture conversion (5.1.10) applied to T; 
       // otherwise, the type to search is the same as the type of the first search. Again, the type arguments, if any, are given by the method reference.
       if (PsiUtil.isRawSubstitutor(containingClass, psiSubstitutor)) {
-        final PsiClassType.ClassResolveResult pResult = PsiUtil.resolveGenericsClassInType(PsiImplUtil.normalizeWildcardTypeByPosition(pType, (PsiExpression)myContext));
-        final PsiClass pClass = pResult.getElement();
-        final PsiSubstitutor receiverSubstitutor = pClass != null ? TypeConversionUtil
-          .getClassSubstitutor(containingClass, pClass, pResult.getSubstitutor()) : null;
+        PsiType normalizedPType = PsiImplUtil.normalizeWildcardTypeByPosition(pType, (PsiExpression)myContext);
+        final PsiSubstitutor receiverSubstitutor = PsiMethodReferenceCompatibilityConstraint
+          .getParameterizedTypeSubstitutor(containingClass, normalizedPType);
         if (receiverSubstitutor != null) {
           if (!method.hasTypeParameters()) {
             if (signature.getParameterTypes().length == 1 || PsiUtil.isRawSubstitutor(containingClass, receiverSubstitutor)) {
index 4609b7844a7c57736146adb216c2d34e94214a71..925582ba492154f349b0f2a95131297759bb0e1d 100644 (file)
@@ -22,10 +22,7 @@ import com.intellij.psi.impl.source.resolve.graphInference.FunctionalInterfacePa
 import com.intellij.psi.impl.source.resolve.graphInference.InferenceSession;
 import com.intellij.psi.impl.source.resolve.graphInference.PsiPolyExpressionUtil;
 import com.intellij.psi.infos.MethodCandidateInfo;
-import com.intellij.psi.util.MethodSignature;
-import com.intellij.psi.util.PsiTreeUtil;
-import com.intellij.psi.util.PsiUtil;
-import com.intellij.psi.util.TypeConversionUtil;
+import com.intellij.psi.util.*;
 import com.intellij.util.containers.ContainerUtil;
 import org.jetbrains.annotations.Nullable;
 
@@ -219,13 +216,8 @@ public class PsiMethodReferenceCompatibilityConstraint implements ConstraintForm
       // otherwise, the type to search is the same as the type of the first search. Again, the type arguments, if any, are given by the method reference.
       if ( PsiUtil.isRawSubstitutor(qContainingClass, psiSubstitutor)) {
         if (member instanceof PsiMethod && PsiMethodReferenceUtil.isSecondSearchPossible(signature.getParameterTypes(), qualifierResolveResult, myExpression)) {
-          final PsiType pType = signature.getParameterTypes()[0];
-          PsiClassType.ClassResolveResult resolveResult = PsiUtil.resolveGenericsClassInType(
-            PsiImplUtil.normalizeWildcardTypeByPosition(pType, myExpression));
-          PsiClass paramClass = resolveResult.getElement();
-          LOG.assertTrue(paramClass != null);
-          psiSubstitutor = TypeConversionUtil.getClassSubstitutor(qContainingClass, paramClass, resolveResult.getSubstitutor());
-          LOG.assertTrue(psiSubstitutor != null);
+          final PsiType pType = PsiImplUtil.normalizeWildcardTypeByPosition(signature.getParameterTypes()[0], myExpression);
+          psiSubstitutor = getParameterizedTypeSubstitutor(qContainingClass, pType);
         }
         else if (member instanceof PsiMethod && ((PsiMethod)member).isConstructor() || member instanceof PsiClass) {
           //15.13.1 
@@ -253,6 +245,24 @@ public class PsiMethodReferenceCompatibilityConstraint implements ConstraintForm
     return psiSubstitutor;
   }
 
+  public static PsiSubstitutor getParameterizedTypeSubstitutor(PsiClass qContainingClass, PsiType pType) {
+    if (pType instanceof PsiIntersectionType) {
+      for (PsiType type : ((PsiIntersectionType)pType).getConjuncts()) {
+        PsiClassType.ClassResolveResult resolveResult = PsiUtil.resolveGenericsClassInType(type);
+        if (InheritanceUtil.isInheritorOrSelf(resolveResult.getElement(), qContainingClass, true)) {
+          return getParameterizedTypeSubstitutor(qContainingClass, type);
+        }
+      }
+    }
+
+    PsiClassType.ClassResolveResult resolveResult = PsiUtil.resolveGenericsClassInType(pType);
+    PsiClass paramClass = resolveResult.getElement();
+    LOG.assertTrue(paramClass != null);
+    PsiSubstitutor psiSubstitutor = TypeConversionUtil.getClassSubstitutor(qContainingClass, paramClass, resolveResult.getSubstitutor());
+    LOG.assertTrue(psiSubstitutor != null);
+    return psiSubstitutor;
+  }
+
   @Override
   public void apply(PsiSubstitutor substitutor, boolean cache) {
     myT = substitutor.substitute(myT);
diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/methodRef/IntersectionTypesInReceiverPosition.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/methodRef/IntersectionTypesInReceiverPosition.java
new file mode 100644 (file)
index 0000000..fd4d327
--- /dev/null
@@ -0,0 +1,23 @@
+import java.util.*;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+abstract class Constraint<ConstraintType extends Constraint<ConstraintType>> {
+
+  protected abstract Stream<Event> evStream();
+
+  private void foo(final Set<CConstraint> ctrlSTCs, 
+                   final Set<BConstraint> probCstrs) {
+    ArrayList<Event> a = new ArrayList<Event>(Stream
+                                                .concat(ctrlSTCs.stream(), probCstrs.stream())
+                                                .flatMap(Constraint::evStream)
+                                                .collect(Collectors.toSet()));
+  }
+
+  private abstract class CConstraint extends Constraint<CConstraint> implements I {}
+  private abstract class BConstraint extends Constraint<BConstraint> implements I {}
+
+  interface I {}
+  interface Event {}
+
+}
index 9b4c44547ed4c20c002cde0ab844999c983f7508..97683fca3d57ee4d911ae42161c5e8d08a32c5cc 100644 (file)
@@ -106,6 +106,10 @@ public class MethodRefHighlightingTest extends LightDaemonAnalyzerTestCase {
     doTest();
   }
 
+  public void testIntersectionTypesInReceiverPosition() throws Exception {
+    doTest();
+  }
+
   private void doTest() {
     doTest(false);
   }