diff --git a/pmd-java/etc/grammar/Java.jjt b/pmd-java/etc/grammar/Java.jjt
index 65c76aee3b..60e9dc3902 100644
--- a/pmd-java/etc/grammar/Java.jjt
+++ b/pmd-java/etc/grammar/Java.jjt
@@ -578,17 +578,23 @@ class JavaParserImpl {
prev.setLastToken(top.getLastToken());
}
- /**
+ /**
* Keeps track during tree construction, whether we are currently building an
* explicit constructor invocation. Then the PrimaryExpression that may prefix
* a qualified super constructor call may not consume "super" tokens.
*/
private boolean inExplicitConstructorInvoc = false;
+ /**
+ * Keeps track of the current token context. This is needed to resolve the ambiguities around String Templates:
+ * A closing bracket (RBRACE) might close a block or might be the start of a STRING_TEMPLATE_MID/END token.
+ *
+ * @see JEP 430: String Templates (Preview)
+ */
private Deque tokenContexts = new ArrayDeque();
TokenContext determineTokenContext() {
if (tokenContexts.isEmpty()) {
- return null;
+ return TokenContext.BLOCK;
}
return tokenContexts.peek();
}
diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java21TreeDumpTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java21TreeDumpTest.java
index 162bcfd770..0dbcaf725a 100644
--- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java21TreeDumpTest.java
+++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java21TreeDumpTest.java
@@ -122,4 +122,9 @@ class Java21TreeDumpTest extends BaseTreeDumpTest {
void recordPatternsExhaustiveSwitch() {
doTest("RecordPatternsExhaustiveSwitch");
}
+
+ @Test
+ void canParseAnnotationValueInitializers() {
+ doTest("AnnotationValueInitializers");
+ }
}
diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java21/AnnotationValueInitializers.java b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java21/AnnotationValueInitializers.java
new file mode 100644
index 0000000000..11bf9cc322
--- /dev/null
+++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java21/AnnotationValueInitializers.java
@@ -0,0 +1,13 @@
+/*
+ * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
+ */
+
+/*
+ * Tests parsing after supporting String Templates. "}" is ambiguous.
+ */
+
+@MyAnnotation(a = { "a" }, b = "b") // "}" might be recognized as STRING_TEMPLATE_END, but it is not
+class AnnotationValueInitializers { }
+
+@MyAnnotation(a = { "a" }, b = "#b") // "}" might be recognized as STRING_TEMPLATE_END, but it is not
+class AnnotationValueInitializers2 { }
diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java21/AnnotationValueInitializers.txt b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java21/AnnotationValueInitializers.txt
new file mode 100644
index 0000000000..93deaccbde
--- /dev/null
+++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java21/AnnotationValueInitializers.txt
@@ -0,0 +1,23 @@
++- CompilationUnit[@PackageName = ""]
+ +- ClassOrInterfaceDeclaration[@Abstract = false, @Annotation = false, @Anonymous = false, @BinaryName = "AnnotationValueInitializers", @CanonicalName = "AnnotationValueInitializers", @EffectiveVisibility = Visibility.V_PACKAGE, @Enum = false, @Final = false, @Image = "AnnotationValueInitializers", @Interface = false, @Local = false, @Native = false, @Nested = false, @PackageName = "", @PackagePrivate = true, @Private = false, @Protected = false, @Public = false, @Record = false, @RegularClass = true, @RegularInterface = false, @SimpleName = "AnnotationValueInitializers", @Static = false, @Strictfp = false, @Synchronized = false, @SyntacticallyAbstract = false, @SyntacticallyFinal = false, @SyntacticallyPublic = false, @SyntacticallyStatic = false, @TopLevel = true, @Transient = false, @Visibility = Visibility.V_PACKAGE, @Volatile = false]
+ | +- ModifierList[]
+ | | +- Annotation[@AnnotationName = "MyAnnotation", @SimpleName = "MyAnnotation"]
+ | | +- ClassOrInterfaceType[@ArrayDepth = 0, @ArrayType = false, @ClassOrInterfaceType = true, @FullyQualified = false, @PrimitiveType = false, @ReferenceToClassSameCompilationUnit = false, @SimpleName = "MyAnnotation", @TypeImage = "MyAnnotation"]
+ | | +- AnnotationMemberList[@Empty = false, @Size = 2]
+ | | +- MemberValuePair[@Image = "a", @Name = "a", @Shorthand = false]
+ | | | +- MemberValueArrayInitializer[]
+ | | | +- StringLiteral[@BooleanLiteral = false, @CharLiteral = false, @CompileTimeConstant = true, @ConstValue = "a", @DoubleLiteral = false, @Empty = false, @Expression = true, @FloatLiteral = false, @Image = "\"a\"", @IntLiteral = false, @Length = 1, @LongLiteral = false, @NullLiteral = false, @NumericLiteral = false, @ParenthesisDepth = 0, @Parenthesized = false, @StringLiteral = true, @TextBlock = false]
+ | | +- MemberValuePair[@Image = "b", @Name = "b", @Shorthand = false]
+ | | +- StringLiteral[@BooleanLiteral = false, @CharLiteral = false, @CompileTimeConstant = true, @ConstValue = "b", @DoubleLiteral = false, @Empty = false, @Expression = true, @FloatLiteral = false, @Image = "\"b\"", @IntLiteral = false, @Length = 1, @LongLiteral = false, @NullLiteral = false, @NumericLiteral = false, @ParenthesisDepth = 0, @Parenthesized = false, @StringLiteral = true, @TextBlock = false]
+ | +- ClassOrInterfaceBody[@Empty = true, @Size = 0]
+ +- ClassOrInterfaceDeclaration[@Abstract = false, @Annotation = false, @Anonymous = false, @BinaryName = "AnnotationValueInitializers2", @CanonicalName = "AnnotationValueInitializers2", @EffectiveVisibility = Visibility.V_PACKAGE, @Enum = false, @Final = false, @Image = "AnnotationValueInitializers2", @Interface = false, @Local = false, @Native = false, @Nested = false, @PackageName = "", @PackagePrivate = true, @Private = false, @Protected = false, @Public = false, @Record = false, @RegularClass = true, @RegularInterface = false, @SimpleName = "AnnotationValueInitializers2", @Static = false, @Strictfp = false, @Synchronized = false, @SyntacticallyAbstract = false, @SyntacticallyFinal = false, @SyntacticallyPublic = false, @SyntacticallyStatic = false, @TopLevel = true, @Transient = false, @Visibility = Visibility.V_PACKAGE, @Volatile = false]
+ +- ModifierList[]
+ | +- Annotation[@AnnotationName = "MyAnnotation", @SimpleName = "MyAnnotation"]
+ | +- ClassOrInterfaceType[@ArrayDepth = 0, @ArrayType = false, @ClassOrInterfaceType = true, @FullyQualified = false, @PrimitiveType = false, @ReferenceToClassSameCompilationUnit = false, @SimpleName = "MyAnnotation", @TypeImage = "MyAnnotation"]
+ | +- AnnotationMemberList[@Empty = false, @Size = 2]
+ | +- MemberValuePair[@Image = "a", @Name = "a", @Shorthand = false]
+ | | +- MemberValueArrayInitializer[]
+ | | +- StringLiteral[@BooleanLiteral = false, @CharLiteral = false, @CompileTimeConstant = true, @ConstValue = "a", @DoubleLiteral = false, @Empty = false, @Expression = true, @FloatLiteral = false, @Image = "\"a\"", @IntLiteral = false, @Length = 1, @LongLiteral = false, @NullLiteral = false, @NumericLiteral = false, @ParenthesisDepth = 0, @Parenthesized = false, @StringLiteral = true, @TextBlock = false]
+ | +- MemberValuePair[@Image = "b", @Name = "b", @Shorthand = false]
+ | +- StringLiteral[@BooleanLiteral = false, @CharLiteral = false, @CompileTimeConstant = true, @ConstValue = "#b", @DoubleLiteral = false, @Empty = false, @Expression = true, @FloatLiteral = false, @Image = "\"#b\"", @IntLiteral = false, @Length = 2, @LongLiteral = false, @NullLiteral = false, @NumericLiteral = false, @ParenthesisDepth = 0, @Parenthesized = false, @StringLiteral = true, @TextBlock = false]
+ +- ClassOrInterfaceBody[@Empty = true, @Size = 0]