Java: implement parser for pattern matching in switch : IDEA-270060

GitOrigin-RevId: 586fe6199e79db35098202959c3aeaab2c0ada1f
This commit is contained in:
Roman Ivanov
2021-06-07 22:03:01 +00:00
committed by intellij-monorepo-bot
parent c67d7fae83
commit b0769e53fa
34 changed files with 722 additions and 109 deletions
@@ -61,6 +61,7 @@ expected.comma.or.semicolon=',' or ';' expected
expected.dot='.' expected
expected.eq='=' expected
expected.expression=Expression expected
expected.case.label.element=Expression, pattern, 'default' or 'null' expected
expected.gt='>' expected.
expected.gt.or.comma='>' or ',' expected
expected.identifier=Identifier expected
@@ -48,9 +48,8 @@ public class ExpressionParser {
private static final TokenSet ID_OR_SUPER = TokenSet.create(JavaTokenType.IDENTIFIER, JavaTokenType.SUPER_KEYWORD);
private static final TokenSet TYPE_START = TokenSet.orSet(
ElementType.PRIMITIVE_TYPE_BIT_SET, TokenSet.create(JavaTokenType.IDENTIFIER, JavaTokenType.AT));
private static final TokenSet PATTERN_MODIFIERS = TokenSet.create(JavaTokenType.FINAL_KEYWORD);
private static final Key<Boolean> CASE_LABEL = Key.create("java.parser.case.label.expr");
static final Key<Boolean> CASE_LABEL = Key.create("java.parser.case.label.expr");
private final JavaParser myParser;
@@ -65,17 +64,10 @@ public class ExpressionParser {
@Nullable
public PsiBuilder.Marker parseCaseLabel(@NotNull PsiBuilder builder) {
CASE_LABEL.set(builder, Boolean.TRUE);
try {
return parseAssignment(builder);
}
finally {
CASE_LABEL.set(builder, null);
}
return myParser.getStatementParser().parseCaseLabel(builder).first;
}
@Nullable
private PsiBuilder.Marker parseAssignment(final PsiBuilder builder) {
@Nullable PsiBuilder.Marker parseAssignment(final PsiBuilder builder) {
final PsiBuilder.Marker left = parseConditional(builder);
if (left == null) return null;
@@ -175,45 +167,6 @@ public class ExpressionParser {
}
}
@Nullable
private PsiBuilder.Marker parsePattern(final PsiBuilder builder) {
PsiBuilder.Marker typeTestPattern = parseSimpleTypeTest(builder);
if (typeTestPattern != null) return typeTestPattern;
PsiBuilder.Marker pattern = builder.mark();
PsiBuilder.Marker patternVariable = builder.mark();
PsiBuilder.Marker modifiers = myParser.getDeclarationParser().parseModifierList(builder, PATTERN_MODIFIERS).first;
PsiBuilder.Marker type = myParser.getReferenceParser().parseType(builder, ReferenceParser.EAT_LAST_DOT | ReferenceParser.WILDCARD);
if (type == null) {
patternVariable.drop();
pattern.drop();
modifiers.drop();
return null;
}
if (!expect(builder, JavaTokenType.IDENTIFIER)) {
patternVariable.drop();
modifiers.drop();
} else {
patternVariable.done(JavaElementType.PATTERN_VARIABLE);
}
pattern.done(JavaElementType.TYPE_TEST_PATTERN);
return pattern;
}
@Nullable
private PsiBuilder.Marker parseSimpleTypeTest(final PsiBuilder builder) {
PsiBuilder.Marker pattern = builder.mark();
PsiBuilder.Marker type = myParser.getReferenceParser().parseType(builder, ReferenceParser.EAT_LAST_DOT | ReferenceParser.WILDCARD);
if (type == null || builder.getTokenType() == JavaTokenType.IDENTIFIER) {
pattern.rollbackTo();
return null;
}
pattern.done(JavaElementType.TYPE_TEST_PATTERN);
return pattern;
}
@Nullable
private PsiBuilder.Marker parseBinary(final PsiBuilder builder, final ExprType type, final TokenSet ops) {
PsiBuilder.Marker result = parseExpression(builder, type);
@@ -269,12 +222,23 @@ public class ExpressionParser {
final PsiBuilder.Marker expression = left.precede();
advanceGtToken(builder, tokenType);
final PsiBuilder.Marker right = patternExpected ? parsePattern(builder) : parseExpression(builder, ExprType.SHIFT);
if (right == null) {
error(builder, JavaPsiBundle.message(patternExpected ? "expected.type" : "expected.expression"));
expression.done(toCreate);
return expression;
if (patternExpected) {
if (!myParser.getPatternParser().isPattern(builder)) {
PsiBuilder.Marker type = parseExpression(builder, ExprType.TYPE);
if (type == null) {
error(builder, JavaPsiBundle.message("expected.type"));
}
expression.done(toCreate);
return expression;
}
myParser.getPatternParser().parsePrimaryPattern(builder);
} else {
final PsiBuilder.Marker right = parseExpression(builder, ExprType.SHIFT);
if (right == null) {
error(builder, JavaPsiBundle.message("expected.expression"));
expression.done(toCreate);
return expression;
}
}
expression.done(toCreate);
@@ -26,6 +26,7 @@ public class JavaParser {
private final StatementParser myStatementParser;
private final ExpressionParser myExpressionParser;
private final ReferenceParser myReferenceParser;
private final PatternParser myPatternParser;
public JavaParser() {
myFileParser = new FileParser(this);
@@ -34,6 +35,7 @@ public class JavaParser {
myStatementParser = new StatementParser(this);
myExpressionParser = new ExpressionParser(this);
myReferenceParser = new ReferenceParser(this);
myPatternParser = new PatternParser(this);
}
@NotNull
@@ -65,4 +67,9 @@ public class JavaParser {
public ReferenceParser getReferenceParser() {
return myReferenceParser;
}
@NotNull
public PatternParser getPatternParser() {
return myPatternParser;
}
}
@@ -0,0 +1,86 @@
// 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.lang.java.parser;
import com.intellij.core.JavaPsiBundle;
import com.intellij.lang.PsiBuilder;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.psi.JavaTokenType;
import com.intellij.psi.impl.source.tree.JavaElementType;
import com.intellij.psi.tree.TokenSet;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import static com.intellij.lang.PsiBuilderUtil.expect;
import static com.intellij.lang.java.parser.JavaParserUtil.*;
public class PatternParser {
private static final TokenSet PATTERN_MODIFIERS = TokenSet.create(JavaTokenType.FINAL_KEYWORD);
private final JavaParser myParser;
public PatternParser(JavaParser javaParser) {
myParser = javaParser;
}
@Contract(pure = true)
public boolean isPattern(final PsiBuilder builder) {
PsiBuilder.Marker patternStart = builder.mark();
if (getLanguageLevel(builder).isAtLeast(LanguageLevel.JDK_X)) {
while (builder.getTokenType() == JavaTokenType.LPARENTH) {
builder.advanceLexer();
}
}
myParser.getDeclarationParser().parseModifierList(builder, PATTERN_MODIFIERS);
PsiBuilder.Marker type = myParser.getReferenceParser().parseType(builder, ReferenceParser.EAT_LAST_DOT | ReferenceParser.WILDCARD);
boolean isPattern = type != null && builder.getTokenType() == JavaTokenType.IDENTIFIER;
patternStart.rollbackTo();
return isPattern;
}
PsiBuilder.@NotNull Marker parsePattern(final PsiBuilder builder) {
PsiBuilder.Marker guardPattern = builder.mark();
PsiBuilder.Marker primaryPattern = parsePrimaryPattern(builder);
if (builder.getTokenType() != JavaTokenType.ANDAND) {
guardPattern.drop();
return primaryPattern;
}
builder.advanceLexer();
PsiBuilder.Marker guardingExpression = myParser.getExpressionParser().parseAssignment(builder);
if (guardingExpression == null) {
error(builder, JavaPsiBundle.message("expected.expression"));
}
done(guardPattern, JavaElementType.GUARDED_PATTERN);
return guardPattern;
}
PsiBuilder.@NotNull Marker parsePrimaryPattern(final PsiBuilder builder) {
if (builder.getTokenType() == JavaTokenType.LPARENTH && getLanguageLevel(builder).isAtLeast(LanguageLevel.JDK_X)) {
PsiBuilder.Marker parenPattern = builder.mark();
builder.advanceLexer();
parsePattern(builder);
if (!expect(builder, JavaTokenType.RPARENTH)) {
error(builder, JavaPsiBundle.message("expected.rparen"));
}
done(parenPattern, JavaElementType.PARENTHESIZED_PATTERN);
return parenPattern;
}
return parseTypePattern(builder);
}
private PsiBuilder.@NotNull Marker parseTypePattern(final PsiBuilder builder) {
PsiBuilder.Marker pattern = builder.mark();
PsiBuilder.Marker patternVariable = builder.mark();
PsiBuilder.Marker modifiers = myParser.getDeclarationParser().parseModifierList(builder, PATTERN_MODIFIERS).first;
PsiBuilder.Marker type = myParser.getReferenceParser().parseType(builder, ReferenceParser.EAT_LAST_DOT | ReferenceParser.WILDCARD);
assert type != null; // guarded by isPattern
if (!expect(builder, JavaTokenType.IDENTIFIER)) {
patternVariable.drop();
modifiers.drop();
} else {
done(patternVariable, JavaElementType.PATTERN_VARIABLE);
}
done(pattern, JavaElementType.TYPE_TEST_PATTERN);
return pattern;
}
}
@@ -4,6 +4,7 @@ package com.intellij.lang.java.parser;
import com.intellij.core.JavaPsiBundle;
import com.intellij.lang.PsiBuilder;
import com.intellij.lang.WhitespacesBinders;
import com.intellij.openapi.util.Pair;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.psi.JavaTokenType;
import com.intellij.psi.PsiKeyword;
@@ -16,6 +17,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import static com.intellij.lang.PsiBuilderUtil.*;
import static com.intellij.lang.java.parser.ExpressionParser.CASE_LABEL;
import static com.intellij.lang.java.parser.JavaParserUtil.*;
public class StatementParser {
@@ -428,21 +430,59 @@ public class StatementParser {
return parseExprInParenthWithBlock(builder, JavaElementType.SWITCH_STATEMENT, true);
}
/**
* @return marker and whether it contains expression inside
*/
@NotNull
Pair<PsiBuilder.@Nullable Marker, Boolean> parseCaseLabel(PsiBuilder builder) {
CASE_LABEL.set(builder, Boolean.TRUE);
try {
if (getLanguageLevel(builder).isAtLeast(LanguageLevel.JDK_X)) {
if (builder.getTokenType() == JavaTokenType.DEFAULT_KEYWORD) {
PsiBuilder.Marker defaultElement = builder.mark();
builder.advanceLexer();
done(defaultElement, JavaElementType.DEFAULT_ELEMENT);
return Pair.create(defaultElement, false);
}
if (builder.getTokenType() == JavaTokenType.NULL_KEYWORD) {
PsiBuilder.Marker defaultElement = builder.mark();
builder.advanceLexer();
done(defaultElement, JavaElementType.NULL_ELEMENT);
return Pair.create(defaultElement, false);
}
if (myParser.getPatternParser().isPattern(builder)) {
return Pair.create(myParser.getPatternParser().parsePattern(builder), false);
}
}
return Pair.create(myParser.getExpressionParser().parseAssignment(builder), true);
}
finally {
CASE_LABEL.set(builder, null);
}
}
private PsiBuilder.Marker parseSwitchLabelStatement(PsiBuilder builder) {
PsiBuilder.Marker statement = builder.mark();
boolean isCase = builder.getTokenType() == JavaTokenType.CASE_KEYWORD;
builder.advanceLexer();
if (isCase) {
PsiBuilder.Marker expressionList = builder.mark();
boolean patternsAllowed = getLanguageLevel(builder).isAtLeast(LanguageLevel.JDK_X);
PsiBuilder.Marker list = builder.mark();
boolean isExpressionList = true;
do {
PsiBuilder.Marker nextExpression = myParser.getExpressionParser().parseCaseLabel(builder);
if (nextExpression == null) {
error(builder, JavaPsiBundle.message("expected.expression"));
Pair<PsiBuilder.Marker, Boolean> markerAndIsExpression = parseCaseLabel(builder);
PsiBuilder.Marker caseLabel = markerAndIsExpression.first;
Boolean isExpression = markerAndIsExpression.second;
if (!isExpression) {
isExpressionList = false;
}
if (caseLabel == null) {
error(builder, JavaPsiBundle.message(patternsAllowed ? "expected.case.label.element" : "expected.expression"));
}
}
while (expect(builder, JavaTokenType.COMMA));
done(expressionList, JavaElementType.EXPRESSION_LIST);
done(list, isExpressionList ? JavaElementType.EXPRESSION_LIST : JavaElementType.CASE_LABEL_ELEMENT_LIST);
}
if (expect(builder, JavaTokenType.ARROW)) {
@@ -138,6 +138,11 @@ public interface JavaElementType {
IElementType MODULE_REFERENCE = new JavaCompositeElementType("MODULE_REFERENCE", () -> new PsiJavaModuleReferenceElementImpl());
IElementType TYPE_TEST_PATTERN = new JavaCompositeElementType("TYPE_TEST_PATTERN", () -> new PsiTypeTestPatternImpl());
IElementType PATTERN_VARIABLE = new JavaCompositeElementType("PATTERN_VARIABLE", () -> new PsiPatternVariableImpl());
IElementType PARENTHESIZED_PATTERN = new JavaCompositeElementType("PARENTHESIZED_PATTERN", () -> new PsiParenthesizedPatternImpl());
IElementType GUARDED_PATTERN = new JavaCompositeElementType("GUARDED_PATTERN", () -> new PsiGuardedPatternImpl());
IElementType DEFAULT_ELEMENT = new JavaCompositeElementType("DEFAULT_ELEMENT", () -> new PsiDefaultElementImpl());
IElementType NULL_ELEMENT = new JavaCompositeElementType("NULL_ELEMENT", () -> new PsiNullElementImpl());
IElementType CASE_LABEL_ELEMENT_LIST = new JavaCompositeElementType("CASE_LABEL_ELEMENT_LIST", () -> new PsiCaseLabelElementListImpl());
final class ICodeBlockElementType extends IErrorCounterReparseableElementType implements ICompositeElementType, ILightLazyParseableElementType {
private ICodeBlockElementType() {
@@ -577,21 +577,20 @@ PsiJavaFile:TypeAnnotations.java
PsiWhiteSpace(' ')
PsiKeyword:instanceof('instanceof')
PsiWhiteSpace(' ')
PsiTypeTestPattern
PsiTypeElement:@NonNull String
PsiAnnotation
PsiJavaToken:AT('@')
PsiJavaCodeReferenceElement:NonNull
PsiIdentifier:NonNull('NonNull')
PsiReferenceParameterList
<empty list>
PsiAnnotationParameterList
<empty list>
PsiWhiteSpace(' ')
PsiJavaCodeReferenceElement:String
PsiIdentifier:String('String')
PsiTypeElement:@NonNull String
PsiAnnotation
PsiJavaToken:AT('@')
PsiJavaCodeReferenceElement:NonNull
PsiIdentifier:NonNull('NonNull')
PsiReferenceParameterList
<empty list>
PsiAnnotationParameterList
<empty list>
PsiWhiteSpace(' ')
PsiJavaCodeReferenceElement:String
PsiIdentifier:String('String')
PsiReferenceParameterList
<empty list>
PsiJavaToken:SEMICOLON(';')
PsiWhiteSpace('\n ')
PsiExpressionStatement
@@ -334,12 +334,11 @@ PsiJavaFile:AnonymousErrors1.java
PsiWhiteSpace(' ')
PsiKeyword:instanceof('instanceof')
PsiWhiteSpace(' ')
PsiTypeTestPattern
PsiTypeElement:Integer
PsiJavaCodeReferenceElement:Integer
PsiIdentifier:Integer('Integer')
PsiReferenceParameterList
<empty list>
PsiTypeElement:Integer
PsiJavaCodeReferenceElement:Integer
PsiIdentifier:Integer('Integer')
PsiReferenceParameterList
<empty list>
PsiWhiteSpace(' ')
PsiJavaToken:QUEST('?')
PsiWhiteSpace(' ')
@@ -32,12 +32,11 @@ PsiJavaFile:InstanceOf0.java
PsiWhiteSpace(' ')
PsiKeyword:instanceof('instanceof')
PsiWhiteSpace(' ')
PsiTypeTestPattern
PsiTypeElement:String
PsiJavaCodeReferenceElement:String
PsiIdentifier:String('String')
PsiReferenceParameterList
<empty list>
PsiTypeElement:String
PsiJavaCodeReferenceElement:String
PsiIdentifier:String('String')
PsiReferenceParameterList
<empty list>
PsiJavaToken:SEMICOLON(';')
PsiWhiteSpace('\n ')
PsiJavaToken:RBRACE('}')
@@ -130,21 +130,20 @@ PsiJavaFile:TypeAnno.java
PsiWhiteSpace(' ')
PsiKeyword:instanceof('instanceof')
PsiWhiteSpace(' ')
PsiTypeTestPattern
PsiTypeElement:@F C
PsiAnnotation
PsiJavaToken:AT('@')
PsiJavaCodeReferenceElement:F
PsiIdentifier:F('F')
PsiReferenceParameterList
<empty list>
PsiAnnotationParameterList
<empty list>
PsiWhiteSpace(' ')
PsiJavaCodeReferenceElement:C
PsiIdentifier:C('C')
PsiTypeElement:@F C
PsiAnnotation
PsiJavaToken:AT('@')
PsiJavaCodeReferenceElement:F
PsiIdentifier:F('F')
PsiReferenceParameterList
<empty list>
PsiAnnotationParameterList
<empty list>
PsiWhiteSpace(' ')
PsiJavaCodeReferenceElement:C
PsiIdentifier:C('C')
PsiReferenceParameterList
<empty list>
PsiJavaToken:SEMICOLON(';')
PsiWhiteSpace('\n ')
PsiDeclarationStatement
@@ -7,9 +7,8 @@ PsiJavaFile:InstanceOf0.java
PsiWhiteSpace(' ')
PsiKeyword:instanceof('instanceof')
PsiWhiteSpace(' ')
PsiTypeTestPattern
PsiTypeElement:String
PsiJavaCodeReferenceElement:String
PsiIdentifier:String('String')
PsiReferenceParameterList
<empty list>
PsiTypeElement:String
PsiJavaCodeReferenceElement:String
PsiIdentifier:String('String')
PsiReferenceParameterList
<empty list>
@@ -0,0 +1,17 @@
PsiJavaFile:InstanceOfPattern3.java
PsiInstanceofExpression
PsiReferenceExpression:x
PsiReferenceParameterList
<empty list>
PsiIdentifier:x('x')
PsiWhiteSpace(' ')
PsiKeyword:instanceof('instanceof')
PsiErrorElement:Type expected
<empty list>
PsiWhiteSpace(' ')
PsiErrorElement:Unparsed tokens
PsiJavaToken:LPARENTH('(')
PsiIdentifier:Foo('Foo')
PsiWhiteSpace(' ')
PsiIdentifier:v('v')
PsiJavaToken:RPARENTH(')')
@@ -0,0 +1,34 @@
PsiJavaFile:InstanceOfPattern4.java
PsiBinaryExpression:x instanceof Foo v && v > 10
PsiInstanceofExpression
PsiReferenceExpression:x
PsiReferenceParameterList
<empty list>
PsiIdentifier:x('x')
PsiWhiteSpace(' ')
PsiKeyword:instanceof('instanceof')
PsiWhiteSpace(' ')
PsiTypeTestPattern
PsiPatternVariable:v
PsiModifierList:
<empty list>
PsiTypeElement:Foo
PsiJavaCodeReferenceElement:Foo
PsiIdentifier:Foo('Foo')
PsiReferenceParameterList
<empty list>
PsiWhiteSpace(' ')
PsiIdentifier:v('v')
PsiWhiteSpace(' ')
PsiJavaToken:ANDAND('&&')
PsiWhiteSpace(' ')
PsiBinaryExpression:v > 10
PsiReferenceExpression:v
PsiReferenceParameterList
<empty list>
PsiIdentifier:v('v')
PsiWhiteSpace(' ')
PsiJavaToken:GT('>')
PsiWhiteSpace(' ')
PsiLiteralExpression:10
PsiJavaToken:INTEGER_LITERAL('10')
@@ -0,0 +1,37 @@
PsiJavaFile:InstanceOfPattern5.java
PsiInstanceofExpression
PsiReferenceExpression:x
PsiReferenceParameterList
<empty list>
PsiIdentifier:x('x')
PsiWhiteSpace(' ')
PsiKeyword:instanceof('instanceof')
PsiWhiteSpace(' ')
PsiParenthesizedPattern
PsiJavaToken:LPARENTH('(')
PsiGuardedPattern
PsiTypeTestPattern
PsiPatternVariable:v
PsiModifierList:
<empty list>
PsiTypeElement:Foo
PsiJavaCodeReferenceElement:Foo
PsiIdentifier:Foo('Foo')
PsiReferenceParameterList
<empty list>
PsiWhiteSpace(' ')
PsiIdentifier:v('v')
PsiWhiteSpace(' ')
PsiJavaToken:ANDAND('&&')
PsiWhiteSpace(' ')
PsiBinaryExpression:v > 10
PsiReferenceExpression:v
PsiReferenceParameterList
<empty list>
PsiIdentifier:v('v')
PsiWhiteSpace(' ')
PsiJavaToken:GT('>')
PsiWhiteSpace(' ')
PsiLiteralExpression:10
PsiJavaToken:INTEGER_LITERAL('10')
PsiJavaToken:RPARENTH(')')
@@ -2,7 +2,7 @@ PsiJavaFile:SwitchLabelsIncomplete0.java
PsiSwitchLabelStatement
PsiKeyword:case('case')
PsiExpressionList
PsiErrorElement:Expression expected
PsiErrorElement:Expression, pattern, 'default' or 'null' expected
<empty list>
PsiErrorElement:':' expected
<empty list>
@@ -2,7 +2,7 @@ PsiJavaFile:SwitchLabelsIncomplete4.java
PsiSwitchLabelStatement
PsiKeyword:case('case')
PsiExpressionList
PsiErrorElement:Expression expected
PsiErrorElement:Expression, pattern, 'default' or 'null' expected
<empty list>
PsiWhiteSpace(' ')
PsiJavaToken:COLON(':')
@@ -6,7 +6,7 @@ PsiJavaFile:SwitchLabelsIncomplete5.java
PsiLiteralExpression:1
PsiJavaToken:INTEGER_LITERAL('1')
PsiJavaToken:COMMA(',')
PsiErrorElement:Expression expected
PsiErrorElement:Expression, pattern, 'default' or 'null' expected
<empty list>
PsiWhiteSpace(' ')
PsiJavaToken:COLON(':')
@@ -0,0 +1,43 @@
PsiJavaFile:SwitchLabelsWithPattern.java
PsiSwitchLabelStatement
PsiKeyword:case('case')
PsiWhiteSpace(' ')
PsiCaseLabelElementList
PsiGuardedPattern
PsiTypeTestPattern
PsiPatternVariable:ia
PsiModifierList:
<empty list>
PsiTypeElement:int[]
PsiTypeElement:int
PsiKeyword:int('int')
PsiJavaToken:LBRACKET('[')
PsiJavaToken:RBRACKET(']')
PsiWhiteSpace(' ')
PsiIdentifier:ia('ia')
PsiWhiteSpace(' ')
PsiJavaToken:ANDAND('&&')
PsiWhiteSpace(' ')
PsiBinaryExpression:ia.length > 10
PsiReferenceExpression:ia.length
PsiReferenceExpression:ia
PsiReferenceParameterList
<empty list>
PsiIdentifier:ia('ia')
PsiJavaToken:DOT('.')
PsiReferenceParameterList
<empty list>
PsiIdentifier:length('length')
PsiWhiteSpace(' ')
PsiJavaToken:GT('>')
PsiWhiteSpace(' ')
PsiLiteralExpression:10
PsiJavaToken:INTEGER_LITERAL('10')
PsiWhiteSpace(' ')
PsiJavaToken:COLON(':')
PsiWhiteSpace(' ')
PsiBlockStatement
PsiCodeBlock
PsiJavaToken:LBRACE('{')
PsiWhiteSpace(' ')
PsiJavaToken:RBRACE('}')
@@ -6,7 +6,7 @@ PsiJavaFile:SwitchRules12.java
PsiLiteralExpression:1
PsiJavaToken:INTEGER_LITERAL('1')
PsiJavaToken:COMMA(',')
PsiErrorElement:Expression expected
PsiErrorElement:Expression, pattern, 'default' or 'null' expected
<empty list>
PsiWhiteSpace(' ')
PsiJavaToken:ARROW('->')
@@ -0,0 +1,19 @@
PsiJavaFile:SwitchRules13.java
PsiSwitchLabeledRule
PsiKeyword:case('case')
PsiWhiteSpace(' ')
PsiCaseLabelElementList
PsiNullElementImpl
PsiJavaToken:NULL_KEYWORD('null')
PsiJavaToken:COMMA(',')
PsiWhiteSpace(' ')
PsiDefaultElement
PsiKeyword:default('default')
PsiWhiteSpace(' ')
PsiJavaToken:ARROW('->')
PsiWhiteSpace(' ')
PsiBlockStatement
PsiCodeBlock
PsiJavaToken:LBRACE('{')
PsiWhiteSpace(' ')
PsiJavaToken:RBRACE('}')
@@ -0,0 +1,15 @@
PsiJavaFile:SwitchRules14.java
PsiSwitchLabeledRule
PsiKeyword:case('case')
PsiWhiteSpace(' ')
PsiCaseLabelElementList
PsiDefaultElement
PsiKeyword:default('default')
PsiWhiteSpace(' ')
PsiJavaToken:ARROW('->')
PsiWhiteSpace(' ')
PsiBlockStatement
PsiCodeBlock
PsiJavaToken:LBRACE('{')
PsiWhiteSpace(' ')
PsiJavaToken:RBRACE('}')
@@ -0,0 +1,24 @@
PsiJavaFile:SwitchRulesWithPattern0.java
PsiSwitchLabeledRule
PsiKeyword:case('case')
PsiWhiteSpace(' ')
PsiCaseLabelElementList
PsiTypeTestPattern
PsiPatternVariable:i
PsiModifierList:
<empty list>
PsiTypeElement:Integer
PsiJavaCodeReferenceElement:Integer
PsiIdentifier:Integer('Integer')
PsiReferenceParameterList
<empty list>
PsiWhiteSpace(' ')
PsiIdentifier:i('i')
PsiWhiteSpace(' ')
PsiJavaToken:ARROW('->')
PsiWhiteSpace(' ')
PsiBlockStatement
PsiCodeBlock
PsiJavaToken:LBRACE('{')
PsiWhiteSpace(' ')
PsiJavaToken:RBRACE('}')
@@ -0,0 +1,24 @@
PsiJavaFile:SwitchRulesWithPattern1.java
PsiSwitchLabeledRule
PsiKeyword:case('case')
PsiWhiteSpace(' ')
PsiCaseLabelElementList
PsiTypeTestPattern
PsiPatternVariable:ia
PsiModifierList:
<empty list>
PsiTypeElement:int[]
PsiTypeElement:int
PsiKeyword:int('int')
PsiJavaToken:LBRACKET('[')
PsiJavaToken:RBRACKET(']')
PsiWhiteSpace(' ')
PsiIdentifier:ia('ia')
PsiWhiteSpace(' ')
PsiJavaToken:ARROW('->')
PsiWhiteSpace(' ')
PsiBlockStatement
PsiCodeBlock
PsiJavaToken:LBRACE('{')
PsiWhiteSpace(' ')
PsiJavaToken:RBRACE('}')
@@ -0,0 +1,38 @@
PsiJavaFile:SwitchRulesWithPattern2.java
PsiSwitchLabeledRule
PsiKeyword:case('case')
PsiWhiteSpace(' ')
PsiCaseLabelElementList
PsiGuardedPattern
PsiTypeTestPattern
PsiPatternVariable:i
PsiModifierList:
<empty list>
PsiTypeElement:Integer
PsiJavaCodeReferenceElement:Integer
PsiIdentifier:Integer('Integer')
PsiReferenceParameterList
<empty list>
PsiWhiteSpace(' ')
PsiIdentifier:i('i')
PsiWhiteSpace(' ')
PsiJavaToken:ANDAND('&&')
PsiWhiteSpace(' ')
PsiBinaryExpression:i > 10
PsiReferenceExpression:i
PsiReferenceParameterList
<empty list>
PsiIdentifier:i('i')
PsiWhiteSpace(' ')
PsiJavaToken:GT('>')
PsiWhiteSpace(' ')
PsiLiteralExpression:10
PsiJavaToken:INTEGER_LITERAL('10')
PsiWhiteSpace(' ')
PsiJavaToken:ARROW('->')
PsiWhiteSpace(' ')
PsiBlockStatement
PsiCodeBlock
PsiJavaToken:LBRACE('{')
PsiWhiteSpace(' ')
PsiJavaToken:RBRACE('}')
@@ -0,0 +1,53 @@
PsiJavaFile:SwitchRulesWithPattern3.java
PsiSwitchLabeledRule
PsiKeyword:case('case')
PsiWhiteSpace(' ')
PsiCaseLabelElementList
PsiGuardedPattern
PsiParenthesizedPattern
PsiJavaToken:LPARENTH('(')
PsiGuardedPattern
PsiTypeTestPattern
PsiPatternVariable:i
PsiModifierList:
<empty list>
PsiTypeElement:Integer
PsiJavaCodeReferenceElement:Integer
PsiIdentifier:Integer('Integer')
PsiReferenceParameterList
<empty list>
PsiWhiteSpace(' ')
PsiIdentifier:i('i')
PsiWhiteSpace(' ')
PsiJavaToken:ANDAND('&&')
PsiWhiteSpace(' ')
PsiBinaryExpression:i > 10
PsiReferenceExpression:i
PsiReferenceParameterList
<empty list>
PsiIdentifier:i('i')
PsiWhiteSpace(' ')
PsiJavaToken:GT('>')
PsiWhiteSpace(' ')
PsiLiteralExpression:10
PsiJavaToken:INTEGER_LITERAL('10')
PsiJavaToken:RPARENTH(')')
PsiWhiteSpace(' ')
PsiJavaToken:ANDAND('&&')
PsiWhiteSpace(' ')
PsiMethodCallExpression:boolExpr()
PsiReferenceExpression:boolExpr
PsiReferenceParameterList
<empty list>
PsiIdentifier:boolExpr('boolExpr')
PsiExpressionList
PsiJavaToken:LPARENTH('(')
PsiJavaToken:RPARENTH(')')
PsiWhiteSpace(' ')
PsiJavaToken:ARROW('->')
PsiWhiteSpace(' ')
PsiBlockStatement
PsiCodeBlock
PsiJavaToken:LBRACE('{')
PsiWhiteSpace(' ')
PsiJavaToken:RBRACE('}')
@@ -0,0 +1,28 @@
PsiJavaFile:SwitchRulesWithPattern4.java
PsiSwitchLabelStatement
PsiKeyword:case('case')
PsiWhiteSpace(' ')
PsiExpressionList
PsiReferenceExpression:Integer
PsiReferenceParameterList
<empty list>
PsiIdentifier:Integer('Integer')
PsiErrorElement:':' expected
<empty list>
PsiWhiteSpace(' ')
PsiExpressionStatement
PsiLambdaExpression
PsiParameterList:i
PsiParameter:i
PsiModifierList:
<empty list>
PsiIdentifier:i('i')
PsiWhiteSpace(' ')
PsiJavaToken:ARROW('->')
PsiWhiteSpace(' ')
PsiCodeBlock
PsiJavaToken:LBRACE('{')
PsiWhiteSpace(' ')
PsiJavaToken:RBRACE('}')
PsiErrorElement:';' expected
<empty list>
@@ -0,0 +1,19 @@
PsiJavaFile:SwitchRulesWithPattern5.java
PsiSwitchLabeledRule
PsiKeyword:case('case')
PsiWhiteSpace(' ')
PsiCaseLabelElementList
PsiNullElementImpl
PsiJavaToken:NULL_KEYWORD('null')
PsiJavaToken:COMMA(',')
PsiWhiteSpace(' ')
PsiDefaultElement
PsiKeyword:default('default')
PsiWhiteSpace(' ')
PsiJavaToken:ARROW('->')
PsiWhiteSpace(' ')
PsiBlockStatement
PsiCodeBlock
PsiJavaToken:LBRACE('{')
PsiWhiteSpace(' ')
PsiJavaToken:RBRACE('}')
@@ -0,0 +1,15 @@
PsiJavaFile:SwitchRulesWithPattern6.java
PsiSwitchLabeledRule
PsiKeyword:case('case')
PsiWhiteSpace(' ')
PsiCaseLabelElementList
PsiNullElementImpl
PsiJavaToken:NULL_KEYWORD('null')
PsiWhiteSpace(' ')
PsiJavaToken:ARROW('->')
PsiWhiteSpace(' ')
PsiBlockStatement
PsiCodeBlock
PsiJavaToken:LBRACE('{')
PsiWhiteSpace(' ')
PsiJavaToken:RBRACE('}')
@@ -0,0 +1,29 @@
PsiJavaFile:SwitchRulesWithPatternIncomplete0.java
PsiSwitchLabeledRule
PsiKeyword:case('case')
PsiWhiteSpace(' ')
PsiCaseLabelElementList
PsiGuardedPattern
PsiTypeTestPattern
PsiPatternVariable:i
PsiModifierList:
<empty list>
PsiTypeElement:Integer
PsiJavaCodeReferenceElement:Integer
PsiIdentifier:Integer('Integer')
PsiReferenceParameterList
<empty list>
PsiWhiteSpace(' ')
PsiIdentifier:i('i')
PsiWhiteSpace(' ')
PsiJavaToken:ANDAND('&&')
PsiErrorElement:Expression expected
<empty list>
PsiWhiteSpace(' ')
PsiJavaToken:ARROW('->')
PsiWhiteSpace(' ')
PsiBlockStatement
PsiCodeBlock
PsiJavaToken:LBRACE('{')
PsiWhiteSpace(' ')
PsiJavaToken:RBRACE('}')
@@ -0,0 +1,28 @@
PsiJavaFile:SwitchRulesWithPatternIncomplete1.java
PsiSwitchLabeledRule
PsiKeyword:case('case')
PsiWhiteSpace(' ')
PsiCaseLabelElementList
PsiParenthesizedPattern
PsiJavaToken:LPARENTH('(')
PsiTypeTestPattern
PsiPatternVariable:i
PsiModifierList:
<empty list>
PsiTypeElement:Integer
PsiJavaCodeReferenceElement:Integer
PsiIdentifier:Integer('Integer')
PsiReferenceParameterList
<empty list>
PsiWhiteSpace(' ')
PsiIdentifier:i('i')
PsiErrorElement:')' expected
<empty list>
PsiWhiteSpace(' ')
PsiJavaToken:ARROW('->')
PsiWhiteSpace(' ')
PsiBlockStatement
PsiCodeBlock
PsiJavaToken:LBRACE('{')
PsiWhiteSpace(' ')
PsiJavaToken:RBRACE('}')
@@ -0,0 +1,27 @@
PsiJavaFile:SwitchRulesWithPatternIncomplete2.java
PsiSwitchLabeledRule
PsiKeyword:case('case')
PsiWhiteSpace(' ')
PsiCaseLabelElementList
PsiTypeTestPattern
PsiPatternVariable:i
PsiModifierList:
<empty list>
PsiTypeElement:Integer
PsiJavaCodeReferenceElement:Integer
PsiIdentifier:Integer('Integer')
PsiReferenceParameterList
<empty list>
PsiWhiteSpace(' ')
PsiIdentifier:i('i')
PsiJavaToken:COMMA(',')
PsiErrorElement:Expression, pattern, 'default' or 'null' expected
<empty list>
PsiWhiteSpace(' ')
PsiJavaToken:ARROW('->')
PsiWhiteSpace(' ')
PsiBlockStatement
PsiCodeBlock
PsiJavaToken:LBRACE('{')
PsiWhiteSpace(' ')
PsiJavaToken:RBRACE('}')
@@ -0,0 +1,45 @@
PsiJavaFile:SwitchRulesWithPatternIncomplete3.java
PsiSwitchLabeledRule
PsiKeyword:case('case')
PsiWhiteSpace(' ')
PsiCaseLabelElementList
PsiGuardedPattern
PsiParenthesizedPattern
PsiJavaToken:LPARENTH('(')
PsiGuardedPattern
PsiTypeTestPattern
PsiPatternVariable:i
PsiModifierList:
<empty list>
PsiTypeElement:Integer
PsiJavaCodeReferenceElement:Integer
PsiIdentifier:Integer('Integer')
PsiReferenceParameterList
<empty list>
PsiWhiteSpace(' ')
PsiIdentifier:i('i')
PsiWhiteSpace(' ')
PsiJavaToken:ANDAND('&&')
PsiErrorElement:Expression expected
<empty list>
PsiWhiteSpace(' ')
PsiJavaToken:RPARENTH(')')
PsiWhiteSpace(' ')
PsiJavaToken:ANDAND('&&')
PsiWhiteSpace(' ')
PsiMethodCallExpression:boolExpr()
PsiReferenceExpression:boolExpr
PsiReferenceParameterList
<empty list>
PsiIdentifier:boolExpr('boolExpr')
PsiExpressionList
PsiJavaToken:LPARENTH('(')
PsiJavaToken:RPARENTH(')')
PsiWhiteSpace(' ')
PsiJavaToken:ARROW('->')
PsiWhiteSpace(' ')
PsiBlockStatement
PsiCodeBlock
PsiJavaToken:LBRACE('{')
PsiWhiteSpace(' ')
PsiJavaToken:RBRACE('}')
@@ -3,6 +3,7 @@ package com.intellij.java.parser.partial;
import com.intellij.java.parser.JavaParsingTestCase;
import com.intellij.lang.java.parser.JavaParser;
import com.intellij.pom.java.LanguageLevel;
public class ExpressionParserTest extends JavaParsingTestCase {
public ExpressionParserTest() {
@@ -34,6 +35,9 @@ public class ExpressionParserTest extends JavaParsingTestCase {
public void testInstanceOfPattern0() { doParserTest("x instanceof Foo v"); }
public void testInstanceOfPattern1() { doParserTest("x instanceof final Foo v"); }
public void testInstanceOfPattern2() { doParserTest("x instanceof @Ann() final Foo v"); }
public void testInstanceOfPattern3() { setLanguageLevel(LanguageLevel.JDK_16); doParserTest("x instanceof (Foo v)"); }
public void testInstanceOfPattern4() { doParserTest("x instanceof Foo v && v > 10"); }
public void testInstanceOfPattern5() { doParserTest("x instanceof (Foo v && v > 10)"); }
public void testNot0() { doParserTest("!!a"); }
public void testNot1() { doParserTest("!"); }
@@ -112,6 +112,7 @@ public class StatementParserTest extends JavaParsingTestCase {
public void testSwitchIncomplete5() { doParserTest("switch(\n foo();"); }
public void testSwitchLabelsNormal() { doParserTest("case 1: break; default: break;"); }
public void testSwitchLabelsWithPattern() { doParserTest("case int[] ia && ia.length > 10 : { }"); }
public void testSwitchLabelsMultiple() { doParserTest("case 1, 2: break;"); }
public void testSwitchLabelsIncomplete0() { doParserTest("case"); }
public void testSwitchLabelsIncomplete1() { doParserTest("case 2"); }
@@ -133,6 +134,21 @@ public class StatementParserTest extends JavaParsingTestCase {
public void testSwitchRules10() { doParserTest("case (b) -> f(b);"); }
public void testSwitchRules11() { doParserTest("case 1, 2 -> { }"); }
public void testSwitchRules12() { doParserTest("case 1, -> { }"); }
public void testSwitchRules13() { doParserTest("case null, default -> { }"); }
public void testSwitchRules14() { doParserTest("case default -> { }"); }
public void testSwitchRulesWithPattern0() { doParserTest("case Integer i -> { }"); }
public void testSwitchRulesWithPattern1() { doParserTest("case int[] ia -> { }"); }
public void testSwitchRulesWithPattern2() { doParserTest("case Integer i && i > 10 -> { }"); }
public void testSwitchRulesWithPattern3() { doParserTest("case (Integer i && i > 10) && boolExpr() -> { }"); }
public void testSwitchRulesWithPattern4() { setLanguageLevel(LanguageLevel.JDK_16); doParserTest("case Integer i -> { }"); }
public void testSwitchRulesWithPattern5() { doParserTest("case null, default -> { }"); }
public void testSwitchRulesWithPattern6() { doParserTest("case null -> { }"); }
public void testSwitchRulesWithPatternIncomplete0() { doParserTest("case Integer i && -> { }"); }
public void testSwitchRulesWithPatternIncomplete1() { doParserTest("case (Integer i -> { }"); }
public void testSwitchRulesWithPatternIncomplete2() { doParserTest("case Integer i, -> { }"); }
public void testSwitchRulesWithPatternIncomplete3() { doParserTest("case (Integer i && ) && boolExpr() -> { }"); }
public void testSyncNormal() { doParserTest("synchronized(o){}"); }
public void testSyncIncomplete0() { doParserTest("synchronized"); }