diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionSorting.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionSorting.java index c1d9496ab292..0b73809e9d4e 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionSorting.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionSorting.java @@ -64,6 +64,7 @@ public class JavaCompletionSorting { ContainerUtil.addIfNotNull(afterProximity, PreferMostUsedWeigher.create(position)); afterProximity.add(new PreferContainingSameWords(expectedTypes)); afterProximity.add(new PreferShorter(expectedTypes)); + afterProximity.add(new DispreferTechnicalOverloads(position)); CompletionSorter sorter = CompletionSorter.defaultSorter(parameters, result.getPrefixMatcher()); if (!smart && afterNew) { @@ -608,6 +609,42 @@ public class JavaCompletionSorting { } } + /** + * Sometimes there's core vararg method and a couple of overloads of fixed arity to avoid runtime invocation costs of varargs. + * We prefer the vararg method then. + */ + private static class DispreferTechnicalOverloads extends LookupElementWeigher { + private final PsiElement myPlace; + + DispreferTechnicalOverloads(PsiElement place) { + super("technicalOverloads"); + myPlace = place; + } + + @NotNull + @Override + public Comparable weigh(@NotNull LookupElement element) { + Object object = element.getObject(); + if (object instanceof PsiMethod && element.getUserData(JavaCompletionUtil.FORCE_SHOW_SIGNATURE_ATTR) == null) { + PsiMethod method = (PsiMethod)object; + PsiClass containingClass = method.getContainingClass(); + if (!method.isVarArgs() && + containingClass != null && + ContainerUtil.exists(containingClass.findMethodsByName(method.getName(), false), m -> isPurelyVarargOverload(method, m))) { + return true; + } + } + return false; + } + + private boolean isPurelyVarargOverload(PsiMethod original, PsiMethod candidate) { + return candidate.hasModifierProperty(PsiModifier.STATIC) == original.hasModifierProperty(PsiModifier.STATIC) && + candidate.isVarArgs() && + candidate.getParameterList().getParametersCount() == 1 && + PsiResolveHelper.SERVICE.getInstance(candidate.getProject()).isAccessible(candidate, myPlace, null); + } + } + private static class LiftShorterClasses extends ClassifierFactory { final ProjectFileIndex fileIndex; private final PsiElement myPosition; diff --git a/java/java-tests/testData/codeInsight/completion/normal/PutCaretInsideParensInFixedPlusVarargOverloads.java b/java/java-tests/testData/codeInsight/completion/normal/PutCaretInsideParensInFixedPlusVarargOverloads.java new file mode 100644 index 000000000000..b6ab7b3e9047 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/normal/PutCaretInsideParensInFixedPlusVarargOverloads.java @@ -0,0 +1,10 @@ +class C { + void method() {} + void method(String s) {} + void method(String... s) {} + void method1(String... s) {} + + { + me + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/completion/normal/PutCaretInsideParensInFixedPlusVarargOverloads_after.java b/java/java-tests/testData/codeInsight/completion/normal/PutCaretInsideParensInFixedPlusVarargOverloads_after.java new file mode 100644 index 000000000000..d5627c0db3a0 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/normal/PutCaretInsideParensInFixedPlusVarargOverloads_after.java @@ -0,0 +1,10 @@ +class C { + void method() {} + void method(String s) {} + void method(String... s) {} + void method1(String... s) {} + + { + method(); + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/NormalCompletionTest.groovy b/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/NormalCompletionTest.groovy index d07ac5245f4a..fffd63b9d354 100644 --- a/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/NormalCompletionTest.groovy +++ b/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/NormalCompletionTest.groovy @@ -1892,4 +1892,6 @@ class Abc { void testNoSuggestionsAfterEnumConstant() { doAntiTest() } + void testPutCaretInsideParensInFixedPlusVarargOverloads() { doTest('\n') } + }