[java] JEP 395: Records for Java16

- Renamed ASTRecordConstructorDeclaration to
  ASTCompactConstructorDeclaration to align naming to JLS
- ASTRecordDeclaration, ASTRecordComponentList, ASTRecordComponent,
  ASTRecordBody, ASTCompactConstructorDeclaration are not
  longer @Experimental
This commit is contained in:
Andreas Dangel
2021-02-14 19:42:59 +01:00
parent 03731f8c16
commit 8bc26f95aa
24 changed files with 983 additions and 76 deletions

View File

@ -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=<IDENTIFIER> {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() <IDENTIFIER> "{"
}
void RecordConstructorDeclaration():
void CompactConstructorDeclaration():
{
int modifiers;
}
@ -2071,7 +2083,6 @@ void LocalTypeDecl(int mods) #void:
| LOOKAHEAD(<INTERFACE>) ClassOrInterfaceDeclaration(mods) { checkForLocalInterfaceOrEnumType(); }
| LOOKAHEAD({isKeyword("record")}) RecordDeclaration(mods) { checkForLocalInterfaceOrEnumType(); }
| LOOKAHEAD({isKeyword("enum")}) EnumDeclaration(mods) { checkForLocalInterfaceOrEnumType(); }
| AnnotationTypeDeclaration(mods) { checkForLocalInterfaceOrEnumType(); }
)
}

View File

@ -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).
*
* <pre class="grammar">
*
* RecordConstructorDeclaration ::= ({@linkplain ASTAnnotation Annotation})*
* CompactConstructorDeclaration ::= ({@linkplain ASTAnnotation Annotation})*
* RecordModifiers
* &lt;IDENTIFIER&gt;
* {@link ASTBlock Block}
@ -20,13 +18,12 @@ import net.sourceforge.pmd.annotation.Experimental;
* </pre>
*
*/
@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;
}

View File

@ -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.
*
* <pre class="grammar">
*
* RecordBody ::= "{" ( {@linkplain ASTRecordConstructorDeclaration RecordConstructorDeclaration}
* RecordBody ::= "{" ( {@linkplain ASTCompactConstructorDeclaration CompactConstructorDeclaration}
* | {@linkplain ASTClassOrInterfaceBodyDeclaration ClassOrInterfaceBodyDeclaration} )* "}"
*
* </pre>
*
*/
@Experimental
public final class ASTRecordBody extends AbstractJavaNode {
ASTRecordBody(int id) {
super(id);

View File

@ -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).
*
* <pre class="grammar">
*
@ -19,7 +17,6 @@ import net.sourceforge.pmd.annotation.Experimental;
*
* </pre>
*/
@Experimental
public final class ASTRecordComponent extends AbstractJavaAnnotatableNode {
private boolean varargs;

View File

@ -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).
*
* <pre class="grammar">
*
@ -18,7 +16,6 @@ import net.sourceforge.pmd.annotation.Experimental;
*
* </pre>
*/
@Experimental
public final class ASTRecordComponentList extends AbstractJavaNode implements Iterable<ASTRecordComponent> {
ASTRecordComponentList(int id) {
super(id);

View File

@ -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.
*
* <pre class="grammar">
@ -25,9 +24,8 @@ import net.sourceforge.pmd.lang.ast.Node;
*
* </pre>
*
* @see <a href="https://openjdk.java.net/jeps/384">JEP 384: Records (Second Preview)</a>
* @see <a href="https://openjdk.java.net/jeps/395">JEP 395: Records</a>
*/
@Experimental
public final class ASTRecordDeclaration extends AbstractAnyTypeDeclaration {
ASTRecordDeclaration(int id) {
super(id);

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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;

View File

@ -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);
}

View File

@ -149,7 +149,7 @@ public class Java14PreviewTest {
ASTRecordDeclaration range = recordDecls.get(2);
Assert.assertEquals("Range", range.getSimpleName());
Assert.assertEquals(2, range.getComponentList().size());
List<ASTRecordConstructorDeclaration> rangeConstructors = range.findDescendantsOfType(ASTRecordConstructorDeclaration.class);
List<ASTCompactConstructorDeclaration> 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);

View File

@ -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<ASTRecordComponent> 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 {}");
}
}

View File

@ -14,6 +14,7 @@ public class LocalInterfacesAndEnums {
enum MyLocalEnum { A }
@interface MyLocalAnnotation {}
// not supported anymore with Java16
//@interface MyLocalAnnotation {}
}
}

View File

@ -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"]

View File

@ -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"]

View File

@ -0,0 +1,32 @@
/*
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
/**
* @see <a href="http://cr.openjdk.java.net/~gbierman/jep395/jep395-20201019/specs/local-statics-jls.html">Local and Nested Static Declarations</a>
*/
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 {}
}
}

View File

@ -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"]

View File

@ -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 <a href="https://openjdk.java.net/jeps/395">JEP 395: Records</a>
*/
public class LocalRecords {
public interface Merchant {}
public static double computeSales(Merchant merchant, int month) {
return month;
}
List<Merchant> findTopMerchants(List<Merchant> 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);
}
}

View File

@ -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"]

View File

@ -0,0 +1,14 @@
/*
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
/**
* @see <a href="https://openjdk.java.net/jeps/395">JEP 395: Records</a>
*/
public record Point(int x, int y) {
public static void main(String[] args) {
Point p = new Point(1, 2);
System.out.println("p = " + p);
}
}

View File

@ -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"]

View File

@ -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 <a href="https://openjdk.java.net/jeps/395">JEP 395: Records</a>
*/
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<Type>() {
public void foo() { }
public Type bar() { return null; }
public static void baz() {
EmptyRec<String> 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 {
}
}