[java] Update implementation for "Pattern Matching for switch"

See JEP 427
This is a preview feature
This commit is contained in:
Andreas Dangel
2022-07-07 14:07:49 +02:00
parent 2b6774e750
commit eeeccde494
26 changed files with 3618 additions and 12 deletions

View File

@ -26,6 +26,13 @@
<!-- this file contains are parse error explicitly -->
<exclude-pattern>.*/net/sourceforge/pmd/lang/java/ast/InfiniteLoopInLookahead.java</exclude-pattern>
<!-- the following files cannot be parsed with the latest java version (19 preview) anymore
since java 17/18 preview grammar is different.
-->
<exclude-pattern>.*/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java17p/GuardedAndParenthesizedPatterns.java</exclude-pattern>
<exclude-pattern>.*/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java18p/GuardedAndParenthesizedPatterns.java</exclude-pattern>
<exclude-pattern>.*/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java18p/RefiningPatternsInSwitch.java</exclude-pattern>
<rule ref="category/java/bestpractices.xml" />
<rule ref="category/java/codestyle.xml" />
<rule ref="category/java/design.xml" />

View File

@ -1,4 +1,9 @@
/**
* Support "JEP 427: Pattern Matching for switch (Third Preview)" for Java 19 Preview
* Note: GuardedPattern is deprecated and only valid for 17-preview and 18-preview
* New AST node: Guard - used within switch case labels for refining a pattern
* Andreas Dangel 07/2022
*====================================================================
* Support "JEP 420: Pattern Matching for switch (Second Preview)" for Java 18 Preview
* There were no grammar changes between 18-preview and 17-preview
* Remove support for Java 16 preview language features
@ -556,8 +561,20 @@ public class JavaParser {
}
private void checkForGuardedPatterns() {
if (!isJEP406Supported()) {
throwParseException("Guarded patterns are only supported with JDK 17 Preview or JDK 18 Preview or JDK 19 Preview.");
if (!((jdkVersion == 17 || jdkVersion == 18) && preview)) {
throwParseException("Guarded patterns are only supported with JDK 17 Preview or JDK 18 Preview.");
}
}
private void checkForParenthesizedInstanceOfPattern() {
if (!((jdkVersion == 17 || jdkVersion == 18) && preview)) {
throwParseException("Parenthesized InstanceOf patterns are only supported with JDK 17 Preview or JDK 18 Preview.");
}
}
private void checkForGuard() {
if (!((jdkVersion == 19) && preview)) {
throwParseException("Guards are only supported with JDK 19 Preview.");
}
}
@ -1761,7 +1778,8 @@ void EqualityExpression() #EqualityExpression(>1):
void Pattern() #void:
{}
{
PrimaryPattern() [ GuardedPatternCondition() #GuardedPattern(2) {checkForGuardedPatterns();} ]
TypePattern() [ GuardedPatternCondition() #GuardedPattern(2) {checkForGuardedPatterns();} ]
| ParenthesizedPattern()
}
void GuardedPatternCondition() #void:
@ -1770,11 +1788,10 @@ void GuardedPatternCondition() #void:
"&&" ConditionalAndExpression()
}
void PrimaryPattern() #void:
void ParenthesizedPattern() #void:
{}
{
TypePattern()
| "(" Pattern() ")" { AstImplUtil.bumpParenDepth((ASTPattern) jjtree.peekNode()); }
"(" Pattern() ")" { AstImplUtil.bumpParenDepth((ASTPattern) jjtree.peekNode()); }
}
void TypePattern():
@ -1791,9 +1808,9 @@ void InstanceOfExpression() #InstanceOfExpression(>1):
RelationalExpression()
[ "instanceof"
(
LOOKAHEAD("final" | "@") {checkforBadInstanceOfPattern();} PrimaryPattern()
LOOKAHEAD("final" | "@") {checkforBadInstanceOfPattern();} Pattern()
|
LOOKAHEAD("(") Pattern() {checkforBadInstanceOfPattern();}
LOOKAHEAD("(") Pattern() {checkForParenthesizedInstanceOfPattern();}
|
Type()
[ {checkforBadInstanceOfPattern();} VariableDeclaratorId() #TypePattern(2) ]
@ -2275,7 +2292,7 @@ void CaseLabelElement(ASTSwitchLabel label) #void:
{
"default" {label.setDefault(); checkForDefaultCaseLabel();}
|
LOOKAHEAD(Pattern()) Pattern() {checkForPatternMatchingInSwitch();}
LOOKAHEAD(Pattern()) Pattern() {checkForPatternMatchingInSwitch();} ( LOOKAHEAD({isKeyword("when")}) Guard() )*
|
ConditionalExpression() #Expression
{
@ -2285,6 +2302,21 @@ void CaseLabelElement(ASTSwitchLabel label) #void:
}
}
void Guard() :
{
Token t;
checkForGuard();
}
{
t = <IDENTIFIER> {
if (!"when".equals(t.image)) {
throw new ParseException("ERROR: expected 'when'");
}
}
Expression()
}
void YieldStatement() :
{ checkForYieldStatement(); }
{

View File

@ -0,0 +1,41 @@
/*
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.java.ast;
import net.sourceforge.pmd.annotation.Experimental;
/**
* A guard for refining a switch case in {@link ASTSwitchLabel}s.
*
* <pre class="grammar">
*
* SwitchLabel := "case" {@linkplain ASTPattern Pattern} "when" {@linkplain ASTGuard Guard}
* Guard ::= {@linkplain ASTExpression Expression}
*
* </pre>
*
* @see <a href="https://openjdk.org/jeps/427">JEP 427: Pattern Matching for switch (Third Preview)</a>
*/
@Experimental
public final class ASTGuard extends AbstractJavaNode {
ASTGuard(int id) {
super(id);
}
ASTGuard(JavaParser p, int id) {
super(p, id);
}
@Override
public Object jjtAccept(JavaParserVisitor visitor, Object data) {
return visitor.visit(this, data);
}
public ASTExpression getGuard() {
return (ASTExpression) getChild(0);
}
}

View File

@ -17,8 +17,11 @@ import net.sourceforge.pmd.annotation.Experimental;
* </pre>
*
* @see <a href="https://openjdk.java.net/jeps/406">JEP 406: Pattern Matching for switch (Preview)</a>
*
* @deprecated This is not used with java 19 preview anymore. Only valid for java 18 preview.
*/
@Experimental
@Deprecated
public final class ASTGuardedPattern extends AbstractJavaNode implements ASTPattern {
private int parenDepth;

View File

@ -17,7 +17,6 @@ import net.sourceforge.pmd.annotation.Experimental;
* <pre class="grammar">
*
* Pattern ::= {@link ASTTypePattern TypePattern}
* | {@link ASTGuardedPattern GuardedPattern}
*
* </pre>
*

View File

@ -944,9 +944,17 @@ public class JavaParserDecoratedVisitor implements JavaParserVisitor {
}
@Experimental
@Deprecated
@Override
public Object visit(ASTGuardedPattern node, Object data) {
visitor.visit(node, data);
return visit((JavaNode) node, data);
}
@Experimental
@Override
public Object visit(ASTGuard node, Object data) {
visitor.visit(node, data);
return visit((JavaNode) node, data);
}
}

View File

@ -664,8 +664,15 @@ public class JavaParserVisitorAdapter implements JavaParserVisitor {
}
@Experimental
@Deprecated
@Override
public Object visit(ASTGuardedPattern node, Object data) {
return visit((JavaNode) node, data);
}
@Experimental
@Override
public Object visit(ASTGuard node, Object data) {
return visit((JavaNode) node, data);
}
}

View File

@ -796,8 +796,15 @@ public class JavaParserVisitorDecorator implements JavaParserControllessVisitor
}
@Experimental
@Deprecated
@Override
public Object visit(ASTGuardedPattern node, Object data) {
return visitor.visit(node, data);
}
@Experimental
@Override
public Object visit(ASTGuard node, Object data) {
return visitor.visit(node, data);
}
}

View File

@ -60,6 +60,7 @@ import net.sourceforge.pmd.lang.java.ast.ASTForStatement;
import net.sourceforge.pmd.lang.java.ast.ASTForUpdate;
import net.sourceforge.pmd.lang.java.ast.ASTFormalParameter;
import net.sourceforge.pmd.lang.java.ast.ASTFormalParameters;
import net.sourceforge.pmd.lang.java.ast.ASTGuard;
import net.sourceforge.pmd.lang.java.ast.ASTGuardedPattern;
import net.sourceforge.pmd.lang.java.ast.ASTIfStatement;
import net.sourceforge.pmd.lang.java.ast.ASTImplementsList;
@ -874,11 +875,19 @@ public abstract class AbstractJavaRule extends AbstractRule implements JavaParse
return visit((JavaNode) node, data);
}
@Experimental
@Deprecated
@Override
public Object visit(ASTGuardedPattern node, Object data) {
return visit((JavaNode) node, data);
}
@Experimental
@Override
public Object visit(ASTGuard node, Object data) {
return visit((JavaNode) node, data);
}
// CPD-ON
}

View File

@ -82,7 +82,7 @@ public class Java17PreviewTreeDumpTest extends BaseTreeDumpTest {
}
});
Assert.assertTrue("Unexpected message: " + thrown.getMessage(),
thrown.getMessage().contains("Guarded patterns are only supported with JDK 17 Preview or JDK 18 Preview or JDK 19 Preview."));
thrown.getMessage().contains("Guarded patterns are only supported with JDK 17 Preview or JDK 18 Preview."));
}
@Test

View File

