diff --git a/java/java-tests/testData/codeInsight/completion/normalSorting/StatisticsByPrefix.java b/java/java-tests/testData/codeInsight/completion/normalSorting/StatisticsByPrefix.java new file mode 100644 index 000000000000..3e96c0452b07 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/normalSorting/StatisticsByPrefix.java @@ -0,0 +1,6 @@ +class FooBar { + int _foo1, _foo2, _boo1, _boo2, _goo1, _goo2; + { + + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionOrderingTest.groovy b/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionOrderingTest.groovy index f32e491cbf72..a5797213a6c9 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionOrderingTest.groovy +++ b/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionOrderingTest.groovy @@ -14,6 +14,7 @@ import com.intellij.ide.ui.UISettings import com.intellij.psi.PsiClass import com.intellij.psi.PsiMethod import com.intellij.openapi.fileEditor.FileDocumentManager +import com.intellij.psi.statistics.StatisticsManager public class NormalCompletionOrderingTest extends CompletionSortingTestCase { private static final String BASE_PATH = "/codeInsight/completion/normalSorting"; @@ -397,4 +398,39 @@ public class NormalCompletionOrderingTest extends CompletionSortingTestCase { assert lookup.currentItem.lookupString == 'JComponent' } + public void testStatisticsByPrefix() { + Closure repeatCompletion = { String letter -> + String var1 = "_${letter}oo1" + String var2 = "_${letter}oo2" + + myFixture.type("_$letter"); + myFixture.completeBasic(); + assertPreferredItems(0, var1, var2) + myFixture.type('2\n;\n') + + for (i in 0.. items = lookupImpl.getItems(); final int count = Math.min(3, lookupImpl.getList().getSelectedIndex()); - final List ignored = new ArrayList(); + final List toIncrement = new ArrayList(); for (int i = 0; i < count; i++) { final LookupElement element = items.get(i); StatisticsInfo baseInfo = StatisticsManager.serialize(CompletionService.STATISTICS_KEY, element, myLocation); if (baseInfo != null && baseInfo != StatisticsInfo.EMPTY && StatisticsManager.getInstance().getUseCount(baseInfo) == 0) { - ignored.add(new StatisticsInfo(composeContextWithValue(baseInfo), IGNORED)); + toIncrement.add(new StatisticsInfo(composeContextWithValue(baseInfo), IGNORED)); } } + if (main != null && main != StatisticsInfo.EMPTY) { + toIncrement.addAll(StatisticsWeigher.composeStatsWithPrefix(main, myLocation, item)); + } - StatisticsInfo info = StatisticsManager.serialize(CompletionService.STATISTICS_KEY, item, myLocation); - final StatisticsInfo selected = - info != null && info != StatisticsInfo.EMPTY ? new StatisticsInfo(composeContextWithValue(info), SELECTED) : null; - - StatisticsUpdate update = new StatisticsUpdate(ignored, selected, main); + StatisticsUpdate update = new StatisticsUpdate(toIncrement); ourPendingUpdate = update; Disposer.register(update, new Disposable() { @Override @@ -363,27 +362,17 @@ public class CompletionLookupArranger extends LookupArranger { } static class StatisticsUpdate implements Disposable { - private final List myIgnored; - private final StatisticsInfo mySelected; - private final StatisticsInfo myMain; + private final List myInfos; private int mySpared; - public StatisticsUpdate(List ignored, StatisticsInfo selected, StatisticsInfo main) { - myIgnored = ignored; - mySelected = selected; - myMain = main; + public StatisticsUpdate(List infos) { + myInfos = infos; } void performUpdate() { - for (StatisticsInfo statisticsInfo : myIgnored) { + for (StatisticsInfo statisticsInfo : myInfos) { StatisticsManager.getInstance().incUseCount(statisticsInfo); } - if (mySelected != null) { - StatisticsManager.getInstance().incUseCount(mySelected); - } - if (myMain != null) { - StatisticsManager.getInstance().incUseCount(myMain); - } ((FeatureUsageTrackerImpl)FeatureUsageTracker.getInstance()).getCompletionStatistics().registerInvocation(mySpared); } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/completion/StatisticsWeigher.java b/platform/lang-impl/src/com/intellij/codeInsight/completion/StatisticsWeigher.java index 141d96b7c443..f8aa0d023eaf 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/completion/StatisticsWeigher.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/StatisticsWeigher.java @@ -16,15 +16,54 @@ package com.intellij.codeInsight.completion; import com.intellij.codeInsight.lookup.LookupElement; +import com.intellij.codeInsight.lookup.LookupElementWeigher; +import com.intellij.psi.statistics.StatisticsInfo; import com.intellij.psi.statistics.StatisticsManager; import org.jetbrains.annotations.NotNull; +import java.util.ArrayList; +import java.util.List; + /** * @author peter */ public class StatisticsWeigher extends CompletionWeigher { + private static final StatisticsManager ourStatManager = StatisticsManager.getInstance(); public Comparable weigh(@NotNull final LookupElement item, @NotNull final CompletionLocation location) { - return StatisticsManager.getInstance().getUseCount(CompletionService.STATISTICS_KEY, item, location); + throw new UnsupportedOperationException(); + } + + public static class LookupStatisticsWeigher extends LookupElementWeigher { + private final CompletionLocation myLocation; + + public LookupStatisticsWeigher(CompletionLocation location) { + super("stats", true, true); + myLocation = location; + } + + @Override + public Integer weigh(@NotNull LookupElement item) { + final StatisticsInfo info = StatisticsManager.serialize(CompletionService.STATISTICS_KEY, item, myLocation); + if (info == null || info == StatisticsInfo.EMPTY) { + return 0; + } + int max = 0; + for (StatisticsInfo statisticsInfo : composeStatsWithPrefix(info, myLocation, item)) { + max = Math.max(max, ourStatManager.getUseCount(statisticsInfo)); + } + return max; + } + } + + public static List composeStatsWithPrefix(StatisticsInfo info, CompletionLocation location, LookupElement item) { + String fullPrefix = location.getCompletionParameters().getLookup().itemPattern(item); + ArrayList infos = new ArrayList(fullPrefix.length() + 1); + infos.add(info); + for (int i = 1; i <= fullPrefix.length(); i++) { + String subPrefix = fullPrefix.substring(0, i); + infos.add(new StatisticsInfo(info.getContext() + "###prefix=" + subPrefix, info.getValue())); + } + return infos; } } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/completion/impl/CompletionServiceImpl.java b/platform/lang-impl/src/com/intellij/codeInsight/completion/impl/CompletionServiceImpl.java index 585cac87ec4b..1bb16ce24f1c 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/completion/impl/CompletionServiceImpl.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/impl/CompletionServiceImpl.java @@ -245,6 +245,9 @@ public class CompletionServiceImpl extends CompletionService{ if ("prefix".equals(id)) { sorter = sorter.withClassifier(CompletionSorterImpl.weighingFactory(new PrefixMatchingClassifier(location))); } + else if ("stats".equals(id)) { + sorter = sorter.withClassifier(CompletionSorterImpl.weighingFactory(new StatisticsWeigher.LookupStatisticsWeigher(location))); + } else { sorter = sorter.weigh(new LookupElementWeigher(id, true, false) { @Override