diff --git a/java/java-tests/testData/codeInsight/completion/normalSorting/UnderscoresDontMakeMatchMiddle.java b/java/java-tests/testData/codeInsight/completion/normalSorting/UnderscoresDontMakeMatchMiddle.java new file mode 100644 index 000000000000..7867e3415883 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/normalSorting/UnderscoresDontMakeMatchMiddle.java @@ -0,0 +1,5 @@ +class FooBar { + void foo(FooBar _fooBar) { + fb + } +} \ 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 0f73a23f289f..771413f86736 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionOrderingTest.groovy +++ b/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionOrderingTest.groovy @@ -378,4 +378,9 @@ public class NormalCompletionOrderingTest extends CompletionSortingTestCase { assertPreferredItems(0, 'fooy', 'foox', 'fooAClass', 'fooBar'); } + public void testUnderscoresDontMakeMatchMiddle() { + CodeInsightSettings.getInstance().COMPLETION_CASE_SENSITIVE = CodeInsightSettings.NONE; + checkPreferredItems(0, '_fooBar', 'FooBar') + } + } 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 ba7543e680da..63f738b5b147 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 @@ -147,10 +147,7 @@ public class CompletionServiceImpl extends CompletionService{ Iterable fragments = matcher.matchingFragments(ls); if (fragments != null) { Iterator iterator = fragments.iterator(); - if (!ls.isEmpty() && prefix.charAt(0) == ls.charAt(0)) { - return false; - } - if (iterator.hasNext() && iterator.next().contains(0)) { + if (!iterator.hasNext() || MinusculeMatcher.isStartMatch(ls, iterator.next().getStartOffset())) { return false; } } diff --git a/platform/platform-tests/testSrc/com/intellij/psi/util/NameUtilTest.java b/platform/platform-tests/testSrc/com/intellij/psi/util/NameUtilTest.java index ef0108a05aa4..d02b2e454f64 100644 --- a/platform/platform-tests/testSrc/com/intellij/psi/util/NameUtilTest.java +++ b/platform/platform-tests/testSrc/com/intellij/psi/util/NameUtilTest.java @@ -380,6 +380,7 @@ public class NameUtilTest extends UsefulTestCase { } public void testPreferStartMatchToMiddleMatch() { + assertPreference(" fb", "FooBar", "_fooBar", NameUtil.MatchingCaseSensitivity.NONE); assertPreference("*foo", "barFoo", "foobar"); assertPreference("*f", "barfoo", "barFoo"); assertPreference("*f", "barfoo", "foo"); diff --git a/platform/util/src/com/intellij/psi/codeStyle/MinusculeMatcher.java b/platform/util/src/com/intellij/psi/codeStyle/MinusculeMatcher.java index fcac227f07d9..59919fd3e0d0 100644 --- a/platform/util/src/com/intellij/psi/codeStyle/MinusculeMatcher.java +++ b/platform/util/src/com/intellij/psi/codeStyle/MinusculeMatcher.java @@ -269,18 +269,31 @@ public class MinusculeMatcher implements Matcher { fragmentCount++; } + if (first == null) { + return 0; + } + int commonStart = 0; while (commonStart < name.length() && commonStart < myPattern.length && name.charAt(commonStart) == myPattern[commonStart]) { commonStart++; } - boolean prefixMatching = first != null && first.getStartOffset() == 0; - boolean middleWordStart = first != null && first.getStartOffset() > 0 && NameUtil.isWordStart(name, first.getStartOffset()); - int startIndex = first != null ? first.getStartOffset() : 42; + int startIndex = first.getStartOffset(); + boolean prefixMatching = isStartMatch(name, startIndex); + boolean middleWordStart = !prefixMatching && NameUtil.isWordStart(name, first.getStartOffset()); return -fragmentCount + matchingCase * 10 + commonStart - startIndex + (prefixMatching ? 2 : middleWordStart ? 1 : 0) * 100; } + public static boolean isStartMatch(String name, int startIndex) { + for (int i = 0; i < startIndex; i++) { + if (!NameUtil.isWordSeparator(name.charAt(i))) { + return false; + } + } + return true; + } + @Override public boolean matches(String name) { return matchingFragments(name) != null;