Java: Fixed completion of overloaded method parameters in getDeclaredMethod("methodName", ...) (IDEA-171721)

This commit is contained in:
Pavel Dolgov
2017-04-25 14:30:43 +03:00
parent 5349c37432
commit e8dabd42ff
8 changed files with 72 additions and 33 deletions

View File

@@ -17,8 +17,8 @@ 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.lookup.LookupElement;
import com.intellij.codeInsight.lookup.LookupElementBuilder;
import com.intellij.psi.*;
import com.intellij.psi.util.MethodSignatureBackedByPsiMethod;
import com.intellij.util.IncorrectOperationException;
@@ -30,6 +30,7 @@ import org.jetbrains.annotations.Nullable;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Objects;
import java.util.Set;
import static com.intellij.psi.impl.source.resolve.reference.impl.JavaReflectionReferenceUtil.*;
@@ -126,6 +127,7 @@ public class JavaLangClassMemberReference extends PsiReferenceBase<PsiLiteralExp
.filter(method -> isRegularMethod(method))
.sorted(Comparator.comparing(PsiMethod::getName))
.map(method -> lookupMethod(method))
.filter(Objects::nonNull)
.toArray();
case GET_METHOD: {
@@ -135,6 +137,7 @@ public class JavaLangClassMemberReference extends PsiReferenceBase<PsiLiteralExp
.filter(method -> isRegularMethod(method) && isPotentiallyAccessible(method, psiClass))
.sorted(Comparator.comparingInt((PsiMethod method) -> getMethodSortOrder(method)).thenComparing(PsiMethod::getName))
.map(method -> withPriority(lookupMethod(method), -getMethodSortOrder(method)))
.filter(Objects::nonNull)
.toArray();
}
}
@@ -152,19 +155,24 @@ public class JavaLangClassMemberReference extends PsiReferenceBase<PsiLiteralExp
return member != null && (member.getContainingClass() == psiClass || isPublic(member));
}
@NotNull
private LookupElement lookupMethod(PsiMethod method) {
return JavaLookupElementBuilder.forMethod(method, PsiSubstitutor.EMPTY).withInsertHandler(this);
@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();
if (object instanceof PsiMethod) {
final String text = getParameterTypesText((PsiMethod)object);
if (text != null) {
replaceText(context, text.isEmpty() ? "" : ", " + text);
}
if (object instanceof ReflectiveSignature) {
final ReflectiveSignature signature = (ReflectiveSignature)object;
final String text = signature.getText(false, false, type -> type + ".class");
replaceText(context, text.isEmpty() ? "" : ", " + text);
}
}
}

View File

@@ -32,6 +32,7 @@ import org.jetbrains.annotations.Nullable;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Objects;
import java.util.Set;
import java.util.function.Predicate;
@@ -144,6 +145,7 @@ public class JavaLangInvokeHandleReference extends PsiReferenceBase<PsiLiteralEx
.map(method -> withPriority(JavaLookupElementBuilder.forMethod(method, PsiSubstitutor.EMPTY)
.withInsertHandler(this),
-getMethodSortOrder(method)))
.filter(Objects::nonNull)
.toArray();
}

View File

