From 87cdd60e391f9ed120b59b12dec1cdb8b92dca29 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Fri, 12 Feb 2021 09:27:10 +0100 Subject: [PATCH 1/8] [java] Add versions 16 and 16-preview, update asm --- .../pmd/lang/java/JavaLanguageModule.java | 4 +++- .../typeresolution/visitors/PMDASMVisitor.java | 11 ++++++----- .../pmd/LanguageVersionDiscovererTest.java | 18 +++++++++++++++--- .../sourceforge/pmd/LanguageVersionTest.java | 10 +++++++--- .../pmd/lang/java/ast/KotlinTestingDsl.kt | 3 ++- pom.xml | 2 +- 6 files changed, 34 insertions(+), 14 deletions(-) diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/JavaLanguageModule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/JavaLanguageModule.java index 5a1caf587d..a39744d6aa 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/JavaLanguageModule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/JavaLanguageModule.java @@ -29,8 +29,10 @@ public class JavaLanguageModule extends BaseLanguageModule { addVersion("13", new JavaLanguageHandler(13)); addVersion("14", new JavaLanguageHandler(14)); addVersion("14-preview", new JavaLanguageHandler(14, true)); - addDefaultVersion("15", new JavaLanguageHandler(15)); // 15 is the default + addVersion("15", new JavaLanguageHandler(15)); addVersion("15-preview", new JavaLanguageHandler(15, true)); + addDefaultVersion("16", new JavaLanguageHandler(16)); // 16 is the default + addVersion("16-preview", new JavaLanguageHandler(16, true)); } } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/typeresolution/visitors/PMDASMVisitor.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/typeresolution/visitors/PMDASMVisitor.java index e3fe30b2ac..b1c0b2dcf2 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/typeresolution/visitors/PMDASMVisitor.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/typeresolution/visitors/PMDASMVisitor.java @@ -24,6 +24,7 @@ import net.sourceforge.pmd.annotation.InternalApi; @Deprecated @InternalApi public class PMDASMVisitor extends ClassVisitor { + private static final int ASM_API = Opcodes.ASM9; // latest, non-experimental API version private String outerName; @@ -40,7 +41,7 @@ public class PMDASMVisitor extends ClassVisitor { public List innerClasses; public PMDASMVisitor(String outerName) { - super(Opcodes.ASM9); + super(ASM_API); this.outerName = outerName; } @@ -181,7 +182,7 @@ public class PMDASMVisitor extends ClassVisitor { private PMDASMVisitor parent; PMDFieldVisitor(PMDASMVisitor visitor) { - super(Opcodes.ASM9); + super(ASM_API); parent = visitor; } @@ -196,7 +197,7 @@ public class PMDASMVisitor extends ClassVisitor { private PMDASMVisitor parent; PMDAnnotationVisitor(PMDASMVisitor visitor) { - super(Opcodes.ASM9); + super(ASM_API); parent = visitor; } @@ -228,7 +229,7 @@ public class PMDASMVisitor extends ClassVisitor { private PMDASMVisitor parent; PMDSignatureVisitor(PMDASMVisitor visitor) { - super(Opcodes.ASM9); + super(ASM_API); this.parent = visitor; } @@ -292,7 +293,7 @@ public class PMDASMVisitor extends ClassVisitor { private PMDASMVisitor parent; PMDMethodVisitor(PMDASMVisitor visitor) { - super(Opcodes.ASM9); + super(ASM_API); parent = visitor; } diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/LanguageVersionDiscovererTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/LanguageVersionDiscovererTest.java index 1961e37dfd..9da6aa61ae 100644 --- a/pmd-java/src/test/java/net/sourceforge/pmd/LanguageVersionDiscovererTest.java +++ b/pmd-java/src/test/java/net/sourceforge/pmd/LanguageVersionDiscovererTest.java @@ -19,15 +19,27 @@ public class LanguageVersionDiscovererTest { /** * Test on Java file with default options. + * Always the latest non-preview version will be the default version. */ @Test public void testJavaFileUsingDefaults() { LanguageVersionDiscoverer discoverer = new LanguageVersionDiscoverer(); File javaFile = new File("/path/to/MyClass.java"); + LanguageVersion latest = determineLatestNonPreviewVersion(); + LanguageVersion languageVersion = discoverer.getDefaultLanguageVersionForFile(javaFile); - assertEquals("LanguageVersion must be Java 15 !", - LanguageRegistry.getLanguage(JavaLanguageModule.NAME).getVersion("15"), languageVersion); + assertEquals("Latest language version must be default", latest, languageVersion); + } + + private LanguageVersion determineLatestNonPreviewVersion() { + LanguageVersion latest = null; + for (LanguageVersion lv : LanguageRegistry.getLanguage(JavaLanguageModule.NAME).getVersions()) { + if (!lv.getName().endsWith("preview")) { + latest = lv; + } + } + return latest; } /** @@ -48,7 +60,7 @@ public class LanguageVersionDiscovererTest { public void testLanguageVersionDiscoverer() { PMDConfiguration configuration = new PMDConfiguration(); LanguageVersionDiscoverer languageVersionDiscoverer = configuration.getLanguageVersionDiscoverer(); - assertEquals("Default Java version", LanguageRegistry.getLanguage(JavaLanguageModule.NAME).getVersion("15"), + assertEquals("Default Java version", determineLatestNonPreviewVersion(), languageVersionDiscoverer .getDefaultLanguageVersion(LanguageRegistry.getLanguage(JavaLanguageModule.NAME))); configuration diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/LanguageVersionTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/LanguageVersionTest.java index 9197fe2f7c..6079eb9067 100644 --- a/pmd-java/src/test/java/net/sourceforge/pmd/LanguageVersionTest.java +++ b/pmd-java/src/test/java/net/sourceforge/pmd/LanguageVersionTest.java @@ -53,9 +53,13 @@ public class LanguageVersionTest extends AbstractLanguageVersionTest { { JavaLanguageModule.NAME, JavaLanguageModule.TERSE_NAME, "14-preview", LanguageRegistry.getLanguage(JavaLanguageModule.NAME).getVersion("14-preview"), }, { JavaLanguageModule.NAME, JavaLanguageModule.TERSE_NAME, "15", - LanguageRegistry.getLanguage(JavaLanguageModule.NAME).getVersion("15"), }, - { JavaLanguageModule.NAME, JavaLanguageModule.TERSE_NAME, "15-preview", - LanguageRegistry.getLanguage(JavaLanguageModule.NAME).getVersion("15-preview"), }, + LanguageRegistry.getLanguage(JavaLanguageModule.NAME).getVersion("15"), }, + { JavaLanguageModule.NAME, JavaLanguageModule.TERSE_NAME, "15-preview", + LanguageRegistry.getLanguage(JavaLanguageModule.NAME).getVersion("15-preview"), }, + { JavaLanguageModule.NAME, JavaLanguageModule.TERSE_NAME, "16", + LanguageRegistry.getLanguage(JavaLanguageModule.NAME).getVersion("16"), }, + { JavaLanguageModule.NAME, JavaLanguageModule.TERSE_NAME, "16-preview", + LanguageRegistry.getLanguage(JavaLanguageModule.NAME).getVersion("16-preview"), }, // this one won't be found: case sensitive! { "JAVA", "JAVA", "1.7", null, }, diff --git a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/KotlinTestingDsl.kt b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/KotlinTestingDsl.kt index dec931720f..be8007b1db 100644 --- a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/KotlinTestingDsl.kt +++ b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/KotlinTestingDsl.kt @@ -21,7 +21,8 @@ enum class JavaVersion : Comparable { J12, J13, J14, J14__PREVIEW, - J15, J15__PREVIEW; + J15, J15__PREVIEW, + J16, J16__PREVIEW; /** Name suitable for use with e.g. [JavaParsingHelper.parse] */ val pmdName: String = name.removePrefix("J").replaceFirst("__", "-").replace('_', '.').toLowerCase() diff --git a/pom.xml b/pom.xml index b266d53e3f..055df246dd 100644 --- a/pom.xml +++ b/pom.xml @@ -672,7 +672,7 @@ org.ow2.asm asm - 9.0-beta + 9.1 net.sourceforge.pmd From 8c755fabe22986f3e66aca447a4906c262a97ac8 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Fri, 12 Feb 2021 12:44:08 +0100 Subject: [PATCH 2/8] [java] JEP 394: Pattern Matching for instanceof for Java16 The TypePattern now allows the final keyword and Annotations. Pattern variables are now only effectively final. --- pmd-java/etc/grammar/Java.jjt | 25 +- .../pmd/lang/java/ast/ASTPattern.java | 11 +- .../pmd/lang/java/ast/ASTTypeTestPattern.java | 30 +- .../java/ast/ASTVariableDeclaratorId.java | 7 +- .../pmd/lang/java/ast/Java14PreviewTest.java | 2 +- .../pmd/lang/java/ast/Java16TreeDumpTest.java | 55 ++ .../pmd/lang/java/ast/ASTPatternTest.kt | 49 +- .../java15p/PatternMatchingInstanceof.txt | 8 +- .../java16/PatternMatchingInstanceof.java | 55 ++ .../java16/PatternMatchingInstanceof.txt | 530 ++++++++++++++++++ 10 files changed, 741 insertions(+), 31 deletions(-) create mode 100644 pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java16TreeDumpTest.java create mode 100644 pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16/PatternMatchingInstanceof.java create mode 100644 pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16/PatternMatchingInstanceof.txt diff --git a/pmd-java/etc/grammar/Java.jjt b/pmd-java/etc/grammar/Java.jjt index 7fc17b1edf..132280c698 100644 --- a/pmd-java/etc/grammar/Java.jjt +++ b/pmd-java/etc/grammar/Java.jjt @@ -1,4 +1,7 @@ /** + * JEP 394: Pattern Matching for instanceof for Java16 + * Andreas Dangel 02/2021 + *==================================================================== * Remove support for Java 13 preview language features. * Promote text blocks as a permanent language features with Java 15. * Support Pattern Matching for instanceof with Java 15 Preview. @@ -378,8 +381,8 @@ public class JavaParser { } private void checkforBadInstanceOfPattern() { - if (jdkVersion != 14 && jdkVersion != 15 || !preview) { - throwParseException("Pattern Matching for instanceof is only supported with Java 14 Preview and Java 15 Preview"); + if (!(jdkVersion == 14 && preview || jdkVersion == 15 && preview || jdkVersion == 16)) { + throwParseException("Pattern Matching for instanceof is only supported with Java 14 Preview and Java 15 Preview and Java 16"); } } @@ -1682,10 +1685,26 @@ void EqualityExpression() #EqualityExpression(>1): InstanceOfExpression() ( LOOKAHEAD(2) ( "==" {jjtThis.setImage("==");} | "!=" {jjtThis.setImage("!=");} ) InstanceOfExpression() )* } +void TypePattern() #TypeTestPattern: +{} +{ + ( "final" {jjtThis.setFinal(true);} | Annotation() )* + Type() + VariableDeclaratorId() +} + void InstanceOfExpression() #InstanceOfExpression(>1): {} { - RelationalExpression() [ LOOKAHEAD(2) "instanceof" Type() [ {checkforBadInstanceOfPattern();} VariableDeclaratorId() #TypeTestPattern(2) ] ] + RelationalExpression() + [ "instanceof" + ( + LOOKAHEAD("final" | "@") {checkforBadInstanceOfPattern();} TypePattern() + | + Type() + [ {checkforBadInstanceOfPattern();} VariableDeclaratorId() #TypeTestPattern(2) ] + ) + ] } void RelationalExpression() #RelationalExpression(>1): diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTPattern.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTPattern.java index 707be4e0cd..ef957a26c5 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTPattern.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTPattern.java @@ -1,4 +1,4 @@ -/** +/* * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ @@ -8,22 +8,21 @@ import net.sourceforge.pmd.annotation.Experimental; /** * A pattern (for pattern matching constructs like {@link ASTInstanceOfExpression InstanceOfExpression}). - * This is a JDK 14 and JDK 15 preview feature and is subject to change. + * This is a JDK 16 feature. * *

This interface will be implemented by all forms of patterns. For * now, only type test patterns are supported. Record deconstruction - * patterns are in the works for JDK 15 preview. - * - *

See https://openjdk.java.net/jeps/305, https://openjdk.java.net/jeps/8235186 + * patterns is planned for a future JDK version. * *

  *
  * Pattern ::= {@link ASTTypeTestPattern TypeTestPattern}
  *
  * 
+ * + * @see JEP 394: Pattern Matching for instanceof */ @Experimental public interface ASTPattern extends JavaNode { - } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTTypeTestPattern.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTTypeTestPattern.java index c126b89198..40c59ff9b4 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTTypeTestPattern.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTTypeTestPattern.java @@ -1,24 +1,29 @@ -/** +/* * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ package net.sourceforge.pmd.lang.java.ast; +import java.util.List; + import net.sourceforge.pmd.annotation.Experimental; /** - * A type test pattern (JDK 14 preview feature). This can be found on + * A type pattern (JDK16). This can be found on * the right-hand side of an {@link ASTInstanceOfExpression InstanceOfExpression}. * *
  *
- * TypeTestPattern ::= {@linkplain ASTType Type} {@link ASTVariableDeclaratorId VariableDeclaratorId}
+ * TypeTestPattern ::= ( "final" | {@linkplain ASTAnnotation Annotation} )* {@linkplain ASTType Type} {@link ASTVariableDeclaratorId VariableDeclaratorId}
  *
  * 
- */ + * + * @see JEP 394: Pattern Matching for instanceof +*/ @Experimental -public final class ASTTypeTestPattern extends AbstractJavaNode implements ASTPattern { +public final class ASTTypeTestPattern extends AbstractJavaAnnotatableNode implements ASTPattern { + private boolean isFinal; ASTTypeTestPattern(int id) { super(id); @@ -34,17 +39,28 @@ public final class ASTTypeTestPattern extends AbstractJavaNode implements ASTPat return visitor.visit(this, data); } + @Override + public List getDeclaredAnnotations() { + return this.findChildrenOfType(ASTAnnotation.class); + } /** * Gets the type against which the expression is tested. */ public ASTType getTypeNode() { - return (ASTType) getChild(0); + return getFirstChildOfType(ASTType.class); } /** Returns the declared variable. */ public ASTVariableDeclaratorId getVarId() { - return (ASTVariableDeclaratorId) getChild(1); + return getFirstChildOfType(ASTVariableDeclaratorId.class); } + void setFinal(boolean isFinal) { + this.isFinal = isFinal; + } + + boolean isFinal() { + return isFinal; + } } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTVariableDeclaratorId.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTVariableDeclaratorId.java index a8703fa98d..c1c213f000 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTVariableDeclaratorId.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTVariableDeclaratorId.java @@ -199,9 +199,10 @@ public class ASTVariableDeclaratorId extends AbstractJavaTypeNode implements Dim return true; } else if (isLambdaParamWithNoType()) { return false; - } else if (isPatternBinding()) { - // implicitly like final, assignment of a pattern binding is not allowed - return true; + } + + if (getParent() instanceof ASTTypeTestPattern) { + return ((ASTTypeTestPattern) getParent()).isFinal(); } if (getParent() instanceof ASTRecordComponent) { diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java14PreviewTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java14PreviewTest.java index b487c35267..ac22623748 100644 --- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java14PreviewTest.java +++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java14PreviewTest.java @@ -83,7 +83,7 @@ public class Java14PreviewTest { Assert.assertEquals(String.class, variable.getType()); Assert.assertEquals("s", variable.getVariableName()); Assert.assertTrue(variable.isPatternBinding()); - Assert.assertTrue(variable.isFinal()); + Assert.assertFalse(variable.isFinal()); // Note: these variables are not part of the symbol table // See ScopeAndDeclarationFinder#visit(ASTVariableDeclaratorId, Object) Assert.assertNull(variable.getNameDeclaration()); diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java16TreeDumpTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java16TreeDumpTest.java new file mode 100644 index 0000000000..8afcc25eee --- /dev/null +++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java16TreeDumpTest.java @@ -0,0 +1,55 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java.ast; + +import java.util.List; + +import org.junit.Assert; +import org.junit.Test; + +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 Java16TreeDumpTest extends BaseTreeDumpTest { + private final JavaParsingHelper java16 = + JavaParsingHelper.WITH_PROCESSING.withDefaultVersion("16") + .withResourceContext(Java15TreeDumpTest.class, "jdkversiontests/java16/"); + private final JavaParsingHelper java16p = java16.withDefaultVersion("16-preview"); + private final JavaParsingHelper java15 = java16.withDefaultVersion("15"); + + public Java16TreeDumpTest() { + super(new RelevantAttributePrinter(), ".java"); + } + + @Override + public BaseParsingHelper getParser() { + return java16; + } + + @Test + public void patternMatchingInstanceof() { + doTest("PatternMatchingInstanceof"); + + // extended tests for type resolution etc. + ASTCompilationUnit compilationUnit = java16.parseResource("PatternMatchingInstanceof.java"); + List instanceOfExpressions = compilationUnit.findDescendantsOfType(ASTInstanceOfExpression.class); + for (ASTInstanceOfExpression expr : instanceOfExpressions) { + ASTVariableDeclaratorId variable = expr.getChild(1).getFirstChildOfType(ASTVariableDeclaratorId.class); + Assert.assertEquals(String.class, variable.getType()); + // Note: these variables are not part of the symbol table + // See ScopeAndDeclarationFinder#visit(ASTVariableDeclaratorId, Object) + Assert.assertNull(variable.getNameDeclaration()); + } + } + + @Test(expected = ParseException.class) + public void patternMatchingInstanceofBeforeJava16ShouldFail() { + java15.parseResource("PatternMatchingInstanceof.java"); + } + +} diff --git a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTPatternTest.kt b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTPatternTest.kt index f513429d89..806588b2eb 100644 --- a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTPatternTest.kt +++ b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTPatternTest.kt @@ -4,32 +4,67 @@ package net.sourceforge.pmd.lang.java.ast -import net.sourceforge.pmd.lang.ast.test.shouldBe +import io.kotest.matchers.shouldBe +import net.sourceforge.pmd.lang.ast.test.shouldBe as typeShouldBe import net.sourceforge.pmd.lang.java.ast.JavaVersion import net.sourceforge.pmd.lang.java.ast.JavaVersion.* import java.io.IOException class ASTPatternTest : ParserTestSpec({ - parserTest("Test patterns only available on JDK 14+15 (preview)", javaVersions = JavaVersion.values().asList().minus(J14__PREVIEW).minus(J15__PREVIEW)) { + parserTest("Test patterns only available on JDK 14+15 (preview) and JDK16 and JDK16 (preview)", + javaVersions = JavaVersion.values().asList().minus(J14__PREVIEW).minus(J15__PREVIEW).minus(J16).minus(J16__PREVIEW)) { - expectParseException("Pattern Matching for instanceof is only supported with Java 14 Preview and Java 15 Preview") { + expectParseException("Pattern Matching for instanceof is only supported with Java 14 Preview and Java 15 Preview and Java 16") { parseAstExpression("obj instanceof Class c") } } - parserTest("Test simple patterns", javaVersions = listOf(J14__PREVIEW, J15__PREVIEW)) { + parserTest("Test simple patterns", javaVersions = listOf(J14__PREVIEW, J15__PREVIEW, J16)) { importedTypes += IOException::class.java "obj instanceof Class c" should matchExpr { unspecifiedChild() child { - it::getTypeNode shouldBe child(ignoreChildren = true) {} + it.isAnnotationPresent("java.lang.Deprecated") shouldBe false + it::getTypeNode typeShouldBe child(ignoreChildren = true) {} - it::getVarId shouldBe child { - it::getVariableName shouldBe "c" + it::getVarId typeShouldBe child { + it.name shouldBe "c" + it.isFinal shouldBe false + } + } + } + + "obj instanceof final Class c" should matchExpr { + unspecifiedChild() + child { + it.isAnnotationPresent("java.lang.Deprecated") shouldBe false + it::getTypeNode typeShouldBe child(ignoreChildren = true) {} + + it::getVarId typeShouldBe child { + it.name shouldBe "c" + it.isFinal shouldBe true + } + } + } + + "obj instanceof @Deprecated Class c" should matchExpr { + unspecifiedChild() + child { + child(ignoreChildren = true) { + it.annotationName shouldBe "Deprecated" + } + + it.isAnnotationPresent("java.lang.Deprecated") shouldBe true + + it::getTypeNode typeShouldBe child(ignoreChildren = true) {} + + it::getVarId typeShouldBe child { + it.name shouldBe "c" + it.isFinal shouldBe false } } } diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java15p/PatternMatchingInstanceof.txt b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java15p/PatternMatchingInstanceof.txt index e69073e1e7..00481b37e4 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java15p/PatternMatchingInstanceof.txt +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java15p/PatternMatchingInstanceof.txt @@ -44,7 +44,7 @@ | | | +- 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 = true, @FormalParameter = false, @Image = "s", @LambdaParameter = false, @LocalVariable = false, @Name = "s", @PatternBinding = true, @ResourceDeclaration = false, @TypeInferred = false, @VariableName = "s"] + | | | +- VariableDeclaratorId[@Array = false, @ArrayDepth = 0, @ArrayType = false, @ExceptionBlockParameter = false, @ExplicitReceiverParameter = false, @Field = false, @Final = false, @FormalParameter = false, @Image = "s", @LambdaParameter = false, @LocalVariable = false, @Name = "s", @PatternBinding = true, @ResourceDeclaration = false, @TypeInferred = false, @VariableName = "s"] | | +- Statement[] | | | +- Block[@containsComment = true] | | | +- BlockStatement[@Allocation = false] @@ -113,7 +113,7 @@ | | | +- 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 = true, @FormalParameter = false, @Image = "s", @LambdaParameter = false, @LocalVariable = false, @Name = "s", @PatternBinding = true, @ResourceDeclaration = false, @TypeInferred = false, @VariableName = "s"] + | | | +- VariableDeclaratorId[@Array = false, @ArrayDepth = 0, @ArrayType = false, @ExceptionBlockParameter = false, @ExplicitReceiverParameter = false, @Field = false, @Final = false, @FormalParameter = false, @Image = "s", @LambdaParameter = false, @LocalVariable = false, @Name = "s", @PatternBinding = true, @ResourceDeclaration = false, @TypeInferred = false, @VariableName = "s"] | | +- Statement[] | | | +- Block[@containsComment = true] | | | +- BlockStatement[@Allocation = false] @@ -179,7 +179,7 @@ | | | | +- 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 = true, @FormalParameter = false, @Image = "s", @LambdaParameter = false, @LocalVariable = false, @Name = "s", @PatternBinding = true, @ResourceDeclaration = false, @TypeInferred = false, @VariableName = "s"] + | | | | +- VariableDeclaratorId[@Array = false, @ArrayDepth = 0, @ArrayType = false, @ExceptionBlockParameter = false, @ExplicitReceiverParameter = false, @Field = false, @Final = false, @FormalParameter = false, @Image = "s", @LambdaParameter = false, @LocalVariable = false, @Name = "s", @PatternBinding = true, @ResourceDeclaration = false, @TypeInferred = false, @VariableName = "s"] | | | +- RelationalExpression[@Image = ">"] | | | +- PrimaryExpression[] | | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] @@ -228,7 +228,7 @@ | | | +- 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 = true, @FormalParameter = false, @Image = "s", @LambdaParameter = false, @LocalVariable = false, @Name = "s", @PatternBinding = true, @ResourceDeclaration = false, @TypeInferred = false, @VariableName = "s"] + | | | +- VariableDeclaratorId[@Array = false, @ArrayDepth = 0, @ArrayType = false, @ExceptionBlockParameter = false, @ExplicitReceiverParameter = false, @Field = false, @Final = false, @FormalParameter = false, @Image = "s", @LambdaParameter = false, @LocalVariable = false, @Name = "s", @PatternBinding = true, @ResourceDeclaration = false, @TypeInferred = false, @VariableName = "s"] | | +- RelationalExpression[@Image = ">"] | | +- PrimaryExpression[] | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16/PatternMatchingInstanceof.java b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16/PatternMatchingInstanceof.java new file mode 100644 index 0000000000..c4e6e46e5a --- /dev/null +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16/PatternMatchingInstanceof.java @@ -0,0 +1,55 @@ +/** + * + * @see JEP 394: Pattern Matching for instanceof + */ +public class PatternMatchingInstanceof { + private String s = "other string"; + + public void test() { + Object obj = "abc"; + //obj = 1; + if (obj instanceof String s) { + System.out.println("a) obj == s: " + (obj == s)); // true + s = "other value"; // not a compile error - s is only effectively final + System.out.println("changed s to " + s + ": obj == s: " + (obj == s)); + } else { + System.out.println("b) obj == s: " + (obj == s)); // false + } + + if (!(obj instanceof String s)) { + System.out.println("c) obj == s: " + (obj == s)); // false + } else { + System.out.println("d) obj == s: " + (obj == s)); // true + } + + if (obj instanceof String s && s.length() > 2) { + System.out.println("e) obj == s: " + (obj == s)); // true + } + if (obj instanceof String s || s.length() > 5) { + System.out.println("f) obj == s: " + (obj == s)); // false + } + + // With Java16 there can be final and annotations + if (obj instanceof final String s) { + System.out.println("g) obj == s: " + (obj == s)); // true + //s = "another value"; // compile error: error: cannot assign a value to final variable s + } else { + System.out.println("h) obj == s: " + (obj == s)); // false + } + if (obj instanceof @Deprecated String s) { + System.out.println("i) obj == s: " + (obj == s)); // true + } else { + System.out.println("j) obj == s: " + (obj == s)); // false + } + if (obj instanceof final @Deprecated String s) { + System.out.println("k) obj == s: " + (obj == s)); // true + //s = "another value"; // compile error: error: cannot assign a value to final variable s + } else { + System.out.println("l) obj == s: " + (obj == s)); // false + } + } + + public static void main(String[] args) { + new PatternMatchingInstanceof().test(); + } +} \ No newline at end of file diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16/PatternMatchingInstanceof.txt b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16/PatternMatchingInstanceof.txt new file mode 100644 index 0000000000..dca5fe68c6 --- /dev/null +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16/PatternMatchingInstanceof.txt @@ -0,0 +1,530 @@ ++- CompilationUnit[@PackageName = "", @declarationsAreInDefaultPackage = true] + +- TypeDeclaration[] + +- ClassOrInterfaceDeclaration[@Abstract = false, @BinaryName = "PatternMatchingInstanceof", @Default = false, @Final = false, @Image = "PatternMatchingInstanceof", @Interface = false, @Local = false, @Modifiers = 1, @Native = false, @Nested = false, @NonSealed = false, @PackagePrivate = false, @Private = false, @Protected = false, @Public = true, @Sealed = false, @SimpleName = "PatternMatchingInstanceof", @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.FIELD] + | +- FieldDeclaration[@Abstract = false, @AnnotationMember = false, @Array = false, @ArrayDepth = 0, @Default = false, @Final = false, @InterfaceMember = false, @Modifiers = 4, @Native = false, @PackagePrivate = false, @Private = true, @Protected = false, @Public = false, @Static = false, @Strictfp = false, @Synchronized = false, @SyntacticallyFinal = false, @SyntacticallyPublic = false, @SyntacticallyStatic = false, @Transient = false, @VariableName = "s", @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 = "s"] + | +- VariableDeclaratorId[@Array = false, @ArrayDepth = 0, @ArrayType = false, @ExceptionBlockParameter = false, @ExplicitReceiverParameter = false, @Field = true, @Final = false, @FormalParameter = false, @Image = "s", @LambdaParameter = false, @LocalVariable = false, @Name = "s", @PatternBinding = false, @ResourceDeclaration = false, @TypeInferred = false, @VariableName = "s"] + | +- VariableInitializer[] + | +- Expression[@StandAlonePrimitive = false] + | +- PrimaryExpression[] + | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""other string"", @FloatLiteral = false, @Image = ""other string"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""other string"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + +- ClassOrInterfaceBodyDeclaration[@AnonymousInnerClass = false, @EnumChild = false, @Kind = DeclarationKind.METHOD] + | +- MethodDeclaration[@Abstract = false, @Arity = 0, @Default = false, @Final = false, @InterfaceMember = false, @Kind = MethodLikeKind.METHOD, @MethodName = "test", @Modifiers = 1, @Name = "test", @Native = false, @PackagePrivate = false, @Private = false, @Protected = false, @Public = true, @Static = false, @Strictfp = false, @Synchronized = false, @SyntacticallyAbstract = false, @SyntacticallyPublic = true, @Transient = false, @Void = true, @Volatile = false] + | +- ResultType[@Void = true, @returnsArray = false] + | +- MethodDeclarator[@Image = "test", @ParameterCount = 0] + | | +- FormalParameters[@ParameterCount = 0, @Size = 0] + | +- 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 = "obj", @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 = "obj"] + | | +- VariableDeclaratorId[@Array = false, @ArrayDepth = 0, @ArrayType = false, @ExceptionBlockParameter = false, @ExplicitReceiverParameter = false, @Field = false, @Final = false, @FormalParameter = false, @Image = "obj", @LambdaParameter = false, @LocalVariable = true, @Name = "obj", @PatternBinding = false, @ResourceDeclaration = false, @TypeInferred = false, @VariableName = "obj"] + | | +- VariableInitializer[] + | | +- Expression[@StandAlonePrimitive = false] + | | +- PrimaryExpression[] + | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""abc"", @FloatLiteral = false, @Image = ""abc"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""abc"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | +- BlockStatement[@Allocation = false] + | | +- Statement[] + | | +- IfStatement[@Else = true] + | | +- Expression[@StandAlonePrimitive = false] + | | | +- InstanceOfExpression[] + | | | +- PrimaryExpression[] + | | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | | | | +- Name[@Image = "obj"] + | | | +- TypeTestPattern[] + | | | +- 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, @FormalParameter = false, @Image = "s", @LambdaParameter = false, @LocalVariable = false, @Name = "s", @PatternBinding = true, @ResourceDeclaration = false, @TypeInferred = false, @VariableName = "s"] + | | +- 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] + | | | | +- AdditiveExpression[@Image = "+", @Operator = "+"] + | | | | +- PrimaryExpression[] + | | | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | | | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""a) obj == s: "", @FloatLiteral = false, @Image = ""a) obj == s: "", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""a) obj == s: "", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | | | +- PrimaryExpression[] + | | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | | | | +- Expression[@StandAlonePrimitive = false] + | | | | +- EqualityExpression[@Image = "==", @Operator = "=="] + | | | | +- PrimaryExpression[] + | | | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | | | | | +- Name[@Image = "obj"] + | | | | +- PrimaryExpression[] + | | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | | | | +- Name[@Image = "s"] + | | | +- BlockStatement[@Allocation = false] + | | | | +- Statement[] + | | | | +- StatementExpression[] + | | | | +- PrimaryExpression[] + | | | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | | | | | +- Name[@Image = "s"] + | | | | +- AssignmentOperator[@Compound = false, @Image = "="] + | | | | +- Expression[@StandAlonePrimitive = false] + | | | | +- PrimaryExpression[] + | | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""other value"", @FloatLiteral = false, @Image = ""other value"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""other value"", @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] + | | | +- AdditiveExpression[@Image = "+", @Operator = "+"] + | | | +- PrimaryExpression[] + | | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""changed s to "", @FloatLiteral = false, @Image = ""changed s to "", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""changed s to "", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | | +- PrimaryExpression[] + | | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | | | | +- Name[@Image = "s"] + | | | +- PrimaryExpression[] + | | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "": obj == s: "", @FloatLiteral = false, @Image = "": obj == s: "", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "": obj == s: "", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | | +- PrimaryExpression[] + | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | | | +- Expression[@StandAlonePrimitive = false] + | | | +- EqualityExpression[@Image = "==", @Operator = "=="] + | | | +- PrimaryExpression[] + | | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | | | | +- Name[@Image = "obj"] + | | | +- PrimaryExpression[] + | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | | | +- Name[@Image = "s"] + | | +- Statement[] + | | +- Block[@containsComment = true] + | | +- 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] + | | +- AdditiveExpression[@Image = "+", @Operator = "+"] + | | +- PrimaryExpression[] + | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""b) obj == s: "", @FloatLiteral = false, @Image = ""b) obj == s: "", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""b) obj == s: "", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | +- PrimaryExpression[] + | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | | +- Expression[@StandAlonePrimitive = false] + | | +- EqualityExpression[@Image = "==", @Operator = "=="] + | | +- PrimaryExpression[] + | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | | | +- Name[@Image = "obj"] + | | +- PrimaryExpression[] + | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | | +- Name[@Image = "s"] + | +- BlockStatement[@Allocation = false] + | | +- Statement[] + | | +- IfStatement[@Else = true] + | | +- Expression[@StandAlonePrimitive = false] + | | | +- UnaryExpressionNotPlusMinus[@Image = "!", @Operator = "!"] + | | | +- PrimaryExpression[] + | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | | | +- Expression[@StandAlonePrimitive = false] + | | | +- InstanceOfExpression[] + | | | +- PrimaryExpression[] + | | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | | | | +- Name[@Image = "obj"] + | | | +- TypeTestPattern[] + | | | +- 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, @FormalParameter = false, @Image = "s", @LambdaParameter = false, @LocalVariable = false, @Name = "s", @PatternBinding = true, @ResourceDeclaration = false, @TypeInferred = false, @VariableName = "s"] + | | +- Statement[] + | | | +- Block[@containsComment = true] + | | | +- 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] + | | | +- AdditiveExpression[@Image = "+", @Operator = "+"] + | | | +- PrimaryExpression[] + | | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""c) obj == s: "", @FloatLiteral = false, @Image = ""c) obj == s: "", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""c) obj == s: "", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | | +- PrimaryExpression[] + | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | | | +- Expression[@StandAlonePrimitive = false] + | | | +- EqualityExpression[@Image = "==", @Operator = "=="] + | | | +- PrimaryExpression[] + | | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | | | | +- Name[@Image = "obj"] + | | | +- PrimaryExpression[] + | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | | | +- Name[@Image = "s"] + | | +- Statement[] + | | +- Block[@containsComment = true] + | | +- 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] + | | +- AdditiveExpression[@Image = "+", @Operator = "+"] + | | +- PrimaryExpression[] + | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""d) obj == s: "", @FloatLiteral = false, @Image = ""d) obj == s: "", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""d) obj == s: "", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | +- PrimaryExpression[] + | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | | +- Expression[@StandAlonePrimitive = false] + | | +- EqualityExpression[@Image = "==", @Operator = "=="] + | | +- PrimaryExpression[] + | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | | | +- Name[@Image = "obj"] + | | +- PrimaryExpression[] + | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | | +- Name[@Image = "s"] + | +- BlockStatement[@Allocation = false] + | | +- Statement[] + | | +- IfStatement[@Else = false] + | | +- Expression[@StandAlonePrimitive = false] + | | | +- ConditionalAndExpression[] + | | | +- InstanceOfExpression[] + | | | | +- PrimaryExpression[] + | | | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | | | | | +- Name[@Image = "obj"] + | | | | +- TypeTestPattern[] + | | | | +- 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, @FormalParameter = false, @Image = "s", @LambdaParameter = false, @LocalVariable = false, @Name = "s", @PatternBinding = true, @ResourceDeclaration = false, @TypeInferred = false, @VariableName = "s"] + | | | +- RelationalExpression[@Image = ">"] + | | | +- PrimaryExpression[] + | | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | | | | | +- Name[@Image = "s.length"] + | | | | +- PrimarySuffix[@ArgumentCount = 0, @Arguments = true, @ArrayDereference = false] + | | | | +- Arguments[@ArgumentCount = 0, @Size = 0] + | | | +- PrimaryExpression[] + | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "2", @FloatLiteral = false, @Image = "2", @IntLiteral = true, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = false, @TextBlock = false, @TextBlockContent = "2", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 2, @ValueAsLong = 2] + | | +- Statement[] + | | +- Block[@containsComment = true] + | | +- 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] + | | +- AdditiveExpression[@Image = "+", @Operator = "+"] + | | +- PrimaryExpression[] + | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""e) obj == s: "", @FloatLiteral = false, @Image = ""e) obj == s: "", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""e) obj == s: "", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | +- PrimaryExpression[] + | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | | +- Expression[@StandAlonePrimitive = false] + | | +- EqualityExpression[@Image = "==", @Operator = "=="] + | | +- PrimaryExpression[] + | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | | | +- Name[@Image = "obj"] + | | +- PrimaryExpression[] + | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | | +- Name[@Image = "s"] + | +- BlockStatement[@Allocation = false] + | | +- Statement[] + | | +- IfStatement[@Else = false] + | | +- Expression[@StandAlonePrimitive = false] + | | | +- ConditionalOrExpression[] + | | | +- InstanceOfExpression[] + | | | | +- PrimaryExpression[] + | | | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | | | | | +- Name[@Image = "obj"] + | | | | +- TypeTestPattern[] + | | | | +- 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, @FormalParameter = false, @Image = "s", @LambdaParameter = false, @LocalVariable = false, @Name = "s", @PatternBinding = true, @ResourceDeclaration = false, @TypeInferred = false, @VariableName = "s"] + | | | +- RelationalExpression[@Image = ">"] + | | | +- PrimaryExpression[] + | | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | | | | | +- Name[@Image = "s.length"] + | | | | +- PrimarySuffix[@ArgumentCount = 0, @Arguments = true, @ArrayDereference = false] + | | | | +- Arguments[@ArgumentCount = 0, @Size = 0] + | | | +- PrimaryExpression[] + | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "5", @FloatLiteral = false, @Image = "5", @IntLiteral = true, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = false, @TextBlock = false, @TextBlockContent = "5", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 5, @ValueAsLong = 5] + | | +- Statement[] + | | +- Block[@containsComment = true] + | | +- 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] + | | +- AdditiveExpression[@Image = "+", @Operator = "+"] + | | +- PrimaryExpression[] + | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""f) obj == s: "", @FloatLiteral = false, @Image = ""f) obj == s: "", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""f) obj == s: "", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | +- PrimaryExpression[] + | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | | +- Expression[@StandAlonePrimitive = false] + | | +- EqualityExpression[@Image = "==", @Operator = "=="] + | | +- PrimaryExpression[] + | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | | | +- Name[@Image = "obj"] + | | +- PrimaryExpression[] + | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | | +- Name[@Image = "s"] + | +- BlockStatement[@Allocation = false] + | | +- Statement[] + | | +- IfStatement[@Else = true] + | | +- Expression[@StandAlonePrimitive = false] + | | | +- InstanceOfExpression[] + | | | +- PrimaryExpression[] + | | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | | | | +- Name[@Image = "obj"] + | | | +- TypeTestPattern[] + | | | +- 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 = true, @FormalParameter = false, @Image = "s", @LambdaParameter = false, @LocalVariable = false, @Name = "s", @PatternBinding = true, @ResourceDeclaration = false, @TypeInferred = false, @VariableName = "s"] + | | +- Statement[] + | | | +- Block[@containsComment = true] + | | | +- 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] + | | | +- AdditiveExpression[@Image = "+", @Operator = "+"] + | | | +- PrimaryExpression[] + | | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""g) obj == s: "", @FloatLiteral = false, @Image = ""g) obj == s: "", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""g) obj == s: "", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | | +- PrimaryExpression[] + | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | | | +- Expression[@StandAlonePrimitive = false] + | | | +- EqualityExpression[@Image = "==", @Operator = "=="] + | | | +- PrimaryExpression[] + | | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | | | | +- Name[@Image = "obj"] + | | | +- PrimaryExpression[] + | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | | | +- Name[@Image = "s"] + | | +- Statement[] + | | +- Block[@containsComment = true] + | | +- 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] + | | +- AdditiveExpression[@Image = "+", @Operator = "+"] + | | +- PrimaryExpression[] + | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""h) obj == s: "", @FloatLiteral = false, @Image = ""h) obj == s: "", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""h) obj == s: "", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | +- PrimaryExpression[] + | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | | +- Expression[@StandAlonePrimitive = false] + | | +- EqualityExpression[@Image = "==", @Operator = "=="] + | | +- PrimaryExpression[] + | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | | | +- Name[@Image = "obj"] + | | +- PrimaryExpression[] + | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | | +- Name[@Image = "s"] + | +- BlockStatement[@Allocation = false] + | | +- Statement[] + | | +- IfStatement[@Else = true] + | | +- Expression[@StandAlonePrimitive = false] + | | | +- InstanceOfExpression[] + | | | +- PrimaryExpression[] + | | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | | | | +- Name[@Image = "obj"] + | | | +- TypeTestPattern[] + | | | +- Annotation[@AnnotationName = "Deprecated"] + | | | | +- MarkerAnnotation[@AnnotationName = "Deprecated"] + | | | | +- Name[@Image = "Deprecated"] + | | | +- 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, @FormalParameter = false, @Image = "s", @LambdaParameter = false, @LocalVariable = false, @Name = "s", @PatternBinding = true, @ResourceDeclaration = false, @TypeInferred = false, @VariableName = "s"] + | | +- Statement[] + | | | +- Block[@containsComment = true] + | | | +- 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] + | | | +- AdditiveExpression[@Image = "+", @Operator = "+"] + | | | +- PrimaryExpression[] + | | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""i) obj == s: "", @FloatLiteral = false, @Image = ""i) obj == s: "", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""i) obj == s: "", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | | +- PrimaryExpression[] + | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | | | +- Expression[@StandAlonePrimitive = false] + | | | +- EqualityExpression[@Image = "==", @Operator = "=="] + | | | +- PrimaryExpression[] + | | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | | | | +- Name[@Image = "obj"] + | | | +- PrimaryExpression[] + | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | | | +- Name[@Image = "s"] + | | +- Statement[] + | | +- Block[@containsComment = true] + | | +- 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] + | | +- AdditiveExpression[@Image = "+", @Operator = "+"] + | | +- PrimaryExpression[] + | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""j) obj == s: "", @FloatLiteral = false, @Image = ""j) obj == s: "", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""j) obj == s: "", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | +- PrimaryExpression[] + | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | | +- Expression[@StandAlonePrimitive = false] + | | +- EqualityExpression[@Image = "==", @Operator = "=="] + | | +- PrimaryExpression[] + | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | | | +- Name[@Image = "obj"] + | | +- PrimaryExpression[] + | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | | +- Name[@Image = "s"] + | +- BlockStatement[@Allocation = false] + | +- Statement[] + | +- IfStatement[@Else = true] + | +- Expression[@StandAlonePrimitive = false] + | | +- InstanceOfExpression[] + | | +- PrimaryExpression[] + | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | | | +- Name[@Image = "obj"] + | | +- TypeTestPattern[] + | | +- Annotation[@AnnotationName = "Deprecated"] + | | | +- MarkerAnnotation[@AnnotationName = "Deprecated"] + | | | +- Name[@Image = "Deprecated"] + | | +- 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 = true, @FormalParameter = false, @Image = "s", @LambdaParameter = false, @LocalVariable = false, @Name = "s", @PatternBinding = true, @ResourceDeclaration = false, @TypeInferred = false, @VariableName = "s"] + | +- Statement[] + | | +- Block[@containsComment = true] + | | +- 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] + | | +- AdditiveExpression[@Image = "+", @Operator = "+"] + | | +- PrimaryExpression[] + | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""k) obj == s: "", @FloatLiteral = false, @Image = ""k) obj == s: "", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""k) obj == s: "", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | +- PrimaryExpression[] + | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | | +- Expression[@StandAlonePrimitive = false] + | | +- EqualityExpression[@Image = "==", @Operator = "=="] + | | +- PrimaryExpression[] + | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | | | +- Name[@Image = "obj"] + | | +- PrimaryExpression[] + | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | | +- Name[@Image = "s"] + | +- Statement[] + | +- Block[@containsComment = true] + | +- 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] + | +- AdditiveExpression[@Image = "+", @Operator = "+"] + | +- PrimaryExpression[] + | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""l) obj == s: "", @FloatLiteral = false, @Image = ""l) obj == s: "", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""l) obj == s: "", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | +- PrimaryExpression[] + | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | +- Expression[@StandAlonePrimitive = false] + | +- EqualityExpression[@Image = "==", @Operator = "=="] + | +- PrimaryExpression[] + | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | | +- Name[@Image = "obj"] + | +- PrimaryExpression[] + | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | +- Name[@Image = "s"] + +- 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, @FormalParameter = true, @Image = "args", @LambdaParameter = false, @LocalVariable = false, @Name = "args", @PatternBinding = false, @ResourceDeclaration = false, @TypeInferred = false, @VariableName = "args"] + +- Block[@containsComment = false] + +- BlockStatement[@Allocation = true] + +- Statement[] + +- StatementExpression[] + +- PrimaryExpression[] + +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | +- AllocationExpression[@AnonymousClass = false] + | +- ClassOrInterfaceType[@AnonymousClass = false, @Array = false, @ArrayDepth = 0, @Image = "PatternMatchingInstanceof", @ReferenceToClassSameCompilationUnit = true] + | +- Arguments[@ArgumentCount = 0, @Size = 0] + +- PrimarySuffix[@ArgumentCount = -1, @Arguments = false, @ArrayDereference = false, @Image = "test"] + +- PrimarySuffix[@ArgumentCount = 0, @Arguments = true, @ArrayDereference = false] + +- Arguments[@ArgumentCount = 0, @Size = 0] From 64b501e0f4c3eedc327376c2980203cf439e7116 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Fri, 12 Feb 2021 12:54:06 +0100 Subject: [PATCH 3/8] [java] Rename ASTTypeTestPattern -> ASTTypePattern, remove @Experimental With JEP 394 / Java16, this production has been renamed. Pattern Matching for Instanceof is now a standard feature, therefore the AST node is not experimental anymore. --- pmd-java/etc/grammar/Java.jjt | 8 ++++---- .../pmd/lang/java/ast/ASTInstanceOfExpression.java | 2 +- .../sourceforge/pmd/lang/java/ast/ASTPattern.java | 5 +---- ...ASTTypeTestPattern.java => ASTTypePattern.java} | 11 ++++------- .../pmd/lang/java/ast/ASTVariableDeclaratorId.java | 10 ++++------ .../lang/java/ast/JavaParserDecoratedVisitor.java | 2 +- .../lang/java/ast/JavaParserVisitorAdapter.java | 2 +- .../lang/java/ast/JavaParserVisitorDecorator.java | 2 +- .../pmd/lang/java/rule/AbstractJavaRule.java | 4 ++-- .../pmd/lang/java/ast/Java14PreviewTest.java | 2 +- .../pmd/lang/java/ast/ASTPatternTest.kt | 8 ++++---- .../java15p/PatternMatchingInstanceof.txt | 8 ++++---- .../java16/PatternMatchingInstanceof.txt | 14 +++++++------- 13 files changed, 35 insertions(+), 43 deletions(-) rename pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/{ASTTypeTestPattern.java => ASTTypePattern.java} (75%) diff --git a/pmd-java/etc/grammar/Java.jjt b/pmd-java/etc/grammar/Java.jjt index 132280c698..3eee2c2100 100644 --- a/pmd-java/etc/grammar/Java.jjt +++ b/pmd-java/etc/grammar/Java.jjt @@ -381,8 +381,8 @@ public class JavaParser { } private void checkforBadInstanceOfPattern() { - if (!(jdkVersion == 14 && preview || jdkVersion == 15 && preview || jdkVersion == 16)) { - throwParseException("Pattern Matching for instanceof is only supported with Java 14 Preview and Java 15 Preview and Java 16"); + if (!(jdkVersion == 14 && preview || jdkVersion == 15 && preview || jdkVersion >= 16)) { + throwParseException("Pattern Matching for instanceof is only supported with Java 14 Preview and Java 15 Preview and Java >= 16"); } } @@ -1685,7 +1685,7 @@ void EqualityExpression() #EqualityExpression(>1): InstanceOfExpression() ( LOOKAHEAD(2) ( "==" {jjtThis.setImage("==");} | "!=" {jjtThis.setImage("!=");} ) InstanceOfExpression() )* } -void TypePattern() #TypeTestPattern: +void TypePattern(): {} { ( "final" {jjtThis.setFinal(true);} | Annotation() )* @@ -1702,7 +1702,7 @@ void InstanceOfExpression() #InstanceOfExpression(>1): LOOKAHEAD("final" | "@") {checkforBadInstanceOfPattern();} TypePattern() | Type() - [ {checkforBadInstanceOfPattern();} VariableDeclaratorId() #TypeTestPattern(2) ] + [ {checkforBadInstanceOfPattern();} VariableDeclaratorId() #TypePattern(2) ] ) ] } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTInstanceOfExpression.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTInstanceOfExpression.java index 091810cbd2..e20c5917bc 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTInstanceOfExpression.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTInstanceOfExpression.java @@ -48,7 +48,7 @@ public class ASTInstanceOfExpression extends AbstractJavaTypeNode { public ASTType getTypeNode() { JavaNode child = getChild(1); return child instanceof ASTType ? (ASTType) child - : ((ASTTypeTestPattern) child).getTypeNode(); + : ((ASTTypePattern) child).getTypeNode(); } } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTPattern.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTPattern.java index ef957a26c5..5a2b275d2c 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTPattern.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTPattern.java @@ -4,8 +4,6 @@ package net.sourceforge.pmd.lang.java.ast; -import net.sourceforge.pmd.annotation.Experimental; - /** * A pattern (for pattern matching constructs like {@link ASTInstanceOfExpression InstanceOfExpression}). * This is a JDK 16 feature. @@ -16,13 +14,12 @@ import net.sourceforge.pmd.annotation.Experimental; * *
  *
- * Pattern ::= {@link ASTTypeTestPattern TypeTestPattern}
+ * Pattern ::= {@link ASTTypePattern TypePattern}
  *
  * 
* * @see JEP 394: Pattern Matching for instanceof */ -@Experimental public interface ASTPattern extends JavaNode { } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTTypeTestPattern.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTTypePattern.java similarity index 75% rename from pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTTypeTestPattern.java rename to pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTTypePattern.java index 40c59ff9b4..2c7c74d576 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTTypeTestPattern.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTTypePattern.java @@ -6,30 +6,27 @@ package net.sourceforge.pmd.lang.java.ast; import java.util.List; -import net.sourceforge.pmd.annotation.Experimental; - /** * A type pattern (JDK16). This can be found on * the right-hand side of an {@link ASTInstanceOfExpression InstanceOfExpression}. * *
  *
- * TypeTestPattern ::= ( "final" | {@linkplain ASTAnnotation Annotation} )* {@linkplain ASTType Type} {@link ASTVariableDeclaratorId VariableDeclaratorId}
+ * TypePattern ::= ( "final" | {@linkplain ASTAnnotation Annotation} )* {@linkplain ASTType Type} {@link ASTVariableDeclaratorId VariableDeclaratorId}
  *
  * 
* * @see JEP 394: Pattern Matching for instanceof */ -@Experimental -public final class ASTTypeTestPattern extends AbstractJavaAnnotatableNode implements ASTPattern { +public final class ASTTypePattern extends AbstractJavaAnnotatableNode implements ASTPattern { private boolean isFinal; - ASTTypeTestPattern(int id) { + ASTTypePattern(int id) { super(id); } - ASTTypeTestPattern(JavaParser p, int id) { + ASTTypePattern(JavaParser p, int id) { super(p, id); } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTVariableDeclaratorId.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTVariableDeclaratorId.java index c1c213f000..bd063be244 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTVariableDeclaratorId.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTVariableDeclaratorId.java @@ -6,7 +6,6 @@ package net.sourceforge.pmd.lang.java.ast; import java.util.List; -import net.sourceforge.pmd.annotation.Experimental; import net.sourceforge.pmd.annotation.InternalApi; import net.sourceforge.pmd.lang.ast.Node; import net.sourceforge.pmd.lang.ast.xpath.internal.DeprecatedAttribute; @@ -201,8 +200,8 @@ public class ASTVariableDeclaratorId extends AbstractJavaTypeNode implements Dim return false; } - if (getParent() instanceof ASTTypeTestPattern) { - return ((ASTTypeTestPattern) getParent()).isFinal(); + if (getParent() instanceof ASTTypePattern) { + return ((ASTTypePattern) getParent()).isFinal(); } if (getParent() instanceof ASTRecordComponent) { @@ -277,7 +276,6 @@ public class ASTVariableDeclaratorId extends AbstractJavaTypeNode implements Dim * Returns true if this is a binding variable in a * {@linkplain ASTPattern pattern}. */ - @Experimental public boolean isPatternBinding() { return getParent() instanceof ASTPattern; } @@ -331,8 +329,8 @@ public class ASTVariableDeclaratorId extends AbstractJavaTypeNode implements Dim } else if (isTypeInferred()) { // lambda expression with lax types. The type is inferred... return null; - } else if (getParent() instanceof ASTTypeTestPattern) { - return ((ASTTypeTestPattern) getParent()).getTypeNode(); + } else if (getParent() instanceof ASTTypePattern) { + return ((ASTTypePattern) getParent()).getTypeNode(); } else if (getParent() instanceof ASTRecordComponent) { return ((ASTRecordComponent) getParent()).getTypeNode(); } else { diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaParserDecoratedVisitor.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaParserDecoratedVisitor.java index ecc15eacd9..436c18e569 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaParserDecoratedVisitor.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaParserDecoratedVisitor.java @@ -903,7 +903,7 @@ public class JavaParserDecoratedVisitor implements JavaParserVisitor { @Override @Experimental - public Object visit(ASTTypeTestPattern node, Object data) { + public Object visit(ASTTypePattern node, Object data) { visitor.visit(node, data); return visit((JavaNode) node, data); } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaParserVisitorAdapter.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaParserVisitorAdapter.java index 359cd8573e..656b66a613 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaParserVisitorAdapter.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaParserVisitorAdapter.java @@ -630,7 +630,7 @@ public class JavaParserVisitorAdapter implements JavaParserVisitor { @Override @Experimental - public Object visit(ASTTypeTestPattern node, Object data) { + public Object visit(ASTTypePattern node, Object data) { return visit((JavaNode) node, data); } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaParserVisitorDecorator.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaParserVisitorDecorator.java index fef4a1bb7f..827f4b4f4f 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaParserVisitorDecorator.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaParserVisitorDecorator.java @@ -762,7 +762,7 @@ public class JavaParserVisitorDecorator implements JavaParserControllessVisitor @Override @Experimental - public Object visit(ASTTypeTestPattern node, Object data) { + public Object visit(ASTTypePattern node, Object data) { return visitor.visit(node, data); } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/AbstractJavaRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/AbstractJavaRule.java index 294eb61ee8..e77ff13efe 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/AbstractJavaRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/AbstractJavaRule.java @@ -130,7 +130,7 @@ import net.sourceforge.pmd.lang.java.ast.ASTTypeBound; import net.sourceforge.pmd.lang.java.ast.ASTTypeDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTTypeParameter; import net.sourceforge.pmd.lang.java.ast.ASTTypeParameters; -import net.sourceforge.pmd.lang.java.ast.ASTTypeTestPattern; +import net.sourceforge.pmd.lang.java.ast.ASTTypePattern; import net.sourceforge.pmd.lang.java.ast.ASTUnaryExpression; import net.sourceforge.pmd.lang.java.ast.ASTUnaryExpressionNotPlusMinus; import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclarator; @@ -839,7 +839,7 @@ public abstract class AbstractJavaRule extends AbstractRule implements JavaParse @Override @Experimental - public Object visit(ASTTypeTestPattern node, Object data) { + public Object visit(ASTTypePattern node, Object data) { return visit((JavaNode) node, data); } diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java14PreviewTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java14PreviewTest.java index ac22623748..e2365d630c 100644 --- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java14PreviewTest.java +++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java14PreviewTest.java @@ -78,7 +78,7 @@ public class Java14PreviewTest { List instanceOfExpressions = compilationUnit.findDescendantsOfType(ASTInstanceOfExpression.class); Assert.assertEquals(4, instanceOfExpressions.size()); for (ASTInstanceOfExpression expr : instanceOfExpressions) { - Assert.assertTrue(expr.getChild(1) instanceof ASTTypeTestPattern); + Assert.assertTrue(expr.getChild(1) instanceof ASTTypePattern); ASTVariableDeclaratorId variable = expr.getChild(1).getFirstChildOfType(ASTVariableDeclaratorId.class); Assert.assertEquals(String.class, variable.getType()); Assert.assertEquals("s", variable.getVariableName()); diff --git a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTPatternTest.kt b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTPatternTest.kt index 806588b2eb..6d3187e205 100644 --- a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTPatternTest.kt +++ b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTPatternTest.kt @@ -15,7 +15,7 @@ class ASTPatternTest : ParserTestSpec({ parserTest("Test patterns only available on JDK 14+15 (preview) and JDK16 and JDK16 (preview)", javaVersions = JavaVersion.values().asList().minus(J14__PREVIEW).minus(J15__PREVIEW).minus(J16).minus(J16__PREVIEW)) { - expectParseException("Pattern Matching for instanceof is only supported with Java 14 Preview and Java 15 Preview and Java 16") { + expectParseException("Pattern Matching for instanceof is only supported with Java 14 Preview and Java 15 Preview and Java >= 16") { parseAstExpression("obj instanceof Class c") } @@ -27,7 +27,7 @@ class ASTPatternTest : ParserTestSpec({ "obj instanceof Class c" should matchExpr { unspecifiedChild() - child { + child { it.isAnnotationPresent("java.lang.Deprecated") shouldBe false it::getTypeNode typeShouldBe child(ignoreChildren = true) {} @@ -40,7 +40,7 @@ class ASTPatternTest : ParserTestSpec({ "obj instanceof final Class c" should matchExpr { unspecifiedChild() - child { + child { it.isAnnotationPresent("java.lang.Deprecated") shouldBe false it::getTypeNode typeShouldBe child(ignoreChildren = true) {} @@ -53,7 +53,7 @@ class ASTPatternTest : ParserTestSpec({ "obj instanceof @Deprecated Class c" should matchExpr { unspecifiedChild() - child { + child { child(ignoreChildren = true) { it.annotationName shouldBe "Deprecated" } diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java15p/PatternMatchingInstanceof.txt b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java15p/PatternMatchingInstanceof.txt index 00481b37e4..7802f51b10 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java15p/PatternMatchingInstanceof.txt +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java15p/PatternMatchingInstanceof.txt @@ -40,7 +40,7 @@ | | | +- PrimaryExpression[] | | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] | | | | +- Name[@Image = "obj"] - | | | +- TypeTestPattern[] + | | | +- TypePattern[] | | | +- 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] @@ -109,7 +109,7 @@ | | | +- PrimaryExpression[] | | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] | | | | +- Name[@Image = "obj"] - | | | +- TypeTestPattern[] + | | | +- TypePattern[] | | | +- 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] @@ -175,7 +175,7 @@ | | | | +- PrimaryExpression[] | | | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] | | | | | +- Name[@Image = "obj"] - | | | | +- TypeTestPattern[] + | | | | +- TypePattern[] | | | | +- 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] @@ -224,7 +224,7 @@ | | | +- PrimaryExpression[] | | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] | | | | +- Name[@Image = "obj"] - | | | +- TypeTestPattern[] + | | | +- TypePattern[] | | | +- 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] diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16/PatternMatchingInstanceof.txt b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16/PatternMatchingInstanceof.txt index dca5fe68c6..37b741a663 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16/PatternMatchingInstanceof.txt +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16/PatternMatchingInstanceof.txt @@ -40,7 +40,7 @@ | | | +- PrimaryExpression[] | | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] | | | | +- Name[@Image = "obj"] - | | | +- TypeTestPattern[] + | | | +- TypePattern[] | | | +- 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] @@ -150,7 +150,7 @@ | | | +- PrimaryExpression[] | | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] | | | | +- Name[@Image = "obj"] - | | | +- TypeTestPattern[] + | | | +- TypePattern[] | | | +- 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] @@ -216,7 +216,7 @@ | | | | +- PrimaryExpression[] | | | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] | | | | | +- Name[@Image = "obj"] - | | | | +- TypeTestPattern[] + | | | | +- TypePattern[] | | | | +- 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] @@ -265,7 +265,7 @@ | | | | +- PrimaryExpression[] | | | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] | | | | | +- Name[@Image = "obj"] - | | | | +- TypeTestPattern[] + | | | | +- TypePattern[] | | | | +- 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] @@ -313,7 +313,7 @@ | | | +- PrimaryExpression[] | | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] | | | | +- Name[@Image = "obj"] - | | | +- TypeTestPattern[] + | | | +- TypePattern[] | | | +- 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] @@ -378,7 +378,7 @@ | | | +- PrimaryExpression[] | | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] | | | | +- Name[@Image = "obj"] - | | | +- TypeTestPattern[] + | | | +- TypePattern[] | | | +- Annotation[@AnnotationName = "Deprecated"] | | | | +- MarkerAnnotation[@AnnotationName = "Deprecated"] | | | | +- Name[@Image = "Deprecated"] @@ -446,7 +446,7 @@ | | +- PrimaryExpression[] | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] | | | +- Name[@Image = "obj"] - | | +- TypeTestPattern[] + | | +- TypePattern[] | | +- Annotation[@AnnotationName = "Deprecated"] | | | +- MarkerAnnotation[@AnnotationName = "Deprecated"] | | | +- Name[@Image = "Deprecated"] From 03731f8c16c308d9a0189d626901b87aaea81467 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Fri, 12 Feb 2021 18:05:53 +0100 Subject: [PATCH 4/8] [java] Remove more @Experimental for ASTTypePattern --- .../pmd/lang/java/ast/JavaParserDecoratedVisitor.java | 1 - .../sourceforge/pmd/lang/java/ast/JavaParserVisitorAdapter.java | 1 - .../pmd/lang/java/ast/JavaParserVisitorDecorator.java | 1 - .../net/sourceforge/pmd/lang/java/rule/AbstractJavaRule.java | 1 - 4 files changed, 4 deletions(-) diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaParserDecoratedVisitor.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaParserDecoratedVisitor.java index 436c18e569..a9fcd9f2f6 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaParserDecoratedVisitor.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaParserDecoratedVisitor.java @@ -902,7 +902,6 @@ public class JavaParserDecoratedVisitor implements JavaParserVisitor { } @Override - @Experimental public Object visit(ASTTypePattern node, Object data) { visitor.visit(node, data); return visit((JavaNode) node, data); diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaParserVisitorAdapter.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaParserVisitorAdapter.java index 656b66a613..cf9e65858b 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaParserVisitorAdapter.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaParserVisitorAdapter.java @@ -629,7 +629,6 @@ public class JavaParserVisitorAdapter implements JavaParserVisitor { } @Override - @Experimental public Object visit(ASTTypePattern node, Object data) { return visit((JavaNode) node, data); } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaParserVisitorDecorator.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaParserVisitorDecorator.java index 827f4b4f4f..da25e067c8 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaParserVisitorDecorator.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaParserVisitorDecorator.java @@ -761,7 +761,6 @@ public class JavaParserVisitorDecorator implements JavaParserControllessVisitor } @Override - @Experimental public Object visit(ASTTypePattern node, Object data) { return visitor.visit(node, data); } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/AbstractJavaRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/AbstractJavaRule.java index e77ff13efe..7202a82a42 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/AbstractJavaRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/AbstractJavaRule.java @@ -838,7 +838,6 @@ public abstract class AbstractJavaRule extends AbstractRule implements JavaParse } @Override - @Experimental public Object visit(ASTTypePattern node, Object data) { return visit((JavaNode) node, data); } From 8bc26f95aa963da403813e0a8edd49c814260464 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Sun, 14 Feb 2021 19:42:59 +0100 Subject: [PATCH 5/8] [java] JEP 395: Records for Java16 - Renamed ASTRecordConstructorDeclaration to ASTCompactConstructorDeclaration to align naming to JLS - ASTRecordDeclaration, ASTRecordComponentList, ASTRecordComponent, ASTRecordBody, ASTCompactConstructorDeclaration are not longer @Experimental --- pmd-java/etc/grammar/Java.jjt | 37 +- ... => ASTCompactConstructorDeclaration.java} | 15 +- .../pmd/lang/java/ast/ASTRecordBody.java | 7 +- .../pmd/lang/java/ast/ASTRecordComponent.java | 5 +- .../lang/java/ast/ASTRecordComponentList.java | 5 +- .../lang/java/ast/ASTRecordDeclaration.java | 6 +- .../java/ast/JavaParserDecoratedVisitor.java | 7 +- .../java/ast/JavaParserVisitorAdapter.java | 7 +- .../java/ast/JavaParserVisitorDecorator.java | 7 +- .../java/internal/JavaDesignerBindings.java | 4 +- .../pmd/lang/java/rule/AbstractJavaRule.java | 9 +- .../pmd/lang/java/ast/Java14PreviewTest.java | 2 +- .../pmd/lang/java/ast/Java16TreeDumpTest.java | 60 ++++ .../java15p/LocalInterfacesAndEnums.java | 3 +- .../java15p/LocalInterfacesAndEnums.txt | 11 +- .../ast/jdkversiontests/java15p/Records.txt | 2 +- .../LocalClassAndInterfaceDeclarations.java | 32 ++ .../LocalClassAndInterfaceDeclarations.txt | 40 +++ .../jdkversiontests/java16/LocalRecords.java | 45 +++ .../jdkversiontests/java16/LocalRecords.txt | 292 ++++++++++++++++ .../ast/jdkversiontests/java16/Point.java | 14 + .../java/ast/jdkversiontests/java16/Point.txt | 64 ++++ .../ast/jdkversiontests/java16/Records.java | 68 ++++ .../ast/jdkversiontests/java16/Records.txt | 317 ++++++++++++++++++ 24 files changed, 983 insertions(+), 76 deletions(-) rename pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/{ASTRecordConstructorDeclaration.java => ASTCompactConstructorDeclaration.java} (62%) create mode 100644 pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16/LocalClassAndInterfaceDeclarations.java create mode 100644 pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16/LocalClassAndInterfaceDeclarations.txt create mode 100644 pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16/LocalRecords.java create mode 100644 pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16/LocalRecords.txt create mode 100644 pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16/Point.java create mode 100644 pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16/Point.txt create mode 100644 pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16/Records.java create mode 100644 pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16/Records.txt diff --git a/pmd-java/etc/grammar/Java.jjt b/pmd-java/etc/grammar/Java.jjt index 3eee2c2100..cf4b22b27f 100644 --- a/pmd-java/etc/grammar/Java.jjt +++ b/pmd-java/etc/grammar/Java.jjt @@ -1,4 +1,5 @@ /** + * JEP 395: Records for Java16 * JEP 394: Pattern Matching for instanceof for Java16 * Andreas Dangel 02/2021 *==================================================================== @@ -429,8 +430,8 @@ public class JavaParser { if (jdkVersion >= 14 && "yield".equals(image)) { throwParseException("With JDK 14, 'yield' is a restricted local variable type and cannot be used for type declarations!"); } - if (jdkVersion >= 14 && preview && "record".equals(image)) { - throwParseException("With JDK 14 Preview and JDK 15 Preview, 'record' is a restricted identifier and cannot be used for type declarations!"); + if ((jdkVersion >= 14 && preview || jdkVersion >= 16) && "record".equals(image)) { + throwParseException("With JDK 14 Preview and JDK 15 Preview and Java >= 16, 'record' is a restricted identifier and cannot be used for type declarations!"); } if (jdkVersion >= 15 && preview && "sealed".equals(image)) { throwParseException("With JDK 15 Preview, 'sealed' is a restricted identifier and cannot be used for type declarations!"); @@ -485,18 +486,18 @@ public class JavaParser { private void checkForRecordType() { if (!isRecordTypeSupported()) { - throwParseException("Records are only supported with Java 14 Preview and Java 15 Preview"); + throwParseException("Records are only supported with Java 14 Preview and Java 15 Preview and Java >= 16"); } } private void checkForLocalInterfaceOrEnumType() { if (!isRecordTypeSupported()) { - throwParseException("Local interfaces and enums are only supported with Java 14 Preview and Java 15 Preview"); + throwParseException("Local interfaces and enums are only supported with Java 14 Preview and Java 15 Preview and Java >= 16"); } } private boolean isRecordTypeSupported() { - return (jdkVersion == 14 || jdkVersion == 15) && preview; + return jdkVersion == 14 && preview || jdkVersion == 15 && preview || jdkVersion >= 16; } private boolean isSealedClassSupported() { @@ -590,7 +591,6 @@ public class JavaParser { Token next = getToken(1); return next.kind == CLASS || isRecordTypeSupported() && next.kind == INTERFACE - || isRecordTypeSupported() && next.kind == AT && isToken(2, INTERFACE) || isRecordTypeSupported() && next.kind == IDENTIFIER && next.image.equals("enum") || isRecordTypeSupported() && next.kind == IDENTIFIER && next.image.equals("record"); } @@ -1279,26 +1279,38 @@ void RecordDeclaration(int modifiers): } t= {checkForBadTypeIdentifierUsage(t.image); jjtThis.setImage(t.image);} [ TypeParameters() ] - RecordComponentList() + RecordHeader() [ ImplementsList() ] RecordBody() } +void RecordHeader() #void: +{} +{ + "(" RecordComponentList() ")" +} + void RecordComponentList() : {} { - "(" [ RecordComponent() ("," RecordComponent())* ] ")" + [ RecordComponent() ("," RecordComponent())* ] } void RecordComponent(): {} { - (Annotation())* + (RecordComponentModifier())* Type() [ "..." {jjtThis.setVarargs();} ] VariableDeclaratorId() } +void RecordComponentModifier() #void: +{} +{ + Annotation() +} + void RecordBody(): {} { @@ -1310,18 +1322,18 @@ void RecordBody(): void RecordBodyDeclaration() #void : {} { - LOOKAHEAD(RecordCtorLookahead()) RecordConstructorDeclaration() + LOOKAHEAD(CompactConstructorDeclarationLookahead()) CompactConstructorDeclaration() | ClassOrInterfaceBodyDeclaration() } -private void RecordCtorLookahead() #void: +private void CompactConstructorDeclarationLookahead() #void: {} { Modifiers() "{" } -void RecordConstructorDeclaration(): +void CompactConstructorDeclaration(): { int modifiers; } @@ -2071,7 +2083,6 @@ void LocalTypeDecl(int mods) #void: | LOOKAHEAD() ClassOrInterfaceDeclaration(mods) { checkForLocalInterfaceOrEnumType(); } | LOOKAHEAD({isKeyword("record")}) RecordDeclaration(mods) { checkForLocalInterfaceOrEnumType(); } | LOOKAHEAD({isKeyword("enum")}) EnumDeclaration(mods) { checkForLocalInterfaceOrEnumType(); } - | AnnotationTypeDeclaration(mods) { checkForLocalInterfaceOrEnumType(); } ) } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTRecordConstructorDeclaration.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTCompactConstructorDeclaration.java similarity index 62% rename from pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTRecordConstructorDeclaration.java rename to pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTCompactConstructorDeclaration.java index ad2facbb3d..7363e1b80d 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTRecordConstructorDeclaration.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTCompactConstructorDeclaration.java @@ -5,14 +5,12 @@ package net.sourceforge.pmd.lang.java.ast; -import net.sourceforge.pmd.annotation.Experimental; - /** - * This defines a compact constructor for a {@linkplain ASTRecordDeclaration RecordDeclaration} (JDK 14 and JDK 15 preview feature). + * This defines a compact constructor for a {@linkplain ASTRecordDeclaration RecordDeclaration} (JDK 16 feature). * *
  *
- * RecordConstructorDeclaration ::=  ({@linkplain ASTAnnotation Annotation})*
+ * CompactConstructorDeclaration ::=  ({@linkplain ASTAnnotation Annotation})*
  *                                   RecordModifiers
  *                                   <IDENTIFIER>
  *                                   {@link ASTBlock Block}
@@ -20,13 +18,12 @@ import net.sourceforge.pmd.annotation.Experimental;
  * 
* */ -@Experimental -public final class ASTRecordConstructorDeclaration extends AbstractJavaAccessNode implements ASTAnyTypeBodyDeclaration { - ASTRecordConstructorDeclaration(int id) { +public final class ASTCompactConstructorDeclaration extends AbstractJavaAccessNode implements ASTAnyTypeBodyDeclaration { + ASTCompactConstructorDeclaration(int id) { super(id); } - ASTRecordConstructorDeclaration(JavaParser p, int id) { + ASTCompactConstructorDeclaration(JavaParser p, int id) { super(p, id); } @@ -36,7 +33,7 @@ public final class ASTRecordConstructorDeclaration extends AbstractJavaAccessNod } @Override - public ASTRecordConstructorDeclaration getDeclarationNode() { + public ASTCompactConstructorDeclaration getDeclarationNode() { return this; } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTRecordBody.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTRecordBody.java index 7646a5fe3c..a8e42c137c 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTRecordBody.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTRecordBody.java @@ -5,21 +5,18 @@ package net.sourceforge.pmd.lang.java.ast; -import net.sourceforge.pmd.annotation.Experimental; - /** - * Defines the body of a {@linkplain ASTRecordDeclaration RecordDeclaration} (JDK 14 and JDK 15 preview feature). + * Defines the body of a {@linkplain ASTRecordDeclaration RecordDeclaration} (JDK 16 feature). * This can contain additional methods and or constructors. * *
  *
- * RecordBody ::= "{" (   {@linkplain ASTRecordConstructorDeclaration RecordConstructorDeclaration}
+ * RecordBody ::= "{" (   {@linkplain ASTCompactConstructorDeclaration CompactConstructorDeclaration}
  *                      | {@linkplain ASTClassOrInterfaceBodyDeclaration ClassOrInterfaceBodyDeclaration} )* "}"
  *
  * 
* */ -@Experimental public final class ASTRecordBody extends AbstractJavaNode { ASTRecordBody(int id) { super(id); diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTRecordComponent.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTRecordComponent.java index c3f54076c2..144da04020 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTRecordComponent.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTRecordComponent.java @@ -5,10 +5,8 @@ package net.sourceforge.pmd.lang.java.ast; -import net.sourceforge.pmd.annotation.Experimental; - /** - * Defines a single component of a {@linkplain ASTRecordDeclaration RecordDeclaration} (JDK 14 and JDK 15 preview feature). + * Defines a single component of a {@linkplain ASTRecordDeclaration RecordDeclaration} (JDK 16 feature). * *
  *
@@ -19,7 +17,6 @@ import net.sourceforge.pmd.annotation.Experimental;
  *
  * 
*/ -@Experimental public final class ASTRecordComponent extends AbstractJavaAnnotatableNode { private boolean varargs; diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTRecordComponentList.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTRecordComponentList.java index 2abfb29c72..6ace826c05 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTRecordComponentList.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTRecordComponentList.java @@ -7,10 +7,8 @@ package net.sourceforge.pmd.lang.java.ast; import java.util.Iterator; -import net.sourceforge.pmd.annotation.Experimental; - /** - * Defines the state description of a {@linkplain ASTRecordDeclaration RecordDeclaration} (JDK 14 and JDK 15 preview feature). + * Defines the state description of a {@linkplain ASTRecordDeclaration RecordDeclaration} (JDK 16 feature). * *
  *
@@ -18,7 +16,6 @@ import net.sourceforge.pmd.annotation.Experimental;
  *
  * 
*/ -@Experimental public final class ASTRecordComponentList extends AbstractJavaNode implements Iterable { ASTRecordComponentList(int id) { super(id); diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTRecordDeclaration.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTRecordDeclaration.java index 9549272604..8677b07122 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTRecordDeclaration.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTRecordDeclaration.java @@ -7,11 +7,10 @@ package net.sourceforge.pmd.lang.java.ast; import java.util.List; -import net.sourceforge.pmd.annotation.Experimental; import net.sourceforge.pmd.lang.ast.Node; /** - * A record declaration is a special data class type (JDK 14 and JDK 15 preview feature). + * A record declaration is a special data class type (JDK 16 feature). * This is a {@linkplain Node#isFindBoundary() find boundary} for tree traversal methods. * *
@@ -25,9 +24,8 @@ import net.sourceforge.pmd.lang.ast.Node;
  *
  * 
* - * @see JEP 384: Records (Second Preview) + * @see JEP 395: Records */ -@Experimental public final class ASTRecordDeclaration extends AbstractAnyTypeDeclaration { ASTRecordDeclaration(int id) { super(id); diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaParserDecoratedVisitor.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaParserDecoratedVisitor.java index a9fcd9f2f6..af9900b450 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaParserDecoratedVisitor.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaParserDecoratedVisitor.java @@ -908,36 +908,31 @@ public class JavaParserDecoratedVisitor implements JavaParserVisitor { } @Override - @Experimental public Object visit(ASTRecordDeclaration node, Object data) { visitor.visit(node, data); return visit((JavaNode) node, data); } @Override - @Experimental public Object visit(ASTRecordComponentList node, Object data) { visitor.visit(node, data); return visit((JavaNode) node, data); } @Override - @Experimental public Object visit(ASTRecordComponent node, Object data) { visitor.visit(node, data); return visit((JavaNode) node, data); } @Override - @Experimental public Object visit(ASTRecordBody node, Object data) { visitor.visit(node, data); return visit((JavaNode) node, data); } @Override - @Experimental - public Object visit(ASTRecordConstructorDeclaration node, Object data) { + public Object visit(ASTCompactConstructorDeclaration node, Object data) { visitor.visit(node, data); return visit((JavaNode) node, data); } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaParserVisitorAdapter.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaParserVisitorAdapter.java index cf9e65858b..d0edd71373 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaParserVisitorAdapter.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaParserVisitorAdapter.java @@ -634,32 +634,27 @@ public class JavaParserVisitorAdapter implements JavaParserVisitor { } @Override - @Experimental public Object visit(ASTRecordDeclaration node, Object data) { return visit((JavaNode) node, data); } @Override - @Experimental public Object visit(ASTRecordComponentList node, Object data) { return visit((JavaNode) node, data); } @Override - @Experimental public Object visit(ASTRecordComponent node, Object data) { return visit((JavaNode) node, data); } @Override - @Experimental public Object visit(ASTRecordBody node, Object data) { return visit((JavaNode) node, data); } @Override - @Experimental - public Object visit(ASTRecordConstructorDeclaration node, Object data) { + public Object visit(ASTCompactConstructorDeclaration node, Object data) { return visit((JavaNode) node, data); } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaParserVisitorDecorator.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaParserVisitorDecorator.java index da25e067c8..7e38503674 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaParserVisitorDecorator.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaParserVisitorDecorator.java @@ -766,32 +766,27 @@ public class JavaParserVisitorDecorator implements JavaParserControllessVisitor } @Override - @Experimental public Object visit(ASTRecordDeclaration node, Object data) { return visitor.visit(node, data); } @Override - @Experimental public Object visit(ASTRecordComponentList node, Object data) { return visitor.visit(node, data); } @Override - @Experimental public Object visit(ASTRecordComponent node, Object data) { return visitor.visit(node, data); } @Override - @Experimental public Object visit(ASTRecordBody node, Object data) { return visitor.visit(node, data); } @Override - @Experimental - public Object visit(ASTRecordConstructorDeclaration node, Object data) { + public Object visit(ASTCompactConstructorDeclaration node, Object data) { return visitor.visit(node, data); } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/internal/JavaDesignerBindings.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/internal/JavaDesignerBindings.java index ff1f44ba3a..75d95d8627 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/internal/JavaDesignerBindings.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/internal/JavaDesignerBindings.java @@ -10,10 +10,10 @@ import java.util.Collections; import net.sourceforge.pmd.lang.ast.Node; import net.sourceforge.pmd.lang.ast.xpath.Attribute; import net.sourceforge.pmd.lang.java.ast.ASTAnyTypeDeclaration; +import net.sourceforge.pmd.lang.java.ast.ASTCompactConstructorDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTConstructorDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTFieldDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration; -import net.sourceforge.pmd.lang.java.ast.ASTRecordConstructorDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclaratorId; import net.sourceforge.pmd.lang.java.ast.JavaNode; import net.sourceforge.pmd.lang.java.ast.JavaParserVisitor; @@ -51,7 +51,7 @@ public final class JavaDesignerBindings extends DefaultDesignerBindings { } else if (node instanceof ASTMethodDeclaration) { return TreeIconId.METHOD; } else if (node instanceof ASTConstructorDeclaration - || node instanceof ASTRecordConstructorDeclaration) { + || node instanceof ASTCompactConstructorDeclaration) { return TreeIconId.CONSTRUCTOR; } else if (node instanceof ASTVariableDeclaratorId) { return TreeIconId.VARIABLE; diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/AbstractJavaRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/AbstractJavaRule.java index 7202a82a42..41e7e6c924 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/AbstractJavaRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/AbstractJavaRule.java @@ -35,6 +35,7 @@ import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceBody; import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceBodyDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceType; +import net.sourceforge.pmd.lang.java.ast.ASTCompactConstructorDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit; import net.sourceforge.pmd.lang.java.ast.ASTConditionalAndExpression; import net.sourceforge.pmd.lang.java.ast.ASTConditionalExpression; @@ -100,7 +101,6 @@ import net.sourceforge.pmd.lang.java.ast.ASTRUNSIGNEDSHIFT; import net.sourceforge.pmd.lang.java.ast.ASTRecordBody; import net.sourceforge.pmd.lang.java.ast.ASTRecordComponent; import net.sourceforge.pmd.lang.java.ast.ASTRecordComponentList; -import net.sourceforge.pmd.lang.java.ast.ASTRecordConstructorDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTRecordDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTReferenceType; import net.sourceforge.pmd.lang.java.ast.ASTRelationalExpression; @@ -843,32 +843,27 @@ public abstract class AbstractJavaRule extends AbstractRule implements JavaParse } @Override - @Experimental public Object visit(ASTRecordDeclaration node, Object data) { return visit((JavaNode) node, data); } @Override - @Experimental public Object visit(ASTRecordComponentList node, Object data) { return visit((JavaNode) node, data); } @Override - @Experimental public Object visit(ASTRecordComponent node, Object data) { return visit((JavaNode) node, data); } @Override - @Experimental public Object visit(ASTRecordBody node, Object data) { return visit((JavaNode) node, data); } @Override - @Experimental - public Object visit(ASTRecordConstructorDeclaration node, Object data) { + public Object visit(ASTCompactConstructorDeclaration node, Object data) { return visit((JavaNode) node, data); } diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java14PreviewTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java14PreviewTest.java index e2365d630c..4d865ae6ca 100644 --- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java14PreviewTest.java +++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java14PreviewTest.java @@ -149,7 +149,7 @@ public class Java14PreviewTest { ASTRecordDeclaration range = recordDecls.get(2); Assert.assertEquals("Range", range.getSimpleName()); Assert.assertEquals(2, range.getComponentList().size()); - List rangeConstructors = range.findDescendantsOfType(ASTRecordConstructorDeclaration.class); + List rangeConstructors = range.findDescendantsOfType(ASTCompactConstructorDeclaration.class); Assert.assertEquals(1, rangeConstructors.size()); Assert.assertEquals("Range", rangeConstructors.get(0).getImage()); Assert.assertTrue(rangeConstructors.get(0).getChild(0) instanceof ASTAnnotation); diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java16TreeDumpTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java16TreeDumpTest.java index 8afcc25eee..6c92ef13d8 100644 --- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java16TreeDumpTest.java +++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java16TreeDumpTest.java @@ -52,4 +52,64 @@ public class Java16TreeDumpTest extends BaseTreeDumpTest { java15.parseResource("PatternMatchingInstanceof.java"); } + @Test + public void localClassAndInterfaceDeclarations() { + doTest("LocalClassAndInterfaceDeclarations"); + } + + @Test(expected = ParseException.class) + public void localClassAndInterfaceDeclarationsBeforeJava16ShouldFail() { + java15.parseResource("LocalClassAndInterfaceDeclarations.java"); + } + + @Test(expected = ParseException.class) + public void localAnnotationsAreNotAllowed() { + java16.parse("public class Foo { { @interface MyLocalAnnotation {} } }"); + } + + @Test + public void localRecords() { + doTest("LocalRecords"); + } + + @Test + public void recordPoint() { + doTest("Point"); + + // extended tests for type resolution etc. + ASTCompilationUnit compilationUnit = java16.parseResource("Point.java"); + ASTRecordDeclaration recordDecl = compilationUnit.getFirstDescendantOfType(ASTRecordDeclaration.class); + List components = recordDecl.getFirstChildOfType(ASTRecordComponentList.class) + .findChildrenOfType(ASTRecordComponent.class); + Assert.assertNull(components.get(0).getVarId().getNameDeclaration().getAccessNodeParent()); + Assert.assertEquals(Integer.TYPE, components.get(0).getVarId().getNameDeclaration().getType()); + Assert.assertEquals("int", components.get(0).getVarId().getNameDeclaration().getTypeImage()); + } + + @Test(expected = ParseException.class) + public void recordPointBeforeJava16ShouldFail() { + java15.parseResource("Point.java"); + } + + @Test(expected = ParseException.class) + public void recordCtorWithThrowsShouldFail() { + java16.parse(" record R {" + + " R throws IOException {}" + + " }"); + } + + @Test(expected = ParseException.class) + public void recordMustNotExtend() { + java16.parse("record RecordEx(int x) extends Number { }"); + } + + @Test + public void innerRecords() { + doTest("Records"); + } + + @Test(expected = ParseException.class) + public void recordIsARestrictedIdentifier() { + java16.parse("public class record {}"); + } } diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java15p/LocalInterfacesAndEnums.java b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java15p/LocalInterfacesAndEnums.java index 0897eb27a4..cbc20db232 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java15p/LocalInterfacesAndEnums.java +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java15p/LocalInterfacesAndEnums.java @@ -14,6 +14,7 @@ public class LocalInterfacesAndEnums { enum MyLocalEnum { A } - @interface MyLocalAnnotation {} + // not supported anymore with Java16 + //@interface MyLocalAnnotation {} } } diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java15p/LocalInterfacesAndEnums.txt b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java15p/LocalInterfacesAndEnums.txt index d2fcaa476a..6c470f7744 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java15p/LocalInterfacesAndEnums.txt +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java15p/LocalInterfacesAndEnums.txt @@ -4,7 +4,7 @@ +- ClassOrInterfaceBody[@AnonymousInnerClass = false, @EnumChild = false] +- ClassOrInterfaceBodyDeclaration[@AnonymousInnerClass = false, @EnumChild = false, @Kind = DeclarationKind.INITIALIZER] +- Initializer[@Static = false] - +- Block[@containsComment = false] + +- Block[@containsComment = true] +- BlockStatement[@Allocation = false] | +- ClassOrInterfaceDeclaration[@Abstract = false, @BinaryName = "LocalInterfacesAndEnums$1MyLocalClass", @Default = false, @Final = false, @Image = "MyLocalClass", @Interface = false, @Local = true, @Modifiers = 0, @Native = false, @Nested = false, @NonSealed = false, @PackagePrivate = false, @Private = false, @Protected = false, @Public = false, @Sealed = false, @SimpleName = "MyLocalClass", @Static = false, @Strictfp = false, @Synchronized = false, @Transient = false, @TypeKind = TypeKind.CLASS, @Volatile = false] | +- ClassOrInterfaceBody[@AnonymousInnerClass = false, @EnumChild = false] @@ -12,9 +12,6 @@ | +- ClassOrInterfaceDeclaration[@Abstract = false, @BinaryName = "LocalInterfacesAndEnums$1MyLocalInterface", @Default = false, @Final = false, @Image = "MyLocalInterface", @Interface = true, @Local = true, @Modifiers = 0, @Native = false, @Nested = false, @NonSealed = false, @PackagePrivate = false, @Private = false, @Protected = false, @Public = false, @Sealed = false, @SimpleName = "MyLocalInterface", @Static = false, @Strictfp = false, @Synchronized = false, @Transient = false, @TypeKind = TypeKind.INTERFACE, @Volatile = false] | +- ClassOrInterfaceBody[@AnonymousInnerClass = false, @EnumChild = false] +- BlockStatement[@Allocation = false] - | +- EnumDeclaration[@Abstract = false, @BinaryName = "LocalInterfacesAndEnums$MyLocalEnum", @Default = false, @Final = false, @Image = "MyLocalEnum", @Local = true, @Modifiers = 0, @Native = false, @Nested = false, @PackagePrivate = true, @Private = false, @Protected = false, @Public = false, @SimpleName = "MyLocalEnum", @Static = false, @Strictfp = false, @Synchronized = false, @Transient = false, @TypeKind = TypeKind.ENUM, @Volatile = false] - | +- EnumBody[] - | +- EnumConstant[@AnonymousClass = false, @Image = "A"] - +- BlockStatement[@Allocation = false] - +- AnnotationTypeDeclaration[@Abstract = false, @BinaryName = "LocalInterfacesAndEnums$MyLocalAnnotation", @Default = false, @Final = false, @Image = "MyLocalAnnotation", @Local = true, @Modifiers = 0, @Native = false, @Nested = false, @PackagePrivate = true, @Private = false, @Protected = false, @Public = false, @SimpleName = "MyLocalAnnotation", @Static = false, @Strictfp = false, @Synchronized = false, @Transient = false, @TypeKind = TypeKind.ANNOTATION, @Volatile = false] - +- AnnotationTypeBody[] + +- EnumDeclaration[@Abstract = false, @BinaryName = "LocalInterfacesAndEnums$MyLocalEnum", @Default = false, @Final = false, @Image = "MyLocalEnum", @Local = true, @Modifiers = 0, @Native = false, @Nested = false, @PackagePrivate = true, @Private = false, @Protected = false, @Public = false, @SimpleName = "MyLocalEnum", @Static = false, @Strictfp = false, @Synchronized = false, @Transient = false, @TypeKind = TypeKind.ENUM, @Volatile = false] + +- EnumBody[] + +- EnumConstant[@AnonymousClass = false, @Image = "A"] diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java15p/Records.txt b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java15p/Records.txt index 3680bc49e4..e0862ad6da 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java15p/Records.txt +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java15p/Records.txt @@ -135,7 +135,7 @@ | | | +- PrimitiveType[@Array = false, @ArrayDepth = 0, @Boolean = false, @Image = "int"] | | +- VariableDeclaratorId[@Array = false, @ArrayDepth = 0, @ArrayType = false, @ExceptionBlockParameter = false, @ExplicitReceiverParameter = false, @Field = false, @Final = true, @FormalParameter = false, @Image = "hi", @LambdaParameter = false, @LocalVariable = false, @Name = "hi", @PatternBinding = false, @ResourceDeclaration = false, @TypeInferred = false, @VariableName = "hi"] | +- RecordBody[] - | +- RecordConstructorDeclaration[@Abstract = false, @Default = false, @Final = false, @Image = "Range", @Kind = DeclarationKind.RECORD_CONSTRUCTOR, @Modifiers = 1, @Native = false, @PackagePrivate = false, @Private = false, @Protected = false, @Public = true, @Static = false, @Strictfp = false, @Synchronized = false, @Transient = false, @Volatile = false] + | +- CompactConstructorDeclaration[@Abstract = false, @Default = false, @Final = false, @Image = "Range", @Kind = DeclarationKind.RECORD_CONSTRUCTOR, @Modifiers = 1, @Native = false, @PackagePrivate = false, @Private = false, @Protected = false, @Public = true, @Static = false, @Strictfp = false, @Synchronized = false, @Transient = false, @Volatile = false] | | +- Annotation[@AnnotationName = "MyAnnotation"] | | | +- MarkerAnnotation[@AnnotationName = "MyAnnotation"] | | | +- Name[@Image = "MyAnnotation"] diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16/LocalClassAndInterfaceDeclarations.java b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16/LocalClassAndInterfaceDeclarations.java new file mode 100644 index 0000000000..199f47bb76 --- /dev/null +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16/LocalClassAndInterfaceDeclarations.java @@ -0,0 +1,32 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +/** + * @see Local and Nested Static Declarations + */ +public class LocalClassAndInterfaceDeclarations { + + { + class MyLocalClass { + // constant fields are always allowed + static final int constantField = 1; + // static members in local classes are allowed with Java16 + static int staticField; + static void staticMethod() { } + } + + // static local classes are not allowed (neither Java16 nor Java16 Preview) + // Note: PMD's parser allows this, but it would actually be a compile error + //static class MyLocalStaticClass {} + + // local interfaces are allowed with Java16 + interface MyLocalInterface {} + + // local enums are allowed with Java16 + enum MyLocalEnum { A } + + // local annotation types are not allowed in Java16 (have been with Java15 Preview) + //@interface MyLocalAnnotation {} + } +} diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16/LocalClassAndInterfaceDeclarations.txt b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16/LocalClassAndInterfaceDeclarations.txt new file mode 100644 index 0000000000..a104e30dac --- /dev/null +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16/LocalClassAndInterfaceDeclarations.txt @@ -0,0 +1,40 @@ ++- CompilationUnit[@PackageName = "", @declarationsAreInDefaultPackage = true] + +- TypeDeclaration[] + +- ClassOrInterfaceDeclaration[@Abstract = false, @BinaryName = "LocalClassAndInterfaceDeclarations", @Default = false, @Final = false, @Image = "LocalClassAndInterfaceDeclarations", @Interface = false, @Local = false, @Modifiers = 1, @Native = false, @Nested = false, @NonSealed = false, @PackagePrivate = false, @Private = false, @Protected = false, @Public = true, @Sealed = false, @SimpleName = "LocalClassAndInterfaceDeclarations", @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.INITIALIZER] + +- Initializer[@Static = false] + +- Block[@containsComment = true] + +- BlockStatement[@Allocation = false] + | +- ClassOrInterfaceDeclaration[@Abstract = false, @BinaryName = "LocalClassAndInterfaceDeclarations$1MyLocalClass", @Default = false, @Final = false, @Image = "MyLocalClass", @Interface = false, @Local = true, @Modifiers = 0, @Native = false, @Nested = false, @NonSealed = false, @PackagePrivate = false, @Private = false, @Protected = false, @Public = false, @Sealed = false, @SimpleName = "MyLocalClass", @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.FIELD] + | | +- FieldDeclaration[@Abstract = false, @AnnotationMember = false, @Array = false, @ArrayDepth = 0, @Default = false, @Final = true, @InterfaceMember = false, @Modifiers = 48, @Native = false, @PackagePrivate = true, @Private = false, @Protected = false, @Public = false, @Static = true, @Strictfp = false, @Synchronized = false, @SyntacticallyFinal = true, @SyntacticallyPublic = false, @SyntacticallyStatic = true, @Transient = false, @VariableName = "constantField", @Volatile = false] + | | +- Type[@Array = false, @ArrayDepth = 0, @ArrayType = false, @TypeImage = "int"] + | | | +- PrimitiveType[@Array = false, @ArrayDepth = 0, @Boolean = false, @Image = "int"] + | | +- VariableDeclarator[@Initializer = true, @Name = "constantField"] + | | +- VariableDeclaratorId[@Array = false, @ArrayDepth = 0, @ArrayType = false, @ExceptionBlockParameter = false, @ExplicitReceiverParameter = false, @Field = true, @Final = true, @FormalParameter = false, @Image = "constantField", @LambdaParameter = false, @LocalVariable = false, @Name = "constantField", @PatternBinding = false, @ResourceDeclaration = false, @TypeInferred = false, @VariableName = "constantField"] + | | +- VariableInitializer[] + | | +- Expression[@StandAlonePrimitive = true] + | | +- PrimaryExpression[] + | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "1", @FloatLiteral = false, @Image = "1", @IntLiteral = true, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = false, @TextBlock = false, @TextBlockContent = "1", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 1, @ValueAsLong = 1] + | +- ClassOrInterfaceBodyDeclaration[@AnonymousInnerClass = false, @EnumChild = false, @Kind = DeclarationKind.FIELD] + | | +- FieldDeclaration[@Abstract = false, @AnnotationMember = false, @Array = false, @ArrayDepth = 0, @Default = false, @Final = false, @InterfaceMember = false, @Modifiers = 16, @Native = false, @PackagePrivate = true, @Private = false, @Protected = false, @Public = false, @Static = true, @Strictfp = false, @Synchronized = false, @SyntacticallyFinal = false, @SyntacticallyPublic = false, @SyntacticallyStatic = true, @Transient = false, @VariableName = "staticField", @Volatile = false] + | | +- Type[@Array = false, @ArrayDepth = 0, @ArrayType = false, @TypeImage = "int"] + | | | +- PrimitiveType[@Array = false, @ArrayDepth = 0, @Boolean = false, @Image = "int"] + | | +- VariableDeclarator[@Initializer = false, @Name = "staticField"] + | | +- VariableDeclaratorId[@Array = false, @ArrayDepth = 0, @ArrayType = false, @ExceptionBlockParameter = false, @ExplicitReceiverParameter = false, @Field = true, @Final = false, @FormalParameter = false, @Image = "staticField", @LambdaParameter = false, @LocalVariable = false, @Name = "staticField", @PatternBinding = false, @ResourceDeclaration = false, @TypeInferred = false, @VariableName = "staticField"] + | +- ClassOrInterfaceBodyDeclaration[@AnonymousInnerClass = false, @EnumChild = false, @Kind = DeclarationKind.METHOD] + | +- MethodDeclaration[@Abstract = false, @Arity = 0, @Default = false, @Final = false, @InterfaceMember = false, @Kind = MethodLikeKind.METHOD, @MethodName = "staticMethod", @Modifiers = 16, @Name = "staticMethod", @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 = "staticMethod", @ParameterCount = 0] + | | +- FormalParameters[@ParameterCount = 0, @Size = 0] + | +- Block[@containsComment = false] + +- BlockStatement[@Allocation = false] + | +- ClassOrInterfaceDeclaration[@Abstract = false, @BinaryName = "LocalClassAndInterfaceDeclarations$1MyLocalInterface", @Default = false, @Final = false, @Image = "MyLocalInterface", @Interface = true, @Local = true, @Modifiers = 0, @Native = false, @Nested = false, @NonSealed = false, @PackagePrivate = false, @Private = false, @Protected = false, @Public = false, @Sealed = false, @SimpleName = "MyLocalInterface", @Static = false, @Strictfp = false, @Synchronized = false, @Transient = false, @TypeKind = TypeKind.INTERFACE, @Volatile = false] + | +- ClassOrInterfaceBody[@AnonymousInnerClass = false, @EnumChild = false] + +- BlockStatement[@Allocation = false] + +- EnumDeclaration[@Abstract = false, @BinaryName = "LocalClassAndInterfaceDeclarations$MyLocalEnum", @Default = false, @Final = false, @Image = "MyLocalEnum", @Local = true, @Modifiers = 0, @Native = false, @Nested = false, @PackagePrivate = true, @Private = false, @Protected = false, @Public = false, @SimpleName = "MyLocalEnum", @Static = false, @Strictfp = false, @Synchronized = false, @Transient = false, @TypeKind = TypeKind.ENUM, @Volatile = false] + +- EnumBody[] + +- EnumConstant[@AnonymousClass = false, @Image = "A"] diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16/LocalRecords.java b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16/LocalRecords.java new file mode 100644 index 0000000000..4deccde837 --- /dev/null +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16/LocalRecords.java @@ -0,0 +1,45 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +import java.util.stream.Collectors; +import java.util.List; + +/** + * @see JEP 395: Records + */ +public class LocalRecords { + public interface Merchant {} + public static double computeSales(Merchant merchant, int month) { + return month; + } + List findTopMerchants(List merchants, int month) { + // Local record + record MerchantSales(Merchant merchant, double sales) {} + + return merchants.stream() + .map(merchant -> new MerchantSales(merchant, computeSales(merchant, month))) + .sorted((m1, m2) -> Double.compare(m2.sales(), m1.sales())) + .map(MerchantSales::merchant) + .collect(Collectors.toList()); + } + + void methodWithLocalRecordAndModifiers() { + final record MyRecord1(String a) {} + final static record MyRecord2(String a) {} + @Deprecated record MyRecord3(String a) {} + final @Deprecated static record MyRecord4(String a) {} + } + + void methodWithLocalClass() { + class MyLocalClass {} + } + + void methodWithLocalVarsNamedSealed() { + int result = 0; + int non = 1; + int sealed = 2; + result = non-sealed; + System.out.println(result); + } +} diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16/LocalRecords.txt b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16/LocalRecords.txt new file mode 100644 index 0000000000..c274834840 --- /dev/null +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16/LocalRecords.txt @@ -0,0 +1,292 @@ ++- CompilationUnit[@PackageName = "", @declarationsAreInDefaultPackage = true] + +- ImportDeclaration[@ImportOnDemand = false, @ImportedName = "java.util.stream.Collectors", @ImportedSimpleName = "Collectors", @PackageName = "java.util.stream", @Static = false] + | +- Name[@Image = "java.util.stream.Collectors"] + +- ImportDeclaration[@ImportOnDemand = false, @ImportedName = "java.util.List", @ImportedSimpleName = "List", @PackageName = "java.util", @Static = false] + | +- Name[@Image = "java.util.List"] + +- TypeDeclaration[] + +- ClassOrInterfaceDeclaration[@Abstract = false, @BinaryName = "LocalRecords", @Default = false, @Final = false, @Image = "LocalRecords", @Interface = false, @Local = false, @Modifiers = 1, @Native = false, @Nested = false, @NonSealed = false, @PackagePrivate = false, @Private = false, @Protected = false, @Public = true, @Sealed = false, @SimpleName = "LocalRecords", @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.INTERFACE] + | +- ClassOrInterfaceDeclaration[@Abstract = false, @BinaryName = "LocalRecords$Merchant", @Default = false, @Final = false, @Image = "Merchant", @Interface = true, @Local = false, @Modifiers = 1, @Native = false, @Nested = true, @NonSealed = false, @PackagePrivate = false, @Private = false, @Protected = false, @Public = true, @Sealed = false, @SimpleName = "Merchant", @Static = false, @Strictfp = false, @Synchronized = false, @Transient = false, @TypeKind = TypeKind.INTERFACE, @Volatile = false] + | +- ClassOrInterfaceBody[@AnonymousInnerClass = false, @EnumChild = false] + +- ClassOrInterfaceBodyDeclaration[@AnonymousInnerClass = false, @EnumChild = false, @Kind = DeclarationKind.METHOD] + | +- MethodDeclaration[@Abstract = false, @Arity = 2, @Default = false, @Final = false, @InterfaceMember = false, @Kind = MethodLikeKind.METHOD, @MethodName = "computeSales", @Modifiers = 17, @Name = "computeSales", @Native = false, @PackagePrivate = false, @Private = false, @Protected = false, @Public = true, @Static = true, @Strictfp = false, @Synchronized = false, @SyntacticallyAbstract = false, @SyntacticallyPublic = true, @Transient = false, @Void = false, @Volatile = false] + | +- ResultType[@Void = false, @returnsArray = false] + | | +- Type[@Array = false, @ArrayDepth = 0, @ArrayType = false, @TypeImage = "double"] + | | +- PrimitiveType[@Array = false, @ArrayDepth = 0, @Boolean = false, @Image = "double"] + | +- MethodDeclarator[@Image = "computeSales", @ParameterCount = 2] + | | +- FormalParameters[@ParameterCount = 2, @Size = 2] + | | +- 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 = "Merchant"] + | | | | +- ReferenceType[@Array = false, @ArrayDepth = 0] + | | | | +- ClassOrInterfaceType[@AnonymousClass = false, @Array = false, @ArrayDepth = 0, @Image = "Merchant", @ReferenceToClassSameCompilationUnit = true] + | | | +- VariableDeclaratorId[@Array = false, @ArrayDepth = 0, @ArrayType = false, @ExceptionBlockParameter = false, @ExplicitReceiverParameter = false, @Field = false, @Final = false, @FormalParameter = true, @Image = "merchant", @LambdaParameter = false, @LocalVariable = false, @Name = "merchant", @PatternBinding = false, @ResourceDeclaration = false, @TypeInferred = false, @VariableName = "merchant"] + | | +- 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 = "int"] + | | | +- PrimitiveType[@Array = false, @ArrayDepth = 0, @Boolean = false, @Image = "int"] + | | +- VariableDeclaratorId[@Array = false, @ArrayDepth = 0, @ArrayType = false, @ExceptionBlockParameter = false, @ExplicitReceiverParameter = false, @Field = false, @Final = false, @FormalParameter = true, @Image = "month", @LambdaParameter = false, @LocalVariable = false, @Name = "month", @PatternBinding = false, @ResourceDeclaration = false, @TypeInferred = false, @VariableName = "month"] + | +- Block[@containsComment = false] + | +- BlockStatement[@Allocation = false] + | +- Statement[] + | +- ReturnStatement[] + | +- Expression[@StandAlonePrimitive = false] + | +- PrimaryExpression[] + | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | +- Name[@Image = "month"] + +- ClassOrInterfaceBodyDeclaration[@AnonymousInnerClass = false, @EnumChild = false, @Kind = DeclarationKind.METHOD] + | +- MethodDeclaration[@Abstract = false, @Arity = 2, @Default = false, @Final = false, @InterfaceMember = false, @Kind = MethodLikeKind.METHOD, @MethodName = "findTopMerchants", @Modifiers = 0, @Name = "findTopMerchants", @Native = false, @PackagePrivate = true, @Private = false, @Protected = false, @Public = false, @Static = false, @Strictfp = false, @Synchronized = false, @SyntacticallyAbstract = false, @SyntacticallyPublic = false, @Transient = false, @Void = false, @Volatile = false] + | +- ResultType[@Void = false, @returnsArray = false] + | | +- Type[@Array = false, @ArrayDepth = 0, @ArrayType = false, @TypeImage = "List"] + | | +- ReferenceType[@Array = false, @ArrayDepth = 0] + | | +- ClassOrInterfaceType[@AnonymousClass = false, @Array = false, @ArrayDepth = 0, @Image = "List", @ReferenceToClassSameCompilationUnit = false] + | | +- TypeArguments[@Diamond = false] + | | +- TypeArgument[@Wildcard = false] + | | +- ReferenceType[@Array = false, @ArrayDepth = 0] + | | +- ClassOrInterfaceType[@AnonymousClass = false, @Array = false, @ArrayDepth = 0, @Image = "Merchant", @ReferenceToClassSameCompilationUnit = true] + | +- MethodDeclarator[@Image = "findTopMerchants", @ParameterCount = 2] + | | +- FormalParameters[@ParameterCount = 2, @Size = 2] + | | +- 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 = "List"] + | | | | +- ReferenceType[@Array = false, @ArrayDepth = 0] + | | | | +- ClassOrInterfaceType[@AnonymousClass = false, @Array = false, @ArrayDepth = 0, @Image = "List", @ReferenceToClassSameCompilationUnit = false] + | | | | +- TypeArguments[@Diamond = false] + | | | | +- TypeArgument[@Wildcard = false] + | | | | +- ReferenceType[@Array = false, @ArrayDepth = 0] + | | | | +- ClassOrInterfaceType[@AnonymousClass = false, @Array = false, @ArrayDepth = 0, @Image = "Merchant", @ReferenceToClassSameCompilationUnit = true] + | | | +- VariableDeclaratorId[@Array = false, @ArrayDepth = 0, @ArrayType = false, @ExceptionBlockParameter = false, @ExplicitReceiverParameter = false, @Field = false, @Final = false, @FormalParameter = true, @Image = "merchants", @LambdaParameter = false, @LocalVariable = false, @Name = "merchants", @PatternBinding = false, @ResourceDeclaration = false, @TypeInferred = false, @VariableName = "merchants"] + | | +- 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 = "int"] + | | | +- PrimitiveType[@Array = false, @ArrayDepth = 0, @Boolean = false, @Image = "int"] + | | +- VariableDeclaratorId[@Array = false, @ArrayDepth = 0, @ArrayType = false, @ExceptionBlockParameter = false, @ExplicitReceiverParameter = false, @Field = false, @Final = false, @FormalParameter = true, @Image = "month", @LambdaParameter = false, @LocalVariable = false, @Name = "month", @PatternBinding = false, @ResourceDeclaration = false, @TypeInferred = false, @VariableName = "month"] + | +- Block[@containsComment = false] + | +- BlockStatement[@Allocation = false] + | | +- RecordDeclaration[@Abstract = false, @BinaryName = "LocalRecords$MerchantSales", @Default = false, @Final = true, @Image = "MerchantSales", @Local = true, @Modifiers = 0, @Native = false, @Nested = false, @PackagePrivate = true, @Private = false, @Protected = false, @Public = false, @SimpleName = "MerchantSales", @Static = false, @Strictfp = false, @Synchronized = false, @Transient = false, @TypeKind = TypeKind.RECORD, @Volatile = false] + | | +- RecordComponentList[@Size = 2] + | | | +- RecordComponent[@Varargs = false] + | | | | +- Type[@Array = false, @ArrayDepth = 0, @ArrayType = false, @TypeImage = "Merchant"] + | | | | | +- ReferenceType[@Array = false, @ArrayDepth = 0] + | | | | | +- ClassOrInterfaceType[@AnonymousClass = false, @Array = false, @ArrayDepth = 0, @Image = "Merchant", @ReferenceToClassSameCompilationUnit = true] + | | | | +- VariableDeclaratorId[@Array = false, @ArrayDepth = 0, @ArrayType = false, @ExceptionBlockParameter = false, @ExplicitReceiverParameter = false, @Field = false, @Final = true, @FormalParameter = false, @Image = "merchant", @LambdaParameter = false, @LocalVariable = false, @Name = "merchant", @PatternBinding = false, @ResourceDeclaration = false, @TypeInferred = false, @VariableName = "merchant"] + | | | +- RecordComponent[@Varargs = false] + | | | +- Type[@Array = false, @ArrayDepth = 0, @ArrayType = false, @TypeImage = "double"] + | | | | +- PrimitiveType[@Array = false, @ArrayDepth = 0, @Boolean = false, @Image = "double"] + | | | +- VariableDeclaratorId[@Array = false, @ArrayDepth = 0, @ArrayType = false, @ExceptionBlockParameter = false, @ExplicitReceiverParameter = false, @Field = false, @Final = true, @FormalParameter = false, @Image = "sales", @LambdaParameter = false, @LocalVariable = false, @Name = "sales", @PatternBinding = false, @ResourceDeclaration = false, @TypeInferred = false, @VariableName = "sales"] + | | +- RecordBody[] + | +- BlockStatement[@Allocation = false] + | +- Statement[] + | +- ReturnStatement[] + | +- Expression[@StandAlonePrimitive = false] + | +- PrimaryExpression[] + | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | | +- Name[@Image = "merchants.stream"] + | +- PrimarySuffix[@ArgumentCount = 0, @Arguments = true, @ArrayDereference = false] + | | +- Arguments[@ArgumentCount = 0, @Size = 0] + | +- PrimarySuffix[@ArgumentCount = -1, @Arguments = false, @ArrayDereference = false, @Image = "map"] + | +- PrimarySuffix[@ArgumentCount = 1, @Arguments = true, @ArrayDereference = false] + | | +- Arguments[@ArgumentCount = 1, @Size = 1] + | | +- ArgumentList[@Size = 1] + | | +- Expression[@StandAlonePrimitive = false] + | | +- PrimaryExpression[] + | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | | +- LambdaExpression[@Abstract = false, @Default = false, @Final = false, @Kind = MethodLikeKind.LAMBDA, @Modifiers = 0, @Native = false, @PackagePrivate = true, @Private = false, @Protected = false, @Public = false, @Static = false, @Strictfp = false, @Synchronized = false, @Transient = false, @Volatile = false] + | | +- VariableDeclaratorId[@Array = false, @ArrayDepth = 0, @ArrayType = false, @ExceptionBlockParameter = false, @ExplicitReceiverParameter = false, @Field = false, @Final = false, @FormalParameter = true, @Image = "merchant", @LambdaParameter = true, @LocalVariable = false, @Name = "merchant", @PatternBinding = false, @ResourceDeclaration = false, @TypeInferred = true, @VariableName = "merchant"] + | | +- Expression[@StandAlonePrimitive = false] + | | +- PrimaryExpression[] + | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | | +- AllocationExpression[@AnonymousClass = false] + | | +- ClassOrInterfaceType[@AnonymousClass = false, @Array = false, @ArrayDepth = 0, @Image = "MerchantSales", @ReferenceToClassSameCompilationUnit = false] + | | +- Arguments[@ArgumentCount = 2, @Size = 2] + | | +- ArgumentList[@Size = 2] + | | +- Expression[@StandAlonePrimitive = false] + | | | +- PrimaryExpression[] + | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | | | +- Name[@Image = "merchant"] + | | +- Expression[@StandAlonePrimitive = false] + | | +- PrimaryExpression[] + | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | | | +- Name[@Image = "computeSales"] + | | +- PrimarySuffix[@ArgumentCount = 2, @Arguments = true, @ArrayDereference = false] + | | +- Arguments[@ArgumentCount = 2, @Size = 2] + | | +- ArgumentList[@Size = 2] + | | +- Expression[@StandAlonePrimitive = false] + | | | +- PrimaryExpression[] + | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | | | +- Name[@Image = "merchant"] + | | +- Expression[@StandAlonePrimitive = false] + | | +- PrimaryExpression[] + | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | | +- Name[@Image = "month"] + | +- PrimarySuffix[@ArgumentCount = -1, @Arguments = false, @ArrayDereference = false, @Image = "sorted"] + | +- PrimarySuffix[@ArgumentCount = 1, @Arguments = true, @ArrayDereference = false] + | | +- Arguments[@ArgumentCount = 1, @Size = 1] + | | +- ArgumentList[@Size = 1] + | | +- Expression[@StandAlonePrimitive = false] + | | +- PrimaryExpression[] + | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | | +- LambdaExpression[@Abstract = false, @Default = false, @Final = false, @Kind = MethodLikeKind.LAMBDA, @Modifiers = 0, @Native = false, @PackagePrivate = true, @Private = false, @Protected = false, @Public = false, @Static = false, @Strictfp = false, @Synchronized = false, @Transient = false, @Volatile = false] + | | +- VariableDeclaratorId[@Array = false, @ArrayDepth = 0, @ArrayType = false, @ExceptionBlockParameter = false, @ExplicitReceiverParameter = false, @Field = false, @Final = false, @FormalParameter = true, @Image = "m1", @LambdaParameter = true, @LocalVariable = false, @Name = "m1", @PatternBinding = false, @ResourceDeclaration = false, @TypeInferred = true, @VariableName = "m1"] + | | +- VariableDeclaratorId[@Array = false, @ArrayDepth = 0, @ArrayType = false, @ExceptionBlockParameter = false, @ExplicitReceiverParameter = false, @Field = false, @Final = false, @FormalParameter = true, @Image = "m2", @LambdaParameter = true, @LocalVariable = false, @Name = "m2", @PatternBinding = false, @ResourceDeclaration = false, @TypeInferred = true, @VariableName = "m2"] + | | +- Expression[@StandAlonePrimitive = false] + | | +- PrimaryExpression[] + | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | | | +- Name[@Image = "Double.compare"] + | | +- PrimarySuffix[@ArgumentCount = 2, @Arguments = true, @ArrayDereference = false] + | | +- Arguments[@ArgumentCount = 2, @Size = 2] + | | +- ArgumentList[@Size = 2] + | | +- Expression[@StandAlonePrimitive = false] + | | | +- PrimaryExpression[] + | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | | | | +- Name[@Image = "m2.sales"] + | | | +- PrimarySuffix[@ArgumentCount = 0, @Arguments = true, @ArrayDereference = false] + | | | +- Arguments[@ArgumentCount = 0, @Size = 0] + | | +- Expression[@StandAlonePrimitive = false] + | | +- PrimaryExpression[] + | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | | | +- Name[@Image = "m1.sales"] + | | +- PrimarySuffix[@ArgumentCount = 0, @Arguments = true, @ArrayDereference = false] + | | +- Arguments[@ArgumentCount = 0, @Size = 0] + | +- PrimarySuffix[@ArgumentCount = -1, @Arguments = false, @ArrayDereference = false, @Image = "map"] + | +- 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 = "MerchantSales"] + | | +- PrimarySuffix[@ArgumentCount = -1, @Arguments = false, @ArrayDereference = false] + | | +- MemberSelector[] + | | +- MethodReference[@Image = "merchant"] + | +- PrimarySuffix[@ArgumentCount = -1, @Arguments = false, @ArrayDereference = false, @Image = "collect"] + | +- 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 = "Collectors.toList"] + | +- PrimarySuffix[@ArgumentCount = 0, @Arguments = true, @ArrayDereference = false] + | +- Arguments[@ArgumentCount = 0, @Size = 0] + +- ClassOrInterfaceBodyDeclaration[@AnonymousInnerClass = false, @EnumChild = false, @Kind = DeclarationKind.METHOD] + | +- MethodDeclaration[@Abstract = false, @Arity = 0, @Default = false, @Final = false, @InterfaceMember = false, @Kind = MethodLikeKind.METHOD, @MethodName = "methodWithLocalRecordAndModifiers", @Modifiers = 0, @Name = "methodWithLocalRecordAndModifiers", @Native = false, @PackagePrivate = true, @Private = false, @Protected = false, @Public = false, @Static = false, @Strictfp = false, @Synchronized = false, @SyntacticallyAbstract = false, @SyntacticallyPublic = false, @Transient = false, @Void = true, @Volatile = false] + | +- ResultType[@Void = true, @returnsArray = false] + | +- MethodDeclarator[@Image = "methodWithLocalRecordAndModifiers", @ParameterCount = 0] + | | +- FormalParameters[@ParameterCount = 0, @Size = 0] + | +- Block[@containsComment = false] + | +- BlockStatement[@Allocation = false] + | | +- RecordDeclaration[@Abstract = false, @BinaryName = "LocalRecords$MyRecord1", @Default = false, @Final = true, @Image = "MyRecord1", @Local = true, @Modifiers = 32, @Native = false, @Nested = false, @PackagePrivate = true, @Private = false, @Protected = false, @Public = false, @SimpleName = "MyRecord1", @Static = false, @Strictfp = false, @Synchronized = false, @Transient = false, @TypeKind = TypeKind.RECORD, @Volatile = false] + | | +- RecordComponentList[@Size = 1] + | | | +- RecordComponent[@Varargs = 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] + | | | +- VariableDeclaratorId[@Array = false, @ArrayDepth = 0, @ArrayType = false, @ExceptionBlockParameter = false, @ExplicitReceiverParameter = false, @Field = false, @Final = true, @FormalParameter = false, @Image = "a", @LambdaParameter = false, @LocalVariable = false, @Name = "a", @PatternBinding = false, @ResourceDeclaration = false, @TypeInferred = false, @VariableName = "a"] + | | +- RecordBody[] + | +- BlockStatement[@Allocation = false] + | | +- RecordDeclaration[@Abstract = false, @BinaryName = "LocalRecords$MyRecord2", @Default = false, @Final = true, @Image = "MyRecord2", @Local = true, @Modifiers = 48, @Native = false, @Nested = false, @PackagePrivate = true, @Private = false, @Protected = false, @Public = false, @SimpleName = "MyRecord2", @Static = true, @Strictfp = false, @Synchronized = false, @Transient = false, @TypeKind = TypeKind.RECORD, @Volatile = false] + | | +- RecordComponentList[@Size = 1] + | | | +- RecordComponent[@Varargs = 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] + | | | +- VariableDeclaratorId[@Array = false, @ArrayDepth = 0, @ArrayType = false, @ExceptionBlockParameter = false, @ExplicitReceiverParameter = false, @Field = false, @Final = true, @FormalParameter = false, @Image = "a", @LambdaParameter = false, @LocalVariable = false, @Name = "a", @PatternBinding = false, @ResourceDeclaration = false, @TypeInferred = false, @VariableName = "a"] + | | +- RecordBody[] + | +- BlockStatement[@Allocation = false] + | | +- Annotation[@AnnotationName = "Deprecated"] + | | | +- MarkerAnnotation[@AnnotationName = "Deprecated"] + | | | +- Name[@Image = "Deprecated"] + | | +- RecordDeclaration[@Abstract = false, @BinaryName = "LocalRecords$MyRecord3", @Default = false, @Final = true, @Image = "MyRecord3", @Local = true, @Modifiers = 0, @Native = false, @Nested = false, @PackagePrivate = true, @Private = false, @Protected = false, @Public = false, @SimpleName = "MyRecord3", @Static = false, @Strictfp = false, @Synchronized = false, @Transient = false, @TypeKind = TypeKind.RECORD, @Volatile = false] + | | +- RecordComponentList[@Size = 1] + | | | +- RecordComponent[@Varargs = 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] + | | | +- VariableDeclaratorId[@Array = false, @ArrayDepth = 0, @ArrayType = false, @ExceptionBlockParameter = false, @ExplicitReceiverParameter = false, @Field = false, @Final = true, @FormalParameter = false, @Image = "a", @LambdaParameter = false, @LocalVariable = false, @Name = "a", @PatternBinding = false, @ResourceDeclaration = false, @TypeInferred = false, @VariableName = "a"] + | | +- RecordBody[] + | +- BlockStatement[@Allocation = false] + | +- Annotation[@AnnotationName = "Deprecated"] + | | +- MarkerAnnotation[@AnnotationName = "Deprecated"] + | | +- Name[@Image = "Deprecated"] + | +- RecordDeclaration[@Abstract = false, @BinaryName = "LocalRecords$MyRecord4", @Default = false, @Final = true, @Image = "MyRecord4", @Local = true, @Modifiers = 48, @Native = false, @Nested = false, @PackagePrivate = true, @Private = false, @Protected = false, @Public = false, @SimpleName = "MyRecord4", @Static = true, @Strictfp = false, @Synchronized = false, @Transient = false, @TypeKind = TypeKind.RECORD, @Volatile = false] + | +- RecordComponentList[@Size = 1] + | | +- RecordComponent[@Varargs = 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] + | | +- VariableDeclaratorId[@Array = false, @ArrayDepth = 0, @ArrayType = false, @ExceptionBlockParameter = false, @ExplicitReceiverParameter = false, @Field = false, @Final = true, @FormalParameter = false, @Image = "a", @LambdaParameter = false, @LocalVariable = false, @Name = "a", @PatternBinding = false, @ResourceDeclaration = false, @TypeInferred = false, @VariableName = "a"] + | +- RecordBody[] + +- ClassOrInterfaceBodyDeclaration[@AnonymousInnerClass = false, @EnumChild = false, @Kind = DeclarationKind.METHOD] + | +- MethodDeclaration[@Abstract = false, @Arity = 0, @Default = false, @Final = false, @InterfaceMember = false, @Kind = MethodLikeKind.METHOD, @MethodName = "methodWithLocalClass", @Modifiers = 0, @Name = "methodWithLocalClass", @Native = false, @PackagePrivate = true, @Private = false, @Protected = false, @Public = false, @Static = false, @Strictfp = false, @Synchronized = false, @SyntacticallyAbstract = false, @SyntacticallyPublic = false, @Transient = false, @Void = true, @Volatile = false] + | +- ResultType[@Void = true, @returnsArray = false] + | +- MethodDeclarator[@Image = "methodWithLocalClass", @ParameterCount = 0] + | | +- FormalParameters[@ParameterCount = 0, @Size = 0] + | +- Block[@containsComment = false] + | +- BlockStatement[@Allocation = false] + | +- ClassOrInterfaceDeclaration[@Abstract = false, @BinaryName = "LocalRecords$1MyLocalClass", @Default = false, @Final = false, @Image = "MyLocalClass", @Interface = false, @Local = true, @Modifiers = 0, @Native = false, @Nested = false, @NonSealed = false, @PackagePrivate = false, @Private = false, @Protected = false, @Public = false, @Sealed = false, @SimpleName = "MyLocalClass", @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 = 0, @Default = false, @Final = false, @InterfaceMember = false, @Kind = MethodLikeKind.METHOD, @MethodName = "methodWithLocalVarsNamedSealed", @Modifiers = 0, @Name = "methodWithLocalVarsNamedSealed", @Native = false, @PackagePrivate = true, @Private = false, @Protected = false, @Public = false, @Static = false, @Strictfp = false, @Synchronized = false, @SyntacticallyAbstract = false, @SyntacticallyPublic = false, @Transient = false, @Void = true, @Volatile = false] + +- ResultType[@Void = true, @returnsArray = false] + +- MethodDeclarator[@Image = "methodWithLocalVarsNamedSealed", @ParameterCount = 0] + | +- FormalParameters[@ParameterCount = 0, @Size = 0] + +- 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 = "result", @Volatile = false] + | +- Type[@Array = false, @ArrayDepth = 0, @ArrayType = false, @TypeImage = "int"] + | | +- PrimitiveType[@Array = false, @ArrayDepth = 0, @Boolean = false, @Image = "int"] + | +- VariableDeclarator[@Initializer = true, @Name = "result"] + | +- VariableDeclaratorId[@Array = false, @ArrayDepth = 0, @ArrayType = false, @ExceptionBlockParameter = false, @ExplicitReceiverParameter = false, @Field = false, @Final = false, @FormalParameter = false, @Image = "result", @LambdaParameter = false, @LocalVariable = true, @Name = "result", @PatternBinding = false, @ResourceDeclaration = false, @TypeInferred = false, @VariableName = "result"] + | +- VariableInitializer[] + | +- Expression[@StandAlonePrimitive = true] + | +- PrimaryExpression[] + | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "0", @FloatLiteral = false, @Image = "0", @IntLiteral = true, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = false, @TextBlock = false, @TextBlockContent = "0", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + +- 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 = "non", @Volatile = false] + | +- Type[@Array = false, @ArrayDepth = 0, @ArrayType = false, @TypeImage = "int"] + | | +- PrimitiveType[@Array = false, @ArrayDepth = 0, @Boolean = false, @Image = "int"] + | +- VariableDeclarator[@Initializer = true, @Name = "non"] + | +- VariableDeclaratorId[@Array = false, @ArrayDepth = 0, @ArrayType = false, @ExceptionBlockParameter = false, @ExplicitReceiverParameter = false, @Field = false, @Final = false, @FormalParameter = false, @Image = "non", @LambdaParameter = false, @LocalVariable = true, @Name = "non", @PatternBinding = false, @ResourceDeclaration = false, @TypeInferred = false, @VariableName = "non"] + | +- VariableInitializer[] + | +- Expression[@StandAlonePrimitive = true] + | +- PrimaryExpression[] + | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "1", @FloatLiteral = false, @Image = "1", @IntLiteral = true, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = false, @TextBlock = false, @TextBlockContent = "1", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 1, @ValueAsLong = 1] + +- 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 = "sealed", @Volatile = false] + | +- Type[@Array = false, @ArrayDepth = 0, @ArrayType = false, @TypeImage = "int"] + | | +- PrimitiveType[@Array = false, @ArrayDepth = 0, @Boolean = false, @Image = "int"] + | +- VariableDeclarator[@Initializer = true, @Name = "sealed"] + | +- VariableDeclaratorId[@Array = false, @ArrayDepth = 0, @ArrayType = false, @ExceptionBlockParameter = false, @ExplicitReceiverParameter = false, @Field = false, @Final = false, @FormalParameter = false, @Image = "sealed", @LambdaParameter = false, @LocalVariable = true, @Name = "sealed", @PatternBinding = false, @ResourceDeclaration = false, @TypeInferred = false, @VariableName = "sealed"] + | +- VariableInitializer[] + | +- Expression[@StandAlonePrimitive = true] + | +- PrimaryExpression[] + | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "2", @FloatLiteral = false, @Image = "2", @IntLiteral = true, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = false, @TextBlock = false, @TextBlockContent = "2", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 2, @ValueAsLong = 2] + +- BlockStatement[@Allocation = false] + | +- Statement[] + | +- StatementExpression[] + | +- PrimaryExpression[] + | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | | +- Name[@Image = "result"] + | +- AssignmentOperator[@Compound = false, @Image = "="] + | +- Expression[@StandAlonePrimitive = false] + | +- AdditiveExpression[@Image = "-", @Operator = "-"] + | +- PrimaryExpression[] + | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | | +- Name[@Image = "non"] + | +- PrimaryExpression[] + | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | +- Name[@Image = "sealed"] + +- 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 = "result"] diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16/Point.java b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16/Point.java new file mode 100644 index 0000000000..2efa76b978 --- /dev/null +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16/Point.java @@ -0,0 +1,14 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +/** + * @see JEP 395: Records + */ +public record Point(int x, int y) { + + public static void main(String[] args) { + Point p = new Point(1, 2); + System.out.println("p = " + p); + } +} diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16/Point.txt b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16/Point.txt new file mode 100644 index 0000000000..088f830cb6 --- /dev/null +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16/Point.txt @@ -0,0 +1,64 @@ ++- CompilationUnit[@PackageName = "", @declarationsAreInDefaultPackage = true] + +- TypeDeclaration[] + +- RecordDeclaration[@Abstract = false, @BinaryName = "Point", @Default = false, @Final = true, @Image = "Point", @Local = false, @Modifiers = 1, @Native = false, @Nested = false, @PackagePrivate = false, @Private = false, @Protected = false, @Public = true, @SimpleName = "Point", @Static = false, @Strictfp = false, @Synchronized = 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, @FormalParameter = false, @Image = "x", @LambdaParameter = false, @LocalVariable = false, @Name = "x", @PatternBinding = false, @ResourceDeclaration = false, @TypeInferred = false, @VariableName = "x"] + | +- 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, @FormalParameter = false, @Image = "y", @LambdaParameter = false, @LocalVariable = false, @Name = "y", @PatternBinding = false, @ResourceDeclaration = false, @TypeInferred = false, @VariableName = "y"] + +- RecordBody[] + +- 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, @FormalParameter = true, @Image = "args", @LambdaParameter = false, @LocalVariable = false, @Name = "args", @PatternBinding = false, @ResourceDeclaration = false, @TypeInferred = false, @VariableName = "args"] + +- Block[@containsComment = false] + +- BlockStatement[@Allocation = true] + | +- 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 = "p", @Volatile = false] + | +- 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] + | +- VariableDeclarator[@Initializer = true, @Name = "p"] + | +- VariableDeclaratorId[@Array = false, @ArrayDepth = 0, @ArrayType = false, @ExceptionBlockParameter = false, @ExplicitReceiverParameter = false, @Field = false, @Final = false, @FormalParameter = false, @Image = "p", @LambdaParameter = false, @LocalVariable = true, @Name = "p", @PatternBinding = false, @ResourceDeclaration = false, @TypeInferred = false, @VariableName = "p"] + | +- VariableInitializer[] + | +- Expression[@StandAlonePrimitive = false] + | +- PrimaryExpression[] + | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | +- AllocationExpression[@AnonymousClass = false] + | +- ClassOrInterfaceType[@AnonymousClass = false, @Array = false, @ArrayDepth = 0, @Image = "Point", @ReferenceToClassSameCompilationUnit = false] + | +- Arguments[@ArgumentCount = 2, @Size = 2] + | +- ArgumentList[@Size = 2] + | +- Expression[@StandAlonePrimitive = true] + | | +- PrimaryExpression[] + | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "1", @FloatLiteral = false, @Image = "1", @IntLiteral = true, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = false, @TextBlock = false, @TextBlockContent = "1", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 1, @ValueAsLong = 1] + | +- Expression[@StandAlonePrimitive = true] + | +- PrimaryExpression[] + | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "2", @FloatLiteral = false, @Image = "2", @IntLiteral = true, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = false, @TextBlock = false, @TextBlockContent = "2", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 2, @ValueAsLong = 2] + +- 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] + +- AdditiveExpression[@Image = "+", @Operator = "+"] + +- PrimaryExpression[] + | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""p = "", @FloatLiteral = false, @Image = ""p = "", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""p = "", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + +- PrimaryExpression[] + +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + +- Name[@Image = "p"] diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16/Records.java b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16/Records.java new file mode 100644 index 0000000000..c542d56727 --- /dev/null +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16/Records.java @@ -0,0 +1,68 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +import java.io.IOException; +import java.lang.annotation.Target; +import java.lang.annotation.ElementType; + +/** + * @see JEP 395: Records + */ +public class Records { + + @Target(ElementType.TYPE_USE) + @interface Nullable { } + + @Target({ElementType.CONSTRUCTOR, ElementType.PARAMETER}) + @interface MyAnnotation { } + + public record MyComplex(int real, @Deprecated int imaginary) { + // explicit declaration of a canonical constructor + @MyAnnotation + public MyComplex(@MyAnnotation int real, int imaginary) { + if (real > 100) throw new IllegalArgumentException("too big"); + this.real = real; + this.imaginary = imaginary; + } + + public record Nested(int a) {} + + public static class NestedClass { } + } + + + public record Range(int lo, int hi) { + // compact record constructor + @MyAnnotation + public Range { + if (lo > hi) /* referring here to the implicit constructor parameters */ + throw new IllegalArgumentException(String.format("(%d,%d)", lo, hi)); + } + + public void foo() { } + } + + public record VarRec(@Nullable @Deprecated String @Nullable ... x) {} + + public record ArrayRec(int[] x) {} + + public record EmptyRec() { + public void foo() { } + public Type bar() { return null; } + public static void baz() { + EmptyRec r = new EmptyRec<>(); + System.out.println(r); + } + } + + // see https://www.javaspecialists.eu/archive/Issue276.html + public interface Person { + String firstName(); + String lastName(); + } + public record PersonRecord(String firstName, String lastName) + implements Person, java.io.Serializable { + + } +} diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16/Records.txt b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16/Records.txt new file mode 100644 index 0000000000..43ad6b3cbb --- /dev/null +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16/Records.txt @@ -0,0 +1,317 @@ ++- CompilationUnit[@PackageName = "", @declarationsAreInDefaultPackage = true] + +- ImportDeclaration[@ImportOnDemand = false, @ImportedName = "java.io.IOException", @ImportedSimpleName = "IOException", @PackageName = "java.io", @Static = false] + | +- Name[@Image = "java.io.IOException"] + +- ImportDeclaration[@ImportOnDemand = false, @ImportedName = "java.lang.annotation.Target", @ImportedSimpleName = "Target", @PackageName = "java.lang.annotation", @Static = false] + | +- Name[@Image = "java.lang.annotation.Target"] + +- ImportDeclaration[@ImportOnDemand = false, @ImportedName = "java.lang.annotation.ElementType", @ImportedSimpleName = "ElementType", @PackageName = "java.lang.annotation", @Static = false] + | +- Name[@Image = "java.lang.annotation.ElementType"] + +- TypeDeclaration[] + +- ClassOrInterfaceDeclaration[@Abstract = false, @BinaryName = "Records", @Default = false, @Final = false, @Image = "Records", @Interface = false, @Local = false, @Modifiers = 1, @Native = false, @Nested = false, @NonSealed = false, @PackagePrivate = false, @Private = false, @Protected = false, @Public = true, @Sealed = false, @SimpleName = "Records", @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.ANNOTATION] + | +- Annotation[@AnnotationName = "Target"] + | | +- SingleMemberAnnotation[@AnnotationName = "Target"] + | | +- Name[@Image = "Target"] + | | +- MemberValue[] + | | +- PrimaryExpression[] + | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | | +- Name[@Image = "ElementType.TYPE_USE"] + | +- AnnotationTypeDeclaration[@Abstract = false, @BinaryName = "Records$Nullable", @Default = false, @Final = false, @Image = "Nullable", @Local = false, @Modifiers = 0, @Native = false, @Nested = true, @PackagePrivate = true, @Private = false, @Protected = false, @Public = false, @SimpleName = "Nullable", @Static = false, @Strictfp = false, @Synchronized = false, @Transient = false, @TypeKind = TypeKind.ANNOTATION, @Volatile = false] + | +- AnnotationTypeBody[] + +- ClassOrInterfaceBodyDeclaration[@AnonymousInnerClass = false, @EnumChild = false, @Kind = DeclarationKind.ANNOTATION] + | +- Annotation[@AnnotationName = "Target"] + | | +- SingleMemberAnnotation[@AnnotationName = "Target"] + | | +- Name[@Image = "Target"] + | | +- MemberValue[] + | | +- MemberValueArrayInitializer[] + | | +- MemberValue[] + | | | +- PrimaryExpression[] + | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | | | +- Name[@Image = "ElementType.CONSTRUCTOR"] + | | +- MemberValue[] + | | +- PrimaryExpression[] + | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | | +- Name[@Image = "ElementType.PARAMETER"] + | +- AnnotationTypeDeclaration[@Abstract = false, @BinaryName = "Records$MyAnnotation", @Default = false, @Final = false, @Image = "MyAnnotation", @Local = false, @Modifiers = 0, @Native = false, @Nested = true, @PackagePrivate = true, @Private = false, @Protected = false, @Public = false, @SimpleName = "MyAnnotation", @Static = false, @Strictfp = false, @Synchronized = false, @Transient = false, @TypeKind = TypeKind.ANNOTATION, @Volatile = false] + | +- AnnotationTypeBody[] + +- ClassOrInterfaceBodyDeclaration[@AnonymousInnerClass = false, @EnumChild = false, @Kind = DeclarationKind.RECORD] + | +- RecordDeclaration[@Abstract = false, @BinaryName = "Records$MyComplex", @Default = false, @Final = true, @Image = "MyComplex", @Local = false, @Modifiers = 1, @Native = false, @Nested = true, @PackagePrivate = false, @Private = false, @Protected = false, @Public = true, @SimpleName = "MyComplex", @Static = false, @Strictfp = false, @Synchronized = 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, @FormalParameter = false, @Image = "real", @LambdaParameter = false, @LocalVariable = false, @Name = "real", @PatternBinding = false, @ResourceDeclaration = false, @TypeInferred = false, @VariableName = "real"] + | | +- RecordComponent[@Varargs = false] + | | +- Annotation[@AnnotationName = "Deprecated"] + | | | +- MarkerAnnotation[@AnnotationName = "Deprecated"] + | | | +- Name[@Image = "Deprecated"] + | | +- 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, @FormalParameter = false, @Image = "imaginary", @LambdaParameter = false, @LocalVariable = false, @Name = "imaginary", @PatternBinding = false, @ResourceDeclaration = false, @TypeInferred = false, @VariableName = "imaginary"] + | +- RecordBody[] + | +- ClassOrInterfaceBodyDeclaration[@AnonymousInnerClass = false, @EnumChild = false, @Kind = DeclarationKind.CONSTRUCTOR] + | | +- Annotation[@AnnotationName = "MyAnnotation"] + | | | +- MarkerAnnotation[@AnnotationName = "MyAnnotation"] + | | | +- Name[@Image = "MyAnnotation"] + | | +- ConstructorDeclaration[@Abstract = false, @Arity = 2, @Default = false, @Final = false, @Image = "MyComplex", @Kind = MethodLikeKind.CONSTRUCTOR, @Modifiers = 1, @Native = false, @PackagePrivate = false, @ParameterCount = 2, @Private = false, @Protected = false, @Public = true, @Static = false, @Strictfp = false, @Synchronized = false, @Transient = false, @Volatile = false, @containsComment = false] + | | +- FormalParameters[@ParameterCount = 2, @Size = 2] + | | | +- 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] + | | | | +- Annotation[@AnnotationName = "MyAnnotation"] + | | | | | +- MarkerAnnotation[@AnnotationName = "MyAnnotation"] + | | | | | +- Name[@Image = "MyAnnotation"] + | | | | +- 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 = false, @FormalParameter = true, @Image = "real", @LambdaParameter = false, @LocalVariable = false, @Name = "real", @PatternBinding = false, @ResourceDeclaration = false, @TypeInferred = false, @VariableName = "real"] + | | | +- 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 = "int"] + | | | | +- PrimitiveType[@Array = false, @ArrayDepth = 0, @Boolean = false, @Image = "int"] + | | | +- VariableDeclaratorId[@Array = false, @ArrayDepth = 0, @ArrayType = false, @ExceptionBlockParameter = false, @ExplicitReceiverParameter = false, @Field = false, @Final = false, @FormalParameter = true, @Image = "imaginary", @LambdaParameter = false, @LocalVariable = false, @Name = "imaginary", @PatternBinding = false, @ResourceDeclaration = false, @TypeInferred = false, @VariableName = "imaginary"] + | | +- BlockStatement[@Allocation = true] + | | | +- Statement[] + | | | +- IfStatement[@Else = false] + | | | +- Expression[@StandAlonePrimitive = false] + | | | | +- RelationalExpression[@Image = ">"] + | | | | +- PrimaryExpression[] + | | | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | | | | | +- Name[@Image = "real"] + | | | | +- PrimaryExpression[] + | | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "100", @FloatLiteral = false, @Image = "100", @IntLiteral = true, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = false, @TextBlock = false, @TextBlockContent = "100", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 100, @ValueAsLong = 100] + | | | +- Statement[] + | | | +- ThrowStatement[@FirstClassOrInterfaceTypeImage = "IllegalArgumentException"] + | | | +- Expression[@StandAlonePrimitive = false] + | | | +- PrimaryExpression[] + | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | | | +- AllocationExpression[@AnonymousClass = false] + | | | +- ClassOrInterfaceType[@AnonymousClass = false, @Array = false, @ArrayDepth = 0, @Image = "IllegalArgumentException", @ReferenceToClassSameCompilationUnit = false] + | | | +- Arguments[@ArgumentCount = 1, @Size = 1] + | | | +- ArgumentList[@Size = 1] + | | | +- Expression[@StandAlonePrimitive = false] + | | | +- PrimaryExpression[] + | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""too big"", @FloatLiteral = false, @Image = ""too big"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""too big"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | +- BlockStatement[@Allocation = false] + | | | +- Statement[] + | | | +- StatementExpression[] + | | | +- PrimaryExpression[] + | | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = true] + | | | | +- PrimarySuffix[@ArgumentCount = -1, @Arguments = false, @ArrayDereference = false, @Image = "real"] + | | | +- AssignmentOperator[@Compound = false, @Image = "="] + | | | +- Expression[@StandAlonePrimitive = false] + | | | +- PrimaryExpression[] + | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | | | +- Name[@Image = "real"] + | | +- BlockStatement[@Allocation = false] + | | +- Statement[] + | | +- StatementExpression[] + | | +- PrimaryExpression[] + | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = true] + | | | +- PrimarySuffix[@ArgumentCount = -1, @Arguments = false, @ArrayDereference = false, @Image = "imaginary"] + | | +- AssignmentOperator[@Compound = false, @Image = "="] + | | +- Expression[@StandAlonePrimitive = false] + | | +- PrimaryExpression[] + | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | | +- Name[@Image = "imaginary"] + | +- ClassOrInterfaceBodyDeclaration[@AnonymousInnerClass = false, @EnumChild = false, @Kind = DeclarationKind.RECORD] + | | +- RecordDeclaration[@Abstract = false, @BinaryName = "Records$MyComplex$Nested", @Default = false, @Final = true, @Image = "Nested", @Local = false, @Modifiers = 1, @Native = false, @Nested = true, @PackagePrivate = false, @Private = false, @Protected = false, @Public = true, @SimpleName = "Nested", @Static = false, @Strictfp = false, @Synchronized = false, @Transient = false, @TypeKind = TypeKind.RECORD, @Volatile = false] + | | +- RecordComponentList[@Size = 1] + | | | +- 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, @FormalParameter = false, @Image = "a", @LambdaParameter = false, @LocalVariable = false, @Name = "a", @PatternBinding = false, @ResourceDeclaration = false, @TypeInferred = false, @VariableName = "a"] + | | +- RecordBody[] + | +- ClassOrInterfaceBodyDeclaration[@AnonymousInnerClass = false, @EnumChild = false, @Kind = DeclarationKind.CLASS] + | +- ClassOrInterfaceDeclaration[@Abstract = false, @BinaryName = "Records$MyComplex$NestedClass", @Default = false, @Final = false, @Image = "NestedClass", @Interface = false, @Local = false, @Modifiers = 17, @Native = false, @Nested = true, @NonSealed = false, @PackagePrivate = false, @Private = false, @Protected = false, @Public = true, @Sealed = false, @SimpleName = "NestedClass", @Static = true, @Strictfp = false, @Synchronized = false, @Transient = false, @TypeKind = TypeKind.CLASS, @Volatile = false] + | +- ClassOrInterfaceBody[@AnonymousInnerClass = false, @EnumChild = false] + +- ClassOrInterfaceBodyDeclaration[@AnonymousInnerClass = false, @EnumChild = false, @Kind = DeclarationKind.RECORD] + | +- RecordDeclaration[@Abstract = false, @BinaryName = "Records$Range", @Default = false, @Final = true, @Image = "Range", @Local = false, @Modifiers = 1, @Native = false, @Nested = true, @PackagePrivate = false, @Private = false, @Protected = false, @Public = true, @SimpleName = "Range", @Static = false, @Strictfp = false, @Synchronized = 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, @FormalParameter = false, @Image = "lo", @LambdaParameter = false, @LocalVariable = false, @Name = "lo", @PatternBinding = false, @ResourceDeclaration = false, @TypeInferred = false, @VariableName = "lo"] + | | +- 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, @FormalParameter = false, @Image = "hi", @LambdaParameter = false, @LocalVariable = false, @Name = "hi", @PatternBinding = false, @ResourceDeclaration = false, @TypeInferred = false, @VariableName = "hi"] + | +- RecordBody[] + | +- CompactConstructorDeclaration[@Abstract = false, @Default = false, @Final = false, @Image = "Range", @Kind = DeclarationKind.RECORD_CONSTRUCTOR, @Modifiers = 1, @Native = false, @PackagePrivate = false, @Private = false, @Protected = false, @Public = true, @Static = false, @Strictfp = false, @Synchronized = false, @Transient = false, @Volatile = false] + | | +- Annotation[@AnnotationName = "MyAnnotation"] + | | | +- MarkerAnnotation[@AnnotationName = "MyAnnotation"] + | | | +- Name[@Image = "MyAnnotation"] + | | +- Block[@containsComment = false] + | | +- BlockStatement[@Allocation = true] + | | +- Statement[] + | | +- IfStatement[@Else = false] + | | +- Expression[@StandAlonePrimitive = false] + | | | +- RelationalExpression[@Image = ">"] + | | | +- PrimaryExpression[] + | | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | | | | +- Name[@Image = "lo"] + | | | +- PrimaryExpression[] + | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | | | +- Name[@Image = "hi"] + | | +- Statement[] + | | +- ThrowStatement[@FirstClassOrInterfaceTypeImage = "IllegalArgumentException"] + | | +- Expression[@StandAlonePrimitive = false] + | | +- PrimaryExpression[] + | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | | +- AllocationExpression[@AnonymousClass = false] + | | +- ClassOrInterfaceType[@AnonymousClass = false, @Array = false, @ArrayDepth = 0, @Image = "IllegalArgumentException", @ReferenceToClassSameCompilationUnit = false] + | | +- Arguments[@ArgumentCount = 1, @Size = 1] + | | +- ArgumentList[@Size = 1] + | | +- Expression[@StandAlonePrimitive = false] + | | +- PrimaryExpression[] + | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | | | +- Name[@Image = "String.format"] + | | +- PrimarySuffix[@ArgumentCount = 3, @Arguments = true, @ArrayDereference = false] + | | +- Arguments[@ArgumentCount = 3, @Size = 3] + | | +- ArgumentList[@Size = 3] + | | +- Expression[@StandAlonePrimitive = false] + | | | +- PrimaryExpression[] + | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""(%d,%d)"", @FloatLiteral = false, @Image = ""(%d,%d)"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""(%d,%d)"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | +- Expression[@StandAlonePrimitive = false] + | | | +- PrimaryExpression[] + | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | | | +- Name[@Image = "lo"] + | | +- Expression[@StandAlonePrimitive = false] + | | +- PrimaryExpression[] + | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | | +- Name[@Image = "hi"] + | +- ClassOrInterfaceBodyDeclaration[@AnonymousInnerClass = false, @EnumChild = false, @Kind = DeclarationKind.METHOD] + | +- MethodDeclaration[@Abstract = false, @Arity = 0, @Default = false, @Final = false, @InterfaceMember = false, @Kind = MethodLikeKind.METHOD, @MethodName = "foo", @Modifiers = 1, @Name = "foo", @Native = false, @PackagePrivate = false, @Private = false, @Protected = false, @Public = true, @Static = false, @Strictfp = false, @Synchronized = false, @SyntacticallyAbstract = false, @SyntacticallyPublic = true, @Transient = false, @Void = true, @Volatile = false] + | +- ResultType[@Void = true, @returnsArray = false] + | +- MethodDeclarator[@Image = "foo", @ParameterCount = 0] + | | +- FormalParameters[@ParameterCount = 0, @Size = 0] + | +- Block[@containsComment = false] + +- ClassOrInterfaceBodyDeclaration[@AnonymousInnerClass = false, @EnumChild = false, @Kind = DeclarationKind.RECORD] + | +- RecordDeclaration[@Abstract = false, @BinaryName = "Records$VarRec", @Default = false, @Final = true, @Image = "VarRec", @Local = false, @Modifiers = 1, @Native = false, @Nested = true, @PackagePrivate = false, @Private = false, @Protected = false, @Public = true, @SimpleName = "VarRec", @Static = false, @Strictfp = false, @Synchronized = false, @Transient = false, @TypeKind = TypeKind.RECORD, @Volatile = false] + | +- RecordComponentList[@Size = 1] + | | +- RecordComponent[@Varargs = true] + | | +- Annotation[@AnnotationName = "Nullable"] + | | | +- MarkerAnnotation[@AnnotationName = "Nullable"] + | | | +- Name[@Image = "Nullable"] + | | +- Annotation[@AnnotationName = "Deprecated"] + | | | +- MarkerAnnotation[@AnnotationName = "Deprecated"] + | | | +- Name[@Image = "Deprecated"] + | | +- 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] + | | | +- Annotation[@AnnotationName = "Nullable"] + | | | +- MarkerAnnotation[@AnnotationName = "Nullable"] + | | | +- Name[@Image = "Nullable"] + | | +- VariableDeclaratorId[@Array = false, @ArrayDepth = 0, @ArrayType = false, @ExceptionBlockParameter = false, @ExplicitReceiverParameter = false, @Field = false, @Final = true, @FormalParameter = false, @Image = "x", @LambdaParameter = false, @LocalVariable = false, @Name = "x", @PatternBinding = false, @ResourceDeclaration = false, @TypeInferred = false, @VariableName = "x"] + | +- RecordBody[] + +- ClassOrInterfaceBodyDeclaration[@AnonymousInnerClass = false, @EnumChild = false, @Kind = DeclarationKind.RECORD] + | +- RecordDeclaration[@Abstract = false, @BinaryName = "Records$ArrayRec", @Default = false, @Final = true, @Image = "ArrayRec", @Local = false, @Modifiers = 1, @Native = false, @Nested = true, @PackagePrivate = false, @Private = false, @Protected = false, @Public = true, @SimpleName = "ArrayRec", @Static = false, @Strictfp = false, @Synchronized = false, @Transient = false, @TypeKind = TypeKind.RECORD, @Volatile = false] + | +- RecordComponentList[@Size = 1] + | | +- RecordComponent[@Varargs = false] + | | +- 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 = true, @FormalParameter = false, @Image = "x", @LambdaParameter = false, @LocalVariable = false, @Name = "x", @PatternBinding = false, @ResourceDeclaration = false, @TypeInferred = false, @VariableName = "x"] + | +- RecordBody[] + +- ClassOrInterfaceBodyDeclaration[@AnonymousInnerClass = false, @EnumChild = false, @Kind = DeclarationKind.RECORD] + | +- RecordDeclaration[@Abstract = false, @BinaryName = "Records$EmptyRec", @Default = false, @Final = true, @Image = "EmptyRec", @Local = false, @Modifiers = 1, @Native = false, @Nested = true, @PackagePrivate = false, @Private = false, @Protected = false, @Public = true, @SimpleName = "EmptyRec", @Static = false, @Strictfp = false, @Synchronized = false, @Transient = false, @TypeKind = TypeKind.RECORD, @Volatile = false] + | +- TypeParameters[] + | | +- TypeParameter[@Image = "Type", @Name = "Type", @ParameterName = "Type", @TypeBound = false] + | +- RecordComponentList[@Size = 0] + | +- RecordBody[] + | +- ClassOrInterfaceBodyDeclaration[@AnonymousInnerClass = false, @EnumChild = false, @Kind = DeclarationKind.METHOD] + | | +- MethodDeclaration[@Abstract = false, @Arity = 0, @Default = false, @Final = false, @InterfaceMember = false, @Kind = MethodLikeKind.METHOD, @MethodName = "foo", @Modifiers = 1, @Name = "foo", @Native = false, @PackagePrivate = false, @Private = false, @Protected = false, @Public = true, @Static = false, @Strictfp = false, @Synchronized = false, @SyntacticallyAbstract = false, @SyntacticallyPublic = true, @Transient = false, @Void = true, @Volatile = false] + | | +- ResultType[@Void = true, @returnsArray = false] + | | +- MethodDeclarator[@Image = "foo", @ParameterCount = 0] + | | | +- FormalParameters[@ParameterCount = 0, @Size = 0] + | | +- Block[@containsComment = false] + | +- ClassOrInterfaceBodyDeclaration[@AnonymousInnerClass = false, @EnumChild = false, @Kind = DeclarationKind.METHOD] + | | +- MethodDeclaration[@Abstract = false, @Arity = 0, @Default = false, @Final = false, @InterfaceMember = false, @Kind = MethodLikeKind.METHOD, @MethodName = "bar", @Modifiers = 1, @Name = "bar", @Native = false, @PackagePrivate = false, @Private = false, @Protected = false, @Public = true, @Static = false, @Strictfp = false, @Synchronized = false, @SyntacticallyAbstract = false, @SyntacticallyPublic = true, @Transient = false, @Void = false, @Volatile = false] + | | +- ResultType[@Void = false, @returnsArray = false] + | | | +- Type[@Array = false, @ArrayDepth = 0, @ArrayType = false, @TypeImage = "Type"] + | | | +- ReferenceType[@Array = false, @ArrayDepth = 0] + | | | +- ClassOrInterfaceType[@AnonymousClass = false, @Array = false, @ArrayDepth = 0, @Image = "Type", @ReferenceToClassSameCompilationUnit = false] + | | +- MethodDeclarator[@Image = "bar", @ParameterCount = 0] + | | | +- FormalParameters[@ParameterCount = 0, @Size = 0] + | | +- Block[@containsComment = false] + | | +- BlockStatement[@Allocation = false] + | | +- Statement[] + | | +- ReturnStatement[] + | | +- 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[] + | +- ClassOrInterfaceBodyDeclaration[@AnonymousInnerClass = false, @EnumChild = false, @Kind = DeclarationKind.METHOD] + | +- MethodDeclaration[@Abstract = false, @Arity = 0, @Default = false, @Final = false, @InterfaceMember = false, @Kind = MethodLikeKind.METHOD, @MethodName = "baz", @Modifiers = 17, @Name = "baz", @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 = "baz", @ParameterCount = 0] + | | +- FormalParameters[@ParameterCount = 0, @Size = 0] + | +- Block[@containsComment = false] + | +- BlockStatement[@Allocation = true] + | | +- 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 = "r", @Volatile = false] + | | +- Type[@Array = false, @ArrayDepth = 0, @ArrayType = false, @TypeImage = "EmptyRec"] + | | | +- ReferenceType[@Array = false, @ArrayDepth = 0] + | | | +- ClassOrInterfaceType[@AnonymousClass = false, @Array = false, @ArrayDepth = 0, @Image = "EmptyRec", @ReferenceToClassSameCompilationUnit = false] + | | | +- TypeArguments[@Diamond = false] + | | | +- TypeArgument[@Wildcard = false] + | | | +- ReferenceType[@Array = false, @ArrayDepth = 0] + | | | +- ClassOrInterfaceType[@AnonymousClass = false, @Array = false, @ArrayDepth = 0, @Image = "String", @ReferenceToClassSameCompilationUnit = false] + | | +- VariableDeclarator[@Initializer = true, @Name = "r"] + | | +- VariableDeclaratorId[@Array = false, @ArrayDepth = 0, @ArrayType = false, @ExceptionBlockParameter = false, @ExplicitReceiverParameter = false, @Field = false, @Final = false, @FormalParameter = false, @Image = "r", @LambdaParameter = false, @LocalVariable = true, @Name = "r", @PatternBinding = false, @ResourceDeclaration = false, @TypeInferred = false, @VariableName = "r"] + | | +- VariableInitializer[] + | | +- Expression[@StandAlonePrimitive = false] + | | +- PrimaryExpression[] + | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | | +- AllocationExpression[@AnonymousClass = false] + | | +- ClassOrInterfaceType[@AnonymousClass = false, @Array = false, @ArrayDepth = 0, @Image = "EmptyRec", @ReferenceToClassSameCompilationUnit = false] + | | | +- TypeArguments[@Diamond = true] + | | +- 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 = "r"] + +- ClassOrInterfaceBodyDeclaration[@AnonymousInnerClass = false, @EnumChild = false, @Kind = DeclarationKind.INTERFACE] + | +- ClassOrInterfaceDeclaration[@Abstract = false, @BinaryName = "Records$Person", @Default = false, @Final = false, @Image = "Person", @Interface = true, @Local = false, @Modifiers = 1, @Native = false, @Nested = true, @NonSealed = false, @PackagePrivate = false, @Private = false, @Protected = false, @Public = true, @Sealed = false, @SimpleName = "Person", @Static = false, @Strictfp = false, @Synchronized = false, @Transient = false, @TypeKind = TypeKind.INTERFACE, @Volatile = false] + | +- ClassOrInterfaceBody[@AnonymousInnerClass = false, @EnumChild = false] + | +- ClassOrInterfaceBodyDeclaration[@AnonymousInnerClass = false, @EnumChild = false, @Kind = DeclarationKind.METHOD] + | | +- MethodDeclaration[@Abstract = true, @Arity = 0, @Default = false, @Final = false, @InterfaceMember = true, @Kind = MethodLikeKind.METHOD, @MethodName = "firstName", @Modifiers = 0, @Name = "firstName", @Native = false, @PackagePrivate = false, @Private = false, @Protected = false, @Public = true, @Static = false, @Strictfp = false, @Synchronized = false, @SyntacticallyAbstract = false, @SyntacticallyPublic = false, @Transient = false, @Void = false, @Volatile = false] + | | +- ResultType[@Void = false, @returnsArray = 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] + | | +- MethodDeclarator[@Image = "firstName", @ParameterCount = 0] + | | +- FormalParameters[@ParameterCount = 0, @Size = 0] + | +- ClassOrInterfaceBodyDeclaration[@AnonymousInnerClass = false, @EnumChild = false, @Kind = DeclarationKind.METHOD] + | +- MethodDeclaration[@Abstract = true, @Arity = 0, @Default = false, @Final = false, @InterfaceMember = true, @Kind = MethodLikeKind.METHOD, @MethodName = "lastName", @Modifiers = 0, @Name = "lastName", @Native = false, @PackagePrivate = false, @Private = false, @Protected = false, @Public = true, @Static = false, @Strictfp = false, @Synchronized = false, @SyntacticallyAbstract = false, @SyntacticallyPublic = false, @Transient = false, @Void = false, @Volatile = false] + | +- ResultType[@Void = false, @returnsArray = 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] + | +- MethodDeclarator[@Image = "lastName", @ParameterCount = 0] + | +- FormalParameters[@ParameterCount = 0, @Size = 0] + +- ClassOrInterfaceBodyDeclaration[@AnonymousInnerClass = false, @EnumChild = false, @Kind = DeclarationKind.RECORD] + +- RecordDeclaration[@Abstract = false, @BinaryName = "Records$PersonRecord", @Default = false, @Final = true, @Image = "PersonRecord", @Local = false, @Modifiers = 1, @Native = false, @Nested = true, @PackagePrivate = false, @Private = false, @Protected = false, @Public = true, @SimpleName = "PersonRecord", @Static = false, @Strictfp = false, @Synchronized = false, @Transient = false, @TypeKind = TypeKind.RECORD, @Volatile = false] + +- RecordComponentList[@Size = 2] + | +- RecordComponent[@Varargs = 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] + | | +- VariableDeclaratorId[@Array = false, @ArrayDepth = 0, @ArrayType = false, @ExceptionBlockParameter = false, @ExplicitReceiverParameter = false, @Field = false, @Final = true, @FormalParameter = false, @Image = "firstName", @LambdaParameter = false, @LocalVariable = false, @Name = "firstName", @PatternBinding = false, @ResourceDeclaration = false, @TypeInferred = false, @VariableName = "firstName"] + | +- RecordComponent[@Varargs = 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] + | +- VariableDeclaratorId[@Array = false, @ArrayDepth = 0, @ArrayType = false, @ExceptionBlockParameter = false, @ExplicitReceiverParameter = false, @Field = false, @Final = true, @FormalParameter = false, @Image = "lastName", @LambdaParameter = false, @LocalVariable = false, @Name = "lastName", @PatternBinding = false, @ResourceDeclaration = false, @TypeInferred = false, @VariableName = "lastName"] + +- ImplementsList[] + | +- ClassOrInterfaceType[@AnonymousClass = false, @Array = false, @ArrayDepth = 0, @Image = "Person", @ReferenceToClassSameCompilationUnit = true] + | +- ClassOrInterfaceType[@AnonymousClass = false, @Array = false, @ArrayDepth = 0, @Image = "java.io.Serializable", @ReferenceToClassSameCompilationUnit = false] + +- RecordBody[] From 3b151e31c4138f06204d637b396747e089478f61 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Mon, 15 Feb 2021 19:33:36 +0100 Subject: [PATCH 6/8] [java] JEP 397: Sealed Classes (Second Preview) for Java16 Preview --- pmd-java/etc/grammar/Java.jjt | 34 ++++++--- .../pmd/lang/java/ast/ASTPermitsList.java | 8 +- .../java/ast/Java16PreviewTreeDumpTest.java | 54 +++++++++++++ .../pmd/lang/java/ast/Java16TreeDumpTest.java | 6 ++ .../java16/NonSealedIdentifier.java | 15 ++++ .../java16/NonSealedIdentifier.txt | 76 +++++++++++++++++++ .../java16p/expression/ConstantExpr.java | 9 +++ .../java16p/expression/Expr.java | 10 +++ .../java16p/expression/Expr.txt | 11 +++ .../java16p/expression/NegExpr.java | 9 +++ .../java16p/expression/PlusExpr.java | 9 +++ .../java16p/expression/TimesExpr.java | 9 +++ .../java16p/geometry/Circle.java | 9 +++ .../java16p/geometry/FilledRectangle.java | 10 +++ .../java16p/geometry/Rectangle.java | 11 +++ .../java16p/geometry/Shape.java | 11 +++ .../java16p/geometry/Shape.txt | 10 +++ .../java16p/geometry/Square.java | 10 +++ .../java16p/geometry/Square.txt | 8 ++ .../geometry/TransparentRectangle.java | 10 +++ 20 files changed, 314 insertions(+), 15 deletions(-) create mode 100644 pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java16PreviewTreeDumpTest.java create mode 100644 pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16/NonSealedIdentifier.java create mode 100644 pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16/NonSealedIdentifier.txt create mode 100644 pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16p/expression/ConstantExpr.java create mode 100644 pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16p/expression/Expr.java create mode 100644 pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16p/expression/Expr.txt create mode 100644 pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16p/expression/NegExpr.java create mode 100644 pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16p/expression/PlusExpr.java create mode 100644 pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16p/expression/TimesExpr.java create mode 100644 pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16p/geometry/Circle.java create mode 100644 pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16p/geometry/FilledRectangle.java create mode 100644 pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16p/geometry/Rectangle.java create mode 100644 pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16p/geometry/Shape.java create mode 100644 pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16p/geometry/Shape.txt create mode 100644 pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16p/geometry/Square.java create mode 100644 pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16p/geometry/Square.txt create mode 100644 pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16p/geometry/TransparentRectangle.java diff --git a/pmd-java/etc/grammar/Java.jjt b/pmd-java/etc/grammar/Java.jjt index cf4b22b27f..e57d7f6e9a 100644 --- a/pmd-java/etc/grammar/Java.jjt +++ b/pmd-java/etc/grammar/Java.jjt @@ -1,4 +1,5 @@ /** + * JEP 397: Sealed Classes (Second Preview) for Java16 Preview * JEP 395: Records for Java16 * JEP 394: Pattern Matching for instanceof for Java16 * Andreas Dangel 02/2021 @@ -425,19 +426,19 @@ public class JavaParser { } private void checkForBadTypeIdentifierUsage(String image) { if (jdkVersion >= 10 && "var".equals(image)) { - throwParseException("With JDK 10, 'var' is a restricted local variable type and cannot be used for type declarations!"); + throwParseException("With JDK 10, 'var' is a contextual keyword and cannot be used for type declarations!"); } if (jdkVersion >= 14 && "yield".equals(image)) { - throwParseException("With JDK 14, 'yield' is a restricted local variable type and cannot be used for type declarations!"); + throwParseException("With JDK 14, 'yield' is a contextual keyword and cannot be used for type declarations!"); } - if ((jdkVersion >= 14 && preview || jdkVersion >= 16) && "record".equals(image)) { - throwParseException("With JDK 14 Preview and JDK 15 Preview and Java >= 16, 'record' is a restricted identifier and cannot be used for type declarations!"); + if ((jdkVersion == 14 && preview || jdkVersion == 15 && preview || jdkVersion >= 16) && "record".equals(image)) { + throwParseException("With JDK 14 Preview and JDK 15 Preview and Java >= 16, 'record' is a contextual keyword and cannot be used for type declarations!"); } - if (jdkVersion >= 15 && preview && "sealed".equals(image)) { - throwParseException("With JDK 15 Preview, 'sealed' is a restricted identifier and cannot be used for type declarations!"); + if ((jdkVersion == 15 && preview || jdkVersion == 16 && preview) && "sealed".equals(image)) { + throwParseException("With JDK 15 Preview and JDK 16 Preview, 'sealed' is a contextual keyword and cannot be used for type declarations!"); } - if (jdkVersion >= 15 && preview && "permits".equals(image)) { - throwParseException("With JDK 15 Preview, 'permits' is a restricted identifier and cannot be used for type declarations!"); + if ((jdkVersion == 15 && preview || jdkVersion == 16 && preview) && "permits".equals(image)) { + throwParseException("With JDK 15 Preview and JDK 16 Preview, 'permits' is a contextual keyword and cannot be used for type declarations!"); } } private void checkForMultipleCaseLabels() { @@ -501,7 +502,7 @@ public class JavaParser { } private boolean isSealedClassSupported() { - return jdkVersion == 15 && preview; + return jdkVersion == 15 && preview || jdkVersion == 16 && preview; } private void checkForSealedClassUsage() { @@ -1219,8 +1220,8 @@ void PermittedSubclasses() #PermitsList: throw new ParseException("ERROR: expecting permits"); } } - (TypeAnnotation())* ClassOrInterfaceType() - ( "," (TypeAnnotation())* ClassOrInterfaceType() )* + TypeName() + ( "," TypeName() )* } void EnumDeclaration(int modifiers): @@ -1536,6 +1537,17 @@ void ClassOrInterfaceType(): {jjtThis.setImage(s.toString());} } +void TypeName() #ClassOrInterfaceType: +{ + StringBuilder s = new StringBuilder(); + Token t; +} +{ + t= {s.append(t.image);} + ( "." t= {s.append('.').append(t.image);} )* + {jjtThis.setImage(s.toString());} +} + void TypeArguments(): {} { diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTPermitsList.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTPermitsList.java index 541a0f812c..4d0f281333 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTPermitsList.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTPermitsList.java @@ -12,14 +12,14 @@ import net.sourceforge.pmd.annotation.Experimental; /** * Represents the {@code permits} clause of a (sealed) class declaration. * - *

This is a Java 15 Preview feature. + *

This is a Java 15 Preview and Java 16 Preview feature. * - *

See https://openjdk.java.net/jeps/360 + *

See https://openjdk.java.net/jeps/397 * *

  *
- *  PermittedSubclasses ::= "permits" (TypeAnnotation)* ClassOrInterfaceType
- *                ( "," (TypeAnnotation)* ClassOrInterfaceType )*
+ *  PermittedSubclasses ::= "permits" ClassOrInterfaceType
+ *                ( "," ClassOrInterfaceType )*
  * 
*/ @Experimental diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java16PreviewTreeDumpTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java16PreviewTreeDumpTest.java new file mode 100644 index 0000000000..0ee445909c --- /dev/null +++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java16PreviewTreeDumpTest.java @@ -0,0 +1,54 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java.ast; + +import org.junit.Test; + +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 Java16PreviewTreeDumpTest extends BaseTreeDumpTest { + private final JavaParsingHelper java16p = + JavaParsingHelper.WITH_PROCESSING.withDefaultVersion("16-preview") + .withResourceContext(Java16PreviewTreeDumpTest.class, "jdkversiontests/java16p/"); + private final JavaParsingHelper java16 = java16p.withDefaultVersion("16"); + + public Java16PreviewTreeDumpTest() { + super(new RelevantAttributePrinter(), ".java"); + } + + @Override + public BaseParsingHelper getParser() { + return java16p; + } + + @Test(expected = ParseException.class) + public void sealedClassBeforeJava16Preview() { + java16.parseResource("geometry/Shape.java"); + } + + @Test + public void sealedClass() { + doTest("geometry/Shape"); + } + + @Test + public void nonSealedClass() { + doTest("geometry/Square"); + } + + @Test(expected = ParseException.class) + public void sealedInterfaceBeforeJava15Preview() { + java16.parseResource("expression/Expr.java"); + } + + @Test + public void sealedInterface() { + doTest("expression/Expr"); + } +} diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java16TreeDumpTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java16TreeDumpTest.java index 6c92ef13d8..ca809cc0e7 100644 --- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java16TreeDumpTest.java +++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java16TreeDumpTest.java @@ -112,4 +112,10 @@ public class Java16TreeDumpTest extends BaseTreeDumpTest { public void recordIsARestrictedIdentifier() { java16.parse("public class record {}"); } + + @Test + public void sealedAndNonSealedIdentifiers() { + doTest("NonSealedIdentifier"); + java16p.parseResource("NonSealedIdentifier.java"); // make sure we can parse it with preview as well + } } diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16/NonSealedIdentifier.java b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16/NonSealedIdentifier.java new file mode 100644 index 0000000000..8826577e8f --- /dev/null +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16/NonSealedIdentifier.java @@ -0,0 +1,15 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +public class NonSealedIdentifier { + public static void main(String[] args) { + int result = 0; + int non = 1; + // sealed is a valid identifier name in both Java16 and Java16 Preview + int sealed = 2; + // non-sealed is a valid subtraction expression in both Java16 and Java16 Preview + result = non-sealed; + System.out.println(result); + } +} diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16/NonSealedIdentifier.txt b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16/NonSealedIdentifier.txt new file mode 100644 index 0000000000..bcd2128440 --- /dev/null +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16/NonSealedIdentifier.txt @@ -0,0 +1,76 @@ ++- CompilationUnit[@PackageName = "", @declarationsAreInDefaultPackage = true] + +- TypeDeclaration[] + +- ClassOrInterfaceDeclaration[@Abstract = false, @BinaryName = "NonSealedIdentifier", @Default = false, @Final = false, @Image = "NonSealedIdentifier", @Interface = false, @Local = false, @Modifiers = 1, @Native = false, @Nested = false, @NonSealed = false, @PackagePrivate = false, @Private = false, @Protected = false, @Public = true, @Sealed = false, @SimpleName = "NonSealedIdentifier", @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, @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 = "result", @Volatile = false] + | +- Type[@Array = false, @ArrayDepth = 0, @ArrayType = false, @TypeImage = "int"] + | | +- PrimitiveType[@Array = false, @ArrayDepth = 0, @Boolean = false, @Image = "int"] + | +- VariableDeclarator[@Initializer = true, @Name = "result"] + | +- VariableDeclaratorId[@Array = false, @ArrayDepth = 0, @ArrayType = false, @ExceptionBlockParameter = false, @ExplicitReceiverParameter = false, @Field = false, @Final = false, @FormalParameter = false, @Image = "result", @LambdaParameter = false, @LocalVariable = true, @Name = "result", @PatternBinding = false, @ResourceDeclaration = false, @TypeInferred = false, @VariableName = "result"] + | +- VariableInitializer[] + | +- Expression[@StandAlonePrimitive = true] + | +- PrimaryExpression[] + | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "0", @FloatLiteral = false, @Image = "0", @IntLiteral = true, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = false, @TextBlock = false, @TextBlockContent = "0", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + +- 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 = "non", @Volatile = false] + | +- Type[@Array = false, @ArrayDepth = 0, @ArrayType = false, @TypeImage = "int"] + | | +- PrimitiveType[@Array = false, @ArrayDepth = 0, @Boolean = false, @Image = "int"] + | +- VariableDeclarator[@Initializer = true, @Name = "non"] + | +- VariableDeclaratorId[@Array = false, @ArrayDepth = 0, @ArrayType = false, @ExceptionBlockParameter = false, @ExplicitReceiverParameter = false, @Field = false, @Final = false, @FormalParameter = false, @Image = "non", @LambdaParameter = false, @LocalVariable = true, @Name = "non", @PatternBinding = false, @ResourceDeclaration = false, @TypeInferred = false, @VariableName = "non"] + | +- VariableInitializer[] + | +- Expression[@StandAlonePrimitive = true] + | +- PrimaryExpression[] + | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "1", @FloatLiteral = false, @Image = "1", @IntLiteral = true, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = false, @TextBlock = false, @TextBlockContent = "1", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 1, @ValueAsLong = 1] + +- 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 = "sealed", @Volatile = false] + | +- Type[@Array = false, @ArrayDepth = 0, @ArrayType = false, @TypeImage = "int"] + | | +- PrimitiveType[@Array = false, @ArrayDepth = 0, @Boolean = false, @Image = "int"] + | +- VariableDeclarator[@Initializer = true, @Name = "sealed"] + | +- VariableDeclaratorId[@Array = false, @ArrayDepth = 0, @ArrayType = false, @ExceptionBlockParameter = false, @ExplicitReceiverParameter = false, @Field = false, @Final = false, @FormalParameter = false, @Image = "sealed", @LambdaParameter = false, @LocalVariable = true, @Name = "sealed", @PatternBinding = false, @ResourceDeclaration = false, @TypeInferred = false, @VariableName = "sealed"] + | +- VariableInitializer[] + | +- Expression[@StandAlonePrimitive = true] + | +- PrimaryExpression[] + | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "2", @FloatLiteral = false, @Image = "2", @IntLiteral = true, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = false, @TextBlock = false, @TextBlockContent = "2", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 2, @ValueAsLong = 2] + +- BlockStatement[@Allocation = false] + | +- Statement[] + | +- StatementExpression[] + | +- PrimaryExpression[] + | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | | +- Name[@Image = "result"] + | +- AssignmentOperator[@Compound = false, @Image = "="] + | +- Expression[@StandAlonePrimitive = false] + | +- AdditiveExpression[@Image = "-", @Operator = "-"] + | +- PrimaryExpression[] + | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | | +- Name[@Image = "non"] + | +- PrimaryExpression[] + | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] + | +- Name[@Image = "sealed"] + +- 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 = "result"] diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16p/expression/ConstantExpr.java b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16p/expression/ConstantExpr.java new file mode 100644 index 0000000000..a4265b4c3b --- /dev/null +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16p/expression/ConstantExpr.java @@ -0,0 +1,9 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ +package com.example.expression; + +/** + * @see JEP 397: Sealed Classes (Second Preview) + */ +public final class ConstantExpr implements Expr { } diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16p/expression/Expr.java b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16p/expression/Expr.java new file mode 100644 index 0000000000..8b7055e9f9 --- /dev/null +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16p/expression/Expr.java @@ -0,0 +1,10 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ +package com.example.expression; + +/** + * @see JEP 397: Sealed Classes (Second Preview) + */ +public sealed interface Expr + permits ConstantExpr, PlusExpr, TimesExpr, NegExpr { } diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16p/expression/Expr.txt b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16p/expression/Expr.txt new file mode 100644 index 0000000000..12d87ee160 --- /dev/null +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16p/expression/Expr.txt @@ -0,0 +1,11 @@ ++- CompilationUnit[@PackageName = "com.example.expression", @declarationsAreInDefaultPackage = false] + +- PackageDeclaration[@Name = "com.example.expression", @PackageNameImage = "com.example.expression"] + | +- Name[@Image = "com.example.expression"] + +- TypeDeclaration[] + +- ClassOrInterfaceDeclaration[@Abstract = false, @BinaryName = "com.example.expression.Expr", @Default = false, @Final = false, @Image = "Expr", @Interface = true, @Local = false, @Modifiers = 16385, @Native = false, @Nested = false, @NonSealed = false, @PackagePrivate = false, @Private = false, @Protected = false, @Public = true, @Sealed = true, @SimpleName = "Expr", @Static = false, @Strictfp = false, @Synchronized = false, @Transient = false, @TypeKind = TypeKind.INTERFACE, @Volatile = false] + +- PermitsList[] + | +- ClassOrInterfaceType[@AnonymousClass = false, @Array = false, @ArrayDepth = 0, @Image = "ConstantExpr", @ReferenceToClassSameCompilationUnit = false] + | +- ClassOrInterfaceType[@AnonymousClass = false, @Array = false, @ArrayDepth = 0, @Image = "PlusExpr", @ReferenceToClassSameCompilationUnit = false] + | +- ClassOrInterfaceType[@AnonymousClass = false, @Array = false, @ArrayDepth = 0, @Image = "TimesExpr", @ReferenceToClassSameCompilationUnit = false] + | +- ClassOrInterfaceType[@AnonymousClass = false, @Array = false, @ArrayDepth = 0, @Image = "NegExpr", @ReferenceToClassSameCompilationUnit = false] + +- ClassOrInterfaceBody[@AnonymousInnerClass = false, @EnumChild = false] diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16p/expression/NegExpr.java b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16p/expression/NegExpr.java new file mode 100644 index 0000000000..727c84a2d6 --- /dev/null +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16p/expression/NegExpr.java @@ -0,0 +1,9 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ +package com.example.expression; + +/** + * @see JEP 397: Sealed Classes (Second Preview) + */ +public final class NegExpr implements Expr { } diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16p/expression/PlusExpr.java b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16p/expression/PlusExpr.java new file mode 100644 index 0000000000..17f8f3a5a2 --- /dev/null +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16p/expression/PlusExpr.java @@ -0,0 +1,9 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ +package com.example.expression; + +/** + * @see JEP 397: Sealed Classes (Second Preview) + */ +public final class PlusExpr implements Expr { } diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16p/expression/TimesExpr.java b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16p/expression/TimesExpr.java new file mode 100644 index 0000000000..13ca04ebc7 --- /dev/null +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16p/expression/TimesExpr.java @@ -0,0 +1,9 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ +package com.example.expression; + +/** + * @see JEP 397: Sealed Classes (Second Preview) + */ +public final class TimesExpr implements Expr { } diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16p/geometry/Circle.java b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16p/geometry/Circle.java new file mode 100644 index 0000000000..5d3c50900c --- /dev/null +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16p/geometry/Circle.java @@ -0,0 +1,9 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ +package com.example.geometry; + +/** + * @see JEP 397: Sealed Classes (Second Preview) + */ +public final class Circle extends Shape { } diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16p/geometry/FilledRectangle.java b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16p/geometry/FilledRectangle.java new file mode 100644 index 0000000000..6b6ec1ccec --- /dev/null +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16p/geometry/FilledRectangle.java @@ -0,0 +1,10 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ +package com.example.geometry; + +/** + * @see JEP 397: Sealed Classes (Second Preview) + */ +public final class FilledRectangle extends Rectangle { } + diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16p/geometry/Rectangle.java b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16p/geometry/Rectangle.java new file mode 100644 index 0000000000..ec502a8cf3 --- /dev/null +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16p/geometry/Rectangle.java @@ -0,0 +1,11 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ +package com.example.geometry; + +/** + * @see JEP 397: Sealed Classes (Second Preview) + */ +public sealed class Rectangle extends Shape + permits TransparentRectangle, FilledRectangle { } + diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16p/geometry/Shape.java b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16p/geometry/Shape.java new file mode 100644 index 0000000000..7d74060afc --- /dev/null +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16p/geometry/Shape.java @@ -0,0 +1,11 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ +package com.example.geometry; + +/** + * @see JEP 397: Sealed Classes (Second Preview) + */ +public sealed class Shape + permits Circle, Rectangle, Square { } + diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16p/geometry/Shape.txt b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16p/geometry/Shape.txt new file mode 100644 index 0000000000..2a2f3f01fc --- /dev/null +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16p/geometry/Shape.txt @@ -0,0 +1,10 @@ ++- CompilationUnit[@PackageName = "com.example.geometry", @declarationsAreInDefaultPackage = false] + +- PackageDeclaration[@Name = "com.example.geometry", @PackageNameImage = "com.example.geometry"] + | +- Name[@Image = "com.example.geometry"] + +- TypeDeclaration[] + +- ClassOrInterfaceDeclaration[@Abstract = false, @BinaryName = "com.example.geometry.Shape", @Default = false, @Final = false, @Image = "Shape", @Interface = false, @Local = false, @Modifiers = 16385, @Native = false, @Nested = false, @NonSealed = false, @PackagePrivate = false, @Private = false, @Protected = false, @Public = true, @Sealed = true, @SimpleName = "Shape", @Static = false, @Strictfp = false, @Synchronized = false, @Transient = false, @TypeKind = TypeKind.CLASS, @Volatile = false] + +- PermitsList[] + | +- ClassOrInterfaceType[@AnonymousClass = false, @Array = false, @ArrayDepth = 0, @Image = "Circle", @ReferenceToClassSameCompilationUnit = false] + | +- ClassOrInterfaceType[@AnonymousClass = false, @Array = false, @ArrayDepth = 0, @Image = "Rectangle", @ReferenceToClassSameCompilationUnit = false] + | +- ClassOrInterfaceType[@AnonymousClass = false, @Array = false, @ArrayDepth = 0, @Image = "Square", @ReferenceToClassSameCompilationUnit = false] + +- ClassOrInterfaceBody[@AnonymousInnerClass = false, @EnumChild = false] diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16p/geometry/Square.java b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16p/geometry/Square.java new file mode 100644 index 0000000000..ff8d2fdeaf --- /dev/null +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16p/geometry/Square.java @@ -0,0 +1,10 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ +package com.example.geometry; + +/** + * @see JEP 397: Sealed Classes (Second Preview) + */ +public non-sealed class Square extends Shape { } + diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16p/geometry/Square.txt b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16p/geometry/Square.txt new file mode 100644 index 0000000000..94cd4275e2 --- /dev/null +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16p/geometry/Square.txt @@ -0,0 +1,8 @@ ++- CompilationUnit[@PackageName = "com.example.geometry", @declarationsAreInDefaultPackage = false] + +- PackageDeclaration[@Name = "com.example.geometry", @PackageNameImage = "com.example.geometry"] + | +- Name[@Image = "com.example.geometry"] + +- TypeDeclaration[] + +- ClassOrInterfaceDeclaration[@Abstract = false, @BinaryName = "com.example.geometry.Square", @Default = false, @Final = false, @Image = "Square", @Interface = false, @Local = false, @Modifiers = 32769, @Native = false, @Nested = false, @NonSealed = true, @PackagePrivate = false, @Private = false, @Protected = false, @Public = true, @Sealed = false, @SimpleName = "Square", @Static = false, @Strictfp = false, @Synchronized = false, @Transient = false, @TypeKind = TypeKind.CLASS, @Volatile = false] + +- ExtendsList[] + | +- ClassOrInterfaceType[@AnonymousClass = false, @Array = false, @ArrayDepth = 0, @Image = "Shape", @ReferenceToClassSameCompilationUnit = false] + +- ClassOrInterfaceBody[@AnonymousInnerClass = false, @EnumChild = false] diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16p/geometry/TransparentRectangle.java b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16p/geometry/TransparentRectangle.java new file mode 100644 index 0000000000..5f515ef038 --- /dev/null +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16p/geometry/TransparentRectangle.java @@ -0,0 +1,10 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ +package com.example.geometry; + +/** + * @see JEP 397: Sealed Classes (Second Preview) + */ +public final class TransparentRectangle extends Rectangle { } + From 2ec77ad02fde8ceb56eed684b3ba34b7510ea9f8 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Mon, 15 Feb 2021 19:51:48 +0100 Subject: [PATCH 7/8] [java] Remove support for Java 14 preview --- pmd-java/etc/grammar/Java.jjt | 23 ++- .../pmd/lang/java/JavaLanguageModule.java | 1 - .../pmd/lang/java/ast/Java14PreviewTest.java | 189 ------------------ .../pmd/lang/java/ast/Java14Test.java | 5 - .../pmd/lang/java/ast/ASTPatternTest.kt | 8 +- .../pmd/lang/java/ast/KotlinTestingDsl.kt | 2 +- .../java14/PatternMatchingInstanceof.java | 34 ---- .../ast/jdkversiontests/java14/Point.java | 10 - .../ast/jdkversiontests/java14/Records.java | 61 ------ .../jdkversiontests/java14/TextBlocks.java | 113 ----------- .../bestpractices/xml/MissingOverride.xml | 2 +- .../xml/InefficientEmptyStringCheck.xml | 2 +- 12 files changed, 19 insertions(+), 431 deletions(-) delete mode 100644 pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java14PreviewTest.java delete mode 100644 pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java14/PatternMatchingInstanceof.java delete mode 100644 pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java14/Point.java delete mode 100644 pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java14/Records.java delete mode 100644 pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java14/TextBlocks.java diff --git a/pmd-java/etc/grammar/Java.jjt b/pmd-java/etc/grammar/Java.jjt index e57d7f6e9a..c742d34f1a 100644 --- a/pmd-java/etc/grammar/Java.jjt +++ b/pmd-java/etc/grammar/Java.jjt @@ -1,4 +1,5 @@ /** + * Remove support for Java 14 preview language features * JEP 397: Sealed Classes (Second Preview) for Java16 Preview * JEP 395: Records for Java16 * JEP 394: Pattern Matching for instanceof for Java16 @@ -383,8 +384,8 @@ public class JavaParser { } private void checkforBadInstanceOfPattern() { - if (!(jdkVersion == 14 && preview || jdkVersion == 15 && preview || jdkVersion >= 16)) { - throwParseException("Pattern Matching for instanceof is only supported with Java 14 Preview and Java 15 Preview and Java >= 16"); + if (!(jdkVersion == 15 && preview || jdkVersion >= 16)) { + throwParseException("Pattern Matching for instanceof is only supported with Java 15 Preview and Java >= 16"); } } @@ -431,8 +432,8 @@ public class JavaParser { if (jdkVersion >= 14 && "yield".equals(image)) { throwParseException("With JDK 14, 'yield' is a contextual keyword and cannot be used for type declarations!"); } - if ((jdkVersion == 14 && preview || jdkVersion == 15 && preview || jdkVersion >= 16) && "record".equals(image)) { - throwParseException("With JDK 14 Preview and JDK 15 Preview and Java >= 16, 'record' is a contextual keyword and cannot be used for type declarations!"); + if ((jdkVersion == 15 && preview || jdkVersion >= 16) && "record".equals(image)) { + throwParseException("With JDK 15 Preview and Java >= 16, 'record' is a contextual keyword and cannot be used for type declarations!"); } if ((jdkVersion == 15 && preview || jdkVersion == 16 && preview) && "sealed".equals(image)) { throwParseException("With JDK 15 Preview and JDK 16 Preview, 'sealed' is a contextual keyword and cannot be used for type declarations!"); @@ -474,31 +475,31 @@ public class JavaParser { } private void checkForTextBlockLiteral() { - if (jdkVersion < 15 && !preview) { - throwParseException("Text block literals are only supported with Java 14 Preview and Java >= 15"); + if (!(jdkVersion >= 15)) { + throwParseException("Text block literals are only supported with Java >= 15"); } } private void checkForNewStringSpaceEscape(String s) { - if ((jdkVersion < 15 && !preview) && s.contains("\\s") && !s.contains("\\\\s")) { - throwParseException("The escape sequence \"\\s\" is only supported with Java 14 Preview and Java >= 15"); + if (!(jdkVersion >= 15) && s.contains("\\s") && !s.contains("\\\\s")) { + throwParseException("The escape sequence \"\\s\" is only supported with Java >= 15"); } } private void checkForRecordType() { if (!isRecordTypeSupported()) { - throwParseException("Records are only supported with Java 14 Preview and Java 15 Preview and Java >= 16"); + throwParseException("Records are only supported with Java 15 Preview and Java >= 16"); } } private void checkForLocalInterfaceOrEnumType() { if (!isRecordTypeSupported()) { - throwParseException("Local interfaces and enums are only supported with Java 14 Preview and Java 15 Preview and Java >= 16"); + throwParseException("Local interfaces and enums are only supported with Java 15 Preview and Java >= 16"); } } private boolean isRecordTypeSupported() { - return jdkVersion == 14 && preview || jdkVersion == 15 && preview || jdkVersion >= 16; + return jdkVersion == 15 && preview || jdkVersion >= 16; } private boolean isSealedClassSupported() { diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/JavaLanguageModule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/JavaLanguageModule.java index a39744d6aa..f9f1588a5a 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/JavaLanguageModule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/JavaLanguageModule.java @@ -28,7 +28,6 @@ public class JavaLanguageModule extends BaseLanguageModule { addVersion("12", new JavaLanguageHandler(12)); addVersion("13", new JavaLanguageHandler(13)); addVersion("14", new JavaLanguageHandler(14)); - addVersion("14-preview", new JavaLanguageHandler(14, true)); addVersion("15", new JavaLanguageHandler(15)); addVersion("15-preview", new JavaLanguageHandler(15, true)); addDefaultVersion("16", new JavaLanguageHandler(16)); // 16 is the default diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java14PreviewTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java14PreviewTest.java deleted file mode 100644 index 4d865ae6ca..0000000000 --- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java14PreviewTest.java +++ /dev/null @@ -1,189 +0,0 @@ -/* - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - - -package net.sourceforge.pmd.lang.java.ast; - -import java.util.ArrayList; -import java.util.List; - -import org.junit.Assert; -import org.junit.Test; - -import net.sourceforge.pmd.lang.ast.ParseException; -import net.sourceforge.pmd.lang.java.JavaParsingHelper; -import net.sourceforge.pmd.lang.java.ast.ASTAnyTypeBodyDeclaration.DeclarationKind; - -/** - * Tests new java14 preview features. - */ -public class Java14PreviewTest { - private final JavaParsingHelper java14 = - JavaParsingHelper.WITH_PROCESSING.withDefaultVersion("14") - .withResourceContext(Java14Test.class, "jdkversiontests/java14/"); - - private final JavaParsingHelper java14p = java14.withDefaultVersion("14-preview"); - private final JavaParsingHelper java13 = java14.withDefaultVersion("13"); - - @Test - public void textBlocks() { - ASTCompilationUnit compilationUnit = java14p.parseResource("TextBlocks.java"); - List literals = compilationUnit.findDescendantsOfType(ASTLiteral.class); - Assert.assertEquals(22, literals.size()); - Assert.assertFalse(literals.get(2).isTextBlock()); - Assert.assertFalse(literals.get(12).isTextBlock()); - Assert.assertFalse(literals.get(17).isTextBlock()); - Assert.assertFalse(literals.get(18).isTextBlock()); - Assert.assertFalse(literals.get(20).isTextBlock()); - Assert.assertFalse(literals.get(21).isTextBlock()); - - List textBlocks = new ArrayList<>(); - for (ASTLiteral literal : literals) { - if (literal.isTextBlock()) { - textBlocks.add(literal); - } - } - Assert.assertEquals(16, textBlocks.size()); - Assert.assertEquals("\"\"\"\n" - + " \n" - + " \n" - + "

Hello, world

\n" - + " \n" - + " \n" - + " \"\"\"", - textBlocks.get(0).getImage()); - Assert.assertEquals("\n" - + " \n" - + "

Hello, world

\n" - + " \n" - + "\n", textBlocks.get(0).getTextBlockContent()); - - // Note: More tests are in ASTLiteralTest. - } - - @Test(expected = ParseException.class) - public void textBlocksBeforeJava14PreviewShouldFail() { - java13.parseResource("TextBlocks.java"); - } - - @Test(expected = ParseException.class) - public void stringEscapeSequenceShouldFail() { - java14.parse("class Foo { String s =\"a\\sb\"; }"); - } - - @Test - public void patternMatchingInstanceof() { - ASTCompilationUnit compilationUnit = java14p.parseResource("PatternMatchingInstanceof.java"); - List instanceOfExpressions = compilationUnit.findDescendantsOfType(ASTInstanceOfExpression.class); - Assert.assertEquals(4, instanceOfExpressions.size()); - for (ASTInstanceOfExpression expr : instanceOfExpressions) { - Assert.assertTrue(expr.getChild(1) instanceof ASTTypePattern); - ASTVariableDeclaratorId variable = expr.getChild(1).getFirstChildOfType(ASTVariableDeclaratorId.class); - Assert.assertEquals(String.class, variable.getType()); - Assert.assertEquals("s", variable.getVariableName()); - Assert.assertTrue(variable.isPatternBinding()); - Assert.assertFalse(variable.isFinal()); - // Note: these variables are not part of the symbol table - // See ScopeAndDeclarationFinder#visit(ASTVariableDeclaratorId, Object) - Assert.assertNull(variable.getNameDeclaration()); - } - } - - @Test(expected = ParseException.class) - public void patternMatchingInstanceofBeforeJava14PreviewShouldFail() { - java14.parseResource("PatternMatchingInstanceof.java"); - } - - @Test - public void recordPoint() { - ASTCompilationUnit compilationUnit = java14p.parseResource("Point.java"); - ASTRecordDeclaration recordDecl = compilationUnit.getFirstDescendantOfType(ASTRecordDeclaration.class); - Assert.assertEquals("Point", recordDecl.getImage()); - Assert.assertFalse(recordDecl.isNested()); - List components = recordDecl.getFirstChildOfType(ASTRecordComponentList.class) - .findChildrenOfType(ASTRecordComponent.class); - Assert.assertEquals(2, components.size()); - Assert.assertEquals("x", components.get(0).getVarId().getImage()); - Assert.assertEquals("y", components.get(1).getVarId().getImage()); - Assert.assertNull(components.get(0).getVarId().getNameDeclaration().getAccessNodeParent()); - Assert.assertEquals(Integer.TYPE, components.get(0).getVarId().getNameDeclaration().getType()); - Assert.assertEquals("int", components.get(0).getVarId().getNameDeclaration().getTypeImage()); - } - - @Test(expected = ParseException.class) - public void recordPointBeforeJava14PreviewShouldFail() { - java14.parseResource("Point.java"); - } - - @Test(expected = ParseException.class) - public void recordCtorWithThrowsShouldFail() { - java14p.parse(" record R {" - + " R throws IOException {}" - + " }"); - } - - @Test - public void innerRecords() { - ASTCompilationUnit compilationUnit = java14p.parseResource("Records.java"); - List recordDecls = compilationUnit.findDescendantsOfType(ASTRecordDeclaration.class, true); - Assert.assertEquals(7, recordDecls.size()); - - ASTRecordDeclaration complex = recordDecls.get(0); - Assert.assertEquals("MyComplex", complex.getSimpleName()); - Assert.assertTrue(complex.isNested()); - Assert.assertEquals(0, getComponent(complex, 0).findChildrenOfType(ASTAnnotation.class).size()); - Assert.assertEquals(1, getComponent(complex, 1).findChildrenOfType(ASTAnnotation.class).size()); - Assert.assertEquals(2, complex.getDeclarations().size()); - Assert.assertTrue(complex.getDeclarations().get(0).getChild(1) instanceof ASTConstructorDeclaration); - Assert.assertTrue(complex.getDeclarations().get(1).getChild(0) instanceof ASTRecordDeclaration); - Assert.assertTrue(complex.getParent() instanceof ASTClassOrInterfaceBodyDeclaration); - ASTClassOrInterfaceBodyDeclaration complexParent = complex.getFirstParentOfType(ASTClassOrInterfaceBodyDeclaration.class); - Assert.assertEquals(DeclarationKind.RECORD, complexParent.getKind()); - Assert.assertSame(complex, complexParent.getDeclarationNode()); - - ASTRecordDeclaration nested = recordDecls.get(1); - Assert.assertEquals("Nested", nested.getSimpleName()); - Assert.assertTrue(nested.isNested()); - - ASTRecordDeclaration range = recordDecls.get(2); - Assert.assertEquals("Range", range.getSimpleName()); - Assert.assertEquals(2, range.getComponentList().size()); - List rangeConstructors = range.findDescendantsOfType(ASTCompactConstructorDeclaration.class); - Assert.assertEquals(1, rangeConstructors.size()); - Assert.assertEquals("Range", rangeConstructors.get(0).getImage()); - Assert.assertTrue(rangeConstructors.get(0).getChild(0) instanceof ASTAnnotation); - Assert.assertEquals(2, range.getDeclarations().size()); - - ASTRecordDeclaration varRec = recordDecls.get(3); - Assert.assertEquals("VarRec", varRec.getSimpleName()); - Assert.assertEquals("x", getComponent(varRec, 0).getVarId().getImage()); - Assert.assertTrue(getComponent(varRec, 0).isVarargs()); - Assert.assertEquals(2, getComponent(varRec, 0).findChildrenOfType(ASTAnnotation.class).size()); - Assert.assertEquals(1, getComponent(varRec, 0).getTypeNode().findDescendantsOfType(ASTAnnotation.class).size()); - - ASTRecordDeclaration arrayRec = recordDecls.get(4); - Assert.assertEquals("ArrayRec", arrayRec.getSimpleName()); - Assert.assertEquals("x", getComponent(arrayRec, 0).getVarId().getImage()); - Assert.assertTrue(getComponent(arrayRec, 0).getVarId().hasArrayType()); - - ASTRecordDeclaration emptyRec = recordDecls.get(5); - Assert.assertEquals("EmptyRec", emptyRec.getSimpleName()); - Assert.assertEquals(0, emptyRec.getComponentList().size()); - - ASTRecordDeclaration personRec = recordDecls.get(6); - Assert.assertEquals("PersonRecord", personRec.getSimpleName()); - ASTImplementsList impl = personRec.getFirstChildOfType(ASTImplementsList.class); - Assert.assertEquals(2, impl.findChildrenOfType(ASTClassOrInterfaceType.class).size()); - } - - private ASTRecordComponent getComponent(ASTRecordDeclaration arrayRec, int index) { - return (ASTRecordComponent) arrayRec.getComponentList().getChild(index); - } - - - @Test(expected = ParseException.class) - public void recordIsARestrictedIdentifier() { - java14p.parse("public class record {}"); - } -} diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java14Test.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java14Test.java index 49da7598fa..832a4381e4 100644 --- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java14Test.java +++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java14Test.java @@ -24,7 +24,6 @@ public class Java14Test { JavaParsingHelper.WITH_PROCESSING.withDefaultVersion("14") .withResourceContext(Java14Test.class, "jdkversiontests/java14/"); - private final JavaParsingHelper java14p = java14.withDefaultVersion("14-preview"); private final JavaParsingHelper java13 = java14.withDefaultVersion("13"); /** @@ -33,7 +32,6 @@ public class Java14Test { @Test public void switchExpressions() { parseAndCheckSwitchExpression(java14); - parseAndCheckSwitchExpression(java14p); } /** @@ -131,7 +129,6 @@ public class Java14Test { @Test public void multipleCaseLabels() { multipleCaseLabels(java14); - multipleCaseLabels(java14p); } private void multipleCaseLabels(JavaParsingHelper parser) { @@ -146,7 +143,6 @@ public class Java14Test { @Test public void switchRules() { switchRules(java14); - switchRules(java14p); } private void switchRules(JavaParsingHelper parser) { @@ -173,7 +169,6 @@ public class Java14Test { @Test public void simpleSwitchExpressions() { simpleSwitchExpressions(java14); - simpleSwitchExpressions(java14p); } private void simpleSwitchExpressions(JavaParsingHelper parser) { diff --git a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTPatternTest.kt b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTPatternTest.kt index 6d3187e205..1ac7c8161e 100644 --- a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTPatternTest.kt +++ b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTPatternTest.kt @@ -12,16 +12,16 @@ import java.io.IOException class ASTPatternTest : ParserTestSpec({ - parserTest("Test patterns only available on JDK 14+15 (preview) and JDK16 and JDK16 (preview)", - javaVersions = JavaVersion.values().asList().minus(J14__PREVIEW).minus(J15__PREVIEW).minus(J16).minus(J16__PREVIEW)) { + parserTest("Test patterns only available on JDK 15 (preview) and JDK16 and JDK16 (preview)", + javaVersions = JavaVersion.values().asList().minus(J15__PREVIEW).minus(J16).minus(J16__PREVIEW)) { - expectParseException("Pattern Matching for instanceof is only supported with Java 14 Preview and Java 15 Preview and Java >= 16") { + expectParseException("Pattern Matching for instanceof is only supported with Java 15 Preview and Java >= 16") { parseAstExpression("obj instanceof Class c") } } - parserTest("Test simple patterns", javaVersions = listOf(J14__PREVIEW, J15__PREVIEW, J16)) { + parserTest("Test simple patterns", javaVersions = listOf(J15__PREVIEW, J16)) { importedTypes += IOException::class.java diff --git a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/KotlinTestingDsl.kt b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/KotlinTestingDsl.kt index be8007b1db..b8970f2e9c 100644 --- a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/KotlinTestingDsl.kt +++ b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/KotlinTestingDsl.kt @@ -20,7 +20,7 @@ enum class JavaVersion : Comparable { J1_3, J1_4, J1_5, J1_6, J1_7, J1_8, J9, J10, J11, J12, J13, - J14, J14__PREVIEW, + J14, J15, J15__PREVIEW, J16, J16__PREVIEW; diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java14/PatternMatchingInstanceof.java b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java14/PatternMatchingInstanceof.java deleted file mode 100644 index 8ec838a50b..0000000000 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java14/PatternMatchingInstanceof.java +++ /dev/null @@ -1,34 +0,0 @@ -/** - * - * @see JEP 305: Pattern Matching for instanceof (Preview) - */ -public class PatternMatchingInstanceof { - private String s = "other string"; - - public void test() { - Object obj = "abc"; - //obj = 1; - if (obj instanceof String s) { - System.out.println("a) obj == s: " + (obj == s)); // true - } else { - System.out.println("b) obj == s: " + (obj == s)); // false - } - - if (!(obj instanceof String s)) { - System.out.println("c) obj == s: " + (obj == s)); // false - } else { - System.out.println("d) obj == s: " + (obj == s)); // true - } - - if (obj instanceof String s && s.length() > 2) { - System.out.println("e) obj == s: " + (obj == s)); // true - } - if (obj instanceof String s || s.length() > 5) { - System.out.println("f) obj == s: " + (obj == s)); // false - } - } - - public static void main(String[] args) { - new PatternMatchingInstanceof().test(); - } -} \ No newline at end of file diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java14/Point.java b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java14/Point.java deleted file mode 100644 index ac3fe4fd46..0000000000 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java14/Point.java +++ /dev/null @@ -1,10 +0,0 @@ -/** - * @see JEP 359: Records (Preview) - */ -public record Point(int x, int y) { - - public static void main(String[] args) { - Point p = new Point(1, 2); - System.out.println("p = " + p); - } -} diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java14/Records.java b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java14/Records.java deleted file mode 100644 index 2368b2ae7c..0000000000 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java14/Records.java +++ /dev/null @@ -1,61 +0,0 @@ -import java.io.IOException; -import java.lang.annotation.Target; -import java.lang.annotation.ElementType; - -/** - * @see JEP 359: Records (Preview) - */ -public class Records { - - @Target(ElementType.TYPE_USE) - @interface Nullable { } - - @Target({ElementType.CONSTRUCTOR, ElementType.PARAMETER}) - @interface MyAnnotation { } - - public record MyComplex(int real, @Deprecated int imaginary) { - // explicit declaration of a canonical constructor - @MyAnnotation - public MyComplex(@MyAnnotation int real, int imaginary) { - if (real > 100) throw new IllegalArgumentException("too big"); - this.real = real; - this.imaginary = imaginary; - } - public record Nested(int a) {} - } - - - public record Range(int lo, int hi) { - // compact record constructor - @MyAnnotation - public Range { - if (lo > hi) /* referring here to the implicit constructor parameters */ - throw new IllegalArgumentException(String.format("(%d,%d)", lo, hi)); - } - - public void foo() { } - } - - public record VarRec(@Nullable @Deprecated String @Nullable ... x) {} - - public record ArrayRec(int x[]) {} - - public record EmptyRec() { - public void foo() { } - public Type bar() { return null; } - public static void baz() { - EmptyRec r = new EmptyRec<>(); - System.out.println(r); - } - } - - // see https://www.javaspecialists.eu/archive/Issue276.html - public interface Person { - String firstName(); - String lastName(); - } - public record PersonRecord(String firstName, String lastName) - implements Person, java.io.Serializable { - - } -} diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java14/TextBlocks.java b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java14/TextBlocks.java deleted file mode 100644 index 5ff553185f..0000000000 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java14/TextBlocks.java +++ /dev/null @@ -1,113 +0,0 @@ -import javax.script.ScriptEngine; -import javax.script.ScriptEngineManager; - -/** - * @see JEP 368: Text Blocks (Second Preview) - */ -public class TextBlocks { - - - public static void main(String[] args) throws Exception { - // note: there is trailing whitespace!! - String html = """ - - -

Hello, world

- - - """; - System.out.println(html); - - String query = """ - SELECT `EMP_ID`, `LAST_NAME` FROM `EMPLOYEE_TB` - WHERE `CITY` = 'INDIANAPOLIS' - ORDER BY `EMP_ID`, `LAST_NAME`; - """; - System.out.println(query); - - ScriptEngine engine = new ScriptEngineManager().getEngineByName("js"); - Object obj = engine.eval(""" - function hello() { - print('"Hello, world"'); - } - - hello(); - """); - - // Escape sequences - String htmlWithEscapes = """ - \r - \r -

Hello, world

\r - \r - \r - """; - System.out.println(htmlWithEscapes); - - String season = """ - winter"""; // the six characters w i n t e r - - String period = """ - winter - """; // the seven characters w i n t e r LF - - String greeting = - """ - Hi, "Bob" - """; // the ten characters H i , SP " B o b " LF - - String salutation = - """ - Hi, - "Bob" - """; // the eleven characters H i , LF SP " B o b " LF - - String empty = """ - """; // the empty string (zero length) - - String quote = """ - " - """; // the two characters " LF - - String backslash = """ - \\ - """; // the two characters \ LF - - String normalStringLiteral = "test"; - - String code = - """ - String text = \""" - A text block inside a text block - \"""; - """; - - // new escape sequences - String text = """ - Lorem ipsum dolor sit amet, consectetur adipiscing \ - elit, sed do eiusmod tempor incididunt ut labore \ - et dolore magna aliqua.\ - """; - System.out.println(text); - - String colors = """ - red \s - green\s - blue \s - """; - System.out.println(colors); - - // empty new line as first content - String emptyLine = """ - -test -"""; - System.out.println(emptyLine.replaceAll("\n", "")); - - // backslash escapes - String bs = """ - \\test - """; - System.out.println(bs.replaceAll("\n", "")); - } -} diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/MissingOverride.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/MissingOverride.xml index 0d2d255eef..a03e00f19e 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/MissingOverride.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/MissingOverride.xml @@ -563,6 +563,6 @@ public record Point(int x, int y) { } } ]]> - java 14-preview + java 16 diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/performance/xml/InefficientEmptyStringCheck.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/performance/xml/InefficientEmptyStringCheck.xml index e77c303c83..8d2af3b1ba 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/performance/xml/InefficientEmptyStringCheck.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/performance/xml/InefficientEmptyStringCheck.xml @@ -198,6 +198,6 @@ public class PatternMatchingInstanceof { } } ]]> - java 14-preview + java 16 From 403c5956b856099d8667405b905a90aa2e9d414d Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Tue, 16 Feb 2021 21:19:22 +0100 Subject: [PATCH 8/8] [doc] Update release notes for Java 16 support --- docs/pages/release_notes.md | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/docs/pages/release_notes.md b/docs/pages/release_notes.md index b8f8783555..bb4ad6ddca 100644 --- a/docs/pages/release_notes.md +++ b/docs/pages/release_notes.md @@ -14,10 +14,40 @@ This is a {{ site.pmd.release_type }} release. ### New and noteworthy +#### Java 16 Support + +This release of PMD brings support for Java 16. PMD supports [JEP 394: Pattern Matching for instanceof](https://openjdk.java.net/jeps/394) and [JEP 395: Records](https://openjdk.java.net/jeps/395). Both have been promoted +to be a standard language feature of Java 16. + +PMD also supports [JEP 397: Sealed Classes (Second Preview)](https://openjdk.java.net/jeps/397) as a preview +language feature. In order to analyze a project with PMD that uses these language features, you'll need to enable +it via the environment variable `PMD_JAVA_OPTS` and select the new language version `16-preview`: + + export PMD_JAVA_OPTS=--enable-preview + ./run.sh pmd -language java -version 16-preview ... + +Note: Support for Java 14 preview language features have been removed. The version "14-preview" is no longer available. + ### Fixed Issues ### API Changes +#### pmd-java + +* The experimental class `ASTTypeTestPattern` has been renamed to {% jdoc java::lang.java.ast.ASTTypePattern %} + in order to align the naming to the JLS. +* The experimental class `ASTRecordConstructorDeclaration` has been renamed to {% jdoc java::lang.java.ast.ASTCompactConstructorDeclaration %} + in order to align the naming to the JLS. +* The AST types and APIs around Pattern Matching and Records are not experimental anymore: + * {% jdoc !!java::lang.java.ast.ASTVariableDeclaratorId#isPatternBinding() %} + * {% jdoc java::lang.java.ast.ASTPattern %} + * {% jdoc java::lang.java.ast.ASTTypePattern %} + * {% jdoc java::lang.java.ast.ASTRecordDeclaration %} + * {% jdoc java::lang.java.ast.ASTRecordComponentList %} + * {% jdoc java::lang.java.ast.ASTRecordComponent %} + * {% jdoc java::lang.java.ast.ASTRecordBody %} + * {% jdoc java::lang.java.ast.ASTCompactConstructorDeclaration %} + ### External Contributions {% endtocmaker %}