From 14bc258e3fb2cca62a42c86642e35e3b83ba66e3 Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Fri, 9 Nov 2018 18:22:32 +0100 Subject: [PATCH] [java] restores multifaceted switch labels support (parser/PSI + basic highlighting) --- .../impl/analysis/GenericsHighlightUtil.java | 3 +- .../daemon/impl/analysis/HighlightUtil.java | 116 +++++++++++------- .../impl/analysis/HighlightVisitorImpl.java | 1 + .../codeInsight/ExpectedTypesProvider.java | 54 +++----- .../psi/PsiSwitchLabelStatementBase.java | 17 ++- .../lang/java/parser/StatementParser.java | 14 ++- .../com/intellij/psi/impl/PsiImplUtil.java | 12 ++ .../java/PsiSwitchLabelStatementBaseImpl.java | 6 +- .../EnhancedSwitchStatements.java | 13 ++ .../advHighlighting6/UnsupportedFeatures.java | 3 + .../statements/SwitchLabelsIncomplete0.txt | 9 +- .../statements/SwitchLabelsIncomplete1.txt | 5 +- .../statements/SwitchLabelsIncomplete4.txt | 8 ++ .../statements/SwitchLabelsIncomplete5.txt | 16 +++ .../statements/SwitchLabelsMultiple.txt | 16 +++ .../statements/SwitchLabelsNormal.txt | 5 +- .../statements/SwitchRules10.txt | 15 +-- .../statements/SwitchRules11.txt | 19 +++ .../statements/SwitchRules12.txt | 18 +++ .../statements/SwitchRules2.txt | 5 +- .../statements/SwitchRules3.txt | 5 +- .../statements/SwitchRules4.txt | 5 +- .../statements/SwitchRules5.txt | 5 +- .../statements/SwitchRules6.txt | 5 +- .../statements/SwitchRules7.txt | 5 +- .../statements/SwitchRules8.txt | 5 +- .../statements/SwitchRules9.txt | 9 +- .../parser/partial/StatementParserTest.java | 5 + 28 files changed, 278 insertions(+), 121 deletions(-) create mode 100644 java/java-tests/testData/psi/parser-partial/statements/SwitchLabelsIncomplete4.txt create mode 100644 java/java-tests/testData/psi/parser-partial/statements/SwitchLabelsIncomplete5.txt create mode 100644 java/java-tests/testData/psi/parser-partial/statements/SwitchLabelsMultiple.txt create mode 100644 java/java-tests/testData/psi/parser-partial/statements/SwitchRules11.txt create mode 100644 java/java-tests/testData/psi/parser-partial/statements/SwitchRules12.txt diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/GenericsHighlightUtil.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/GenericsHighlightUtil.java index a4787ee99da0..6b02968a3295 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/GenericsHighlightUtil.java +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/GenericsHighlightUtil.java @@ -21,6 +21,7 @@ import com.intellij.openapi.vfs.VirtualFile; import com.intellij.pom.java.LanguageLevel; import com.intellij.psi.*; import com.intellij.psi.impl.PsiClassImplUtil; +import com.intellij.psi.impl.PsiImplUtil; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.search.PsiShortNamesCache; import com.intellij.psi.search.searches.ReferencesSearch; @@ -807,7 +808,7 @@ public class GenericsHighlightUtil { if (!(resolved instanceof PsiField)) return null; if (!((PsiModifierListOwner)resolved).hasModifierProperty(PsiModifier.STATIC)) return null; - if (expr.getParent() instanceof PsiSwitchLabelStatement) return null; + if (PsiImplUtil.getSwitchLabel(expr) != null) return null; final PsiMember constructorOrInitializer = PsiUtil.findEnclosingConstructorOrInitializer(expr); if (constructorOrInitializer == null) return null; if (constructorOrInitializer.hasModifierProperty(PsiModifier.STATIC)) return null; diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightUtil.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightUtil.java index 10d0859e1fb3..4e6e671e32d2 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightUtil.java +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightUtil.java @@ -46,6 +46,7 @@ import com.intellij.util.ArrayUtilRt; import com.intellij.util.JavaPsiConstructorUtil; import com.intellij.util.ObjectUtils; import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.containers.MultiMap; import com.intellij.util.containers.hash.HashSet; import com.intellij.util.ui.UIUtil; import com.intellij.xml.util.XmlStringUtil; @@ -1850,63 +1851,78 @@ public class HighlightUtil extends HighlightUtilBase { return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(statement).descriptionAndTooltip(description).create(); } + return null; + } + + @Nullable + static Collection checkSwitchLabelValues(@NotNull PsiSwitchStatement switchStatement) { PsiCodeBlock body = switchStatement.getBody(); if (body == null) return null; PsiExpression switchExpression = switchStatement.getExpression(); PsiType switchType = switchExpression == null ? PsiType.INT : switchExpression.getType(); - boolean defaultCase = statement.isDefaultCase(); - PsiExpression caseValue = statement.getCaseValue(); + MultiMap values = new MultiMap<>(); + Object defaultValue = new Object(); + Collection results = new ArrayList<>(); - // Every case constant expression associated with a switch statement must be assignable ($5.2) to the type of the switch Expression. - if (caseValue != null && switchExpression != null) { - HighlightInfo highlightInfo = checkAssignability(switchType, caseValue.getType(), caseValue, caseValue); - if (highlightInfo != null) return highlightInfo; - } - Object value = null; - boolean isEnumSwitch = false; - if (!defaultCase && caseValue != null) { - if (caseValue instanceof PsiReferenceExpression) { - PsiElement element = ((PsiReferenceExpression)caseValue).resolve(); - if (element instanceof PsiEnumConstant) { - isEnumSwitch = true; - value = ((PsiEnumConstant)element).getName(); - if (((PsiReferenceExpression)caseValue).getQualifier() != null) { - String message = JavaErrorMessages.message("qualified.enum.constant.in.switch"); - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(caseValue).descriptionAndTooltip(message).create(); + for (PsiStatement st : body.getStatements()) { + if (!(st instanceof PsiSwitchLabelStatementBase)) continue; + PsiSwitchLabelStatementBase labelStatement = (PsiSwitchLabelStatementBase)st; + boolean defaultCase = labelStatement.isDefaultCase(); + + if (defaultCase) { + values.putValue(defaultValue, ObjectUtils.notNull(labelStatement.getFirstChild(), labelStatement)); + } + else { + PsiExpressionList expressionList = labelStatement.getCaseValues(); + if (expressionList != null) { + for (PsiExpression expr : expressionList.getExpressions()) { + if (switchExpression != null) { + HighlightInfo result = checkAssignability(switchType, expr.getType(), expr, expr); + if (result != null) { + results.add(result); + continue; + } + } + + Object value = null; + if (expr instanceof PsiReferenceExpression) { + PsiElement element = ((PsiReferenceExpression)expr).resolve(); + if (element instanceof PsiEnumConstant) { + value = ((PsiEnumConstant)element).getName(); + if (((PsiReferenceExpression)expr).getQualifier() != null) { + String message = JavaErrorMessages.message("qualified.enum.constant.in.switch"); + results.add(HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(expr).descriptionAndTooltip(message).create()); + continue; + } + } + } + if (value == null) { + value = ConstantExpressionUtil.computeCastTo(expr, switchType); + } + if (value == null) { + String description = JavaErrorMessages.message("constant.expression.required"); + results.add(HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(expr).descriptionAndTooltip(description).create()); + continue; + } + + values.putValue(value, expr); } } } - if (!isEnumSwitch) { - value = ConstantExpressionUtil.computeCastTo(caseValue, switchType); - } - if (value == null) { - String description = JavaErrorMessages.message("constant.expression.required"); - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(caseValue).descriptionAndTooltip(description).create(); + } + + for (Map.Entry> entry : values.entrySet()) { + if (entry.getValue().size() > 1) { + Object value = entry.getKey(); + String description = value == defaultValue ? JavaErrorMessages.message("duplicate.default.switch.label") : JavaErrorMessages.message("duplicate.switch.label", value); + for (PsiElement element : entry.getValue()) { + results.add(HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(element).descriptionAndTooltip(description).create()); + } } } - // check duplicate - for (PsiStatement st : body.getStatements()) { - if (st == statement || !(st instanceof PsiSwitchLabelStatementBase)) continue; - PsiSwitchLabelStatementBase labelStatement = (PsiSwitchLabelStatementBase)st; - if (labelStatement.isDefaultCase() != defaultCase) continue; - PsiExpression caseExpr = labelStatement.getCaseValue(); - if (isEnumSwitch && caseExpr instanceof PsiReferenceExpression) { - PsiElement element = ((PsiReferenceExpression)caseExpr).resolve(); - if (!(element instanceof PsiEnumConstant && Comparing.equal(((PsiEnumConstant)element).getName(), value))) continue; - } - else { - // not assignable error already caught - if (!TypeConversionUtil.areTypesAssignmentCompatible(switchType, caseExpr)) continue; - if (!Comparing.equal(ConstantExpressionUtil.computeCastTo(caseExpr, switchType), value)) continue; - } - String description = defaultCase ? JavaErrorMessages.message("duplicate.default.switch.label") : JavaErrorMessages.message("duplicate.switch.label", value); - PsiElement element = caseValue != null ? caseValue : ObjectUtils.notNull(statement.getFirstChild(), statement); - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(element).descriptionAndTooltip(description).create(); - } - - return null; + return results; } @@ -2433,6 +2449,16 @@ public class HighlightUtil extends HighlightUtilBase { } classicLabels = true; } + + if (!levelChecked && element instanceof PsiSwitchLabelStatementBase) { + PsiExpressionList values = ((PsiSwitchLabelStatementBase)element).getCaseValues(); + if (values != null && values.getExpressionCount() > 1) { + HighlightInfo info = checkFeature(values, Feature.ENHANCED_SWITCH, languageLevel, file); + if (info != null) return info; + levelChecked = true; + } + } + element = PsiTreeUtil.skipWhitespacesAndCommentsForward(element); } if (alien != null) { diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java index 114c77bbf3ea..f2285c35bcbd 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java @@ -1595,6 +1595,7 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh super.visitSwitchStatement(statement); if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkSwitchBlockStatements(statement, myLanguageLevel, myFile)); if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkSwitchSelectorType(statement, myLanguageLevel)); + if (!myHolder.hasErrorResults()) myHolder.addAll(HighlightUtil.checkSwitchLabelValues(statement)); } @Override diff --git a/java/java-impl/src/com/intellij/codeInsight/ExpectedTypesProvider.java b/java/java-impl/src/com/intellij/codeInsight/ExpectedTypesProvider.java index 815c289a52b7..4fe0ec7667d2 100644 --- a/java/java-impl/src/com/intellij/codeInsight/ExpectedTypesProvider.java +++ b/java/java-impl/src/com/intellij/codeInsight/ExpectedTypesProvider.java @@ -1,18 +1,4 @@ -/* - * Copyright 2000-2017 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. - */ +// Copyright 2000-2018 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; import com.intellij.codeInsight.completion.CompletionMemory; @@ -493,20 +479,6 @@ public class ExpectedTypesProvider { myResult.add(createInfoImpl(enumType, enumType)); } - @Override - public void visitSwitchLabelStatement(@NotNull final PsiSwitchLabelStatement statement) { - final PsiSwitchStatement switchStatement = statement.getEnclosingSwitchStatement(); - if (switchStatement != null) { - final PsiExpression expression = switchStatement.getExpression(); - if (expression != null) { - final PsiType type = expression.getType(); - if (type != null) { - myResult.add(createInfoImpl(type, ExpectedTypeInfo.TYPE_OR_SUBTYPE, type, TailType.CASE_COLON)); - } - } - } - } - @Override public void visitSynchronizedStatement(@NotNull PsiSynchronizedStatement statement) { PsiElementFactory factory = JavaPsiFacade.getElementFactory(statement.getProject()); @@ -597,6 +569,18 @@ public class ExpectedTypesProvider { else if (parent instanceof PsiAnonymousClass) { getExpectedArgumentsTypesForNewExpression((PsiNewExpression)parent.getParent(), list); } + else if (parent instanceof PsiSwitchLabelStatementBase) { + PsiSwitchStatement switchStatement = ((PsiSwitchLabelStatementBase)parent).getEnclosingSwitchStatement(); + if (switchStatement != null) { + PsiExpression expression = switchStatement.getExpression(); + if (expression != null) { + PsiType type = expression.getType(); + if (type != null) { + myResult.add(createInfoImpl(type, ExpectedTypeInfo.TYPE_OR_SUBTYPE, type, TailType.CASE_COLON)); + } + } + } + } } private void getExpectedArgumentsTypesForEnumConstant(@NotNull final PsiEnumConstant enumConstant, @@ -678,9 +662,9 @@ public class ExpectedTypesProvider { } return; } - + PsiType anotherType = anotherExpr != null ? anotherExpr.getType() : null; - + if (op == JavaTokenType.MINUS || op == JavaTokenType.ASTERISK || op == JavaTokenType.DIV || @@ -1006,8 +990,8 @@ public class ExpectedTypesProvider { if (candidateInfo instanceof MethodCandidateInfo) { final MethodCandidateInfo info = (MethodCandidateInfo)candidateInfo; Computable computable = () -> info.inferSubstitutorFromArgs(policy, args); - substitutor = info.isInferencePossible() && targetMethod == method - ? computable.compute() + substitutor = info.isInferencePossible() && targetMethod == method + ? computable.compute() : MethodCandidateInfo.ourOverloadGuard.doPreventingRecursion(argumentList, false, computable); if (!info.isStaticsScopeCorrect() && !method.hasModifierProperty(PsiModifier.STATIC) || info.getInferenceErrorMessage() != null) continue; } @@ -1021,8 +1005,8 @@ public class ExpectedTypesProvider { if (leftArgs != null && candidateInfo instanceof MethodCandidateInfo) { Computable computable = () -> ((MethodCandidateInfo)candidateInfo).inferSubstitutorFromArgs(policy, leftArgs); - substitutor = ((MethodCandidateInfo)candidateInfo).isInferencePossible() && targetMethod == method - ? computable.compute() + substitutor = ((MethodCandidateInfo)candidateInfo).isInferencePossible() && targetMethod == method + ? computable.compute() : MethodCandidateInfo.ourOverloadGuard.doPreventingRecursion(argumentList, false, computable); if (substitutor != null) { inferMethodCallArgumentTypes(argument, forCompletion, leftArgs, index, method, substitutor, array); diff --git a/java/java-psi-api/src/com/intellij/psi/PsiSwitchLabelStatementBase.java b/java/java-psi-api/src/com/intellij/psi/PsiSwitchLabelStatementBase.java index 396a1241d1ac..26da29fab6ca 100644 --- a/java/java-psi-api/src/com/intellij/psi/PsiSwitchLabelStatementBase.java +++ b/java/java-psi-api/src/com/intellij/psi/PsiSwitchLabelStatementBase.java @@ -16,10 +16,23 @@ public interface PsiSwitchLabelStatementBase extends PsiStatement { boolean isDefaultCase(); /** - * Returns the constant associated with the {@code case} block, + * Returns the constants associated with the {@code case} block, * or {@code null} if the statement is incomplete or the element represents a {@code default} section. */ - @Nullable PsiExpression getCaseValue(); + @Nullable PsiExpressionList getCaseValues(); + + /** @deprecated doesn't support enhanced "switch" statement; use {@link #getCaseValues()} instead */ + @Deprecated + default PsiExpression getCaseValue() { + PsiExpressionList expressionList = getCaseValues(); + if (expressionList != null) { + PsiExpression[] expressions = expressionList.getExpressions(); + if (expressions.length == 1) { + return expressions[0]; + } + } + return null; + } /** * Returns the {@code switch} statement with which the section is associated, diff --git a/java/java-psi-impl/src/com/intellij/lang/java/parser/StatementParser.java b/java/java-psi-impl/src/com/intellij/lang/java/parser/StatementParser.java index 1824dd3fce0d..4bce0f329e68 100644 --- a/java/java-psi-impl/src/com/intellij/lang/java/parser/StatementParser.java +++ b/java/java-psi-impl/src/com/intellij/lang/java/parser/StatementParser.java @@ -466,15 +466,21 @@ public class StatementParser { return statement; } - @Nullable private PsiBuilder.Marker parseSwitchLabelStatement(PsiBuilder builder) { PsiBuilder.Marker statement = builder.mark(); boolean isCase = builder.getTokenType() == JavaTokenType.CASE_KEYWORD; builder.advanceLexer(); - if (isCase && myParser.getExpressionParser().parseCaseLabel(builder) == null) { - statement.rollbackTo(); - return null; + if (isCase) { + PsiBuilder.Marker expressionList = builder.mark(); + do { + PsiBuilder.Marker nextExpression = myParser.getExpressionParser().parseCaseLabel(builder); + if (nextExpression == null) { + error(builder, JavaErrorMessages.message("expected.expression")); + } + } + while (expect(builder, JavaTokenType.COMMA)); + done(expressionList, JavaElementType.EXPRESSION_LIST); } if (expect(builder, JavaTokenType.ARROW)) { diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/PsiImplUtil.java b/java/java-psi-impl/src/com/intellij/psi/impl/PsiImplUtil.java index b013bf14a55d..166543ca92fb 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/PsiImplUtil.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/PsiImplUtil.java @@ -632,6 +632,18 @@ public class PsiImplUtil { } } + @Nullable + public static PsiSwitchLabelStatementBase getSwitchLabel(@NotNull PsiExpression expression) { + PsiElement parent = PsiUtil.skipParenthesizedExprUp(expression.getParent()); + if (parent instanceof PsiExpressionList) { + PsiElement grand = parent.getParent(); + if (grand instanceof PsiSwitchLabelStatementBase) { + return (PsiSwitchLabelStatementBase)grand; + } + } + return null; + } + public static boolean isLeafElementOfType(@Nullable PsiElement element, @NotNull IElementType type) { return element instanceof LeafElement && ((LeafElement)element).getElementType() == type; } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiSwitchLabelStatementBaseImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiSwitchLabelStatementBaseImpl.java index c190b9c92999..9e2ca5cbc2fd 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiSwitchLabelStatementBaseImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiSwitchLabelStatementBaseImpl.java @@ -3,7 +3,7 @@ package com.intellij.psi.impl.source.tree.java; import com.intellij.psi.*; import com.intellij.psi.impl.source.tree.CompositePsiElement; -import com.intellij.psi.impl.source.tree.ElementType; +import com.intellij.psi.impl.source.tree.JavaElementType; import com.intellij.psi.scope.ElementClassFilter; import com.intellij.psi.scope.PsiScopeProcessor; import com.intellij.psi.scope.processor.FilterScopeProcessor; @@ -21,8 +21,8 @@ public abstract class PsiSwitchLabelStatementBaseImpl extends CompositePsiElemen } @Override - public PsiExpression getCaseValue() { - return (PsiExpression)findPsiChildByType(ElementType.EXPRESSION_BIT_SET); + public PsiExpressionList getCaseValues() { + return (PsiExpressionList)findPsiChildByType(JavaElementType.EXPRESSION_LIST); } @Override diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting12/EnhancedSwitchStatements.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting12/EnhancedSwitchStatements.java index 412fd04498d6..e39320e0ab18 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting12/EnhancedSwitchStatements.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting12/EnhancedSwitchStatements.java @@ -59,6 +59,19 @@ class EnhancedSwitchStatements { switch (E.valueOf("E1")) { case null -> noop(); + case E.E1 -> noop(); + case E2 -> noop(); + } + + switch (new Random().nextInt()) { + case 1, 1 -> noop(); + } + + switch (new Random().nextInt()) { + case 1, 2: + noop(); break; + case 3, 2: + noop(); break; } } diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting6/UnsupportedFeatures.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting6/UnsupportedFeatures.java index db9d451c2e2d..ccea30d5cdc6 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting6/UnsupportedFeatures.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting6/UnsupportedFeatures.java @@ -29,6 +29,9 @@ class UnsupportedFeatures { case 0 -> throw new IllegalStateException("empty list"); default -> System.out.println("it's okay"); } + switch (list.size()) { + case 1, 2: + } } void f(Object this) { } diff --git a/java/java-tests/testData/psi/parser-partial/statements/SwitchLabelsIncomplete0.txt b/java/java-tests/testData/psi/parser-partial/statements/SwitchLabelsIncomplete0.txt index 98d17d5664e2..d9ec587e2750 100644 --- a/java/java-tests/testData/psi/parser-partial/statements/SwitchLabelsIncomplete0.txt +++ b/java/java-tests/testData/psi/parser-partial/statements/SwitchLabelsIncomplete0.txt @@ -1,3 +1,8 @@ PsiJavaFile:SwitchLabelsIncomplete0.java - PsiErrorElement:Unexpected token - PsiKeyword:case('case') \ No newline at end of file + PsiSwitchLabelStatement + PsiKeyword:case('case') + PsiExpressionList + PsiErrorElement:Expression expected + + PsiErrorElement:':' expected + \ No newline at end of file diff --git a/java/java-tests/testData/psi/parser-partial/statements/SwitchLabelsIncomplete1.txt b/java/java-tests/testData/psi/parser-partial/statements/SwitchLabelsIncomplete1.txt index 32e4e94a76e2..04da1f0ff0d9 100644 --- a/java/java-tests/testData/psi/parser-partial/statements/SwitchLabelsIncomplete1.txt +++ b/java/java-tests/testData/psi/parser-partial/statements/SwitchLabelsIncomplete1.txt @@ -2,7 +2,8 @@ PsiJavaFile:SwitchLabelsIncomplete1.java PsiSwitchLabelStatement PsiKeyword:case('case') PsiWhiteSpace(' ') - PsiLiteralExpression:2 - PsiJavaToken:INTEGER_LITERAL('2') + PsiExpressionList + PsiLiteralExpression:2 + PsiJavaToken:INTEGER_LITERAL('2') PsiErrorElement:':' expected \ No newline at end of file diff --git a/java/java-tests/testData/psi/parser-partial/statements/SwitchLabelsIncomplete4.txt b/java/java-tests/testData/psi/parser-partial/statements/SwitchLabelsIncomplete4.txt new file mode 100644 index 000000000000..460e6ab5c312 --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/statements/SwitchLabelsIncomplete4.txt @@ -0,0 +1,8 @@ +PsiJavaFile:SwitchLabelsIncomplete4.java + PsiSwitchLabelStatement + PsiKeyword:case('case') + PsiExpressionList + PsiErrorElement:Expression expected + + PsiWhiteSpace(' ') + PsiJavaToken:COLON(':') \ No newline at end of file diff --git a/java/java-tests/testData/psi/parser-partial/statements/SwitchLabelsIncomplete5.txt b/java/java-tests/testData/psi/parser-partial/statements/SwitchLabelsIncomplete5.txt new file mode 100644 index 000000000000..ffebca52c5ab --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/statements/SwitchLabelsIncomplete5.txt @@ -0,0 +1,16 @@ +PsiJavaFile:SwitchLabelsIncomplete5.java + PsiSwitchLabelStatement + PsiKeyword:case('case') + PsiWhiteSpace(' ') + PsiExpressionList + PsiLiteralExpression:1 + PsiJavaToken:INTEGER_LITERAL('1') + PsiJavaToken:COMMA(',') + PsiErrorElement:Expression expected + + PsiWhiteSpace(' ') + PsiJavaToken:COLON(':') + PsiWhiteSpace(' ') + PsiBreakStatement + PsiKeyword:break('break') + PsiJavaToken:SEMICOLON(';') \ No newline at end of file diff --git a/java/java-tests/testData/psi/parser-partial/statements/SwitchLabelsMultiple.txt b/java/java-tests/testData/psi/parser-partial/statements/SwitchLabelsMultiple.txt new file mode 100644 index 000000000000..23a3b529467a --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/statements/SwitchLabelsMultiple.txt @@ -0,0 +1,16 @@ +PsiJavaFile:SwitchLabelsMultiple.java + PsiSwitchLabelStatement + PsiKeyword:case('case') + PsiWhiteSpace(' ') + PsiExpressionList + PsiLiteralExpression:1 + PsiJavaToken:INTEGER_LITERAL('1') + PsiJavaToken:COMMA(',') + PsiWhiteSpace(' ') + PsiLiteralExpression:2 + PsiJavaToken:INTEGER_LITERAL('2') + PsiJavaToken:COLON(':') + PsiWhiteSpace(' ') + PsiBreakStatement + PsiKeyword:break('break') + PsiJavaToken:SEMICOLON(';') \ No newline at end of file diff --git a/java/java-tests/testData/psi/parser-partial/statements/SwitchLabelsNormal.txt b/java/java-tests/testData/psi/parser-partial/statements/SwitchLabelsNormal.txt index 0a50f18451e2..605b7431e31f 100644 --- a/java/java-tests/testData/psi/parser-partial/statements/SwitchLabelsNormal.txt +++ b/java/java-tests/testData/psi/parser-partial/statements/SwitchLabelsNormal.txt @@ -2,8 +2,9 @@ PsiJavaFile:SwitchLabelsNormal.java PsiSwitchLabelStatement PsiKeyword:case('case') PsiWhiteSpace(' ') - PsiLiteralExpression:1 - PsiJavaToken:INTEGER_LITERAL('1') + PsiExpressionList + PsiLiteralExpression:1 + PsiJavaToken:INTEGER_LITERAL('1') PsiJavaToken:COLON(':') PsiWhiteSpace(' ') PsiBreakStatement diff --git a/java/java-tests/testData/psi/parser-partial/statements/SwitchRules10.txt b/java/java-tests/testData/psi/parser-partial/statements/SwitchRules10.txt index c7ad93cf228b..221722af2fd5 100644 --- a/java/java-tests/testData/psi/parser-partial/statements/SwitchRules10.txt +++ b/java/java-tests/testData/psi/parser-partial/statements/SwitchRules10.txt @@ -2,13 +2,14 @@ PsiJavaFile:SwitchRules10.java PsiSwitchLabeledRule PsiKeyword:case('case') PsiWhiteSpace(' ') - PsiParenthesizedExpression:(b) - PsiJavaToken:LPARENTH('(') - PsiReferenceExpression:b - PsiReferenceParameterList - - PsiIdentifier:b('b') - PsiJavaToken:RPARENTH(')') + PsiExpressionList + PsiParenthesizedExpression:(b) + PsiJavaToken:LPARENTH('(') + PsiReferenceExpression:b + PsiReferenceParameterList + + PsiIdentifier:b('b') + PsiJavaToken:RPARENTH(')') PsiWhiteSpace(' ') PsiJavaToken:ARROW('->') PsiWhiteSpace(' ') diff --git a/java/java-tests/testData/psi/parser-partial/statements/SwitchRules11.txt b/java/java-tests/testData/psi/parser-partial/statements/SwitchRules11.txt new file mode 100644 index 000000000000..16d24f6d2c08 --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/statements/SwitchRules11.txt @@ -0,0 +1,19 @@ +PsiJavaFile:SwitchRules11.java + PsiSwitchLabeledRule + PsiKeyword:case('case') + PsiWhiteSpace(' ') + PsiExpressionList + PsiLiteralExpression:1 + PsiJavaToken:INTEGER_LITERAL('1') + PsiJavaToken:COMMA(',') + PsiWhiteSpace(' ') + PsiLiteralExpression:2 + PsiJavaToken:INTEGER_LITERAL('2') + PsiWhiteSpace(' ') + PsiJavaToken:ARROW('->') + PsiWhiteSpace(' ') + PsiBlockStatement + PsiCodeBlock + PsiJavaToken:LBRACE('{') + PsiWhiteSpace(' ') + PsiJavaToken:RBRACE('}') \ No newline at end of file diff --git a/java/java-tests/testData/psi/parser-partial/statements/SwitchRules12.txt b/java/java-tests/testData/psi/parser-partial/statements/SwitchRules12.txt new file mode 100644 index 000000000000..2e167d454a3a --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/statements/SwitchRules12.txt @@ -0,0 +1,18 @@ +PsiJavaFile:SwitchRules12.java + PsiSwitchLabeledRule + PsiKeyword:case('case') + PsiWhiteSpace(' ') + PsiExpressionList + PsiLiteralExpression:1 + PsiJavaToken:INTEGER_LITERAL('1') + PsiJavaToken:COMMA(',') + PsiErrorElement:Expression expected + + PsiWhiteSpace(' ') + PsiJavaToken:ARROW('->') + PsiWhiteSpace(' ') + PsiBlockStatement + PsiCodeBlock + PsiJavaToken:LBRACE('{') + PsiWhiteSpace(' ') + PsiJavaToken:RBRACE('}') \ No newline at end of file diff --git a/java/java-tests/testData/psi/parser-partial/statements/SwitchRules2.txt b/java/java-tests/testData/psi/parser-partial/statements/SwitchRules2.txt index d532c623d464..7e747cded928 100644 --- a/java/java-tests/testData/psi/parser-partial/statements/SwitchRules2.txt +++ b/java/java-tests/testData/psi/parser-partial/statements/SwitchRules2.txt @@ -2,8 +2,9 @@ PsiJavaFile:SwitchRules2.java PsiSwitchLabeledRule PsiKeyword:case('case') PsiWhiteSpace(' ') - PsiLiteralExpression:1 - PsiJavaToken:INTEGER_LITERAL('1') + PsiExpressionList + PsiLiteralExpression:1 + PsiJavaToken:INTEGER_LITERAL('1') PsiWhiteSpace(' ') PsiJavaToken:ARROW('->') PsiWhiteSpace(' ') diff --git a/java/java-tests/testData/psi/parser-partial/statements/SwitchRules3.txt b/java/java-tests/testData/psi/parser-partial/statements/SwitchRules3.txt index 441022e86a2f..cc0149d7d55e 100644 --- a/java/java-tests/testData/psi/parser-partial/statements/SwitchRules3.txt +++ b/java/java-tests/testData/psi/parser-partial/statements/SwitchRules3.txt @@ -2,8 +2,9 @@ PsiJavaFile:SwitchRules3.java PsiSwitchLabeledRule PsiKeyword:case('case') PsiWhiteSpace(' ') - PsiLiteralExpression:1 - PsiJavaToken:INTEGER_LITERAL('1') + PsiExpressionList + PsiLiteralExpression:1 + PsiJavaToken:INTEGER_LITERAL('1') PsiWhiteSpace(' ') PsiJavaToken:ARROW('->') PsiWhiteSpace(' ') diff --git a/java/java-tests/testData/psi/parser-partial/statements/SwitchRules4.txt b/java/java-tests/testData/psi/parser-partial/statements/SwitchRules4.txt index 5feda4cf09a9..d2f95f0e89c9 100644 --- a/java/java-tests/testData/psi/parser-partial/statements/SwitchRules4.txt +++ b/java/java-tests/testData/psi/parser-partial/statements/SwitchRules4.txt @@ -2,8 +2,9 @@ PsiJavaFile:SwitchRules4.java PsiSwitchLabeledRule PsiKeyword:case('case') PsiWhiteSpace(' ') - PsiLiteralExpression:1 - PsiJavaToken:INTEGER_LITERAL('1') + PsiExpressionList + PsiLiteralExpression:1 + PsiJavaToken:INTEGER_LITERAL('1') PsiWhiteSpace(' ') PsiJavaToken:ARROW('->') PsiWhiteSpace(' ') diff --git a/java/java-tests/testData/psi/parser-partial/statements/SwitchRules5.txt b/java/java-tests/testData/psi/parser-partial/statements/SwitchRules5.txt index a05cce1cc997..d96d86ca82fc 100644 --- a/java/java-tests/testData/psi/parser-partial/statements/SwitchRules5.txt +++ b/java/java-tests/testData/psi/parser-partial/statements/SwitchRules5.txt @@ -2,8 +2,9 @@ PsiJavaFile:SwitchRules5.java PsiSwitchLabeledRule PsiKeyword:case('case') PsiWhiteSpace(' ') - PsiLiteralExpression:1 - PsiJavaToken:INTEGER_LITERAL('1') + PsiExpressionList + PsiLiteralExpression:1 + PsiJavaToken:INTEGER_LITERAL('1') PsiWhiteSpace(' ') PsiJavaToken:ARROW('->') PsiWhiteSpace(' ') diff --git a/java/java-tests/testData/psi/parser-partial/statements/SwitchRules6.txt b/java/java-tests/testData/psi/parser-partial/statements/SwitchRules6.txt index ea3ca0b66a53..fd099334993b 100644 --- a/java/java-tests/testData/psi/parser-partial/statements/SwitchRules6.txt +++ b/java/java-tests/testData/psi/parser-partial/statements/SwitchRules6.txt @@ -2,8 +2,9 @@ PsiJavaFile:SwitchRules6.java PsiSwitchLabeledRule PsiKeyword:case('case') PsiWhiteSpace(' ') - PsiLiteralExpression:1 - PsiJavaToken:INTEGER_LITERAL('1') + PsiExpressionList + PsiLiteralExpression:1 + PsiJavaToken:INTEGER_LITERAL('1') PsiWhiteSpace(' ') PsiJavaToken:ARROW('->') PsiWhiteSpace(' ') diff --git a/java/java-tests/testData/psi/parser-partial/statements/SwitchRules7.txt b/java/java-tests/testData/psi/parser-partial/statements/SwitchRules7.txt index cd9c8de410a6..f419ca6c3b3a 100644 --- a/java/java-tests/testData/psi/parser-partial/statements/SwitchRules7.txt +++ b/java/java-tests/testData/psi/parser-partial/statements/SwitchRules7.txt @@ -2,8 +2,9 @@ PsiJavaFile:SwitchRules7.java PsiSwitchLabeledRule PsiKeyword:case('case') PsiWhiteSpace(' ') - PsiLiteralExpression:1 - PsiJavaToken:INTEGER_LITERAL('1') + PsiExpressionList + PsiLiteralExpression:1 + PsiJavaToken:INTEGER_LITERAL('1') PsiWhiteSpace(' ') PsiJavaToken:ARROW('->') PsiWhiteSpace(' ') diff --git a/java/java-tests/testData/psi/parser-partial/statements/SwitchRules8.txt b/java/java-tests/testData/psi/parser-partial/statements/SwitchRules8.txt index 9119c1859333..882fc97a528b 100644 --- a/java/java-tests/testData/psi/parser-partial/statements/SwitchRules8.txt +++ b/java/java-tests/testData/psi/parser-partial/statements/SwitchRules8.txt @@ -2,8 +2,9 @@ PsiJavaFile:SwitchRules8.java PsiSwitchLabeledRule PsiKeyword:case('case') PsiWhiteSpace(' ') - PsiLiteralExpression:1 - PsiJavaToken:INTEGER_LITERAL('1') + PsiExpressionList + PsiLiteralExpression:1 + PsiJavaToken:INTEGER_LITERAL('1') PsiWhiteSpace(' ') PsiJavaToken:ARROW('->') PsiErrorElement:Expression, block or throw statement expected diff --git a/java/java-tests/testData/psi/parser-partial/statements/SwitchRules9.txt b/java/java-tests/testData/psi/parser-partial/statements/SwitchRules9.txt index 9da6ca2add3e..f08fa5c67531 100644 --- a/java/java-tests/testData/psi/parser-partial/statements/SwitchRules9.txt +++ b/java/java-tests/testData/psi/parser-partial/statements/SwitchRules9.txt @@ -2,10 +2,11 @@ PsiJavaFile:SwitchRules9.java PsiSwitchLabeledRule PsiKeyword:case('case') PsiWhiteSpace(' ') - PsiReferenceExpression:b - PsiReferenceParameterList - - PsiIdentifier:b('b') + PsiExpressionList + PsiReferenceExpression:b + PsiReferenceParameterList + + PsiIdentifier:b('b') PsiWhiteSpace(' ') PsiJavaToken:ARROW('->') PsiWhiteSpace(' ') diff --git a/java/java-tests/testSrc/com/intellij/java/parser/partial/StatementParserTest.java b/java/java-tests/testSrc/com/intellij/java/parser/partial/StatementParserTest.java index 013fc1a3a9fc..8856c078bd02 100644 --- a/java/java-tests/testSrc/com/intellij/java/parser/partial/StatementParserTest.java +++ b/java/java-tests/testSrc/com/intellij/java/parser/partial/StatementParserTest.java @@ -99,10 +99,13 @@ public class StatementParserTest extends JavaParsingTestCase { public void testSwitchIncomplete5() { doParserTest("switch(\n foo();"); } public void testSwitchLabelsNormal() { doParserTest("case 1: break; default: break;"); } + public void testSwitchLabelsMultiple() { doParserTest("case 1, 2: break;"); } public void testSwitchLabelsIncomplete0() { doParserTest("case"); } public void testSwitchLabelsIncomplete1() { doParserTest("case 2"); } public void testSwitchLabelsIncomplete2() { doParserTest("default"); } public void testSwitchLabelsIncomplete3() { doParserTest("default 3:"); } + public void testSwitchLabelsIncomplete4() { doParserTest("case :"); } + public void testSwitchLabelsIncomplete5() { doParserTest("case 1, : break;"); } public void testSwitchRules0() { doParserTest("default ->"); } public void testSwitchRules1() { doParserTest("default -> return;"); } @@ -115,6 +118,8 @@ public class StatementParserTest extends JavaParsingTestCase { public void testSwitchRules8() { doParserTest("case 1 -> ;"); } public void testSwitchRules9() { doParserTest("case b -> f(b);"); } public void testSwitchRules10() { doParserTest("case (b) -> f(b);"); } + public void testSwitchRules11() { doParserTest("case 1, 2 -> { }"); } + public void testSwitchRules12() { doParserTest("case 1, -> { }"); } public void testSyncNormal() { doParserTest("synchronized(o){}"); } public void testSyncIncomplete0() { doParserTest("synchronized"); }