diff --git a/pmd-java/etc/grammar/Java.jjt b/pmd-java/etc/grammar/Java.jjt index c5b1aa04b3..0ab2883e0a 100644 --- a/pmd-java/etc/grammar/Java.jjt +++ b/pmd-java/etc/grammar/Java.jjt @@ -2213,7 +2213,7 @@ void BlockStatement() #void: | LOOKAHEAD({ isAssertStart() }) AssertStatement() | LOOKAHEAD({ isYieldStart() }) YieldStatement() | LOOKAHEAD({ getToken(2).kind == COLON }) LabeledStatement() - | LOOKAHEAD(ClassOrInterfaceType() ) LocalVariableDeclaration() ";" { fixLastToken(); } + | LOOKAHEAD(ReferenceType() ) LocalVariableDeclaration() ";" { fixLastToken(); } | LOOKAHEAD({true}) ExpressionStatement() ) | LOOKAHEAD(1, LocalTypeStartNoIdent()) ModifierList() LocalTypeDecl() diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAnyTypeDeclaration.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAnyTypeDeclaration.java index c595beced7..f25c7d55dc 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAnyTypeDeclaration.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAnyTypeDeclaration.java @@ -224,6 +224,16 @@ public interface ASTAnyTypeDeclaration return false; } + /** + * Returns true if this is a regular class declaration (not an enum, + * not a record, not an interface or annotation). Note that eg + * {@link JClassSymbol#isClass()} counts records and enums in, just + * like {@link #isInterface()} counts annotations in. + */ + default boolean isRegularClass() { + return false; + } + /** Returns true if this is an {@linkplain ASTAnnotationTypeDeclaration annotation type declaration}. */ default boolean isAnnotation() { diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTClassOrInterfaceDeclaration.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTClassOrInterfaceDeclaration.java index 8e37479791..d022f757ef 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTClassOrInterfaceDeclaration.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTClassOrInterfaceDeclaration.java @@ -49,6 +49,11 @@ public final class ASTClassOrInterfaceDeclaration extends AbstractAnyTypeDeclara return this.isInterface; } + @Override + public boolean isRegularClass() { + return !isInterface; + } + void setInterface() { this.isInterface = true; } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTLocalClassStatement.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTLocalClassStatement.java index 7d28ca04cf..1aa1f6c7f0 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTLocalClassStatement.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTLocalClassStatement.java @@ -26,6 +26,8 @@ public final class ASTLocalClassStatement extends AbstractStatement { super(JavaParserImplTreeConstants.JJTLOCALCLASSSTATEMENT); assert tdecl != null; addChild((AbstractJavaNode) tdecl, 0); + setFirstToken(tdecl.getFirstToken()); + setLastToken(tdecl.getLastToken()); } @Override diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTLocalVariableDeclaration.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTLocalVariableDeclaration.java index 29f84e2d17..39274f18c7 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTLocalVariableDeclaration.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTLocalVariableDeclaration.java @@ -24,6 +24,7 @@ public final class ASTLocalVariableDeclaration extends AbstractJavaNode implements Iterable, ASTStatement, FinalizableNode, + LeftRecursiveNode, // ModifierList is parsed separately in BlockStatement InternalInterfaces.MultiVariableIdOwner { ASTLocalVariableDeclaration(int id) { diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/internal/LanguageLevelChecker.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/internal/LanguageLevelChecker.java index 753f5b73e4..569eba89e0 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/internal/LanguageLevelChecker.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/internal/LanguageLevelChecker.java @@ -124,6 +124,7 @@ public class LanguageLevelChecker { RECORD_DECLARATIONS(14, 15, false), TYPE_TEST_PATTERNS_IN_INSTANCEOF(14, 15, false), SEALED_CLASSES(15, 15, false), + STATIC_LOCAL_TYPE_DECLARATIONS(15, 15, false), // part of the sealed classes JEP ; // SUPPRESS CHECKSTYLE enum trailing semi is awesome @@ -478,8 +479,8 @@ public class LanguageLevelChecker { public Void visit(ASTAnyTypeDeclaration node, T data) { if (node.getModifiers().hasAnyExplicitly(JModifier.SEALED, JModifier.NON_SEALED)) { check(node, PreviewFeature.SEALED_CLASSES, data); - } else if (node.isLocal() && node.isInterface() || node.isEnum()) { - check(node, PreviewFeature.SEALED_CLASSES, data); + } else if (node.isLocal() && !node.isRegularClass()) { + check(node, PreviewFeature.STATIC_LOCAL_TYPE_DECLARATIONS, data); } String simpleName = node.getSimpleName(); diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/JavaQualifiedNameTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/JavaQualifiedNameTest.java index 6a7cae6aa8..28d69d2ec3 100644 --- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/JavaQualifiedNameTest.java +++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/JavaQualifiedNameTest.java @@ -24,7 +24,7 @@ public class JavaQualifiedNameTest { private List getNodes(Class target, String code) { - return JavaParsingHelper.WITH_PROCESSING.getNodes(target, code); + return JavaParsingHelper.WITH_PROCESSING.withDefaultVersion("15-preview").getNodes(target, code); } @Test