IDEA-172186 Autocomplete for interface method does not work if prefixed with 'default' keyword

This commit is contained in:
peter
2017-05-03 16:55:49 +02:00
parent 5a7559c85f
commit 24e81df27c
5 changed files with 70 additions and 25 deletions
@@ -20,20 +20,27 @@ import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.codeInsight.lookup.LookupElementBuilder;
import com.intellij.codeInspection.ex.GlobalInspectionContextBase;
import com.intellij.icons.AllIcons;
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.text.StringUtil;
import com.intellij.psi.*;
import com.intellij.psi.infos.CandidateInfo;
import com.intellij.psi.util.*;
import com.intellij.psi.util.MethodSignature;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.ui.RowIcon;
import com.intellij.util.ObjectUtils;
import com.intellij.util.VisibilityUtil;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.util.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import static com.intellij.patterns.PlatformPatterns.psiElement;
@@ -50,25 +57,30 @@ public class JavaGenerateMemberCompletionContributor {
PsiElement position = parameters.getPosition();
if (psiElement(PsiIdentifier.class).withParents(PsiJavaCodeReferenceElement.class, PsiTypeElement.class, PsiClass.class).
andNot(JavaKeywordCompletion.AFTER_DOT).
andNot(psiElement().afterLeaf(psiElement().inside(PsiModifierList.class))).accepts(position)) {
suggestGeneratedMethods(result, position);
andNot(JavaKeywordCompletion.AFTER_DOT).accepts(position)) {
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()));
}
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);
suggestGeneratedMethods(result.withPrefixMatcher(annotation.getText().substring(0, parameters.getOffset() - annoStart)), position, (PsiModifierList)annotation.getParent());
}
}
private static void suggestGeneratedMethods(CompletionResultSet result, PsiElement position) {
private static void suggestGeneratedMethods(CompletionResultSet result, PsiElement position, @Nullable PsiModifierList modifierList) {
PsiClass parent = CompletionUtil.getOriginalElement(ObjectUtils.assertNotNull(PsiTreeUtil.getParentOfType(position, PsiClass.class)));
if (parent != null) {
Set<MethodSignature> addedSignatures = ContainerUtil.newHashSet();
addGetterSetterElements(result, parent, addedSignatures);
addSuperSignatureElements(parent, true, result, addedSignatures);
addSuperSignatureElements(parent, false, result, addedSignatures);
boolean generateDefaultMethods = modifierList != null && modifierList.hasModifierProperty(PsiModifier.DEFAULT);
addSuperSignatureElements(parent, true, result, addedSignatures, generateDefaultMethods);
addSuperSignatureElements(parent, false, result, addedSignatures, generateDefaultMethods);
}
}
@@ -90,7 +102,7 @@ public class JavaGenerateMemberCompletionContributor {
insertGenerationInfos(context, Collections.singletonList(new PsiGenerationInfo<>(prototype)));
}
}));
}, false, parent));
if (count++ > 100) return;
}
@@ -103,20 +115,20 @@ public class JavaGenerateMemberCompletionContributor {
context.commitDocument();
}
private static void addSuperSignatureElements(final PsiClass parent, boolean implemented, CompletionResultSet result, Set<MethodSignature> addedSignatures) {
private static void addSuperSignatureElements(PsiClass parent, boolean implemented, CompletionResultSet result, Set<MethodSignature> addedSignatures, boolean generateDefaultMethods) {
for (CandidateInfo candidate : OverrideImplementExploreUtil.getMethodsToOverrideImplement(parent, implemented)) {
PsiMethod baseMethod = (PsiMethod)candidate.getElement();
PsiClass baseClass = baseMethod.getContainingClass();
PsiSubstitutor substitutor = candidate.getSubstitutor();
if (!baseMethod.isConstructor() && baseClass != null && addedSignatures.add(baseMethod.getSignature(substitutor))) {
result.addElement(createOverridingLookupElement(implemented, baseMethod, baseClass, substitutor));
result.addElement(createOverridingLookupElement(implemented, baseMethod, baseClass, substitutor, generateDefaultMethods, parent));
}
}
}
private static LookupElementBuilder createOverridingLookupElement(boolean implemented,
final PsiMethod baseMethod,
PsiClass baseClass, PsiSubstitutor substitutor) {
PsiClass baseClass, PsiSubstitutor substitutor, boolean generateDefaultMethods, PsiClass targetClass) {
RowIcon icon = new RowIcon(baseMethod.getIcon(0), implemented ? AllIcons.Gutter.ImplementingMethod : AllIcons.Gutter.OverridingMethod);
return createGenerateMethodElement(baseMethod, substitutor, icon, baseClass.getName(), new InsertHandler<LookupElement>() {
@@ -127,10 +139,25 @@ public class JavaGenerateMemberCompletionContributor {
final PsiClass parent = PsiTreeUtil.findElementOfClassAtOffset(context.getFile(), context.getStartOffset(), PsiClass.class, false);
if (parent == null) return;
List<PsiMethod> prototypes = OverrideImplementUtil.overrideOrImplementMethod(parent, baseMethod, false);
insertGenerationInfos(context, OverrideImplementUtil.convert2GenerationInfos(prototypes));
try (AccessToken ignored = generateDefaultMethods ? forceDefaultMethodsInside() : AccessToken.EMPTY_ACCESS_TOKEN) {
List<PsiMethod> prototypes = OverrideImplementUtil.overrideOrImplementMethod(parent, baseMethod, false);
insertGenerationInfos(context, OverrideImplementUtil.convert2GenerationInfos(prototypes));
}
}
});
}, generateDefaultMethods, targetClass);
}
private static AccessToken forceDefaultMethodsInside() {
CommandProcessor instance = CommandProcessor.getInstance();
String commandName = instance.getCurrentCommandName();
instance.setCurrentCommandName(OverrideImplementUtil.IMPLEMENT_COMMAND_MARKER);
return new AccessToken() {
@Override
public void finish() {
instance.setCurrentCommandName(commandName);
}
};
}
private static void insertGenerationInfos(InsertionContext context, List<PsiGenerationInfo<PsiMethod>> infos) {
@@ -140,10 +167,7 @@ public class JavaGenerateMemberCompletionContributor {
final List<PsiElement> elements = new ArrayList<>();
for (GenerationInfo member : newInfos) {
if (!(member instanceof TemplateGenerationInfo)) {
final PsiMember psiMember = member.getPsiMember();
if (psiMember != null) {
elements.add(psiMember);
}
elements.add(member.getPsiMember());
}
}
@@ -155,11 +179,16 @@ public class JavaGenerateMemberCompletionContributor {
private static LookupElementBuilder createGenerateMethodElement(PsiMethod prototype,
PsiSubstitutor substitutor,
Icon icon,
String typeText, InsertHandler<LookupElement> insertHandler) {
String typeText, InsertHandler<LookupElement> insertHandler,
boolean generateDefaultMethod,
PsiClass targetClass) {
String methodName = prototype.getName();
String visibility = VisibilityUtil.getVisibilityModifier(prototype.getModifierList());
String modifiers = (visibility == PsiModifier.PACKAGE_LOCAL ? "" : visibility + " ");
String modifiers = (visibility == PsiModifier.PACKAGE_LOCAL || visibility == PsiModifier.PUBLIC && targetClass.isInterface() ? "" : visibility + " ");
if (generateDefaultMethod) {
modifiers = "default " + modifiers;
}
PsiType type = substitutor.substitute(prototype.getReturnType());
String signature = modifiers + (type == null ? "" : type.getPresentableText() + " ") + methodName;
@@ -173,7 +202,7 @@ public class JavaGenerateMemberCompletionContributor {
withLookupString(signature).withLookupString(overrideSignature).withInsertHandler(insertHandler).
appendTailText(parameters, false).appendTailText(" {...}", true).withTypeText(typeText).withIcon(icon);
if (prototype.isDeprecated()) {
element = element.setStrikeout(true);
element = element.withStrikeoutness(true);
}
element.putUserData(GENERATE_ELEMENT, true);
return element;
@@ -71,6 +71,7 @@ import java.util.*;
public class OverrideImplementUtil extends OverrideImplementExploreUtil {
private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.generation.OverrideImplementUtil");
public static final String IMPLEMENT_COMMAND_MARKER = "implement";
private OverrideImplementUtil() { }
@@ -385,7 +386,7 @@ public class OverrideImplementUtil extends OverrideImplementExploreUtil {
return false;
}
String commandName = CommandProcessor.getInstance().getCurrentCommandName();
return commandName != null && StringUtil.containsIgnoreCase(commandName, "implement");
return commandName != null && StringUtil.containsIgnoreCase(commandName, IMPLEMENT_COMMAND_MARKER);
}
public static void chooseAndOverrideMethods(Project project, Editor editor, PsiClass aClass){
@@ -0,0 +1,3 @@
interface Foo extends Runnable {
default ru<caret>x
}
@@ -0,0 +1,6 @@
interface Foo extends Runnable {
@Override
default void run() {
<caret>
}
}
@@ -19,7 +19,6 @@ import com.intellij.JavaTestUtil
import com.intellij.codeInsight.CodeInsightSettings
import com.intellij.codeInsight.lookup.LookupElementPresentation
import com.intellij.testFramework.LightProjectDescriptor
/**
* @author anna
*/
@@ -289,4 +288,11 @@ class Test88 {
checkResultByFile(getTestName(false) + "_after.java")
}
void testOverrideMethodAsDefault() {
configureByTestName()
assert LookupElementPresentation.renderElement(myFixture.lookupElements[0]).itemText == 'default void run'
myFixture.type('\t')
checkResultByFile(getTestName(false) + "_after.java")
}
}