java completion: prefer method reference suggestions with exactly matching return type (IDEA-210581)

GitOrigin-RevId: 5522e5c103b72ea9d1a7c9ae860e504b6515b1da
This commit is contained in:
Peter Gromov
2020-06-17 19:39:08 +02:00
committed by intellij-monorepo-bot
parent fd0355b101
commit 112cdd0579
4 changed files with 26 additions and 5 deletions

View File

@@ -42,7 +42,7 @@ import java.util.*;
public class FunctionalExpressionCompletionProvider {
static final Key<Boolean> LAMBDA_ITEM = Key.create("LAMBDA_ITEM");
static final Key<Boolean> METHOD_REF_ITEM = Key.create("METHOD_REF_ITEM");
static final Key<Boolean> METHOD_REF_PREFERRED = Key.create("METHOD_REF_ITEM");
private static boolean isLambdaContext(@NotNull PsiElement element) {
final PsiElement rulezzRef = element.getParent();
@@ -52,7 +52,7 @@ public class FunctionalExpressionCompletionProvider {
}
static boolean isFunExprItem(LookupElement item) {
return item.getUserData(LAMBDA_ITEM) != null || item.getUserData(METHOD_REF_ITEM) != null;
return item.getUserData(LAMBDA_ITEM) != null || item.getUserData(METHOD_REF_PREFERRED) != null;
}
static void addFunctionalVariants(@NotNull CompletionParameters parameters, boolean addInheritors, PrefixMatcher matcher, Consumer<? super LookupElement> result) {
@@ -101,7 +101,8 @@ public class FunctionalExpressionCompletionProvider {
new MethodReferenceCompletion(addInheritors, parameters, matcher, functionalInterfaceType, params, originalPosition,
substitutor, expectedReturnType);
completion.suggestMethodReferences(element -> {
element.putUserData(METHOD_REF_ITEM, true);
Object object = element.getObject();
element.putUserData(METHOD_REF_PREFERRED, object instanceof PsiMethod && completion.hasExactReturnType((PsiMethod)object));
result.consume(parameters.getCompletionType() == CompletionType.SMART
? JavaSmartCompletionContributor.decorate(element, Arrays.asList(expectedTypes))
: element);
@@ -319,6 +320,11 @@ class MethodReferenceCompletion {
return returnType != null && TypeConversionUtil.isAssignable(myExpectedReturnType, mySubstitutor.substitute(returnType));
}
boolean hasExactReturnType(PsiMethod psiMethod) {
PsiType returnType = psiMethod.getReturnType();
return returnType != null && myExpectedReturnType.equals(mySubstitutor.substitute(returnType));
}
private boolean isSignatureAppropriate(PsiMethod psiMethod, int offset, PsiClass accessObjectClass) {
if (!PsiUtil.isAccessible(psiMethod, myPosition, accessObjectClass)) return false;

View File

@@ -158,6 +158,7 @@ public class PreferByKindWeigher extends LookupElementWeigher {
castVariable,
expectedTypeVariable,
lambda,
likelyMethodRef,
methodRef,
variable,
getter,
@@ -213,8 +214,9 @@ public class PreferByKindWeigher extends LookupElementWeigher {
if (item.getUserData(FunctionalExpressionCompletionProvider.LAMBDA_ITEM) != null) {
return MyResult.lambda;
}
if (item.getUserData(FunctionalExpressionCompletionProvider.METHOD_REF_ITEM) != null) {
return MyResult.methodRef;
Boolean methodRefPreference = item.getUserData(FunctionalExpressionCompletionProvider.METHOD_REF_PREFERRED);
if (methodRefPreference != null) {
return methodRefPreference ? MyResult.likelyMethodRef : MyResult.methodRef;
}
if (object instanceof PsiMethod) {

View File

@@ -0,0 +1,7 @@
class C {
void tryToSum() {
mapToDouble(<caret>)
}
void mapToDouble(java.util.function.ToDoubleFunction<Double> mapper) {}
}

View File

@@ -478,4 +478,10 @@ class Test88 {
myFixture.assertPreferredCompletionItems 0, 'new'
}
@NeedsIndex.ForStandardLibrary
void testPreferQualifiedMethodReferenceOfExpectedType() {
configureByTestName()
myFixture.assertPreferredCompletionItems 0, 'aDouble -> ', 'doubleValue'
}
}