mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
method refs: choose more specific return type when checking more specific functional interface
This commit is contained in:
@@ -16,9 +16,11 @@
|
||||
package com.intellij.psi;
|
||||
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.util.Comparing;
|
||||
import com.intellij.openapi.util.Computable;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.psi.codeStyle.JavaCodeStyleManager;
|
||||
import com.intellij.psi.infos.CandidateInfo;
|
||||
import com.intellij.psi.infos.MethodCandidateInfo;
|
||||
import com.intellij.psi.util.*;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -590,9 +592,14 @@ public class LambdaUtil {
|
||||
|
||||
final MethodSignature signature1 = method.getSignature(resolveResult.getSubstitutor());
|
||||
PsiSubstitutor subst = PsiSubstitutor.EMPTY;
|
||||
subst = subst.putAll(result.getSubstitutor());
|
||||
subst = subst.putAll(substRef.get());
|
||||
subst = subst.putAll(result.getSubstitutor());
|
||||
final MethodSignature signature2 = ((PsiMethod)resolve).getSignature(subst);
|
||||
|
||||
final PsiType interfaceReturnType = getFunctionalInterfaceReturnType(left);
|
||||
final PsiType methodReturnType = subst.substitute(((PsiMethod)resolve).getReturnType());
|
||||
if (interfaceReturnType != null && methodReturnType != null && interfaceReturnType != PsiType.VOID &&
|
||||
!TypeConversionUtil.isAssignable(interfaceReturnType, methodReturnType)) return false;
|
||||
if (areAcceptable(signature1, signature2, classRef.get(), substRef.get(), ((PsiMethod)resolve).isVarArgs())) return true;
|
||||
}
|
||||
}
|
||||
@@ -662,6 +669,35 @@ public class LambdaUtil {
|
||||
return (PsiLocalVariable)((PsiDeclarationStatement)assignmentFromText).getDeclaredElements()[0];
|
||||
}
|
||||
|
||||
public static void processMethodReferenceReturnType(List<CandidateInfo> conflicts, int functionalInterfaceIdx) {
|
||||
final CandidateInfo[] newConflictsArray = conflicts.toArray(new CandidateInfo[conflicts.size()]);
|
||||
for (int i = 1; i < newConflictsArray.length; i++) {
|
||||
final CandidateInfo method = newConflictsArray[i];
|
||||
final PsiType interfaceReturnType = getReturnType(functionalInterfaceIdx, method);
|
||||
for (int j = 0; j < i; j++) {
|
||||
final CandidateInfo conflict = newConflictsArray[j];
|
||||
assert conflict != method;
|
||||
final PsiType interfaceReturnType1 = getReturnType(functionalInterfaceIdx, conflict);
|
||||
if (interfaceReturnType != null && interfaceReturnType1 != null && !Comparing.equal(interfaceReturnType, interfaceReturnType1)) {
|
||||
if (TypeConversionUtil.isAssignable(interfaceReturnType, interfaceReturnType1)) {
|
||||
conflicts.remove(method);
|
||||
break;
|
||||
} else if (TypeConversionUtil.isAssignable(interfaceReturnType1, interfaceReturnType)) {
|
||||
conflicts.remove(conflict);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static PsiType getReturnType(int functionalTypeIdx, CandidateInfo method) {
|
||||
final PsiParameter[] methodParameters = ((PsiMethod)method.getElement()).getParameterList().getParameters();
|
||||
final PsiParameter param = functionalTypeIdx < methodParameters.length ? methodParameters[functionalTypeIdx] : methodParameters[methodParameters.length - 1];
|
||||
final PsiType functionalInterfaceType = method.getSubstitutor().substitute(param.getType());
|
||||
return getFunctionalInterfaceReturnType(functionalInterfaceType);
|
||||
}
|
||||
|
||||
private static class TypeParamsChecker extends PsiTypeVisitor<Boolean> {
|
||||
private PsiMethod myMethod;
|
||||
private final PsiClass myClass;
|
||||
|
||||
+6
-2
@@ -288,7 +288,11 @@ public class PsiMethodReferenceExpressionImpl extends PsiReferenceExpressionBase
|
||||
if (signature == null) return PsiSubstitutor.EMPTY;
|
||||
final PsiType[] types = method.getSignature(PsiSubstitutor.EMPTY).getParameterTypes();
|
||||
final PsiType[] rightTypes = signature.getParameterTypes();
|
||||
if (types.length != rightTypes.length) return PsiSubstitutor.EMPTY;
|
||||
if (types.length < rightTypes.length) {
|
||||
return PsiUtil.resolveGenericsClassInType(rightTypes[0]).getSubstitutor();
|
||||
} else if (types.length > rightTypes.length) {
|
||||
return PsiUtil.resolveGenericsClassInType(types[0]).getSubstitutor();
|
||||
}
|
||||
return JavaPsiFacade.getInstance(getProject()).getResolveHelper()
|
||||
.inferTypeArguments(method.getTypeParameters(), types, rightTypes,
|
||||
PsiUtil.getLanguageLevel(PsiMethodReferenceExpressionImpl.this));
|
||||
@@ -356,8 +360,8 @@ public class PsiMethodReferenceExpressionImpl extends PsiReferenceExpressionBase
|
||||
final PsiMethod psiMethod = ((MethodCandidateInfo)conflict).getElement();
|
||||
if (psiMethod == null) continue;
|
||||
PsiSubstitutor subst = PsiSubstitutor.EMPTY;
|
||||
subst = subst.putAll(conflict.getSubstitutor());
|
||||
subst = subst.putAll(mySubstitutor);
|
||||
subst = subst.putAll(conflict.getSubstitutor());
|
||||
final PsiType[] signatureParameterTypes2 = psiMethod.getSignature(subst).getParameterTypes();
|
||||
|
||||
final boolean varArgs = psiMethod.isVarArgs();
|
||||
|
||||
+3
@@ -125,6 +125,9 @@ public class JavaMethodsConflictResolver implements PsiConflictResolver{
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (parameterType instanceof PsiMethodReferenceType) {
|
||||
LambdaUtil.processMethodReferenceReturnType(conflicts, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
class MyTest {
|
||||
|
||||
static class Foo<T> {
|
||||
T m() { return null; };
|
||||
}
|
||||
|
||||
interface I1 {
|
||||
Foo<Object> m(Foo<String> f);
|
||||
}
|
||||
|
||||
interface I2 {
|
||||
Integer m(Foo<Integer> f);
|
||||
}
|
||||
|
||||
interface I3 {
|
||||
Object m(Foo<Integer> f);
|
||||
}
|
||||
|
||||
static void foo(I1 i) {}
|
||||
static void foo(I2 i) {}
|
||||
static void foo(I3 i) {}
|
||||
|
||||
static {
|
||||
foo(Foo::m);
|
||||
}
|
||||
}
|
||||
+4
@@ -81,6 +81,10 @@ public class MethodRefHighlightingTest extends LightDaemonAnalyzerTestCase {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testReturnTypeSpecific() throws Exception {
|
||||
doTest();
|
||||
}
|
||||
|
||||
private void doTest() throws Exception {
|
||||
doTest(BASE_PATH + "/" + getTestName(false) + ".java", false, false);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user