@ -65,7 +65,7 @@ public class Java18PreviewTreeDumpTest extends BaseTreeDumpTest {
}
});
Assert.assertTrue("Unexpected message: " + thrown.getMessage(),
thrown.getMessage().contains("Guarded patterns are only supported with JDK 17 Preview or JDK 18 Preview or JDK 19 Preview."));
thrown.getMessage().contains("Guarded patterns are only supported with JDK 17 Preview or JDK 18 Preview."));
}
@Test

View File

@ -0,0 +1,102 @@
/*
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.java.ast;
import org.junit.Assert;
import org.junit.Test;
import org.junit.function.ThrowingRunnable;
import net.sourceforge.pmd.lang.ast.ParseException;
import net.sourceforge.pmd.lang.ast.test.BaseParsingHelper;
import net.sourceforge.pmd.lang.ast.test.BaseTreeDumpTest;
import net.sourceforge.pmd.lang.ast.test.RelevantAttributePrinter;
import net.sourceforge.pmd.lang.java.JavaParsingHelper;
public class Java19PreviewTreeDumpTest extends BaseTreeDumpTest {
private final JavaParsingHelper java19p =
JavaParsingHelper.WITH_PROCESSING.withDefaultVersion("19-preview")
.withResourceContext(Java19PreviewTreeDumpTest.class, "jdkversiontests/java19p/");
private final JavaParsingHelper java19 = java19p.withDefaultVersion("19");
public Java19PreviewTreeDumpTest() {
super(new RelevantAttributePrinter(), ".java");
}
@Override
public BaseParsingHelper<?, ?> getParser() {
return java19p;
}
@Test
public void dealingWithNullBeforeJava19Preview() {
ParseException thrown = Assert.assertThrows(ParseException.class, new ThrowingRunnable() {
@Override
public void run() throws Throwable {
java19.parseResource("DealingWithNull.java");
}
});
Assert.assertTrue("Unexpected message: " + thrown.getMessage(),
thrown.getMessage().contains("Null case labels in switch are only supported with JDK 17 Preview or JDK 18 Preview or JDK 19 Preview."));
}
@Test
public void dealingWithNull() {
doTest("DealingWithNull");
}
@Test
public void enhancedTypeCheckingSwitch() {
doTest("EnhancedTypeCheckingSwitch");
}
@Test
public void exhaustiveSwitch() {
doTest("ExhaustiveSwitch");
}
@Test
public void guardedAndParenthesizedPatternsBeforeJava19Preview() {
ParseException thrown = Assert.assertThrows(ParseException.class, new ThrowingRunnable() {
@Override
public void run() throws Throwable {
java19.parseResource("GuardedAndParenthesizedPatterns.java");
}
});
Assert.assertTrue("Unexpected message: " + thrown.getMessage(),
thrown.getMessage().contains("Pattern Matching in Switch is only supported with JDK 17 Preview or JDK 18 Preview or JDK 19 Preview."));
}
@Test
public void guardedAndParenthesizedPatterns() {
doTest("GuardedAndParenthesizedPatterns");
}
@Test
public void patternsInSwitchLabelsBeforeJava19Preview() {
ParseException thrown = Assert.assertThrows(ParseException.class, new ThrowingRunnable() {
@Override
public void run() throws Throwable {
java19.parseResource("PatternsInSwitchLabels.java");
}
});
Assert.assertTrue("Unexpected message: " + thrown.getMessage(),
thrown.getMessage().contains("Pattern Matching in Switch is only supported with JDK 17 Preview or JDK 18 Preview or JDK 19 Preview."));
}
@Test
public void patternsInSwitchLabels() {
doTest("PatternsInSwitchLabels");
}
@Test
public void refiningPatternsInSwitch() {
doTest("RefiningPatternsInSwitch");
}
@Test
public void scopeOfPatternVariableDeclarations() {
doTest("ScopeOfPatternVariableDeclarations");
}
}

View File

@ -0,0 +1,90 @@
/*
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
/**
* @see <a href="https://openjdk.org/jeps/427">JEP 427: Pattern Matching for switch (Third Preview)</a>
*/
public class DealingWithNull {
static void testFooBar(String s) {
switch (s) {
case null -> System.out.println("Oops");
case "Foo", "Bar" -> System.out.println("Great");
default -> System.out.println("Ok");
}
}
static void testStringOrNull(Object o) {
switch (o) {
case null, String s -> System.out.println("String: " + s);
case default -> System.out.print("default case");
}
}
static void test(Object o) {
switch (o) {
case null -> System.out.println("null!");
case String s -> System.out.println("String");
default -> System.out.println("Something else");
}
}
static void test2(Object o) {
switch (o) {
case null -> throw new NullPointerException();
case String s -> System.out.println("String: "+s);
case Integer i -> System.out.println("Integer");
default -> System.out.println("default");
}
}
static void test3(Object o) {
switch(o) {
case null: case String s:
System.out.println("String, including null");
break;
default:
System.out.println("default case");
break;
}
switch(o) {
case null, String s -> System.out.println("String, including null");
default -> System.out.println("default case");
}
switch(o) {
case null: default:
System.out.println("The rest (including null)");
}
switch(o) {
case null, default ->
System.out.println("The rest (including null)");
}
}
public static void main(String[] args) {
test("test");
test2(2);
try {
test2(null);
} catch (NullPointerException e) {
System.out.println(e);
}
test3(3);
test3("test");
test3(null);
testFooBar(null);
testFooBar("Foo");
testFooBar("Bar");
testFooBar("baz");
testStringOrNull(null);
testStringOrNull("some string");
}
}

View File

@ -0,0 +1,29 @@
/*
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
/**
* @see <a href="https://openjdk.org/jeps/427">JEP 427: Pattern Matching for switch (Third Preview)</a>
*/
public class EnhancedTypeCheckingSwitch {
static void typeTester(Object o) {
switch (o) {
case null -> System.out.println("null");
case String s -> System.out.println("String");
case Color c -> System.out.println("Color with " + c.values().length + " values");
case Point p -> System.out.println("Record class: " + p.toString());
case int[] ia -> System.out.println("Array of ints of length" + ia.length);
default -> System.out.println("Something else");
}
}
public static void main(String[] args) {
Object o = "test";
typeTester(o);
}
}
record Point(int i, int j) {}
enum Color { RED, GREEN, BLUE; }

View File

