diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionContributor.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionContributor.java index 733b04a2b577..b672dbd71531 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionContributor.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionContributor.java @@ -1,6 +1,7 @@ // Copyright 2000-2020 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.application.options.CodeStyle; import com.intellij.codeInsight.ExpectedTypeInfo; import com.intellij.codeInsight.ExpectedTypesProvider; import com.intellij.codeInsight.TailType; @@ -60,6 +61,7 @@ import org.jetbrains.annotations.Nullable; import java.util.*; +import static com.intellij.codeInsight.completion.ReferenceExpressionCompletionContributor.getSpace; import static com.intellij.patterns.PsiJavaPatterns.*; /** @@ -624,36 +626,50 @@ public class JavaCompletionContributor extends CompletionContributor { if (Objects.equals(existingAttr.getName(), attrName) || PsiAnnotation.DEFAULT_REFERENCED_METHOD_NAME.equals(attrName) && existingAttr.getName() == null) continue methods; } - LookupElementBuilder element = LookupElementBuilder.createWithIcon(method) - .withStrikeoutness(PsiImplUtil.isDeprecated(method)) - .withInsertHandler(new InsertHandler() { - @Override - public void handleInsert(@NotNull InsertionContext context, @NotNull LookupElement item) { - final Editor editor = context.getEditor(); - EqTailType.INSTANCE.processTail(editor, editor.getCaretModel().getOffset()); - context.setAddCompletionChar(false); - - context.commitDocument(); - PsiAnnotationParameterList paramList = - PsiTreeUtil.findElementOfClassAtOffset(context.getFile(), context.getStartOffset(), PsiAnnotationParameterList.class, false); - if (paramList != null && paramList.getAttributes().length > 0 && paramList.getAttributes()[0].getName() == null) { - int valueOffset = paramList.getAttributes()[0].getTextRange().getStartOffset(); - context.getDocument().insertString(valueOffset, PsiAnnotation.DEFAULT_REFERENCED_METHOD_NAME); - EqTailType.INSTANCE.processTail(editor, valueOffset + PsiAnnotation.DEFAULT_REFERENCED_METHOD_NAME.length()); - } - } - }); PsiAnnotationMemberValue defaultValue = ((PsiAnnotationMethod)method).getDefaultValue(); - if (defaultValue != null) { - element = element.withTailText(" default " + defaultValue.getText(), true); + String defText = defaultValue == null ? null : defaultValue.getText(); + if (PsiKeyword.TRUE.equals(defText) || PsiKeyword.FALSE.equals(defText)) { + result.addElement(createAnnotationAttributeElement(method, PsiKeyword.TRUE.equals(defText) ? PsiKeyword.FALSE : PsiKeyword.TRUE)); + result.addElement(PrioritizedLookupElement.withPriority(createAnnotationAttributeElement(method, defText).withTailText(" (default)", true), -1)); + } else { + LookupElementBuilder element = createAnnotationAttributeElement(method, null); + if (defText != null) { + element = element.withTailText(" default " + defText, true); + } + result.addElement(element); } - - result.addElement(element); } } } + @NotNull + private static LookupElementBuilder createAnnotationAttributeElement(PsiMethod annoMethod, @Nullable String value) { + String space = getSpace(CodeStyle.getLanguageSettings(annoMethod.getContainingFile()).SPACE_AROUND_ASSIGNMENT_OPERATORS); + String lookupString = annoMethod.getName() + (value == null ? "" : space + "=" + space + value); + return LookupElementBuilder.create(annoMethod, lookupString).withIcon(annoMethod.getIcon(0)) + .withStrikeoutness(PsiImplUtil.isDeprecated(annoMethod)) + .withInsertHandler(new InsertHandler() { + @Override + public void handleInsert(@NotNull InsertionContext context, @NotNull LookupElement item) { + final Editor editor = context.getEditor(); + if (value == null) { + EqTailType.INSTANCE.processTail(editor, editor.getCaretModel().getOffset()); + } + context.setAddCompletionChar(false); + + context.commitDocument(); + PsiAnnotationParameterList paramList = + PsiTreeUtil.findElementOfClassAtOffset(context.getFile(), context.getStartOffset(), PsiAnnotationParameterList.class, false); + if (paramList != null && paramList.getAttributes().length > 0 && paramList.getAttributes()[0].getName() == null) { + int valueOffset = paramList.getAttributes()[0].getTextRange().getStartOffset(); + context.getDocument().insertString(valueOffset, PsiAnnotation.DEFAULT_REFERENCED_METHOD_NAME); + EqTailType.INSTANCE.processTail(editor, valueOffset + PsiAnnotation.DEFAULT_REFERENCED_METHOD_NAME.length()); + } + } + }); + } + @Override public String advertise(@NotNull final CompletionParameters parameters) { if (!(parameters.getOriginalFile() instanceof PsiJavaFile)) return null; diff --git a/java/java-tests/testData/codeInsight/completion/normal/DisplayDefaultValueInAnnotationMethods.java b/java/java-tests/testData/codeInsight/completion/normal/DisplayDefaultValueInAnnotationMethods.java index 2995c015818a..47b3d15ec392 100644 --- a/java/java-tests/testData/codeInsight/completion/normal/DisplayDefaultValueInAnnotationMethods.java +++ b/java/java-tests/testData/codeInsight/completion/normal/DisplayDefaultValueInAnnotationMethods.java @@ -1,6 +1,6 @@ @interface Anno { String myString() default "unknown"; - boolean myBool() default false; + int myInt() default 42; } @Anno() diff --git a/java/java-tests/testData/codeInsight/completion/normal/SuggestInverseOfDefaultAnnoParamValueForBoolean.java b/java/java-tests/testData/codeInsight/completion/normal/SuggestInverseOfDefaultAnnoParamValueForBoolean.java new file mode 100644 index 000000000000..811e55ad7673 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/normal/SuggestInverseOfDefaultAnnoParamValueForBoolean.java @@ -0,0 +1,8 @@ +@Anno() +class C { +} + +@interface Anno { + boolean value() default true; + boolean smth() default false; +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/completion/normal/SuggestInverseOfDefaultAnnoParamValueForBoolean_after.java b/java/java-tests/testData/codeInsight/completion/normal/SuggestInverseOfDefaultAnnoParamValueForBoolean_after.java new file mode 100644 index 000000000000..8861629f4738 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/normal/SuggestInverseOfDefaultAnnoParamValueForBoolean_after.java @@ -0,0 +1,8 @@ +@Anno(smth = true) +class C { +} + +@interface Anno { + boolean value() default true; + boolean smth() default false; +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/NormalCompletionTest.groovy b/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/NormalCompletionTest.groovy index b052b9d340e8..46b55cb407c5 100644 --- a/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/NormalCompletionTest.groovy +++ b/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/NormalCompletionTest.groovy @@ -103,8 +103,8 @@ class NormalCompletionTest extends NormalCompletionTestCase { void testDisplayDefaultValueInAnnotationMethods() { configure() LookupElementPresentation presentation = renderElement(myItems[0]) - assert "myBool" == presentation.itemText - assert presentation.tailText == " default false" + assert "myInt" == presentation.itemText + assert presentation.tailText == " default 42" assert presentation.tailFragments[0].grayed assert !presentation.typeText assert !presentation.itemTextBold @@ -1984,6 +1984,18 @@ class Abc { checkGetClassPresent("class C implements Unresolved {{ getClx }}") checkGetClassPresent("class C extends Unresolved implements Runnable {{ getClx }}") checkGetClassPresent("class C extends Unresolved1 implements Unresolved2 {{ getClx }}") + } + void testSuggestInverseOfDefaultAnnoParamValueForBoolean() { + configureByTestName() + myFixture.assertPreferredCompletionItems(0, 'smth = true', 'value = false') + + def smthDefault = myItems.find { it.lookupString == 'smth = false' } + def presentation = LookupElementPresentation.renderElement(smthDefault) + assert presentation.tailText == ' (default)' + assert presentation.tailFragments[0].grayed + + myFixture.type('\n') + checkResult() } }