Java: In MethodHandle completion show the list of available signatures of overloaded method, don't complete automatically the first item from that list (IDEA-167319)

This commit is contained in:
Pavel Dolgov
2017-04-28 15:12:25 +03:00
parent 3bf98e7fca
commit 5ef59d28e1
6 changed files with 45 additions and 26 deletions
@@ -126,7 +126,7 @@ public class JavaLangClassMemberReference extends PsiReferenceBase<PsiLiteralExp
return Arrays.stream(psiClass.getMethods())
.filter(method -> isRegularMethod(method))
.sorted(Comparator.comparing(PsiMethod::getName))
.map(method -> lookupMethod(method))
.map(method -> lookupMethod(method, this))
.filter(Objects::nonNull)
.toArray();
@@ -136,7 +136,7 @@ public class JavaLangClassMemberReference extends PsiReferenceBase<PsiLiteralExp
.map(MethodSignatureBackedByPsiMethod::getMethod)
.filter(method -> isRegularMethod(method) && isPotentiallyAccessible(method, psiClass))
.sorted(Comparator.comparingInt((PsiMethod method) -> getMethodSortOrder(method)).thenComparing(PsiMethod::getName))
.map(method -> withPriority(lookupMethod(method), -getMethodSortOrder(method)))
.map(method -> withPriority(lookupMethod(method, this), -getMethodSortOrder(method)))
.filter(Objects::nonNull)
.toArray();
}
@@ -155,17 +155,6 @@ public class JavaLangClassMemberReference extends PsiReferenceBase<PsiLiteralExp
return member != null && (member.getContainingClass() == psiClass || isPublic(member));
}
@Nullable
private LookupElement lookupMethod(@NotNull PsiMethod method) {
final ReflectiveSignature signature = getMethodSignature(method);
return signature != null
? LookupElementBuilder.create(signature, method.getName())
.withIcon(signature.getIcon())
.withTailText(signature.getShortArgumentTypes())
.withInsertHandler(this)
: null;
}
@Override
public void handleInsert(InsertionContext context, LookupElement item) {
final Object object = item.getObject();
@@ -142,8 +142,7 @@ public class JavaLangInvokeHandleReference extends PsiReferenceBase<PsiLiteralEx
.map(MethodSignatureBackedByPsiMethod::getMethod)
.filter(filter)
.sorted(Comparator.comparingInt((PsiMethod method) -> getMethodSortOrder(method)).thenComparing(PsiMethod::getName))
.map(method -> withPriority(JavaLookupElementBuilder.forMethod(method, PsiSubstitutor.EMPTY)
.withInsertHandler(this),
.map(method -> withPriority(lookupMethod(method, this),
-getMethodSortOrder(method)))
.filter(Objects::nonNull)
.toArray();
@@ -181,12 +180,9 @@ public class JavaLangInvokeHandleReference extends PsiReferenceBase<PsiLiteralEx
public void handleInsert(@NotNull InsertionContext context, @NotNull LookupElement item) {
final Object object = item.getObject();
if (object instanceof PsiMethod) {
final ReflectiveSignature signature = getMethodSignature((PsiMethod)object);
if (signature != null) {
final String text = ", " + getMethodTypeExpressionText(signature);
replaceText(context, text);
}
if (object instanceof ReflectiveSignature) {
final String text = ", " + getMethodTypeExpressionText((ReflectiveSignature)object);
replaceText(context, text);
}
else if (object instanceof PsiField) {
final PsiField field = (PsiField)object;
@@ -15,10 +15,12 @@
*/
package com.intellij.psi.impl.source.resolve.reference.impl;
import com.intellij.codeInsight.completion.InsertHandler;
import com.intellij.codeInsight.completion.InsertionContext;
import com.intellij.codeInsight.completion.JavaLookupElementBuilder;
import com.intellij.codeInsight.completion.PrioritizedLookupElement;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.codeInsight.lookup.LookupElementBuilder;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Iconable;
import com.intellij.openapi.util.RecursionGuard;
@@ -374,6 +376,17 @@ public class JavaReflectionReferenceUtil {
return JavaLookupElementBuilder.forField(field);
}
@Nullable
static LookupElement lookupMethod(@NotNull PsiMethod method, @Nullable InsertHandler<LookupElement> insertHandler) {
final ReflectiveSignature signature = getMethodSignature(method);
return signature != null
? LookupElementBuilder.create(signature, method.getName())
.withIcon(signature.getIcon())
.withTailText(signature.getShortArgumentTypes())
.withInsertHandler(insertHandler)
: null;
}
static void replaceText(@NotNull InsertionContext context, @NotNull String text) {
final PsiElement newElement = PsiUtilCore.getElementAtOffset(context.getFile(), context.getStartOffset());
final PsiElement params = newElement.getParent().getParent();
@@ -0,0 +1,8 @@
import java.lang.invoke.*;
public class Main {
void foo() throws Throwable {
MethodHandles.Lookup lookup = MethodHandles.lookup();
lookup.findVirtual(Types.class, "strMethod<caret>");
}
}
@@ -0,0 +1,8 @@
import java.lang.invoke.*;
public class Main {
void foo() throws Throwable {
MethodHandles.Lookup lookup = MethodHandles.lookup();
lookup.findVirtual(Types.class, "strMethod", MethodType.methodType(String.class, int.class, int.class));
}
}
@@ -30,10 +30,10 @@ class JavaLangInvokeHandleCompletionTest : LightFixtureCompletionTestCase() {
override fun getBasePath() = JavaTestUtil.getRelativeJavaTestDataPath() + "/codeInsight/completion/invokeHandle/"
fun testVirtual() = doTestFirst(1, "m1", "pm1", "m2")
fun testVirtualPrefixed() = doTest(1, "m1", "m2", "pm1")
fun testVirtual() = doTestFirst(1, "m1(int)", "pm1(int)", "m2(float, double)")
fun testVirtualPrefixed() = doTest(1, "m1(int)", "m2(float, double)", "pm1(int)")
fun testStatic() = doTest(0, "psm1", "sm1", "sm2")
fun testStatic() = doTest(0, "psm1(char)", "sm1(char)", "sm2(short)")
fun testGetter() = doTest(0, "f1", "pf1", "f2")
fun testSetter() = doTest(2, "f1", "pf1", "f2")
@@ -44,6 +44,8 @@ class JavaLangInvokeHandleCompletionTest : LightFixtureCompletionTestCase() {
fun testVarHandle() = doTest(0, "f1", "pf1", "f2")
fun testStaticVarHandle() = doTest(0, "psf1", "sf1", "sf2")
fun testOverloaded() = doTestTypes(1, "strMethod()", "strMethod(int, int)")
fun testVirtualType() = doTestTypes(0, "MethodType.methodType(String.class)", "MethodType.methodType(String.class, int.class, int.class)")
fun testStaticType() = doTestTypes(1,
@@ -77,7 +79,7 @@ class JavaLangInvokeHandleCompletionTest : LightFixtureCompletionTestCase() {
}
private fun doTestFirst(index: Int, vararg expected: String) {
doTest(index, { assertLookupTexts(true, *expected, "clone") })
doTest(index, { assertLookupTexts(true, *expected, "clone()") })
}
private fun doTestTypes(index: Int, vararg expected: String) {
@@ -113,7 +115,10 @@ public class Constructed<T> {
private fun assertLookupTexts(compareFirst: Boolean, vararg expected: String) {
val elements = myFixture.lookupElements
assertNotNull(elements)
val lookupTexts = elements!!.map { LookupElementPresentation.renderElement(it).itemText }
val lookupTexts = elements!!.map {
val presentation = LookupElementPresentation.renderElement(it)
(presentation.itemText ?: "") + (presentation.tailText ?: "")
}
val actual = if (compareFirst) lookupTexts.subList(0, Math.min(expected.size, lookupTexts.size)) else lookupTexts
assertOrderedEquals(actual, *expected)