@@ -259,9 +259,9 @@ public class JavaReflectionReferenceUtil {
return hasPriority ? lookupElement : PrioritizedLookupElement.withPriority(lookupElement, -1);
}
@NotNull
static LookupElement withPriority(@NotNull LookupElement lookupElement, int priority) {
return priority == 0 ? lookupElement : PrioritizedLookupElement.withPriority(lookupElement, priority);
@Nullable
static LookupElement withPriority(@Nullable LookupElement lookupElement, int priority) {
return priority == 0 || lookupElement == null ? lookupElement : PrioritizedLookupElement.withPriority(lookupElement, priority);
}
static int getMethodSortOrder(@NotNull PsiMethod method) {
@@ -460,7 +460,11 @@ public class JavaReflectionReferenceUtil {
}
public String getText(boolean withReturnType, @NotNull Function<String, String> transformation) {
final StringJoiner joiner = new StringJoiner(", ", "(", ")");
return getText(withReturnType, true, transformation);
}
public String getText(boolean withReturnType, boolean withParentheses, @NotNull Function<String, String> transformation) {
final StringJoiner joiner = new StringJoiner(", ", withParentheses ? "(" : "", withParentheses ? ")" : "");
if (withReturnType) {
joiner.add(transformation.apply(myReturnType));
}

View File

@@ -0,0 +1,11 @@
class Main {
void foo() {
Test.class.getDeclaredMethod("foo<caret>");
}
}
class Test {
public void foo(){}
public void foo(int n){}
public void foo(String s){}
}

View File

@@ -0,0 +1,11 @@
class Main {
void foo() {
Test.class.getDeclaredMethod("foo", String.class);
}
}
class Test {
public void foo(){}
public void foo(int n){}
public void foo(String s){}
}

View File

@@ -25,37 +25,40 @@ class JavaReflectionCompletionOverloadTest : LightFixtureCompletionTestCase() {
override fun getBasePath() = JavaTestUtil.getRelativeJavaTestDataPath() + "/codeInsight/completion/reflectionOverload/"
fun testOverloadMethods() = doTest(2,
"method()", "method(C c)", "method(A a,B b)",
"equals(java.lang.Object obj)")
"method()", "method(C)", "method(A, B)",
"equals(Object)")
fun testJavaLangObjectMethods() = doTest(6,
fun testJavaLangObjectMethods() = doTest(5,
"method()",
"equals(java.lang.Object obj)", "hashCode()", "toString()",
"getClass()", "notify()", "notifyAll()",
"wait()", "wait(long timeout)", "wait(long timeout,int nanos)"
"equals(Object)", "getClass()", "hashCode()",
"notify()", "notifyAll()", "toString()",
"wait()", "wait(long)", "wait(long, int)"
)
fun testJavaLangObjectOwnMethods() = doTest(9,
"clone()", "equals(java.lang.Object obj)", "hashCode()",
"toString()", "finalize()", "getClass()",
"notify()", "notifyAll()",
"wait()", "wait(long timeout)", "wait(long timeout,int nanos)")
fun testJavaLangObjectOwnMethods() = doTest(10,
"clone()", "equals(Object)",
"finalize()", "getClass()", "hashCode()",
"notify()", "notifyAll()", "registerNatives()", "toString()",
"wait()", "wait(long)", "wait(long, int)")
fun testOverriddenMethod() = doTest(2,
"gpMethod(A a,B b)", "method()", "pMethod(C c)",
"equals(java.lang.Object obj)")
"gpMethod(A, B)", "method()", "pMethod(C)",
"equals(Object)")
fun testShadowedMethod() = doTest(0,
"shadowed()",
"equals(java.lang.Object obj)")
"equals(Object)")
fun testOverloadedMethod() = doTest(1,
"overloaded()", "overloaded(int n)",
"equals(java.lang.Object obj)")
"overloaded()", "overloaded(int)",
"equals(Object)")
fun testOverloadedMethodPrefix() = doTest(2,
"foo()", "foo(int)", "foo(String)")
fun testOverloadedInheritedMethod() = doTest(1,
"overloaded(int n)", "overloaded(java.lang.String s)",
"equals(java.lang.Object obj)")
"overloaded(int)", "overloaded(String)",
"equals(Object)")
private fun doTest(index: Int, vararg expected: String) {

View File

@@ -39,7 +39,7 @@ public class JavaReflectionCompletionTest extends LightFixtureCompletionTestCase
}
public void testDeclaredMethod() throws Exception {
doTest(2, "method", "method1", "method2", "method0");
doTest(3, "method", "method0", "method1", "method2");
}
public void testDeclaredMethod2() throws Exception {

View File

@@ -121,7 +121,7 @@ fun lookupFirstItemsTexts(lookupItems: List<LookupElement?>, maxSize: Int): List
else -> {
val presentation = LookupElementPresentation()
it?.renderElement(presentation)
presentation.itemText ?: ""
(presentation.itemText ?: "") + (presentation.tailText ?: "")
}
}
}