@ -0,0 +1,199 @@
+- CompilationUnit[@PackageName = "", @declarationsAreInDefaultPackage = true]
+- TypeDeclaration[]
| +- ClassOrInterfaceDeclaration[@Abstract = false, @BinaryName = "EnhancedTypeCheckingSwitch", @Default = false, @Final = false, @Image = "EnhancedTypeCheckingSwitch", @Interface = false, @Local = false, @Modifiers = 1, @Native = false, @Nested = false, @NonSealed = false, @PackagePrivate = false, @Private = false, @Protected = false, @Public = true, @Sealed = false, @SimpleName = "EnhancedTypeCheckingSwitch", @Static = false, @Strictfp = false, @Synchronized = false, @Transient = false, @TypeKind = TypeKind.CLASS, @Volatile = false]
| +- ClassOrInterfaceBody[@AnonymousInnerClass = false, @EnumChild = false]
| +- ClassOrInterfaceBodyDeclaration[@AnonymousInnerClass = false, @EnumChild = false, @Kind = DeclarationKind.METHOD]
| | +- MethodDeclaration[@Abstract = false, @Arity = 1, @Default = false, @Final = false, @InterfaceMember = false, @Kind = MethodLikeKind.METHOD, @MethodName = "typeTester", @Modifiers = 16, @Name = "typeTester", @Native = false, @PackagePrivate = true, @Private = false, @Protected = false, @Public = false, @Static = true, @Strictfp = false, @Synchronized = false, @SyntacticallyAbstract = false, @SyntacticallyPublic = false, @Transient = false, @Void = true, @Volatile = false]
| | +- ResultType[@Void = true, @returnsArray = false]
| | +- MethodDeclarator[@Image = "typeTester", @ParameterCount = 1]
| | | +- FormalParameters[@ParameterCount = 1, @Size = 1]
| | | +- FormalParameter[@Abstract = false, @Array = false, @ArrayDepth = 0, @Default = false, @ExplicitReceiverParameter = false, @Final = false, @Modifiers = 0, @Native = false, @PackagePrivate = true, @Private = false, @Protected = false, @Public = false, @Static = false, @Strictfp = false, @Synchronized = false, @Transient = false, @TypeInferred = false, @Varargs = false, @Volatile = false]
| | | +- Type[@Array = false, @ArrayDepth = 0, @ArrayType = false, @TypeImage = "Object"]
| | | | +- ReferenceType[@Array = false, @ArrayDepth = 0]
| | | | +- ClassOrInterfaceType[@AnonymousClass = false, @Array = false, @ArrayDepth = 0, @Image = "Object", @ReferenceToClassSameCompilationUnit = false]
| | | +- VariableDeclaratorId[@Array = false, @ArrayDepth = 0, @ArrayType = false, @ExceptionBlockParameter = false, @ExplicitReceiverParameter = false, @Field = false, @Final = false, @ForeachVariable = false, @FormalParameter = true, @Image = "o", @LambdaParameter = false, @LocalVariable = false, @Name = "o", @PatternBinding = false, @ResourceDeclaration = false, @TypeInferred = false, @VariableName = "o"]
| | +- Block[@containsComment = false]
| | +- BlockStatement[@Allocation = false]
| | +- Statement[]
| | +- SwitchStatement[@DefaultCase = true, @ExhaustiveEnumSwitch = false, @FallthroughSwitch = false]
| | +- Expression[@StandAlonePrimitive = false]
| | | +- PrimaryExpression[]
| | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false]
| | | +- Name[@Image = "o"]
| | +- SwitchLabeledExpression[]
| | | +- SwitchLabel[@Default = false]
| | | | +- Expression[@StandAlonePrimitive = false]
| | | | +- PrimaryExpression[]
| | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false]
| | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = null, @FloatLiteral = false, @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = false, @TextBlock = false, @TextBlockContent = null, @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0]
| | | | +- NullLiteral[]
| | | +- Expression[@StandAlonePrimitive = false]
| | | +- PrimaryExpression[]
| | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false]
| | | | +- Name[@Image = "System.out.println"]
| | | +- PrimarySuffix[@ArgumentCount = 1, @Arguments = true, @ArrayDereference = false]
| | | +- Arguments[@ArgumentCount = 1, @Size = 1]
| | | +- ArgumentList[@Size = 1]
| | | +- Expression[@StandAlonePrimitive = false]
| | | +- PrimaryExpression[]
| | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false]
| | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"null\"", @FloatLiteral = false, @Image = "\"null\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"null\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0]
| | +- SwitchLabeledExpression[]
| | | +- SwitchLabel[@Default = false]
| | | | +- TypePattern[@ParenthesisDepth = 0]
| | | | +- Type[@Array = false, @ArrayDepth = 0, @ArrayType = false, @TypeImage = "String"]
| | | | | +- ReferenceType[@Array = false, @ArrayDepth = 0]
| | | | | +- ClassOrInterfaceType[@AnonymousClass = false, @Array = false, @ArrayDepth = 0, @Image = "String", @ReferenceToClassSameCompilationUnit = false]
| | | | +- VariableDeclaratorId[@Array = false, @ArrayDepth = 0, @ArrayType = false, @ExceptionBlockParameter = false, @ExplicitReceiverParameter = false, @Field = false, @Final = false, @ForeachVariable = false, @FormalParameter = false, @Image = "s", @LambdaParameter = false, @LocalVariable = false, @Name = "s", @PatternBinding = true, @ResourceDeclaration = false, @TypeInferred = false, @VariableName = "s"]
| | | +- Expression[@StandAlonePrimitive = false]
| | | +- PrimaryExpression[]
| | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false]
| | | | +- Name[@Image = "System.out.println"]
| | | +- PrimarySuffix[@ArgumentCount = 1, @Arguments = true, @ArrayDereference = false]
| | | +- Arguments[@ArgumentCount = 1, @Size = 1]
| | | +- ArgumentList[@Size = 1]
| | | +- Expression[@StandAlonePrimitive = false]
| | | +- PrimaryExpression[]
| | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false]
| | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"String\"", @FloatLiteral = false, @Image = "\"String\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"String\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0]
| | +- SwitchLabeledExpression[]
| | | +- SwitchLabel[@Default = false]
| | | | +- TypePattern[@ParenthesisDepth = 0]
| | | | +- Type[@Array = false, @ArrayDepth = 0, @ArrayType = false, @TypeImage = "Color"]
| | | | | +- ReferenceType[@Array = false, @ArrayDepth = 0]
| | | | | +- ClassOrInterfaceType[@AnonymousClass = false, @Array = false, @ArrayDepth = 0, @Image = "Color", @ReferenceToClassSameCompilationUnit = true]
| | | | +- VariableDeclaratorId[@Array = false, @ArrayDepth = 0, @ArrayType = false, @ExceptionBlockParameter = false, @ExplicitReceiverParameter = false, @Field = false, @Final = false, @ForeachVariable = false, @FormalParameter = false, @Image = "c", @LambdaParameter = false, @LocalVariable = false, @Name = "c", @PatternBinding = true, @ResourceDeclaration = false, @TypeInferred = false, @VariableName = "c"]
| | | +- Expression[@StandAlonePrimitive = false]
| | | +- PrimaryExpression[]
| | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false]
| | | | +- Name[@Image = "System.out.println"]
| | | +- PrimarySuffix[@ArgumentCount = 1, @Arguments = true, @ArrayDereference = false]
| | | +- Arguments[@ArgumentCount = 1, @Size = 1]
| | | +- ArgumentList[@Size = 1]
| | | +- Expression[@StandAlonePrimitive = false]
| | | +- AdditiveExpression[@Image = "+", @Operator = "+"]
| | | +- PrimaryExpression[]
| | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false]
| | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"Color with \"", @FloatLiteral = false, @Image = "\"Color with \"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"Color with \"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0]
| | | +- PrimaryExpression[]
| | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false]
| | | | | +- Name[@Image = "c.values"]
| | | | +- PrimarySuffix[@ArgumentCount = 0, @Arguments = true, @ArrayDereference = false]
| | | | | +- Arguments[@ArgumentCount = 0, @Size = 0]
| | | | +- PrimarySuffix[@ArgumentCount = -1, @Arguments = false, @ArrayDereference = false, @Image = "length"]
| | | +- PrimaryExpression[]
| | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false]
| | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\" values\"", @FloatLiteral = false, @Image = "\" values\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\" values\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0]
| | +- SwitchLabeledExpression[]
| | | +- SwitchLabel[@Default = false]
| | | | +- TypePattern[@ParenthesisDepth = 0]
| | | | +- Type[@Array = false, @ArrayDepth = 0, @ArrayType = false, @TypeImage = "Point"]
| | | | | +- ReferenceType[@Array = false, @ArrayDepth = 0]
| | | | | +- ClassOrInterfaceType[@AnonymousClass = false, @Array = false, @ArrayDepth = 0, @Image = "Point", @ReferenceToClassSameCompilationUnit = false]
| | | | +- VariableDeclaratorId[@Array = false, @ArrayDepth = 0, @ArrayType = false, @ExceptionBlockParameter = false, @ExplicitReceiverParameter = false, @Field = false, @Final = false, @ForeachVariable = false, @FormalParameter = false, @Image = "p", @LambdaParameter = false, @LocalVariable = false, @Name = "p", @PatternBinding = true, @ResourceDeclaration = false, @TypeInferred = false, @VariableName = "p"]
| | | +- Expression[@StandAlonePrimitive = false]
| | | +- PrimaryExpression[]
| | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false]
| | | | +- Name[@Image = "System.out.println"]
| | | +- PrimarySuffix[@ArgumentCount = 1, @Arguments = true, @ArrayDereference = false]
| | | +- Arguments[@ArgumentCount = 1, @Size = 1]
| | | +- ArgumentList[@Size = 1]
| | | +- Expression[@StandAlonePrimitive = false]
| | | +- AdditiveExpression[@Image = "+", @Operator = "+"]
| | | +- PrimaryExpression[]
| | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false]
| | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"Record class: \"", @FloatLiteral = false, @Image = "\"Record class: \"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"Record class: \"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0]
| | | +- PrimaryExpression[]
| | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false]
| | | | +- Name[@Image = "p.toString"]
| | | +- PrimarySuffix[@ArgumentCount = 0, @Arguments = true, @ArrayDereference = false]
| | | +- Arguments[@ArgumentCount = 0, @Size = 0]
| | +- SwitchLabeledExpression[]
| | | +- SwitchLabel[@Default = false]
| | | | +- TypePattern[@ParenthesisDepth = 0]
| | | | +- Type[@Array = true, @ArrayDepth = 1, @ArrayType = true, @TypeImage = "int"]
| | | | | +- ReferenceType[@Array = true, @ArrayDepth = 1]
| | | | | +- PrimitiveType[@Array = false, @ArrayDepth = 0, @Boolean = false, @Image = "int"]
| | | | +- VariableDeclaratorId[@Array = false, @ArrayDepth = 0, @ArrayType = true, @ExceptionBlockParameter = false, @ExplicitReceiverParameter = false, @Field = false, @Final = false, @ForeachVariable = false, @FormalParameter = false, @Image = "ia", @LambdaParameter = false, @LocalVariable = false, @Name = "ia", @PatternBinding = true, @ResourceDeclaration = false, @TypeInferred = false, @VariableName = "ia"]
| | | +- Expression[@StandAlonePrimitive = false]
| | | +- PrimaryExpression[]
| | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false]
| | | | +- Name[@Image = "System.out.println"]
| | | +- PrimarySuffix[@ArgumentCount = 1, @Arguments = true, @ArrayDereference = false]
| | | +- Arguments[@ArgumentCount = 1, @Size = 1]
| | | +- ArgumentList[@Size = 1]
| | | +- Expression[@StandAlonePrimitive = false]
| | | +- AdditiveExpression[@Image = "+", @Operator = "+"]
| | | +- PrimaryExpression[]
| | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false]
| | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"Array of ints of length\"", @FloatLiteral = false, @Image = "\"Array of ints of length\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"Array of ints of length\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0]
| | | +- PrimaryExpression[]
| | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false]
| | | +- Name[@Image = "ia.length"]
| | +- SwitchLabeledExpression[]
| | +- SwitchLabel[@Default = true]
| | +- Expression[@StandAlonePrimitive = false]
| | +- PrimaryExpression[]
| | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false]
| | | +- Name[@Image = "System.out.println"]
| | +- PrimarySuffix[@ArgumentCount = 1, @Arguments = true, @ArrayDereference = false]
| | +- Arguments[@ArgumentCount = 1, @Size = 1]
| | +- ArgumentList[@Size = 1]
| | +- Expression[@StandAlonePrimitive = false]
| | +- PrimaryExpression[]
| | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false]
| | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"Something else\"", @FloatLiteral = false, @Image = "\"Something else\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"Something else\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0]
| +- ClassOrInterfaceBodyDeclaration[@AnonymousInnerClass = false, @EnumChild = false, @Kind = DeclarationKind.METHOD]
| +- MethodDeclaration[@Abstract = false, @Arity = 1, @Default = false, @Final = false, @InterfaceMember = false, @Kind = MethodLikeKind.METHOD, @MethodName = "main", @Modifiers = 17, @Name = "main", @Native = false, @PackagePrivate = false, @Private = false, @Protected = false, @Public = true, @Static = true, @Strictfp = false, @Synchronized = false, @SyntacticallyAbstract = false, @SyntacticallyPublic = true, @Transient = false, @Void = true, @Volatile = false]
| +- ResultType[@Void = true, @returnsArray = false]
| +- MethodDeclarator[@Image = "main", @ParameterCount = 1]
| | +- FormalParameters[@ParameterCount = 1, @Size = 1]
| | +- FormalParameter[@Abstract = false, @Array = true, @ArrayDepth = 1, @Default = false, @ExplicitReceiverParameter = false, @Final = false, @Modifiers = 0, @Native = false, @PackagePrivate = true, @Private = false, @Protected = false, @Public = false, @Static = false, @Strictfp = false, @Synchronized = false, @Transient = false, @TypeInferred = false, @Varargs = false, @Volatile = false]
| | +- Type[@Array = true, @ArrayDepth = 1, @ArrayType = true, @TypeImage = "String"]
| | | +- ReferenceType[@Array = true, @ArrayDepth = 1]
| | | +- ClassOrInterfaceType[@AnonymousClass = false, @Array = true, @ArrayDepth = 1, @Image = "String", @ReferenceToClassSameCompilationUnit = false]
| | +- VariableDeclaratorId[@Array = false, @ArrayDepth = 0, @ArrayType = true, @ExceptionBlockParameter = false, @ExplicitReceiverParameter = false, @Field = false, @Final = false, @ForeachVariable = false, @FormalParameter = true, @Image = "args", @LambdaParameter = false, @LocalVariable = false, @Name = "args", @PatternBinding = false, @ResourceDeclaration = false, @TypeInferred = false, @VariableName = "args"]
| +- Block[@containsComment = false]
| +- BlockStatement[@Allocation = false]
| | +- LocalVariableDeclaration[@Abstract = false, @Array = false, @ArrayDepth = 0, @Default = false, @Final = false, @Modifiers = 0, @Native = false, @PackagePrivate = true, @Private = false, @Protected = false, @Public = false, @Static = false, @Strictfp = false, @Synchronized = false, @Transient = false, @TypeInferred = false, @VariableName = "o", @Volatile = false]
| | +- Type[@Array = false, @ArrayDepth = 0, @ArrayType = false, @TypeImage = "Object"]
| | | +- ReferenceType[@Array = false, @ArrayDepth = 0]
| | | +- ClassOrInterfaceType[@AnonymousClass = false, @Array = false, @ArrayDepth = 0, @Image = "Object", @ReferenceToClassSameCompilationUnit = false]
| | +- VariableDeclarator[@Initializer = true, @Name = "o"]
| | +- VariableDeclaratorId[@Array = false, @ArrayDepth = 0, @ArrayType = false, @ExceptionBlockParameter = false, @ExplicitReceiverParameter = false, @Field = false, @Final = false, @ForeachVariable = false, @FormalParameter = false, @Image = "o", @LambdaParameter = false, @LocalVariable = true, @Name = "o", @PatternBinding = false, @ResourceDeclaration = false, @TypeInferred = false, @VariableName = "o"]
| | +- VariableInitializer[]
| | +- Expression[@StandAlonePrimitive = false]
| | +- PrimaryExpression[]
| | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false]
| | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"test\"", @FloatLiteral = false, @Image = "\"test\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"test\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0]
| +- BlockStatement[@Allocation = false]
| +- Statement[]
| +- StatementExpression[]
| +- PrimaryExpression[]
| +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false]
| | +- Name[@Image = "typeTester"]
| +- PrimarySuffix[@ArgumentCount = 1, @Arguments = true, @ArrayDereference = false]
| +- Arguments[@ArgumentCount = 1, @Size = 1]
| +- ArgumentList[@Size = 1]
| +- Expression[@StandAlonePrimitive = false]
| +- PrimaryExpression[]
| +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false]
| +- Name[@Image = "o"]
+- TypeDeclaration[]
| +- RecordDeclaration[@Abstract = false, @BinaryName = "Point", @Default = false, @Final = true, @Image = "Point", @Local = false, @Modifiers = 0, @Native = false, @Nested = false, @PackagePrivate = true, @Private = false, @Protected = false, @Public = false, @SimpleName = "Point", @Static = false, @Strictfp = false, @Synchronized = false, @SyntacticallyFinal = false, @Transient = false, @TypeKind = TypeKind.RECORD, @Volatile = false]
| +- RecordComponentList[@Size = 2]
| | +- RecordComponent[@Varargs = false]
| | | +- Type[@Array = false, @ArrayDepth = 0, @ArrayType = false, @TypeImage = "int"]
| | | | +- PrimitiveType[@Array = false, @ArrayDepth = 0, @Boolean = false, @Image = "int"]
| | | +- VariableDeclaratorId[@Array = false, @ArrayDepth = 0, @ArrayType = false, @ExceptionBlockParameter = false, @ExplicitReceiverParameter = false, @Field = false, @Final = true, @ForeachVariable = false, @FormalParameter = false, @Image = "i", @LambdaParameter = false, @LocalVariable = false, @Name = "i", @PatternBinding = false, @ResourceDeclaration = false, @TypeInferred = false, @VariableName = "i"]
| | +- RecordComponent[@Varargs = false]
| | +- Type[@Array = false, @ArrayDepth = 0, @ArrayType = false, @TypeImage = "int"]
| | | +- PrimitiveType[@Array = false, @ArrayDepth = 0, @Boolean = false, @Image = "int"]
| | +- VariableDeclaratorId[@Array = false, @ArrayDepth = 0, @ArrayType = false, @ExceptionBlockParameter = false, @ExplicitReceiverParameter = false, @Field = false, @Final = true, @ForeachVariable = false, @FormalParameter = false, @Image = "j", @LambdaParameter = false, @LocalVariable = false, @Name = "j", @PatternBinding = false, @ResourceDeclaration = false, @TypeInferred = false, @VariableName = "j"]
| +- RecordBody[]
+- TypeDeclaration[]
+- EnumDeclaration[@Abstract = false, @BinaryName = "Color", @Default = false, @Final = false, @Image = "Color", @Local = false, @Modifiers = 0, @Native = false, @Nested = false, @PackagePrivate = true, @Private = false, @Protected = false, @Public = false, @SimpleName = "Color", @Static = false, @Strictfp = false, @Synchronized = false, @Transient = false, @TypeKind = TypeKind.ENUM, @Volatile = false]
+- EnumBody[]
+- EnumConstant[@AnonymousClass = false, @Image = "RED"]
+- EnumConstant[@AnonymousClass = false, @Image = "GREEN"]
+- EnumConstant[@AnonymousClass = false, @Image = "BLUE"]

