Merge branch 'master' into 7.0.x

This commit is contained in:
Clément Fournier
2021-03-05 11:54:58 +01:00
6 changed files with 59 additions and 7 deletions

View File

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

View File

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

View File

@ -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.
*

View File

@ -15,7 +15,7 @@ public class InfiniteLoopInLookahead {
resList.forEach(f -> {
resList.forEach(g -> {
resList.forEach(h -> {
resList
resList // note: missing semicolon -> parse error here...
});
});
});

View File

@ -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 {}
}

View File

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