[java][switch completion] IDEA-270439 Code completion for pattern matching in switch

Adjust the completion variants for switch statements and expressions

GitOrigin-RevId: 05119897b0eb72bb875097cd197f376534d15db9
This commit is contained in:
Nikita Eshkeev
2021-07-13 19:51:15 +00:00
committed by intellij-monorepo-bot
parent 1e0a217143
commit afc2a8cd37
13 changed files with 256 additions and 19 deletions
@@ -1,4 +1,4 @@
// Copyright 2000-2019 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.
// Copyright 2000-2021 JetBrains s.r.o. and contributors. 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.codeInsight.ExpectedTypeInfo;
@@ -99,7 +99,7 @@ public class JavaKeywordCompletion {
}
static final ElementPattern<PsiElement> START_SWITCH =
psiElement().afterLeaf(psiElement().withText("{").withParents(PsiCodeBlock.class, PsiSwitchStatement.class));
psiElement().afterLeaf(psiElement().withText("{").withParents(PsiCodeBlock.class, PsiSwitchBlock.class));
private static final ElementPattern<PsiElement> SUPER_OR_THIS_PATTERN =
and(JavaSmartCompletionContributor.INSIDE_EXPRESSION,
@@ -217,12 +217,14 @@ public class JavaKeywordCompletion {
addKeyword(new OverridableSpace(createKeyword(PsiKeyword.ASSERT), TailType.INSERT_SPACE));
}
TailType returnTail = getReturnTail(myPosition);
LookupElement ret = createKeyword(PsiKeyword.RETURN);
if (returnTail != TailType.NONE) {
ret = new OverridableSpace(ret, returnTail);
if (!psiElement().inside(PsiSwitchExpression.class).accepts(myPosition)) {
TailType returnTail = getReturnTail(myPosition);
LookupElement ret = createKeyword(PsiKeyword.RETURN);
if (returnTail != TailType.NONE) {
ret = new OverridableSpace(ret, returnTail);
}
addKeyword(ret);
}
addKeyword(ret);
if (psiElement().withText(";").withSuperParent(2, PsiIfStatement.class).accepts(myPrevLeaf) ||
psiElement().withText("}").withSuperParent(3, PsiIfStatement.class).accepts(myPrevLeaf)) {
@@ -284,6 +286,19 @@ public class JavaKeywordCompletion {
addClassLiteral();
addExtendsImplements();
addCaseNullToSwitch();
}
private void addCaseNullToSwitch() {
if (!isInsidePatternMatchingSwitch()) return;
addKeyword(createKeyword(PsiKeyword.NULL));
}
private boolean isInsidePatternMatchingSwitch() {
if (!HighlightingFeature.PATTERNS_IN_SWITCH.isAvailable(myPosition)) return false;
return psiElement().withSuperParent(2, PsiCaseLabelElementList.class).accepts(myPosition);
}
private void addVar() {
@@ -349,6 +364,13 @@ public class JavaKeywordCompletion {
addKeyword(LookupElementDecorator.withInsertHandler(
new OverridableSpace(createKeyword(PsiKeyword.DEFAULT), TailTypes.forSwitchLabel(switchBlock)),
ADJUST_LINE_OFFSET));
if (HighlightingFeature.PATTERNS_IN_SWITCH.isAvailable(myPosition)) {
final LookupElement caseNull = LookupElementBuilder.create(PsiKeyword.CASE + " " + PsiKeyword.NULL)
.bold()
.withAutoCompletionPolicy(AutoCompletionPolicy.GIVE_CHANCE_TO_OVERWRITE);
final OverridableSpace element = new OverridableSpace(caseNull, TailTypes.forSwitchLabel(switchBlock));
addKeyword(LookupElementDecorator.withInsertHandler(element, ADJUST_LINE_OFFSET));
}
}
}
@@ -391,7 +413,7 @@ public class JavaKeywordCompletion {
private void addFinal() {
PsiStatement statement = PsiTreeUtil.getParentOfType(myPosition, PsiExpressionStatement.class, PsiDeclarationStatement.class);
if (statement != null && statement.getTextRange().getStartOffset() == myPosition.getTextRange().getStartOffset()) {
if (!psiElement().withSuperParent(2, PsiSwitchStatement.class).afterLeaf("{").accepts(statement)) {
if (!psiElement().withSuperParent(2, PsiSwitchBlock.class).afterLeaf("{").accepts(statement)) {
PsiTryStatement tryStatement = PsiTreeUtil.getParentOfType(myPrevLeaf, PsiTryStatement.class);
if (tryStatement == null ||
tryStatement.getCatchSections().length > 0 ||
@@ -475,10 +497,8 @@ public class JavaKeywordCompletion {
if (myPosition.getParent() instanceof PsiReferenceExpression) {
PsiExpression qualifier = ((PsiReferenceExpression)myPosition.getParent()).getQualifierExpression();
PsiClass qualifierClass = PsiUtil.resolveClassInClassTypeOnly(qualifier == null ? null : qualifier.getType());
if (qualifierClass != null &&
ContainerUtil.exists(qualifierClass.getAllInnerClasses(), inner -> canBeCreatedInQualifiedNew(qualifierClass, inner))) {
return true;
}
return qualifierClass != null &&
ContainerUtil.exists(qualifierClass.getAllInnerClasses(), inner -> canBeCreatedInQualifiedNew(qualifierClass, inner));
}
return false;
}
@@ -730,10 +750,8 @@ public class JavaKeywordCompletion {
PsiType type = ((PsiLocalVariable) position.getParent()).getType();
if (type instanceof PsiClassType && ((PsiClassType) type).resolve() == null) {
PsiElement grandParent = position.getParent().getParent();
if (!(grandParent instanceof PsiDeclarationStatement) || !(grandParent.getParent() instanceof PsiForStatement) ||
((PsiForStatement) grandParent.getParent()).getInitialization() != grandParent) {
return true;
}
return !(grandParent instanceof PsiDeclarationStatement) || !(grandParent.getParent() instanceof PsiForStatement) ||
((PsiForStatement)grandParent.getParent()).getInitialization() != grandParent;
}
}
@@ -926,9 +944,7 @@ public class JavaKeywordCompletion {
psiElement().afterLeaf(".")).accepts(position)) {
PsiElement stmt = position.getParent().getParent();
PsiIfStatement ifStatement = (PsiIfStatement)stmt.getParent();
if (ifStatement.getElseBranch() == stmt || ifStatement.getThenBranch() == stmt) {
return true;
}
return ifStatement.getElseBranch() == stmt || ifStatement.getThenBranch() == stmt;
}
return false;
@@ -0,0 +1,21 @@
class Main {
int f(Object o) {
return switch(o) {
case Integer i, nul<caret>
}
}
int g(Object o) {
return switch(o) {
case nul<caret>, Integer i
}
}
int h(Object o) {
return switch(o) {
case nul<caret>
}
}
}
@@ -0,0 +1,21 @@
class Main {
int f(Object o) {
return switch(o) {
case Integer i, null<caret>
}
}
int g(Object o) {
return switch(o) {
case null<caret>, Integer i
}
}
int h(Object o) {
return switch(o) {
case null<caret>
}
}
}
@@ -0,0 +1,21 @@
class Main {
void f(Object o) {
switch(o) {
case Integer i, nul<caret>
}
}
void g(Object o) {
switch(o) {
case nul<caret>, Integer i
}
}
void h(Object o) {
switch(o) {
case nul<caret>
}
}
}
@@ -0,0 +1,21 @@
class Main {
void f(Object o) {
switch(o) {
case Integer i, null<caret>
}
}
void g(Object o) {
switch(o) {
case null<caret>, Integer i
}
}
void h(Object o) {
switch(o) {
case null<caret>
}
}
}
@@ -0,0 +1,20 @@
class Main {
int f(Object o) {
return switch(o) {
case Integer integer && inte<caret>, null
}
}
int g(Object o) {
return switch(o) {
case null, Integer integer && inte<caret>
}
}
int h(Object o) {
return switch(o) {
case Integer integer && inte<caret>
}
}
}
@@ -0,0 +1,20 @@
class Main {
int f(Object o) {
return switch(o) {
case Integer integer && integer<caret>, null
}
}
int g(Object o) {
return switch(o) {
case null, Integer integer && integer<caret>
}
}
int h(Object o) {
return switch(o) {
case Integer integer && integer<caret>
}
}
}
@@ -0,0 +1,20 @@
class Main {
void f(Object o) {
switch(o) {
case Integer integer && inte<caret>, null
}
}
void g(Object o) {
switch(o) {
case null, Integer integer && inte<caret>
}
}
void h(Object o) {
switch(o) {
case Integer integer && inte<caret>
}
}
}
@@ -0,0 +1,20 @@
class Main {
void f(Object o) {
switch(o) {
case Integer integer && integer<caret>, null
}
}
void g(Object o) {
switch(o) {
case null, Integer integer && integer<caret>
}
}
void h(Object o) {
switch(o) {
case Integer integer && integer<caret>
}
}
}
@@ -0,0 +1,8 @@
class Main {
int f(Object o) {
return switch(o) {
<caret>
}
}
}
@@ -0,0 +1,8 @@
class Main {
void f(Object o) {
switch(o) {
<caret>
}
}
}
@@ -29,4 +29,9 @@ class NormalSwitchCompletionTest extends NormalCompletionTestCase {
void testCompleteConstantInSwitchExpr() { doTest() }
void testCompleteConstantInSwitchStmt() { doTest() }
void testCompleteNullInSwitchStmt() { doTest() }
void testCompleteNullInSwitchExpr() { doTest() }
void testCompletePatternVariableSwitchStmt() { doTest() }
void testCompletePatternVariableSwitchExpr() { doTest() }
}
@@ -0,0 +1,36 @@
// Copyright 2000-2021 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.java.codeInsight.completion
import com.intellij.JavaTestUtil
import com.intellij.codeInsight.completion.CompletionType
import com.intellij.codeInsight.completion.LightFixtureCompletionTestCase
import com.intellij.testFramework.LightProjectDescriptor
import groovy.transform.CompileStatic
import org.jetbrains.annotations.NotNull
@CompileStatic
class NormalSwitchCompletionVariantsTest extends LightFixtureCompletionTestCase {
private static final String[] VARIANTS = ["case", "case null", "default"]
@Override
protected String getBasePath() {
return JavaTestUtil.getRelativeJavaTestDataPath() + "/codeInsight/completion/normal/variants/"
}
@NotNull
@Override
protected LightProjectDescriptor getProjectDescriptor() {
return JAVA_17
}
void testCompletionVariantsInStmt() { doTest() }
void testCompletionVariantsInExpr() { doTest() }
void doTest() {
myFixture.configureByFile(getTestName(false) + ".java")
myFixture.complete(CompletionType.BASIC)
final List<String> lookupElementStrings = myFixture.getLookupElementStrings()
assertSameElements(lookupElementStrings, VARIANTS)
}
}