View File

@ -0,0 +1,95 @@
/*
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
/**
* @see <a href="https://openjdk.org/jeps/427">JEP 427: Pattern Matching for switch (Third Preview)</a>
*/
public class ExhaustiveSwitch {
static int coverage(Object o) {
return switch (o) {
case String s -> s.length();
case Integer i -> i;
default -> 0;
};
}
static int coverageDefaultCase(Object o) {
return switch (o) {
case String s -> s.length();
case Integer i -> i;
case default -> 0;
};
}
static void coverageStatement(Object o) {
switch (o) {
case String s:
System.out.println(s);
break;
case Integer i:
System.out.println("Integer");
break;
default: // Now exhaustive!
break;
}
}
sealed interface S permits A, B, C {}
final static class A implements S {}
final static class B implements S {}
record C(int i) implements S {} // Implicitly final
static int testSealedExhaustive(S s) {
return switch (s) {
case A a -> 1;
case B b -> 2;
case C c -> 3;
};
}
static void switchStatementExhaustive(S s) {
switch (s) {
case A a :
System.out.println("A");
break;
case C c :
System.out.println("C");
break;
default:
System.out.println("default case, should be B");
break;
};
}
sealed interface I<T> permits E, F {}
final static class E<X> implements I<String> {}
final static class F<Y> implements I<Y> {}
static int testGenericSealedExhaustive(I<Integer> i) {
return switch (i) {
// Exhaustive as no E case possible!
case F<Integer> bi -> 42;
};
}
public static void main(String[] args) {
System.out.println(coverage("a string"));
System.out.println(coverage(42));
System.out.println(coverage(new Object()));
coverageStatement("a string");
coverageStatement(21);
coverageStatement(new Object());
System.out.println("A:" + testSealedExhaustive(new A()));
System.out.println("B:" + testSealedExhaustive(new B()));
System.out.println("C:" + testSealedExhaustive(new C(1)));
switchStatementExhaustive(new A());
switchStatementExhaustive(new B());
switchStatementExhaustive(new C(2));
System.out.println("F:" + testGenericSealedExhaustive(new F<Integer>()));
}
}

View File

