java completion: don't suggest overridden members if they match by middle of the name (IDEA-195106)

This commit is contained in:
peter
2018-11-22 15:30:03 +01:00
parent b5ad7b6f89
commit 12db18b111
3 changed files with 49 additions and 2 deletions
@@ -1,6 +1,7 @@
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.codeInsight.completion;
import com.intellij.codeInsight.completion.impl.CamelHumpMatcher;
import com.intellij.codeInsight.generation.*;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.codeInsight.lookup.LookupElementBuilder;
@@ -10,6 +11,7 @@ import com.intellij.openapi.application.AccessToken;
import com.intellij.openapi.command.CommandProcessor;
import com.intellij.openapi.util.Iconable;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.*;
import com.intellij.psi.infos.CandidateInfo;
@@ -19,6 +21,7 @@ import com.intellij.ui.RowIcon;
import com.intellij.util.ObjectUtils;
import com.intellij.util.VisibilityUtil;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.FList;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.java.generate.exception.GenerateCodeException;
@@ -48,14 +51,19 @@ public class JavaGenerateMemberCompletionContributor {
PsiElement prevLeaf = PsiTreeUtil.prevVisibleLeaf(position);
PsiModifierList modifierList = PsiTreeUtil.getParentOfType(prevLeaf, PsiModifierList.class);
if (modifierList != null) {
result = result.withPrefixMatcher(position.getContainingFile().getText().substring(modifierList.getTextRange().getStartOffset(), parameters.getOffset()));
String fileText = position.getContainingFile().getText();
result = result.withPrefixMatcher(new NoMiddleMatchesAfterSpace(
fileText.substring(modifierList.getTextRange().getStartOffset(), parameters.getOffset())));
}
suggestGeneratedMethods(result, position, modifierList);
} else if (psiElement(PsiIdentifier.class)
.withParents(PsiJavaCodeReferenceElement.class, PsiAnnotation.class, PsiModifierList.class, PsiClass.class).accepts(position)) {
PsiAnnotation annotation = ObjectUtils.assertNotNull(PsiTreeUtil.getParentOfType(position, PsiAnnotation.class));
int annoStart = annotation.getTextRange().getStartOffset();
suggestGeneratedMethods(result.withPrefixMatcher(annotation.getText().substring(0, parameters.getOffset() - annoStart)), position, (PsiModifierList)annotation.getParent());
suggestGeneratedMethods(
result.withPrefixMatcher(new NoMiddleMatchesAfterSpace(annotation.getText().substring(0, parameters.getOffset() - annoStart))),
position,
(PsiModifierList)annotation.getParent());
}
}
@@ -208,4 +216,29 @@ public class JavaGenerateMemberCompletionContributor {
private static String getShortParameterName(PsiSubstitutor substitutor, PsiParameter p) {
return PsiNameHelper.getShortClassName(substitutor.substitute(p.getType()).getPresentableText(false));
}
private static class NoMiddleMatchesAfterSpace extends CamelHumpMatcher {
NoMiddleMatchesAfterSpace(String prefix) {
super(prefix);
}
@Override
public boolean prefixMatches(@NotNull LookupElement element) {
if (!super.prefixMatches(element)) return false;
if (!myPrefix.contains(" ")) return true;
String signature = element.getLookupString();
FList<TextRange> fragments = matchingFragments(signature);
return fragments == null || fragments.stream().noneMatch(f -> isMiddleMatch(signature, f));
}
private static boolean isMiddleMatch(String signature, TextRange fragment) {
int start = fragment.getStartOffset();
return start > 0 &&
Character.isJavaIdentifierPart(signature.charAt(start)) &&
Character.isJavaIdentifierPart(signature.charAt(start - 1));
}
}
}
@@ -0,0 +1,9 @@
class Foo extends Bar {
public Editor<caret>x
}
class Bar {
public void removeTemporaryEditorNode() {}
}
class Editor {}
@@ -1675,6 +1675,11 @@ class Bar {
assert 'Door' == LookupElementPresentation.renderElement(myFixture.lookup.items[0]).typeText
}
void testNoOverrideWithMiddleMatchedName() {
configure()
assert !('public void removeTemporaryEditorNode' in myFixture.lookupElementStrings)
}
void testShowVarInitializers() {
configure()
assert LookupElementPresentation.renderElement(myFixture.lookup.items[0]).tailText == '( "x")'