[java-psi] Support method references with intersection type qualifier

Fixes IDEA-319068 Good code is red: Optional.ifPresent(AbstractSet::add) complains about add method

GitOrigin-RevId: 7fe34c7041a09504536ce99cd52e7ed89997ec73
This commit is contained in:
Tagir Valeev
2023-05-03 12:47:58 +02:00
committed by intellij-monorepo-bot
parent 846c2b4787
commit 69e2e794f3
3 changed files with 60 additions and 10 deletions

View File

@@ -1,4 +1,4 @@
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.psi;
import com.intellij.core.JavaPsiBundle;
@@ -8,10 +8,13 @@ import com.intellij.psi.util.MethodSignature;
import com.intellij.psi.util.PsiTypesUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.psi.util.TypeConversionUtil;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
public final class PsiMethodReferenceUtil {
public static boolean isSecondSearchPossible(PsiType[] parameterTypes,
@@ -220,16 +223,25 @@ public final class PsiMethodReferenceUtil {
final PsiExpression expression = methodReferenceExpression.getQualifierExpression();
if (expression != null) {
PsiType expressionType = expression.getType();
if (expressionType instanceof PsiCapturedWildcardType) {
expressionType = ((PsiCapturedWildcardType)expressionType).getUpperBound();
if (expressionType instanceof PsiIntersectionType) {
List<PsiClassType> types = ContainerUtil.filterIsInstance(((PsiIntersectionType)expressionType).getConjuncts(), PsiClassType.class);
substitutor = types.stream().map(t -> t.resolveGenerics().getSubstitutor())
.reduce(PsiSubstitutor.EMPTY, PsiSubstitutor::putAll);
containingClass = JavaPsiFacade.getElementFactory(methodReferenceExpression.getProject()).createTypeParameter(
"$SYNTHETIC$", types.toArray(PsiClassType.EMPTY_ARRAY));
}
else {
expressionType = replaceArrayType(expressionType, expression);
}
PsiClassType.ClassResolveResult result = PsiUtil.resolveGenericsClassInType(expressionType);
containingClass = result.getElement();
if (containingClass != null) {
substitutor = result.getSubstitutor();
if (expressionType instanceof PsiCapturedWildcardType) {
expressionType = ((PsiCapturedWildcardType)expressionType).getUpperBound();
}
else {
expressionType = replaceArrayType(expressionType, expression);
}
PsiClassType.ClassResolveResult result = PsiUtil.resolveGenericsClassInType(expressionType);
containingClass = result.getElement();
if (containingClass != null) {
substitutor = result.getSubstitutor();
}
}
if (containingClass == null && expression instanceof PsiReferenceExpression) {
final JavaResolveResult resolveResult = ((PsiReferenceExpression)expression).advancedResolve(false);

View File

@@ -0,0 +1,34 @@
import java.util.*;
class Main {
enum Enum {}
@FunctionalInterface
interface EnumConsumer {
void accept(Enum e);
}
public static void main(String[] args) {
var set = Math.random() > 0.5d ? new HashSet<Enum>() : EnumSet.noneOf(Enum.class);
EnumConsumer consumer = set::add;
}
}
class X {
interface A {
void add(int x);
}
interface B {
void add(String s);
}
interface StringConsumer {
void accept(String s);
}
<T extends A & B> void x(T t) {
StringConsumer cons1 = s -> t.add(s);
StringConsumer cons2 = t::add;
var i = (A & B)t;
StringConsumer cons3 = s -> i.add(s);
StringConsumer cons4 = i::add; // good code red
}
}

View File

@@ -1,4 +1,4 @@
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.java.codeInsight.daemon;
import com.intellij.codeInsight.daemon.LightDaemonAnalyzerTestCase;
@@ -84,6 +84,10 @@ public class LightAdvLVTIHighlightingTest extends LightDaemonAnalyzerTestCase {
assertInstanceOf(element, PsiClass.class);
assertEquals(CommonClassNames.JAVA_LANG_STRING, ((PsiClass)element).getQualifiedName());
}
public void testIntersectionTypeMethodRef() {
doTest();
}
@Override
protected Sdk getProjectJDK() {