@ -0,0 +1,66 @@
/*
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
/**
* @see <a href="https://openjdk.org/jeps/427">JEP 427: Pattern Matching for switch (Third Preview)</a>
*/
public class GuardedAndParenthesizedPatterns {
static void test(Object o) {
switch (o) {
case String s when s.length() == 1 -> System.out.println("single char string");
case String s -> System.out.println("string");
case Integer i when i.intValue() == 1 -> System.out.println("integer 1");
case (Long l) when l.longValue() == 1L -> System.out.println("long 1 with parens");
case (((Double d))) -> System.out.println("double with parens");
default -> System.out.println("default case");
}
}
static void testWithNull(Object o) {
switch (o) {
case String s when (s.length() == 1) -> System.out.println("single char string");
case String s -> System.out.println("string");
case (Integer i) when i.intValue() == 1 -> System.out.println("integer 1");
case ((Long l)) when ((l.longValue() == 1L)) -> System.out.println("long 1 with parens");
case (((Double d))) -> System.out.println("double with parens");
case null -> System.out.println("null!");
default -> System.out.println("default case");
}
}
static void instanceOfPattern(Object o) {
if (o instanceof String s && s.length() > 2) {
System.out.println("A string containing at least two characters");
}
if (o != null && (o instanceof String s && s.length() > 3)) {
System.out.println("A string containing at least three characters");
}
// note: with this 3rd preview, the following is not allowed anymore:
// if (o instanceof (String s && s.length() > 4)) {
// > An alternative to guarded pattern labels is to support guarded patterns directly as a special pattern form,
// > e.g. p && e. Having experimented with this in previous previews, the resulting ambiguity with boolean
// > expressions have lead us to prefer when clauses in pattern switches.
if ((o instanceof String s) && (s.length() > 4)) {
System.out.println("A string containing at least four characters");
}
}
public static void main(String[] args) {
test("a");
test("fooo");
test(1);
test(1L);
instanceOfPattern("abcde");
try {
test(null); // throws NPE
} catch (NullPointerException e) {
e.printStackTrace();
}
testWithNull(null);
}
}

View File

@ -0,0 +1,22 @@
/*
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
/**
* @see <a href="https://openjdk.org/jeps/427">JEP 427: Pattern Matching for switch (Third Preview)</a>
*/
public class PatternsInSwitchLabels {
public static void main(String[] args) {
Object o = 123L;
String formatted = switch (o) {
case Integer i -> String.format("int %d", i);
case Long l -> String.format("long %d", l);
case Double d -> String.format("double %f", d);
case String s -> String.format("String %s", s);
default -> o.toString();
};
System.out.println(formatted);
}
}

View File

@ -0,0 +1,150 @@
+- CompilationUnit[@PackageName = "", @declarationsAreInDefaultPackage = true]
+- TypeDeclaration[]
+- ClassOrInterfaceDeclaration[@Abstract = false, @BinaryName = "PatternsInSwitchLabels", @Default = false, @Final = false, @Image = "PatternsInSwitchLabels", @Interface = false, @Local = false, @Modifiers = 1, @Native = false, @Nested = false, @NonSealed = false, @PackagePrivate = false, @Private = false, @Protected = false, @Public = true, @Sealed = false, @SimpleName = "PatternsInSwitchLabels", @Static = false, @Strictfp = false, @Synchronized = false, @Transient = false, @TypeKind = TypeKind.CLASS, @Volatile = false]
+- ClassOrInterfaceBody[@AnonymousInnerClass = false, @EnumChild = false]
+- ClassOrInterfaceBodyDeclaration[@AnonymousInnerClass = false, @EnumChild = false, @Kind = DeclarationKind.METHOD]
+- MethodDeclaration[@Abstract = false, @Arity = 1, @Default = false, @Final = false, @InterfaceMember = false, @Kind = MethodLikeKind.METHOD, @MethodName = "main", @Modifiers = 17, @Name = "main", @Native = false, @PackagePrivate = false, @Private = false, @Protected = false, @Public = true, @Static = true, @Strictfp = false, @Synchronized = false, @SyntacticallyAbstract = false, @SyntacticallyPublic = true, @Transient = false, @Void = true, @Volatile = false]
+- ResultType[@Void = true, @returnsArray = false]
+- MethodDeclarator[@Image = "main", @ParameterCount = 1]
| +- FormalParameters[@ParameterCount = 1, @Size = 1]
| +- FormalParameter[@Abstract = false, @Array = true, @ArrayDepth = 1, @Default = false, @ExplicitReceiverParameter = false, @Final = false, @Modifiers = 0, @Native = false, @PackagePrivate = true, @Private = false, @Protected = false, @Public = false, @Static = false, @Strictfp = false, @Synchronized = false, @Transient = false, @TypeInferred = false, @Varargs = false, @Volatile = false]
| +- Type[@Array = true, @ArrayDepth = 1, @ArrayType = true, @TypeImage = "String"]
| | +- ReferenceType[@Array = true, @ArrayDepth = 1]
| | +- ClassOrInterfaceType[@AnonymousClass = false, @Array = true, @ArrayDepth = 1, @Image = "String", @ReferenceToClassSameCompilationUnit = false]
| +- VariableDeclaratorId[@Array = false, @ArrayDepth = 0, @ArrayType = true, @ExceptionBlockParameter = false, @ExplicitReceiverParameter = false, @Field = false, @Final = false, @ForeachVariable = false, @FormalParameter = true, @Image = "args", @LambdaParameter = false, @LocalVariable = false, @Name = "args", @PatternBinding = false, @ResourceDeclaration = false, @TypeInferred = false, @VariableName = "args"]
+- Block[@containsComment = false]
+- BlockStatement[@Allocation = false]
| +- LocalVariableDeclaration[@Abstract = false, @Array = false, @ArrayDepth = 0, @Default = false, @Final = false, @Modifiers = 0, @Native = false, @PackagePrivate = true, @Private = false, @Protected = false, @Public = false, @Static = false, @Strictfp = false, @Synchronized = false, @Transient = false, @TypeInferred = false, @VariableName = "o", @Volatile = false]
| +- Type[@Array = false, @ArrayDepth = 0, @ArrayType = false, @TypeImage = "Object"]
| | +- ReferenceType[@Array = false, @ArrayDepth = 0]
| | +- ClassOrInterfaceType[@AnonymousClass = false, @Array = false, @ArrayDepth = 0, @Image = "Object", @ReferenceToClassSameCompilationUnit = false]
| +- VariableDeclarator[@Initializer = true, @Name = "o"]
| +- VariableDeclaratorId[@Array = false, @ArrayDepth = 0, @ArrayType = false, @ExceptionBlockParameter = false, @ExplicitReceiverParameter = false, @Field = false, @Final = false, @ForeachVariable = false, @FormalParameter = false, @Image = "o", @LambdaParameter = false, @LocalVariable = true, @Name = "o", @PatternBinding = false, @ResourceDeclaration = false, @TypeInferred = false, @VariableName = "o"]
| +- VariableInitializer[]
| +- Expression[@StandAlonePrimitive = true]
| +- PrimaryExpression[]
| +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false]
| +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "123L", @FloatLiteral = false, @Image = "123L", @IntLiteral = false, @LongLiteral = true, @SingleCharacterStringLiteral = false, @StringLiteral = false, @TextBlock = false, @TextBlockContent = "123L", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 123, @ValueAsLong = 123]
+- BlockStatement[@Allocation = false]
| +- LocalVariableDeclaration[@Abstract = false, @Array = false, @ArrayDepth = 0, @Default = false, @Final = false, @Modifiers = 0, @Native = false, @PackagePrivate = true, @Private = false, @Protected = false, @Public = false, @Static = false, @Strictfp = false, @Synchronized = false, @Transient = false, @TypeInferred = false, @VariableName = "formatted", @Volatile = false]
| +- Type[@Array = false, @ArrayDepth = 0, @ArrayType = false, @TypeImage = "String"]
| | +- ReferenceType[@Array = false, @ArrayDepth = 0]
| | +- ClassOrInterfaceType[@AnonymousClass = false, @Array = false, @ArrayDepth = 0, @Image = "String", @ReferenceToClassSameCompilationUnit = false]
| +- VariableDeclarator[@Initializer = true, @Name = "formatted"]
| +- VariableDeclaratorId[@Array = false, @ArrayDepth = 0, @ArrayType = false, @ExceptionBlockParameter = false, @ExplicitReceiverParameter = false, @Field = false, @Final = false, @ForeachVariable = false, @FormalParameter = false, @Image = "formatted", @LambdaParameter = false, @LocalVariable = true, @Name = "formatted", @PatternBinding = false, @ResourceDeclaration = false, @TypeInferred = false, @VariableName = "formatted"]
| +- VariableInitializer[]
| +- Expression[@StandAlonePrimitive = false]
| +- SwitchExpression[]
| +- Expression[@StandAlonePrimitive = false]
| | +- PrimaryExpression[]
| | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false]
| | +- Name[@Image = "o"]
| +- SwitchLabeledExpression[]
| | +- SwitchLabel[@Default = false]
| | | +- TypePattern[@ParenthesisDepth = 0]
| | | +- Type[@Array = false, @ArrayDepth = 0, @ArrayType = false, @TypeImage = "Integer"]
| | | | +- ReferenceType[@Array = false, @ArrayDepth = 0]
| | | | +- ClassOrInterfaceType[@AnonymousClass = false, @Array = false, @ArrayDepth = 0, @Image = "Integer", @ReferenceToClassSameCompilationUnit = false]
| | | +- VariableDeclaratorId[@Array = false, @ArrayDepth = 0, @ArrayType = false, @ExceptionBlockParameter = false, @ExplicitReceiverParameter = false, @Field = false, @Final = false, @ForeachVariable = false, @FormalParameter = false, @Image = "i", @LambdaParameter = false, @LocalVariable = false, @Name = "i", @PatternBinding = true, @ResourceDeclaration = false, @TypeInferred = false, @VariableName = "i"]
| | +- Expression[@StandAlonePrimitive = false]
| | +- PrimaryExpression[]
| | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false]
| | | +- Name[@Image = "String.format"]
| | +- PrimarySuffix[@ArgumentCount = 2, @Arguments = true, @ArrayDereference = false]
| | +- Arguments[@ArgumentCount = 2, @Size = 2]
| | +- ArgumentList[@Size = 2]
| | +- Expression[@StandAlonePrimitive = false]
| | | +- PrimaryExpression[]
| | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false]
| | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"int %d\"", @FloatLiteral = false, @Image = "\"int %d\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"int %d\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0]
| | +- Expression[@StandAlonePrimitive = false]
| | +- PrimaryExpression[]
| | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false]
| | +- Name[@Image = "i"]
| +- SwitchLabeledExpression[]
| | +- SwitchLabel[@Default = false]
| | | +- TypePattern[@ParenthesisDepth = 0]
| | | +- Type[@Array = false, @ArrayDepth = 0, @ArrayType = false, @TypeImage = "Long"]
| | | | +- ReferenceType[@Array = false, @ArrayDepth = 0]
| | | | +- ClassOrInterfaceType[@AnonymousClass = false, @Array = false, @ArrayDepth = 0, @Image = "Long", @ReferenceToClassSameCompilationUnit = false]
| | | +- VariableDeclaratorId[@Array = false, @ArrayDepth = 0, @ArrayType = false, @ExceptionBlockParameter = false, @ExplicitReceiverParameter = false, @Field = false, @Final = false, @ForeachVariable = false, @FormalParameter = false, @Image = "l", @LambdaParameter = false, @LocalVariable = false, @Name = "l", @PatternBinding = true, @ResourceDeclaration = false, @TypeInferred = false, @VariableName = "l"]
| | +- Expression[@StandAlonePrimitive = false]
| | +- PrimaryExpression[]
| | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false]
| | | +- Name[@Image = "String.format"]
| | +- PrimarySuffix[@ArgumentCount = 2, @Arguments = true, @ArrayDereference = false]
| | +- Arguments[@ArgumentCount = 2, @Size = 2]
| | +- ArgumentList[@Size = 2]
| | +- Expression[@StandAlonePrimitive = false]
| | | +- PrimaryExpression[]
| | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false]
| | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"long %d\"", @FloatLiteral = false, @Image = "\"long %d\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"long %d\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0]
| | +- Expression[@StandAlonePrimitive = false]
| | +- PrimaryExpression[]
| | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false]
| | +- Name[@Image = "l"]
| +- SwitchLabeledExpression[]
| | +- SwitchLabel[@Default = false]
| | | +- TypePattern[@ParenthesisDepth = 0]
| | | +- Type[@Array = false, @ArrayDepth = 0, @ArrayType = false, @TypeImage = "Double"]
| | | | +- ReferenceType[@Array = false, @ArrayDepth = 0]
| | | | +- ClassOrInterfaceType[@AnonymousClass = false, @Array = false, @ArrayDepth = 0, @Image = "Double", @ReferenceToClassSameCompilationUnit = false]
| | | +- VariableDeclaratorId[@Array = false, @ArrayDepth = 0, @ArrayType = false, @ExceptionBlockParameter = false, @ExplicitReceiverParameter = false, @Field = false, @Final = false, @ForeachVariable = false, @FormalParameter = false, @Image = "d", @LambdaParameter = false, @LocalVariable = false, @Name = "d", @PatternBinding = true, @ResourceDeclaration = false, @TypeInferred = false, @VariableName = "d"]
| | +- Expression[@StandAlonePrimitive = false]
| | +- PrimaryExpression[]
| | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false]
| | | +- Name[@Image = "String.format"]
| | +- PrimarySuffix[@ArgumentCount = 2, @Arguments = true, @ArrayDereference = false]
| | +- Arguments[@ArgumentCount = 2, @Size = 2]
| | +- ArgumentList[@Size = 2]
| | +- Expression[@StandAlonePrimitive = false]
| | | +- PrimaryExpression[]
| | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false]
| | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"double %f\"", @FloatLiteral = false, @Image = "\"double %f\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"double %f\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0]
| | +- Expression[@StandAlonePrimitive = false]
| | +- PrimaryExpression[]
| | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false]
| | +- Name[@Image = "d"]
| +- SwitchLabeledExpression[]
| | +- SwitchLabel[@Default = false]
| | | +- TypePattern[@ParenthesisDepth = 0]
| | | +- Type[@Array = false, @ArrayDepth = 0, @ArrayType = false, @TypeImage = "String"]
| | | | +- ReferenceType[@Array = false, @ArrayDepth = 0]
| | | | +- ClassOrInterfaceType[@AnonymousClass = false, @Array = false, @ArrayDepth = 0, @Image = "String", @ReferenceToClassSameCompilationUnit = false]
| | | +- VariableDeclaratorId[@Array = false, @ArrayDepth = 0, @ArrayType = false, @ExceptionBlockParameter = false, @ExplicitReceiverParameter = false, @Field = false, @Final = false, @ForeachVariable = false, @FormalParameter = false, @Image = "s", @LambdaParameter = false, @LocalVariable = false, @Name = "s", @PatternBinding = true, @ResourceDeclaration = false, @TypeInferred = false, @VariableName = "s"]
| | +- Expression[@StandAlonePrimitive = false]
| | +- PrimaryExpression[]
| | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false]
| | | +- Name[@Image = "String.format"]
| | +- PrimarySuffix[@ArgumentCount = 2, @Arguments = true, @ArrayDereference = false]
| | +- Arguments[@ArgumentCount = 2, @Size = 2]
| | +- ArgumentList[@Size = 2]
| | +- Expression[@StandAlonePrimitive = false]
| | | +- PrimaryExpression[]
| | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false]
| | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"String %s\"", @FloatLiteral = false, @Image = "\"String %s\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"String %s\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0]
| | +- Expression[@StandAlonePrimitive = false]
| | +- PrimaryExpression[]
| | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false]
| | +- Name[@Image = "s"]
| +- SwitchLabeledExpression[]
| +- SwitchLabel[@Default = true]
| +- Expression[@StandAlonePrimitive = false]
| +- PrimaryExpression[]
| +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false]
| | +- Name[@Image = "o.toString"]
| +- PrimarySuffix[@ArgumentCount = 0, @Arguments = true, @ArrayDereference = false]
| +- Arguments[@ArgumentCount = 0, @Size = 0]
+- BlockStatement[@Allocation = false]
+- Statement[]
+- StatementExpression[]
+- PrimaryExpression[]
+- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false]
| +- Name[@Image = "System.out.println"]
+- PrimarySuffix[@ArgumentCount = 1, @Arguments = true, @ArrayDereference = false]
+- Arguments[@ArgumentCount = 1, @Size = 1]
+- ArgumentList[@Size = 1]
+- Expression[@StandAlonePrimitive = false]
+- PrimaryExpression[]
+- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false]
+- Name[@Image = "formatted"]

