From 480104b91da300c0ec266c051cf4fe7e1ae7692a Mon Sep 17 00:00:00 2001 From: Peter Gromov Date: Wed, 17 Jun 2020 06:54:34 +0200 Subject: [PATCH] java completion: supply same-named classes in batches for more deterministic sorting and preselection (IDEA-229266) GitOrigin-RevId: 44c3e4a0f9a150082b1f3210b25f5b4c79f64e7f --- .../completion/JavaCompletionContributor.java | 6 +---- .../completion/JavaNoVariantsDelegator.java | 19 ++++++++----- .../completion/CompletionSortingTestCase.java | 3 ++- .../completion/JavaAutoPopupTest.groovy | 27 +++++++++++++++++++ 4 files changed, 42 insertions(+), 13 deletions(-) diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionContributor.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionContributor.java index 04a30bc8bbb7..3cf7dce28caa 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionContributor.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionContributor.java @@ -527,11 +527,7 @@ public class JavaCompletionContributor extends CompletionContributor { } if (parameters.getInvocationCount() >= 2) { - JavaClassNameCompletionContributor.addAllClasses(parameters, parameters.getInvocationCount() <= 2, result.getPrefixMatcher(), element -> { - if (!session.alreadyProcessed(element)) { - result.addElement(JavaCompletionUtil.highlightIfNeeded(null, element, element.getObject(), parameters.getPosition())); - } - }); + JavaNoVariantsDelegator.suggestNonImportedClasses(parameters, result, session); } else { advertiseSecondCompletion(parameters.getPosition().getProject(), result); diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaNoVariantsDelegator.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaNoVariantsDelegator.java index cad19a169634..5b8d792b31ab 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaNoVariantsDelegator.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaNoVariantsDelegator.java @@ -32,9 +32,7 @@ import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.Collections; -import java.util.LinkedHashSet; -import java.util.Set; +import java.util.*; import static com.intellij.patterns.PsiJavaPatterns.psiElement; @@ -196,18 +194,25 @@ public class JavaNoVariantsDelegator extends CompletionContributor { return allClasses; } - private static void suggestNonImportedClasses(CompletionParameters parameters, CompletionResultSet result, @Nullable JavaCompletionSession session) { - JavaClassNameCompletionContributor.addAllClasses(parameters, true, result.getPrefixMatcher(), element -> { + static void suggestNonImportedClasses(CompletionParameters parameters, CompletionResultSet result, @Nullable JavaCompletionSession session) { + List sameNamedBatch = new ArrayList<>(); + JavaClassNameCompletionContributor.addAllClasses(parameters, parameters.getInvocationCount() <= 2, result.getPrefixMatcher(), element -> { if (session != null && session.alreadyProcessed(element)) { return; } JavaPsiClassReferenceElement classElement = element.as(JavaPsiClassReferenceElement.CLASS_CONDITION_KEY); - if (classElement != null) { + if (classElement != null && parameters.getInvocationCount() < 2) { classElement.setAutoCompletionPolicy(AutoCompletionPolicy.NEVER_AUTOCOMPLETE); } - result.addElement(element); + element = JavaCompletionUtil.highlightIfNeeded(null, element, element.getObject(), parameters.getPosition()); + if (!sameNamedBatch.isEmpty() && !element.getLookupString().equals(sameNamedBatch.get(0).getLookupString())) { + result.addAllElements(sameNamedBatch); + sameNamedBatch.clear(); + } + sameNamedBatch.add(element); }); + result.addAllElements(sameNamedBatch); } public static class ResultTracker implements Consumer { diff --git a/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/CompletionSortingTestCase.java b/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/CompletionSortingTestCase.java index 9b12a7b68e2a..6324b851aa2d 100644 --- a/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/CompletionSortingTestCase.java +++ b/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/CompletionSortingTestCase.java @@ -5,6 +5,7 @@ import com.intellij.codeInsight.completion.CompletionType; import com.intellij.codeInsight.completion.LightFixtureCompletionTestCase; import com.intellij.codeInsight.completion.StatisticsUpdate; import com.intellij.codeInsight.lookup.LookupElement; +import com.intellij.codeInsight.lookup.LookupEx; import com.intellij.codeInsight.lookup.impl.LookupImpl; import com.intellij.ide.ui.UISettings; import com.intellij.psi.statistics.StatisticsManager; @@ -76,7 +77,7 @@ public abstract class CompletionSortingTestCase extends LightFixtureCompletionTe lookup.resort(true); } - protected static void imitateItemSelection(final LookupImpl lookup, final int index) { + protected static void imitateItemSelection(LookupEx lookup, final int index) { final LookupElement item = lookup.getItems().get(index); lookup.setCurrentItem(item); StatisticsUpdate.collectStatisticChanges(item); diff --git a/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/JavaAutoPopupTest.groovy b/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/JavaAutoPopupTest.groovy index a47141cd8be9..a46b4942f2ad 100644 --- a/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/JavaAutoPopupTest.groovy +++ b/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/JavaAutoPopupTest.groovy @@ -40,6 +40,8 @@ import com.intellij.psi.NavigatablePsiElement import com.intellij.psi.PsiClass import com.intellij.psi.PsiJavaFile import com.intellij.psi.PsiMethod +import com.intellij.psi.statistics.StatisticsManager +import com.intellij.psi.statistics.impl.StatisticsManagerImpl import com.intellij.psi.util.InheritanceUtil import com.intellij.testFramework.TestModeFlags import com.intellij.testFramework.fixtures.CodeInsightTestUtil @@ -1809,4 +1811,29 @@ ita assert firstItems.each { InheritanceUtil.isInheritor(it.object as PsiClass, List.name) } } + void "test prefer previously selected despite many namesakes"() { + ((StatisticsManagerImpl)StatisticsManager.getInstance()).enableStatistics(myFixture.getTestRootDisposable()) + + def count = 400 + def toSelect = 390 + for (i in 0.." + type 'MyCla' + myFixture.assertPreferredCompletionItems 0, Collections.nCopies(count, 'MyClass') as String[] + + edt { + assert LookupElementPresentation.renderElement(myFixture.lookup.items[toSelect]).tailText == " p$toSelect" + CompletionSortingTestCase.imitateItemSelection(myFixture.lookup, toSelect) + myFixture.lookup.hideLookup(true) + } + + type 's' + myFixture.assertPreferredCompletionItems 0, Collections.nCopies(count, 'MyClass') as String[] + edt { + assert LookupElementPresentation.renderElement(myFixture.lookup.items[0]).tailText == " p$toSelect" + } + } + }