From 802f71e3d3d656a1019316454032d6599e935e81 Mon Sep 17 00:00:00 2001 From: Peter Gromov Date: Tue, 9 Jun 2020 19:25:08 +0200 Subject: [PATCH] IDEA-91292 Instant completion after new keyword GitOrigin-RevId: 309d8eca41fb84a81bbc8ea1eab939f4da09b53a --- .../completion/JavaKeywordCompletion.java | 13 ++++++++++--- .../JavaSmartCompletionContributor.java | 6 +----- .../editorActions/JavaTypedHandler.java | 19 +++++++++++++++++++ .../normalSorting/AfterThrowNew.java | 5 +++++ .../completion/JavaAutoPopupTest.groovy | 9 +++++++++ .../NormalCompletionOrderingTest.groovy | 4 ++++ .../completion/SmartTypeCompletionTest.java | 4 ++-- 7 files changed, 50 insertions(+), 10 deletions(-) create mode 100644 java/java-tests/testData/codeInsight/completion/normalSorting/AfterThrowNew.java diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaKeywordCompletion.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaKeywordCompletion.java index 288824d61ed4..58720cc846ad 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaKeywordCompletion.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaKeywordCompletion.java @@ -714,12 +714,19 @@ public class JavaKeywordCompletion { return; } - boolean afterNew = psiElement().afterLeaf( - psiElement().withText(PsiKeyword.NEW).andNot(psiElement().afterLeaf(PsiKeyword.THROW, "."))).accepts(position); + boolean afterNew = JavaSmartCompletionContributor.AFTER_NEW.accepts(position) && + !psiElement().afterLeaf(psiElement().afterLeaf(".")).accepts(position); if (afterNew) { + Set expected = ContainerUtil.map2Set(JavaSmartCompletionContributor.getExpectedTypes(position, false), + ExpectedTypeInfo::getDefaultType); + boolean addAll = expected.isEmpty() || ContainerUtil.exists(expected, t -> + t.equalsToText(CommonClassNames.JAVA_LANG_OBJECT) || t.equalsToText(CommonClassNames.JAVA_IO_SERIALIZABLE)); PsiElementFactory factory = JavaPsiFacade.getElementFactory(position.getProject()); for (String primitiveType : PRIMITIVE_TYPES) { - result.consume(PsiTypeLookupItem.createLookupItem(factory.createTypeFromText(primitiveType + "[]", null), null)); + PsiType array = factory.createTypeFromText(primitiveType + "[]", null); + if (addAll || expected.contains(array)) { + result.consume(PsiTypeLookupItem.createLookupItem(array, null)); + } } return; } diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaSmartCompletionContributor.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaSmartCompletionContributor.java index 7b63e5c1c122..77427668c0ac 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaSmartCompletionContributor.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaSmartCompletionContributor.java @@ -47,11 +47,7 @@ public class JavaSmartCompletionContributor { }; private static final ElementExtractorFilter THROWABLES_FILTER = new ElementExtractorFilter(new AssignableFromFilter(CommonClassNames.JAVA_LANG_THROWABLE)); - public static final ElementPattern AFTER_NEW = - psiElement().afterLeaf( - psiElement().withText(PsiKeyword.NEW).andNot( - psiElement().afterLeaf( - psiElement().withText(PsiKeyword.THROW)))); + static final ElementPattern AFTER_NEW = psiElement().afterLeaf(psiElement().withText(PsiKeyword.NEW)); static final ElementPattern AFTER_THROW_NEW = psiElement().afterLeaf(psiElement().withText(PsiKeyword.NEW).afterLeaf(PsiKeyword.THROW)); public static final ElementPattern INSIDE_EXPRESSION = or( psiElement().withParent(PsiExpression.class) diff --git a/java/java-impl/src/com/intellij/codeInsight/editorActions/JavaTypedHandler.java b/java/java-impl/src/com/intellij/codeInsight/editorActions/JavaTypedHandler.java index 79dbcfbd950f..112f268a53d1 100644 --- a/java/java-impl/src/com/intellij/codeInsight/editorActions/JavaTypedHandler.java +++ b/java/java-impl/src/com/intellij/codeInsight/editorActions/JavaTypedHandler.java @@ -17,6 +17,7 @@ package com.intellij.codeInsight.editorActions; import com.intellij.codeInsight.AutoPopupController; import com.intellij.codeInsight.CodeInsightSettings; +import com.intellij.codeInsight.completion.CompletionType; import com.intellij.codeInsight.completion.JavaClassReferenceCompletionContributor; import com.intellij.codeInsight.editorActions.smartEnter.JavaSmartEnterProcessor; import com.intellij.ide.highlighter.JavaFileType; @@ -32,6 +33,7 @@ import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.util.text.StringUtil; +import com.intellij.patterns.PsiJavaPatterns; import com.intellij.psi.*; import com.intellij.psi.codeStyle.CodeStyleManager; import com.intellij.psi.javadoc.PsiDocComment; @@ -84,6 +86,23 @@ public class JavaTypedHandler extends TypedHandlerDelegate { }); } + @Override + public @NotNull Result checkAutoPopup(char charTyped, @NotNull Project project, @NotNull Editor editor, @NotNull PsiFile file) { + int offset = editor.getCaretModel().getOffset(); + if (charTyped == ' ' && + StringUtil.endsWith(editor.getDocument().getImmutableCharSequence(), 0, offset, PsiKeyword.NEW)) { + AutoPopupController.getInstance(project).scheduleAutoPopup(editor, CompletionType.BASIC, f -> { + PsiElement leaf = f.findElementAt(offset - PsiKeyword.NEW.length()); + return leaf instanceof PsiKeyword && + leaf.textMatches(PsiKeyword.NEW) && + !PsiJavaPatterns.psiElement().insideStarting(PsiJavaPatterns.psiExpressionStatement()).accepts(leaf); + }); + return Result.STOP; + } + + return super.checkAutoPopup(charTyped, project, editor, file); + } + @NotNull @Override public Result beforeCharTyped(final char c, @NotNull final Project project, @NotNull final Editor editor, @NotNull final PsiFile file, @NotNull final FileType fileType) { diff --git a/java/java-tests/testData/codeInsight/completion/normalSorting/AfterThrowNew.java b/java/java-tests/testData/codeInsight/completion/normalSorting/AfterThrowNew.java new file mode 100644 index 000000000000..6a748451994c --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/normalSorting/AfterThrowNew.java @@ -0,0 +1,5 @@ +class C { + public static void main(String[] args) { + throw new + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/JavaAutoPopupTest.groovy b/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/JavaAutoPopupTest.groovy index 953e949f21fd..77e084a40cd2 100644 --- a/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/JavaAutoPopupTest.groovy +++ b/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/JavaAutoPopupTest.groovy @@ -39,6 +39,7 @@ import com.intellij.psi.NavigatablePsiElement import com.intellij.psi.PsiClass import com.intellij.psi.PsiJavaFile import com.intellij.psi.PsiMethod +import com.intellij.psi.util.InheritanceUtil import com.intellij.testFramework.TestModeFlags import com.intellij.testFramework.fixtures.CodeInsightTestUtil import com.intellij.util.ThrowableRunnable @@ -1809,4 +1810,12 @@ ita assert lookup } + void "test autopopup after new"() { + myFixture.configureByText('a.java', 'class Foo { { java.util.List l = new }}') + type ' ' + assert lookup + def firstItems = myFixture.lookupElements[0..<4] + assert firstItems.each { InheritanceUtil.isInheritor(it.object as PsiClass, List.name) } + } + } diff --git a/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/NormalCompletionOrderingTest.groovy b/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/NormalCompletionOrderingTest.groovy index 6c3cddc3dfc2..a2097d7f304e 100644 --- a/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/NormalCompletionOrderingTest.groovy +++ b/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/NormalCompletionOrderingTest.groovy @@ -136,6 +136,10 @@ class NormalCompletionOrderingTest extends CompletionSortingTestCase { assertPreferredItems(0, "XxxImpl", "Xxx") } + void testAfterThrowNew() { + checkPreferredItems(0, "Exception", "RuntimeException") + } + void testPreferLessHumps() throws Throwable { myFixture.addClass("package foo; public interface XaYa {}") myFixture.addClass("package foo; public interface XyYa {}") diff --git a/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/SmartTypeCompletionTest.java b/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/SmartTypeCompletionTest.java index 2b5ecb907db4..a2374b98a5bf 100644 --- a/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/SmartTypeCompletionTest.java +++ b/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/SmartTypeCompletionTest.java @@ -218,7 +218,7 @@ public class SmartTypeCompletionTest extends LightFixtureCompletionTestCase { String path = "/afterNew"; configureByFile(path + "/before14.java"); - //select(); + select(); checkResultByFile(path + "/after14.java"); } @@ -234,7 +234,7 @@ public class SmartTypeCompletionTest extends LightFixtureCompletionTestCase { String path = "/afterNew"; configureByFile(path + "/before16.java"); - //select(); + select(); checkResultByFile(path + "/after16.java"); }