View File

@ -0,0 +1,71 @@
/*
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
/**
* @see <a href="https://openjdk.org/jeps/427">JEP 427: Pattern Matching for switch (Third Preview)</a>
*/
public class RefiningPatternsInSwitch {
static class Shape {}
static class Rectangle extends Shape {}
static class Triangle extends Shape {
private int area;
Triangle(int area) {
this.area = area;
}
int calculateArea() { return area; }
}
static void testTriangle(Shape s) {
switch (s) {
case null:
break;
case Triangle t:
if (t.calculateArea() > 100) {
System.out.println("Large triangle");
break;
}
default:
System.out.println("A shape, possibly a small triangle");
}
}
static void testTriangleRefined(Shape s) {
switch (s) {
case Triangle t when t.calculateArea() > 100 ->
System.out.println("Large triangle");
default ->
System.out.println("A shape, possibly a small triangle");
}
}
static void testTriangleRefined2(Shape s) {
switch (s) {
case Triangle t when t.calculateArea() > 100 ->
System.out.println("Large triangle");
case Triangle t ->
System.out.println("Small triangle");
default ->
System.out.println("Non-triangle");
}
}
public static void main(String[] args) {
Triangle large = new Triangle(200);
Triangle small = new Triangle(10);
Rectangle rect = new Rectangle();
testTriangle(large);
testTriangle(small);
testTriangle(rect);
testTriangleRefined(large);
testTriangleRefined(small);
testTriangleRefined(rect);
testTriangleRefined2(large);
testTriangleRefined2(small);
testTriangleRefined2(rect);
}
}

View File

@ -0,0 +1,48 @@
/*
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
/**
* @see <a href="https://openjdk.org/jeps/427">JEP 427: Pattern Matching for switch (Third Preview)</a>
*/
public class ScopeOfPatternVariableDeclarations {
static void test(Object o) {
switch (o) {
case Character c -> {
if (c.charValue() == 7) {
System.out.println("Ding!");
}
System.out.println("Character");
}
case Integer i ->
throw new IllegalStateException("Invalid Integer argument of value " + i.intValue());
default -> {
break;
}
}
}
static void test2(Object o) {
switch (o) {
case Character c:
if (c.charValue() == 7) {
System.out.print("Ding ");
}
if (c.charValue() == 9) {
System.out.print("Tab ");
}
System.out.println("character");
default:
System.out.println();
}
}
public static void main(String[] args) {
test('A');
test2('\t');
}
}

View File

