Merge branch 'master' into 7.0.x
This commit is contained in:
@ -21,6 +21,10 @@ This is a {{ site.pmd.release_type }} release.
|
||||
|
||||
### Fixed Issues
|
||||
|
||||
* java
|
||||
* [#3117](https://github.com/pmd/pmd/issues/3117): \[java] Infinite loop when parsing invalid code nested in lambdas
|
||||
* [#3145](https://github.com/pmd/pmd/issues/3145): \[java] Parse exception when using "record" as variable name
|
||||
|
||||
### API Changes
|
||||
|
||||
### External Contributions
|
||||
|
@ -1,4 +1,10 @@
|
||||
/**
|
||||
* Fix #3117 - infinite loop when parsing invalid code nested in lambdas
|
||||
* Andreas Dangel 03/2021
|
||||
*====================================================================
|
||||
* Fix #3145 - parse exception with local records
|
||||
* Clément Fournier 03/2021
|
||||
*====================================================================
|
||||
* Remove support for Java 14 preview language features
|
||||
* JEP 397: Sealed Classes (Second Preview) for Java16 Preview
|
||||
* JEP 395: Records for Java16
|
||||
@ -232,6 +238,11 @@ options {
|
||||
VISITOR = true;
|
||||
NODE_PACKAGE="net.sourceforge.pmd.lang.java.ast";
|
||||
|
||||
// disable the calculation of expected tokens when a parse error occurs
|
||||
// depending on the possible allowed next tokens, this
|
||||
// could be expensive (see https://github.com/pmd/pmd/issues/3117)
|
||||
//ERROR_REPORTING = false;
|
||||
|
||||
//DEBUG_PARSER = true;
|
||||
//DEBUG_LOOKAHEAD = true;
|
||||
//DEBUG_TOKEN_MANAGER = true;
|
||||
@ -312,7 +323,7 @@ class JavaParserImpl {
|
||||
}
|
||||
|
||||
private boolean isRecordStart() {
|
||||
return isRecordTypeSupported() && isKeyword("record");
|
||||
return isRecordTypeSupported() && isKeyword("record") && isToken(2, IDENTIFIER);
|
||||
}
|
||||
|
||||
private boolean isEnumStart() {
|
||||
@ -381,8 +392,7 @@ class JavaParserImpl {
|
||||
next.kind == INTERFACE
|
||||
|| next.kind == AT && isToken(2, INTERFACE)
|
||||
|| next.kind == IDENTIFIER && next.getImage().equals("enum")
|
||||
||
|
||||
next.kind == IDENTIFIER && next.image.equals("record")
|
||||
|| next.kind == IDENTIFIER && next.getImage().equals("record") && isToken(2, IDENTIFIER)
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -186,13 +186,22 @@ public class ParserCornersTest extends BaseJavaTreeDumpTest {
|
||||
doTest("GitHubBug309", java8);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Test(timeout = 30000)
|
||||
public void testInfiniteLoopInLookahead() {
|
||||
expect.expect(ParseException.class); // the code is invalid. The test fails if it times out
|
||||
expect.expect(ParseException.class);
|
||||
// https://github.com/pmd/pmd/issues/3117
|
||||
java8.parseResource("InfiniteLoopInLookahead.java");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void stringConcatentationShouldNotBeCast() {
|
||||
// https://github.com/pmd/pmd/issues/1484
|
||||
String code = "public class Test {\n" + " public static void main(String[] args) {\n"
|
||||
+ " System.out.println(\"X\" + (args) + \"Y\");\n" + " }\n" + "}";
|
||||
Assert.assertEquals(0, java8.parse(code).findDescendantsOfType(ASTCastExpression.class).size());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Empty statements should be allowed.
|
||||
*
|
||||
|
@ -15,7 +15,7 @@ public class InfiniteLoopInLookahead {
|
||||
resList.forEach(f -> {
|
||||
resList.forEach(g -> {
|
||||
resList.forEach(h -> {
|
||||
resList
|
||||
resList // note: missing semicolon -> parse error here...
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -31,6 +31,12 @@ public class LocalRecords {
|
||||
final @Deprecated static record MyRecord4(String a) {}
|
||||
}
|
||||
|
||||
void statementThatStartsWithRecordAsRegularIdent() {
|
||||
// https://github.com/pmd/pmd/issues/3145
|
||||
final Map<String, String> record = new HashMap<>();
|
||||
record.put("key", "value");
|
||||
}
|
||||
|
||||
void methodWithLocalClass() {
|
||||
class MyLocalClass {}
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
+- ImportDeclaration[@ImportOnDemand = "false", @ImportedName = "java.util.List", @ImportedSimpleName = "List", @PackageName = "java.util", @Static = "false"]
|
||||
+- ClassOrInterfaceDeclaration[@Abstract = "false", @Annotation = "false", @Anonymous = "false", @BinaryName = "LocalRecords", @CanonicalName = "LocalRecords", @EffectiveVisibility = "public", @Enum = "false", @Final = "false", @Interface = "false", @Local = "false", @Nested = "false", @PackageName = "", @PackagePrivate = "false", @Record = "false", @RegularClass = "true", @SimpleName = "LocalRecords", @TopLevel = "true", @Visibility = "public"]
|
||||
+- ModifierList[@EffectiveModifiers = "{public}", @ExplicitModifiers = "{public}"]
|
||||
+- ClassOrInterfaceBody[@Size = "6"]
|
||||
+- ClassOrInterfaceBody[@Size = "7"]
|
||||
+- ClassOrInterfaceDeclaration[@Abstract = "true", @Annotation = "false", @Anonymous = "false", @BinaryName = "LocalRecords$Merchant", @CanonicalName = "LocalRecords.Merchant", @EffectiveVisibility = "public", @Enum = "false", @Final = "false", @Interface = "true", @Local = "false", @Nested = "true", @PackageName = "", @PackagePrivate = "false", @Record = "false", @RegularClass = "false", @SimpleName = "Merchant", @TopLevel = "false", @Visibility = "public"]
|
||||
| +- ModifierList[@EffectiveModifiers = "{public, abstract, static}", @ExplicitModifiers = "{public}"]
|
||||
| +- ClassOrInterfaceBody[@Size = "0"]
|
||||
@ -147,6 +147,29 @@
|
||||
| | +- ClassOrInterfaceType[@FullyQualified = "false", @SimpleName = "String"]
|
||||
| | +- VariableDeclaratorId[@ArrayType = "false", @EffectiveVisibility = "local", @EnumConstant = "false", @ExceptionBlockParameter = "false", @Field = "false", @Final = "true", @FormalParameter = "false", @LambdaParameter = "false", @LocalVariable = "false", @Name = "a", @PatternBinding = "false", @RecordComponent = "true", @ResourceDeclaration = "false", @TypeInferred = "false", @Visibility = "private"]
|
||||
| +- RecordBody[@Size = "0"]
|
||||
+- MethodDeclaration[@Abstract = "false", @Arity = "0", @EffectiveVisibility = "package", @Image = "statementThatStartsWithRecordAsRegularIdent", @Name = "statementThatStartsWithRecordAsRegularIdent", @Overridden = "false", @Varargs = "false", @Visibility = "package", @Void = "true"]
|
||||
| +- ModifierList[@EffectiveModifiers = "{}", @ExplicitModifiers = "{}"]
|
||||
| +- VoidType[]
|
||||
| +- FormalParameters[@Size = "0"]
|
||||
| +- Block[@Size = "2", @containsComment = "false"]
|
||||
| +- LocalVariableDeclaration[@EffectiveVisibility = "local", @Final = "true", @TypeInferred = "false", @Visibility = "local"]
|
||||
| | +- ModifierList[@EffectiveModifiers = "{final}", @ExplicitModifiers = "{final}"]
|
||||
| | +- ClassOrInterfaceType[@FullyQualified = "false", @SimpleName = "Map"]
|
||||
| | | +- TypeArguments[@Diamond = "false", @Size = "2"]
|
||||
| | | +- ClassOrInterfaceType[@FullyQualified = "false", @SimpleName = "String"]
|
||||
| | | +- ClassOrInterfaceType[@FullyQualified = "false", @SimpleName = "String"]
|
||||
| | +- VariableDeclarator[@Initializer = "true", @Name = "record"]
|
||||
| | +- VariableDeclaratorId[@ArrayType = "false", @EffectiveVisibility = "local", @EnumConstant = "false", @ExceptionBlockParameter = "false", @Field = "false", @Final = "true", @FormalParameter = "false", @LambdaParameter = "false", @LocalVariable = "true", @Name = "record", @PatternBinding = "false", @RecordComponent = "false", @ResourceDeclaration = "false", @TypeInferred = "false", @Visibility = "local"]
|
||||
| | +- ConstructorCall[@AnonymousClass = "false", @CompileTimeConstant = "false", @DiamondTypeArgs = "true", @MethodName = "new", @ParenthesisDepth = "0", @Parenthesized = "false", @QualifiedInstanceCreation = "false"]
|
||||
| | +- ClassOrInterfaceType[@FullyQualified = "false", @SimpleName = "HashMap"]
|
||||
| | | +- TypeArguments[@Diamond = "true", @Size = "0"]
|
||||
| | +- ArgumentList[@Size = "0"]
|
||||
| +- ExpressionStatement[]
|
||||
| +- MethodCall[@CompileTimeConstant = "false", @Image = "put", @MethodName = "put", @ParenthesisDepth = "0", @Parenthesized = "false"]
|
||||
| +- VariableAccess[@AccessType = "READ", @CompileTimeConstant = "false", @Image = "record", @Name = "record", @ParenthesisDepth = "0", @Parenthesized = "false"]
|
||||
| +- ArgumentList[@Size = "2"]
|
||||
| +- StringLiteral[@CompileTimeConstant = "true", @ConstValue = "key", @Empty = "false", @Image = "\"key\"", @Length = "3", @ParenthesisDepth = "0", @Parenthesized = "false", @TextBlock = "false"]
|
||||
| +- StringLiteral[@CompileTimeConstant = "true", @ConstValue = "value", @Empty = "false", @Image = "\"value\"", @Length = "5", @ParenthesisDepth = "0", @Parenthesized = "false", @TextBlock = "false"]
|
||||
+- MethodDeclaration[@Abstract = "false", @Arity = "0", @EffectiveVisibility = "package", @Image = "methodWithLocalClass", @Name = "methodWithLocalClass", @Overridden = "false", @Varargs = "false", @Visibility = "package", @Void = "true"]
|
||||
| +- ModifierList[@EffectiveModifiers = "{}", @ExplicitModifiers = "{}"]
|
||||
| +- VoidType[]
|
||||
|
Reference in New Issue
Block a user