Keyword completion for new extension method syntax

This commit is contained in:
Roman Shevchenko
2012-11-11 17:09:29 +01:00
parent 9eb756f2a0
commit 947259fa76
6 changed files with 59 additions and 91 deletions
@@ -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<PsiElement, ?> AFTER_PARENTH_IN_EXT_METHOD = psiElement()
.afterLeaf(psiElement(JavaTokenType.RPARENTH).withParent(PsiParameterList.class))
.withSuperParent(3, psiClass().isInterface().nonAnnotationType());
private static final PsiElementPattern<PsiElement, ?> 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();
}
}
}
@@ -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;
}
}
@@ -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<caret>
}
@@ -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 <caret>
}
@@ -0,0 +1,3 @@
interface I {
<caret>
}
@@ -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);