From 947259fa76dd36a30f521b1ba00933cbc73cb987 Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Sun, 11 Nov 2012 17:09:29 +0100 Subject: [PATCH] Keyword completion for new extension method syntax --- .../completion/Java18CompletionData.java | 27 ++++---- .../completion/ModifierChooser.java | 67 +++++++++---------- .../keywords/defaultInExtMethod.java | 18 ----- .../keywords/defaultInExtMethod_after.java | 18 ----- .../completion/keywords/interfaceScope.java | 3 + .../completion/KeywordCompletionTest.java | 17 +++-- 6 files changed, 59 insertions(+), 91 deletions(-) delete mode 100644 java/java-tests/testData/codeInsight/completion/keywords/defaultInExtMethod.java delete mode 100644 java/java-tests/testData/codeInsight/completion/keywords/defaultInExtMethod_after.java create mode 100644 java/java-tests/testData/codeInsight/completion/keywords/interfaceScope.java diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/Java18CompletionData.java b/java/java-impl/src/com/intellij/codeInsight/completion/Java18CompletionData.java index 8f5f10348d09..8c1e9a5fc980 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/Java18CompletionData.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/Java18CompletionData.java @@ -20,32 +20,33 @@ import com.intellij.patterns.PsiElementPattern; import com.intellij.psi.*; import com.intellij.psi.util.PsiTreeUtil; -import static com.intellij.patterns.PsiJavaPatterns.psiClass; import static com.intellij.patterns.PsiJavaPatterns.psiElement; public class Java18CompletionData extends Java15CompletionData { - private static final PsiElementPattern AFTER_PARENTH_IN_EXT_METHOD = psiElement() - .afterLeaf(psiElement(JavaTokenType.RPARENTH).withParent(PsiParameterList.class)) - .withSuperParent(3, psiClass().isInterface().nonAnnotationType()); - private static final PsiElementPattern AFTER_DOUBLE_COLON = psiElement() .afterLeaf(psiElement(JavaTokenType.DOUBLE_COLON)); @Override public void fillCompletions(final CompletionParameters parameters, final CompletionResultSet result) { - final PsiElement position = parameters.getPosition(); + PsiElement position = parameters.getPosition(); if (!inComment(position)) { - if (AFTER_PARENTH_IN_EXT_METHOD.accepts(position)) { - result.addElement(new OverrideableSpace(createKeyword(position, PsiKeyword.DEFAULT), TailType.SPACE)); + if (AFTER_DOUBLE_COLON.accepts(position)) { + PsiMethodReferenceExpression parent = PsiTreeUtil.getParentOfType(parameters.getPosition(), PsiMethodReferenceExpression.class); + TailType tail = parent != null && !LambdaHighlightingUtil.insertSemicolon(parent.getParent()) ? TailType.SEMICOLON : TailType.NONE; + result.addElement(new OverrideableSpace(createKeyword(position, PsiKeyword.NEW), tail)); return; } - if (AFTER_DOUBLE_COLON.accepts(position)) { - final PsiMethodReferenceExpression parent = PsiTreeUtil.getParentOfType(parameters.getPosition(), PsiMethodReferenceExpression.class); - final TailType tailType = parent != null && !LambdaHighlightingUtil.insertSemicolon(parent.getParent()) ? TailType.SEMICOLON : TailType.NONE; - result.addElement(new OverrideableSpace(createKeyword(position, PsiKeyword.NEW), tailType)); - return; + if (isSuitableForClass(position)) { + PsiElement scope = position.getParent(); + while (scope != null && !(scope instanceof PsiFile)) { + if (scope instanceof PsiClass && ((PsiClass)scope).isInterface()) { + result.addElement(new OverrideableSpace(createKeyword(position, PsiKeyword.DEFAULT), TailType.HUMBLE_SPACE_BEFORE_WORD)); + break; + } + scope = scope.getParent(); + } } } diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/ModifierChooser.java b/java/java-impl/src/com/intellij/codeInsight/completion/ModifierChooser.java index f972eddcf227..3762bb671c15 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/ModifierChooser.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/ModifierChooser.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2012 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -29,15 +29,29 @@ import java.util.ArrayList; import java.util.List; /** - * Created by IntelliJ IDEA. - * User: ik - * Date: 17.02.2003 - * Time: 17:03:09 - * To change this template use Options | File Templates. + * @author ik + * @since 17.02.2003 */ - -@SuppressWarnings({"HardCodedStringLiteral"}) public class ModifierChooser { + private static final String[][] CLASS_MODIFIERS = { + {PsiKeyword.PUBLIC}, + {PsiKeyword.FINAL, PsiKeyword.ABSTRACT} + }; + private static final String[][] CLASS_MEMBER_MODIFIERS = { + {PsiKeyword.PUBLIC, PsiKeyword.PROTECTED, PsiKeyword.PRIVATE}, + {PsiKeyword.STATIC}, + {PsiKeyword.FINAL, PsiKeyword.ABSTRACT}, + {PsiKeyword.NATIVE}, + {PsiKeyword.SYNCHRONIZED}, + {PsiKeyword.STRICTFP}, + {PsiKeyword.VOLATILE}, + {PsiKeyword.TRANSIENT} + }; + private static final String[][] INTERFACE_MEMBER_MODIFIERS = { + {PsiKeyword.PUBLIC, PsiKeyword.PROTECTED}, + {PsiKeyword.STATIC}, + {PsiKeyword.FINAL, PsiKeyword.ABSTRACT} + }; static String[] getKeywords(@NotNull PsiElement position) { final PsiModifierList list = findModifierList(position); @@ -61,27 +75,11 @@ public class ModifierChooser { } public static String[] addClassModifiers(PsiModifierList list) { - return addKeywords(list, new String[][]{ - new String[]{"public"}, - new String[]{"final", "abstract"} - }); + return addKeywords(list, CLASS_MODIFIERS); } public static String[] addMemberModifiers(PsiModifierList list, final boolean inInterface) { - return addKeywords(list, inInterface ? new String[][]{ - new String[]{"public", "protected"}, - new String[]{"static"}, - new String[]{"final", "abstract"} - } : new String[][]{ - new String[]{"public", "protected", "private"}, - new String[]{"static"}, - new String[]{"final", "abstract"}, - new String[]{"native"}, - new String[]{"synchronized"}, - new String[]{"strictfp"}, - new String[]{"volatile"}, - new String[]{"transient"} - }); + return addKeywords(list, inInterface ? INTERFACE_MEMBER_MODIFIERS : CLASS_MEMBER_MODIFIERS); } private static String[] addKeywords(PsiModifierList list, String[][] keywordSets) { @@ -90,7 +88,7 @@ public class ModifierChooser { final String[] keywords = keywordSets[keywordSets.length - i - 1]; boolean containModifierFlag = false; if (list != null) { - for (String keyword : keywords) { + for (@PsiModifier.ModifierConstant String keyword : keywords) { if (list.hasExplicitModifier(keyword)) { containModifierFlag = true; break; @@ -115,19 +113,19 @@ public class ModifierChooser { private static boolean shouldSuggestModifiers(PsiElement element) { PsiElement parent = element.getParent(); - while(parent != null && (parent instanceof PsiJavaCodeReferenceElement - || parent instanceof PsiErrorElement || parent instanceof PsiTypeElement - || parent instanceof PsiMethod || parent instanceof PsiVariable - || parent instanceof PsiDeclarationStatement || parent instanceof PsiImportList - || parent instanceof PsiDocComment - || element.getText().equals(parent.getText()))){ + while (parent != null && (parent instanceof PsiJavaCodeReferenceElement || + parent instanceof PsiErrorElement || parent instanceof PsiTypeElement || + parent instanceof PsiMethod || parent instanceof PsiVariable || + parent instanceof PsiDeclarationStatement || parent instanceof PsiImportList || + parent instanceof PsiDocComment || + element.getText().equals(parent.getText()))) { parent = parent.getParent(); if (parent instanceof JspClassLevelDeclarationStatement) { parent = parent.getContext(); } } - if(parent == null) return false; + if (parent == null) return false; PsiElement prev = FilterPositionUtil.searchNonSpaceNonCommentBack(element); @@ -139,5 +137,4 @@ public class ModifierChooser { return false; } - } diff --git a/java/java-tests/testData/codeInsight/completion/keywords/defaultInExtMethod.java b/java/java-tests/testData/codeInsight/completion/keywords/defaultInExtMethod.java deleted file mode 100644 index 04b2a8a7035f..000000000000 --- a/java/java-tests/testData/codeInsight/completion/keywords/defaultInExtMethod.java +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Copyright 2000-2012 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -interface Foo { - String foo() def -} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/completion/keywords/defaultInExtMethod_after.java b/java/java-tests/testData/codeInsight/completion/keywords/defaultInExtMethod_after.java deleted file mode 100644 index 22031018f7bc..000000000000 --- a/java/java-tests/testData/codeInsight/completion/keywords/defaultInExtMethod_after.java +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Copyright 2000-2012 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -interface Foo { - String foo() default -} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/completion/keywords/interfaceScope.java b/java/java-tests/testData/codeInsight/completion/keywords/interfaceScope.java new file mode 100644 index 000000000000..701fa8c4096f --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/keywords/interfaceScope.java @@ -0,0 +1,3 @@ +interface I { + +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/completion/KeywordCompletionTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/completion/KeywordCompletionTest.java index 055daa7ed0c2..6cee39b7d7a2 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/completion/KeywordCompletionTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/completion/KeywordCompletionTest.java @@ -27,12 +27,14 @@ import org.jetbrains.annotations.NotNull; public class KeywordCompletionTest extends LightCompletionTestCase { private static final String BASE_PATH = "/codeInsight/completion/keywords"; - private static final String[] FILE_SCOPE_KEYWORDS = new String[]{ - "package", "public", "private", "import", "final", "class", "interface", "abstract", "enum", null}; - private static final String[] CLASS_SCOPE_KEYWORDS = new String[]{ - "public", "private", "protected", "import", "final", "class", "interface", "abstract", "enum", null}; - private static final String[] CLASS_SCOPE_KEYWORDS_2 = new String[]{ - "package", "public", "private", "protected", "transient", "volatile", "static", "import", "final", "class", "interface", "abstract"}; + private static final String[] FILE_SCOPE_KEYWORDS = { + "package", "public", "private", "import", "final", "class", "interface", "abstract", "enum", "default", null}; + private static final String[] CLASS_SCOPE_KEYWORDS = { + "public", "private", "protected", "import", "final", "class", "interface", "abstract", "enum", "default", null}; + private static final String[] CLASS_SCOPE_KEYWORDS_2 = { + "package", "public", "private", "protected", "transient", "volatile", "static", "import", "final", "class", "interface", "abstract", "default"}; + private static final String[] INTERFACE_SCOPE_KEYWORDS = { + "package", "public", "private", "protected", "transient", "volatile", "static", "import", "final", "class", "interface", "abstract", "default"}; @NotNull @Override @@ -46,6 +48,7 @@ public class KeywordCompletionTest extends LightCompletionTestCase { public void testClassScope2() throws Exception { doTest(4, CLASS_SCOPE_KEYWORDS); } public void testClassScope3() throws Exception { doTest(0, CLASS_SCOPE_KEYWORDS); } public void testClassScope4() throws Exception { doTest(10, CLASS_SCOPE_KEYWORDS_2); } + public void testInterfaceScope() throws Exception { doTest(8, INTERFACE_SCOPE_KEYWORDS); } public void testAfterAnnotations() throws Exception { doTest(6, "public", "final", "class", "interface", "abstract", "enum", null); } public void testExtends1() throws Exception { doTest(2, "extends", "implements", null); } public void testExtends2() throws Exception { doTest(1, "extends", "implements", "AAA", "BBB", "instanceof"); } @@ -96,7 +99,6 @@ public class KeywordCompletionTest extends LightCompletionTestCase { public void testContinue() throws Exception { doTest(false); } public void testThrowsOnSeparateLine() throws Exception { doTest(true); } public void testDefaultInAnno() throws Exception { doTest(false); } - public void testDefaultInExtMethod() throws Exception { doTest(false); } public void testNullInMethodCall() throws Exception { doTest(true); } public void testNullInMethodCall2() throws Exception { doTest(false); } public void testNewInMethodRefs() throws Exception { doTest(1, "new"); } @@ -127,6 +129,7 @@ public class KeywordCompletionTest extends LightCompletionTestCase { checkResultByFile(BASE_PATH + "/" + getTestName(true) + "_after.java"); } + // todo: check included/excluded variants separately protected void doTest(int finalCount, @NonNls String... values) { configureByFile(BASE_PATH + "/" + getTestName(true) + ".java"); testByCount(finalCount, values);