mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IDEA-172186 Autocomplete for interface method does not work if prefixed with 'default' keyword
This commit is contained in:
+52
-23
@@ -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){
|
||||
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
interface Foo extends Runnable {
|
||||
default ru<caret>x
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
interface Foo extends Runnable {
|
||||
@Override
|
||||
default void run() {
|
||||
<caret>
|
||||
}
|
||||
}
|
||||
+7
-1
@@ -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")
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user