@ -0,0 +1,241 @@
+- CompilationUnit[@PackageName = "", @declarationsAreInDefaultPackage = true]
+- TypeDeclaration[]
+- ClassOrInterfaceDeclaration[@Abstract = false, @BinaryName = "ScopeOfPatternVariableDeclarations", @Default = false, @Final = false, @Image = "ScopeOfPatternVariableDeclarations", @Interface = false, @Local = false, @Modifiers = 1, @Native = false, @Nested = false, @NonSealed = false, @PackagePrivate = false, @Private = false, @Protected = false, @Public = true, @Sealed = false, @SimpleName = "ScopeOfPatternVariableDeclarations", @Static = false, @Strictfp = false, @Synchronized = false, @Transient = false, @TypeKind = TypeKind.CLASS, @Volatile = false]
+- ClassOrInterfaceBody[@AnonymousInnerClass = false, @EnumChild = false]
+- ClassOrInterfaceBodyDeclaration[@AnonymousInnerClass = false, @EnumChild = false, @Kind = DeclarationKind.METHOD]
| +- MethodDeclaration[@Abstract = false, @Arity = 1, @Default = false, @Final = false, @InterfaceMember = false, @Kind = MethodLikeKind.METHOD, @MethodName = "test", @Modifiers = 16, @Name = "test", @Native = false, @PackagePrivate = true, @Private = false, @Protected = false, @Public = false, @Static = true, @Strictfp = false, @Synchronized = false, @SyntacticallyAbstract = false, @SyntacticallyPublic = false, @Transient = false, @Void = true, @Volatile = false]
| +- ResultType[@Void = true, @returnsArray = false]
| +- MethodDeclarator[@Image = "test", @ParameterCount = 1]
| | +- FormalParameters[@ParameterCount = 1, @Size = 1]
| | +- FormalParameter[@Abstract = false, @Array = false, @ArrayDepth = 0, @Default = false, @ExplicitReceiverParameter = false, @Final = false, @Modifiers = 0, @Native = false, @PackagePrivate = true, @Private = false, @Protected = false, @Public = false, @Static = false, @Strictfp = false, @Synchronized = false, @Transient = false, @TypeInferred = false, @Varargs = false, @Volatile = false]
| | +- Type[@Array = false, @ArrayDepth = 0, @ArrayType = false, @TypeImage = "Object"]
| | | +- ReferenceType[@Array = false, @ArrayDepth = 0]
| | | +- ClassOrInterfaceType[@AnonymousClass = false, @Array = false, @ArrayDepth = 0, @Image = "Object", @ReferenceToClassSameCompilationUnit = false]
| | +- VariableDeclaratorId[@Array = false, @ArrayDepth = 0, @ArrayType = false, @ExceptionBlockParameter = false, @ExplicitReceiverParameter = false, @Field = false, @Final = false, @ForeachVariable = false, @FormalParameter = true, @Image = "o", @LambdaParameter = false, @LocalVariable = false, @Name = "o", @PatternBinding = false, @ResourceDeclaration = false, @TypeInferred = false, @VariableName = "o"]
| +- Block[@containsComment = false]
| +- BlockStatement[@Allocation = true]
| +- Statement[]
| +- SwitchStatement[@DefaultCase = true, @ExhaustiveEnumSwitch = false, @FallthroughSwitch = false]
| +- Expression[@StandAlonePrimitive = false]
| | +- PrimaryExpression[]
| | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false]
| | +- Name[@Image = "o"]
| +- SwitchLabeledBlock[]
| | +- SwitchLabel[@Default = false]
| | | +- TypePattern[@ParenthesisDepth = 0]
| | | +- Type[@Array = false, @ArrayDepth = 0, @ArrayType = false, @TypeImage = "Character"]
| | | | +- ReferenceType[@Array = false, @ArrayDepth = 0]
| | | | +- ClassOrInterfaceType[@AnonymousClass = false, @Array = false, @ArrayDepth = 0, @Image = "Character", @ReferenceToClassSameCompilationUnit = false]
| | | +- VariableDeclaratorId[@Array = false, @ArrayDepth = 0, @ArrayType = false, @ExceptionBlockParameter = false, @ExplicitReceiverParameter = false, @Field = false, @Final = false, @ForeachVariable = false, @FormalParameter = false, @Image = "c", @LambdaParameter = false, @LocalVariable = false, @Name = "c", @PatternBinding = true, @ResourceDeclaration = false, @TypeInferred = false, @VariableName = "c"]
| | +- Block[@containsComment = false]
| | +- BlockStatement[@Allocation = false]
| | | +- Statement[]
| | | +- IfStatement[@Else = false]
| | | +- Expression[@StandAlonePrimitive = false]
| | | | +- EqualityExpression[@Image = "==", @Operator = "=="]
| | | | +- PrimaryExpression[]
| | | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false]
| | | | | | +- Name[@Image = "c.charValue"]
| | | | | +- PrimarySuffix[@ArgumentCount = 0, @Arguments = true, @ArrayDereference = false]
| | | | | +- Arguments[@ArgumentCount = 0, @Size = 0]
| | | | +- PrimaryExpression[]
| | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false]
| | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "7", @FloatLiteral = false, @Image = "7", @IntLiteral = true, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = false, @TextBlock = false, @TextBlockContent = "7", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 7, @ValueAsLong = 7]
| | | +- Statement[]
| | | +- Block[@containsComment = false]
| | | +- BlockStatement[@Allocation = false]
| | | +- Statement[]
| | | +- StatementExpression[]
| | | +- PrimaryExpression[]
| | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false]
| | | | +- Name[@Image = "System.out.println"]
| | | +- PrimarySuffix[@ArgumentCount = 1, @Arguments = true, @ArrayDereference = false]
| | | +- Arguments[@ArgumentCount = 1, @Size = 1]
| | | +- ArgumentList[@Size = 1]
| | | +- Expression[@StandAlonePrimitive = false]
| | | +- PrimaryExpression[]
| | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false]
| | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"Ding!\"", @FloatLiteral = false, @Image = "\"Ding!\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"Ding!\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0]
| | +- BlockStatement[@Allocation = false]
| | +- Statement[]
| | +- StatementExpression[]
| | +- PrimaryExpression[]
| | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false]
| | | +- Name[@Image = "System.out.println"]
| | +- PrimarySuffix[@ArgumentCount = 1, @Arguments = true, @ArrayDereference = false]
| | +- Arguments[@ArgumentCount = 1, @Size = 1]
| | +- ArgumentList[@Size = 1]
| | +- Expression[@StandAlonePrimitive = false]
| | +- PrimaryExpression[]
| | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false]
| | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"Character\"", @FloatLiteral = false, @Image = "\"Character\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"Character\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0]
| +- SwitchLabeledThrowStatement[]
| | +- SwitchLabel[@Default = false]
| | | +- TypePattern[@ParenthesisDepth = 0]
| | | +- Type[@Array = false, @ArrayDepth = 0, @ArrayType = false, @TypeImage = "Integer"]
| | | | +- ReferenceType[@Array = false, @ArrayDepth = 0]
| | | | +- ClassOrInterfaceType[@AnonymousClass = false, @Array = false, @ArrayDepth = 0, @Image = "Integer", @ReferenceToClassSameCompilationUnit = false]
| | | +- VariableDeclaratorId[@Array = false, @ArrayDepth = 0, @ArrayType = false, @ExceptionBlockParameter = false, @ExplicitReceiverParameter = false, @Field = false, @Final = false, @ForeachVariable = false, @FormalParameter = false, @Image = "i", @LambdaParameter = false, @LocalVariable = false, @Name = "i", @PatternBinding = true, @ResourceDeclaration = false, @TypeInferred = false, @VariableName = "i"]
| | +- ThrowStatement[@FirstClassOrInterfaceTypeImage = "IllegalStateException"]
| | +- Expression[@StandAlonePrimitive = false]
| | +- PrimaryExpression[]
| | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false]
| | +- AllocationExpression[@AnonymousClass = false]
| | +- ClassOrInterfaceType[@AnonymousClass = false, @Array = false, @ArrayDepth = 0, @Image = "IllegalStateException", @ReferenceToClassSameCompilationUnit = false]
| | +- Arguments[@ArgumentCount = 1, @Size = 1]
| | +- ArgumentList[@Size = 1]
| | +- Expression[@StandAlonePrimitive = false]
| | +- AdditiveExpression[@Image = "+", @Operator = "+"]
| | +- PrimaryExpression[]
| | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false]
| | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"Invalid Integer argument of value \"", @FloatLiteral = false, @Image = "\"Invalid Integer argument of value \"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"Invalid Integer argument of value \"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0]
| | +- PrimaryExpression[]
| | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false]
| | | +- Name[@Image = "i.intValue"]
| | +- PrimarySuffix[@ArgumentCount = 0, @Arguments = true, @ArrayDereference = false]
| | +- Arguments[@ArgumentCount = 0, @Size = 0]
| +- SwitchLabeledBlock[]
| +- SwitchLabel[@Default = true]
| +- Block[@containsComment = false]
| +- BlockStatement[@Allocation = false]
| +- Statement[]
| +- BreakStatement[]
+- ClassOrInterfaceBodyDeclaration[@AnonymousInnerClass = false, @EnumChild = false, @Kind = DeclarationKind.METHOD]
| +- MethodDeclaration[@Abstract = false, @Arity = 1, @Default = false, @Final = false, @InterfaceMember = false, @Kind = MethodLikeKind.METHOD, @MethodName = "test2", @Modifiers = 16, @Name = "test2", @Native = false, @PackagePrivate = true, @Private = false, @Protected = false, @Public = false, @Static = true, @Strictfp = false, @Synchronized = false, @SyntacticallyAbstract = false, @SyntacticallyPublic = false, @Transient = false, @Void = true, @Volatile = false]
| +- ResultType[@Void = true, @returnsArray = false]
| +- MethodDeclarator[@Image = "test2", @ParameterCount = 1]
| | +- FormalParameters[@ParameterCount = 1, @Size = 1]
| | +- FormalParameter[@Abstract = false, @Array = false, @ArrayDepth = 0, @Default = false, @ExplicitReceiverParameter = false, @Final = false, @Modifiers = 0, @Native = false, @PackagePrivate = true, @Private = false, @Protected = false, @Public = false, @Static = false, @Strictfp = false, @Synchronized = false, @Transient = false, @TypeInferred = false, @Varargs = false, @Volatile = false]
| | +- Type[@Array = false, @ArrayDepth = 0, @ArrayType = false, @TypeImage = "Object"]
| | | +- ReferenceType[@Array = false, @ArrayDepth = 0]
| | | +- ClassOrInterfaceType[@AnonymousClass = false, @Array = false, @ArrayDepth = 0, @Image = "Object", @ReferenceToClassSameCompilationUnit = false]
| | +- VariableDeclaratorId[@Array = false, @ArrayDepth = 0, @ArrayType = false, @ExceptionBlockParameter = false, @ExplicitReceiverParameter = false, @Field = false, @Final = false, @ForeachVariable = false, @FormalParameter = true, @Image = "o", @LambdaParameter = false, @LocalVariable = false, @Name = "o", @PatternBinding = false, @ResourceDeclaration = false, @TypeInferred = false, @VariableName = "o"]
| +- Block[@containsComment = false]
| +- BlockStatement[@Allocation = false]
| +- Statement[]
| +- SwitchStatement[@DefaultCase = true, @ExhaustiveEnumSwitch = false, @FallthroughSwitch = true]
| +- Expression[@StandAlonePrimitive = false]
| | +- PrimaryExpression[]
| | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false]
| | +- Name[@Image = "o"]
| +- SwitchLabel[@Default = false]
| | +- TypePattern[@ParenthesisDepth = 0]
| | +- Type[@Array = false, @ArrayDepth = 0, @ArrayType = false, @TypeImage = "Character"]
| | | +- ReferenceType[@Array = false, @ArrayDepth = 0]
| | | +- ClassOrInterfaceType[@AnonymousClass = false, @Array = false, @ArrayDepth = 0, @Image = "Character", @ReferenceToClassSameCompilationUnit = false]
| | +- VariableDeclaratorId[@Array = false, @ArrayDepth = 0, @ArrayType = false, @ExceptionBlockParameter = false, @ExplicitReceiverParameter = false, @Field = false, @Final = false, @ForeachVariable = false, @FormalParameter = false, @Image = "c", @LambdaParameter = false, @LocalVariable = false, @Name = "c", @PatternBinding = true, @ResourceDeclaration = false, @TypeInferred = false, @VariableName = "c"]
| +- BlockStatement[@Allocation = false]
| | +- Statement[]
| | +- IfStatement[@Else = false]
| | +- Expression[@StandAlonePrimitive = false]
| | | +- EqualityExpression[@Image = "==", @Operator = "=="]
| | | +- PrimaryExpression[]
| | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false]
| | | | | +- Name[@Image = "c.charValue"]
| | | | +- PrimarySuffix[@ArgumentCount = 0, @Arguments = true, @ArrayDereference = false]
| | | | +- Arguments[@ArgumentCount = 0, @Size = 0]
| | | +- PrimaryExpression[]
| | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false]
| | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "7", @FloatLiteral = false, @Image = "7", @IntLiteral = true, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = false, @TextBlock = false, @TextBlockContent = "7", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 7, @ValueAsLong = 7]
| | +- Statement[]
| | +- Block[@containsComment = false]
| | +- BlockStatement[@Allocation = false]
| | +- Statement[]
| | +- StatementExpression[]
| | +- PrimaryExpression[]
| | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false]
| | | +- Name[@Image = "System.out.print"]
| | +- PrimarySuffix[@ArgumentCount = 1, @Arguments = true, @ArrayDereference = false]
| | +- Arguments[@ArgumentCount = 1, @Size = 1]
| | +- ArgumentList[@Size = 1]
| | +- Expression[@StandAlonePrimitive = false]
| | +- PrimaryExpression[]
| | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false]
| | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"Ding \"", @FloatLiteral = false, @Image = "\"Ding \"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"Ding \"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0]
| +- BlockStatement[@Allocation = false]
| | +- Statement[]
| | +- IfStatement[@Else = false]
| | +- Expression[@StandAlonePrimitive = false]
| | | +- EqualityExpression[@Image = "==", @Operator = "=="]
| | | +- PrimaryExpression[]
| | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false]
| | | | | +- Name[@Image = "c.charValue"]
| | | | +- PrimarySuffix[@ArgumentCount = 0, @Arguments = true, @ArrayDereference = false]
| | | | +- Arguments[@ArgumentCount = 0, @Size = 0]
| | | +- PrimaryExpression[]
| | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false]
| | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "9", @FloatLiteral = false, @Image = "9", @IntLiteral = true, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = false, @TextBlock = false, @TextBlockContent = "9", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 9, @ValueAsLong = 9]
| | +- Statement[]
| | +- Block[@containsComment = false]
| | +- BlockStatement[@Allocation = false]
| | +- Statement[]
| | +- StatementExpression[]
| | +- PrimaryExpression[]
| | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false]
| | | +- Name[@Image = "System.out.print"]
| | +- PrimarySuffix[@ArgumentCount = 1, @Arguments = true, @ArrayDereference = false]
| | +- Arguments[@ArgumentCount = 1, @Size = 1]
| | +- ArgumentList[@Size = 1]
| | +- Expression[@StandAlonePrimitive = false]
| | +- PrimaryExpression[]
| | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false]
| | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"Tab \"", @FloatLiteral = false, @Image = "\"Tab \"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"Tab \"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0]
| +- BlockStatement[@Allocation = false]
| | +- Statement[]
| | +- StatementExpression[]
| | +- PrimaryExpression[]
| | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false]
| | | +- Name[@Image = "System.out.println"]
| | +- PrimarySuffix[@ArgumentCount = 1, @Arguments = true, @ArrayDereference = false]
| | +- Arguments[@ArgumentCount = 1, @Size = 1]
| | +- ArgumentList[@Size = 1]
| | +- Expression[@StandAlonePrimitive = false]
| | +- PrimaryExpression[]
| | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false]
| | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"character\"", @FloatLiteral = false, @Image = "\"character\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"character\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0]
| +- SwitchLabel[@Default = true]
| +- BlockStatement[@Allocation = false]
| +- Statement[]
| +- StatementExpression[]
| +- PrimaryExpression[]
| +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false]
| | +- Name[@Image = "System.out.println"]
| +- PrimarySuffix[@ArgumentCount = 0, @Arguments = true, @ArrayDereference = false]
| +- Arguments[@ArgumentCount = 0, @Size = 0]
+- ClassOrInterfaceBodyDeclaration[@AnonymousInnerClass = false, @EnumChild = false, @Kind = DeclarationKind.METHOD]
+- MethodDeclaration[@Abstract = false, @Arity = 1, @Default = false, @Final = false, @InterfaceMember = false, @Kind = MethodLikeKind.METHOD, @MethodName = "main", @Modifiers = 17, @Name = "main", @Native = false, @PackagePrivate = false, @Private = false, @Protected = false, @Public = true, @Static = true, @Strictfp = false, @Synchronized = false, @SyntacticallyAbstract = false, @SyntacticallyPublic = true, @Transient = false, @Void = true, @Volatile = false]
+- ResultType[@Void = true, @returnsArray = false]
+- MethodDeclarator[@Image = "main", @ParameterCount = 1]
| +- FormalParameters[@ParameterCount = 1, @Size = 1]
| +- FormalParameter[@Abstract = false, @Array = true, @ArrayDepth = 1, @Default = false, @ExplicitReceiverParameter = false, @Final = false, @Modifiers = 0, @Native = false, @PackagePrivate = true, @Private = false, @Protected = false, @Public = false, @Static = false, @Strictfp = false, @Synchronized = false, @Transient = false, @TypeInferred = false, @Varargs = false, @Volatile = false]
| +- Type[@Array = true, @ArrayDepth = 1, @ArrayType = true, @TypeImage = "String"]
| | +- ReferenceType[@Array = true, @ArrayDepth = 1]
| | +- ClassOrInterfaceType[@AnonymousClass = false, @Array = true, @ArrayDepth = 1, @Image = "String", @ReferenceToClassSameCompilationUnit = false]
| +- VariableDeclaratorId[@Array = false, @ArrayDepth = 0, @ArrayType = true, @ExceptionBlockParameter = false, @ExplicitReceiverParameter = false, @Field = false, @Final = false, @ForeachVariable = false, @FormalParameter = true, @Image = "args", @LambdaParameter = false, @LocalVariable = false, @Name = "args", @PatternBinding = false, @ResourceDeclaration = false, @TypeInferred = false, @VariableName = "args"]
+- Block[@containsComment = false]
+- BlockStatement[@Allocation = false]
| +- Statement[]
| +- StatementExpression[]
| +- PrimaryExpression[]
| +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false]
| | +- Name[@Image = "test"]
| +- PrimarySuffix[@ArgumentCount = 1, @Arguments = true, @ArrayDereference = false]
| +- Arguments[@ArgumentCount = 1, @Size = 1]
| +- ArgumentList[@Size = 1]
| +- Expression[@StandAlonePrimitive = true]
| +- PrimaryExpression[]
| +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false]
| +- Literal[@CharLiteral = true, @DoubleLiteral = false, @EscapedStringLiteral = "\'A\'", @FloatLiteral = false, @Image = "\'A\'", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = false, @TextBlock = false, @TextBlockContent = "\'A\'", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0]
+- BlockStatement[@Allocation = false]
+- Statement[]
+- StatementExpression[]
+- PrimaryExpression[]
+- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false]
| +- Name[@Image = "test2"]
+- PrimarySuffix[@ArgumentCount = 1, @Arguments = true, @ArrayDereference = false]
+- Arguments[@ArgumentCount = 1, @Size = 1]
+- ArgumentList[@Size = 1]
+- Expression[@StandAlonePrimitive = true]
+- PrimaryExpression[]
+- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false]
+- Literal[@CharLiteral = true, @DoubleLiteral = false, @EscapedStringLiteral = "\'\\t\'", @FloatLiteral = false, @Image = "\'\\t\'", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = false, @TextBlock = false, @TextBlockContent = "\'\\t\'", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0]