Add ability to test an AST dump as cheap regression test
This commit is contained in:
parent
ac23b2cb3d
commit
bb92044a15
@ -0,0 +1,22 @@
|
||||
/*
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*/
|
||||
|
||||
package net.sourceforge.pmd.lang.java.ast
|
||||
|
||||
import com.github.oowekyala.treeutils.printers.SimpleTreePrinter
|
||||
import net.sourceforge.pmd.lang.ast.Node
|
||||
import net.sourceforge.pmd.lang.ast.test.BaseTreeDumpTest
|
||||
import net.sourceforge.pmd.lang.ast.test.RelevantAttributePrinter
|
||||
import net.sourceforge.pmd.lang.java.JavaParsingHelper
|
||||
|
||||
abstract class AbstractJavaTreeDumpTest : BaseTreeDumpTest(
|
||||
printer = RelevantAttributePrinter(SimpleTreePrinter.AsciiStrings),
|
||||
pathToFixtures = "testdata",
|
||||
extension = ".java"
|
||||
) {
|
||||
override fun parseFile(fileText: String): Node =
|
||||
JavaParsingHelper.WITH_PROCESSING.parse(fileText)
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,24 @@
|
||||
/*
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*/
|
||||
|
||||
package net.sourceforge.pmd.lang.java.ast
|
||||
|
||||
import org.junit.Test
|
||||
|
||||
/**
|
||||
* Compare a dump of a file against a saved baseline.
|
||||
*
|
||||
* @author Clément Fournier
|
||||
*/
|
||||
class AstTreeDumpTests : AbstractJavaTreeDumpTest() {
|
||||
|
||||
|
||||
@Test
|
||||
fun testCornerCases() = doTest("ParserCornerCases")
|
||||
|
||||
@Test
|
||||
fun testComplicatedLambda() = doTest("Bug1429")
|
||||
|
||||
|
||||
}
|
22
pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/testdata/Bug1429.java
vendored
Normal file
22
pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/testdata/Bug1429.java
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
/*
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*/
|
||||
|
||||
public class Bug1429 {
|
||||
public Set<String> getAttributeTuples() {
|
||||
return (Set<String>) (this.attributes == null ? Collections.<String> emptySet() : new HashSet<String>(
|
||||
CollectionUtils.collect(this.attributes.keySet(), new Transformer() {
|
||||
@Override
|
||||
public Object transform(final Object obj) {
|
||||
final String key = (String) obj;
|
||||
final String value = HGXLIFFTypeConfiguration.this.attributes.get(key);
|
||||
|
||||
String result = key;
|
||||
if (StringUtils.isNotEmpty(value)) {
|
||||
result = result.concat(":").concat(value);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
})));
|
||||
}
|
||||
}
|
94
pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/testdata/Bug1429.txt
vendored
Normal file
94
pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/testdata/Bug1429.txt
vendored
Normal file
@ -0,0 +1,94 @@
|
||||
+-- CompilationUnit[@PackageName = "", @declarationsAreInDefaultPackage = true]
|
||||
+-- TypeDeclaration[]
|
||||
+-- ClassOrInterfaceDeclaration[@Abstract = false, @BinaryName = "Bug1429", @Default = false, @Final = false, @Image = "Bug1429", @Interface = false, @Local = false, @Modifiers = 1, @Native = false, @Nested = null, @PackagePrivate = false, @Private = false, @Protected = false, @Public = true, @SimpleName = "Bug1429", @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, @Image = "getAttributeTuples", @InterfaceMember = false, @Kind = MethodLikeKind.METHOD, @MethodName = "getAttributeTuples", @Modifiers = 1, @Name = "getAttributeTuples", @Native = false, @PackagePrivate = false, @Private = false, @Protected = false, @Public = true, @Static = false, @Strictfp = false, @Synchronized = false, @SyntacticallyAbstract = false, @SyntacticallyPublic = true, @Transient = false, @Varargs = false, @Void = false, @Volatile = false]
|
||||
+-- ResultType[@Void = false, @returnsArray = false]
|
||||
| +-- ClassOrInterfaceType[@AnonymousClass = false, @ArrayDepth = 0, @ArrayType = false, @ClassOrInterfaceType = true, @Image = "Set", @PrimitiveType = false, @ReferenceToClassSameCompilationUnit = false, @ReferenceType = true, @SimpleName = "Set", @TypeImage = "Set"]
|
||||
| +-- TypeArguments[@Diamond = false]
|
||||
| +-- ClassOrInterfaceType[@AnonymousClass = false, @ArrayDepth = 0, @ArrayType = false, @ClassOrInterfaceType = true, @Image = "String", @PrimitiveType = false, @ReferenceToClassSameCompilationUnit = false, @ReferenceType = true, @SimpleName = "String", @TypeImage = "String"]
|
||||
+-- FormalParameters[@ParameterCount = 0]
|
||||
+-- Block[@containsComment = false]
|
||||
+-- ReturnStatement[]
|
||||
+-- CastExpression[@CompileTimeConstant = false, @Expression = true, @ParenthesisDepth = 0, @Parenthesized = false]
|
||||
+-- ClassOrInterfaceType[@AnonymousClass = false, @ArrayDepth = 0, @ArrayType = false, @ClassOrInterfaceType = true, @Image = "Set", @PrimitiveType = false, @ReferenceToClassSameCompilationUnit = false, @ReferenceType = true, @SimpleName = "Set", @TypeImage = "Set"]
|
||||
| +-- TypeArguments[@Diamond = false]
|
||||
| +-- ClassOrInterfaceType[@AnonymousClass = false, @ArrayDepth = 0, @ArrayType = false, @ClassOrInterfaceType = true, @Image = "String", @PrimitiveType = false, @ReferenceToClassSameCompilationUnit = false, @ReferenceType = true, @SimpleName = "String", @TypeImage = "String"]
|
||||
+-- ConditionalExpression[@CompileTimeConstant = false, @Expression = true, @ParenthesisDepth = 1, @Parenthesized = true]
|
||||
+-- InfixExpression[@CompileTimeConstant = false, @Expression = true, @Operator = BinaryOp.EQ, @ParenthesisDepth = 0, @Parenthesized = false]
|
||||
| +-- FieldAccess[@AccessType = AccessType.READ, @CompileTimeConstant = false, @Expression = true, @FieldName = "attributes", @Image = "attributes", @ParenthesisDepth = 0, @Parenthesized = false]
|
||||
| | +-- ThisExpression[@CompileTimeConstant = false, @Expression = true, @ParenthesisDepth = 0, @Parenthesized = false]
|
||||
| +-- NullLiteral[@BooleanLiteral = false, @CharLiteral = false, @CompileTimeConstant = false, @DoubleLiteral = false, @Expression = true, @FloatLiteral = false, @IntLiteral = false, @LongLiteral = false, @NullLiteral = true, @NumericLiteral = false, @ParenthesisDepth = 0, @Parenthesized = false, @StringLiteral = false]
|
||||
+-- MethodCall[@CompileTimeConstant = false, @Expression = true, @Image = "emptySet", @MethodName = "emptySet", @ParenthesisDepth = 0, @Parenthesized = false]
|
||||
| +-- AmbiguousName[@ArrayDepth = 0, @ArrayType = false, @ClassOrInterfaceType = false, @CompileTimeConstant = false, @Expression = true, @Image = "Collections", @Name = "Collections", @ParenthesisDepth = 0, @Parenthesized = false, @PrimitiveType = false, @ReferenceType = true, @Segments = null, @TypeImage = "Collections"]
|
||||
| +-- TypeArguments[@Diamond = false]
|
||||
| | +-- ClassOrInterfaceType[@AnonymousClass = false, @ArrayDepth = 0, @ArrayType = false, @ClassOrInterfaceType = true, @Image = "String", @PrimitiveType = false, @ReferenceToClassSameCompilationUnit = false, @ReferenceType = true, @SimpleName = "String", @TypeImage = "String"]
|
||||
| +-- ArgumentList[@ArgumentCount = 0]
|
||||
+-- ConstructorCall[@AnonymousClass = false, @CompileTimeConstant = false, @DiamondTypeArgs = false, @Expression = true, @ParenthesisDepth = 0, @Parenthesized = false, @QualifiedInstanceCreation = false]
|
||||
+-- ClassOrInterfaceType[@AnonymousClass = false, @ArrayDepth = 0, @ArrayType = false, @ClassOrInterfaceType = true, @Image = "HashSet", @PrimitiveType = false, @ReferenceToClassSameCompilationUnit = false, @ReferenceType = true, @SimpleName = "HashSet", @TypeImage = "HashSet"]
|
||||
| +-- TypeArguments[@Diamond = false]
|
||||
| +-- ClassOrInterfaceType[@AnonymousClass = false, @ArrayDepth = 0, @ArrayType = false, @ClassOrInterfaceType = true, @Image = "String", @PrimitiveType = false, @ReferenceToClassSameCompilationUnit = false, @ReferenceType = true, @SimpleName = "String", @TypeImage = "String"]
|
||||
+-- ArgumentList[@ArgumentCount = 1]
|
||||
+-- MethodCall[@CompileTimeConstant = false, @Expression = true, @Image = "collect", @MethodName = "collect", @ParenthesisDepth = 0, @Parenthesized = false]
|
||||
+-- AmbiguousName[@ArrayDepth = 0, @ArrayType = false, @ClassOrInterfaceType = false, @CompileTimeConstant = false, @Expression = true, @Image = "CollectionUtils", @Name = "CollectionUtils", @ParenthesisDepth = 0, @Parenthesized = false, @PrimitiveType = false, @ReferenceType = true, @Segments = null, @TypeImage = "CollectionUtils"]
|
||||
+-- ArgumentList[@ArgumentCount = 2]
|
||||
+-- MethodCall[@CompileTimeConstant = false, @Expression = true, @Image = "keySet", @MethodName = "keySet", @ParenthesisDepth = 0, @Parenthesized = false]
|
||||
| +-- FieldAccess[@AccessType = AccessType.READ, @CompileTimeConstant = false, @Expression = true, @FieldName = "attributes", @Image = "attributes", @ParenthesisDepth = 0, @Parenthesized = false]
|
||||
| | +-- ThisExpression[@CompileTimeConstant = false, @Expression = true, @ParenthesisDepth = 0, @Parenthesized = false]
|
||||
| +-- ArgumentList[@ArgumentCount = 0]
|
||||
+-- ConstructorCall[@AnonymousClass = true, @CompileTimeConstant = false, @DiamondTypeArgs = false, @Expression = true, @ParenthesisDepth = 0, @Parenthesized = false, @QualifiedInstanceCreation = false]
|
||||
+-- ClassOrInterfaceType[@AnonymousClass = false, @ArrayDepth = 0, @ArrayType = false, @ClassOrInterfaceType = true, @Image = "Transformer", @PrimitiveType = false, @ReferenceToClassSameCompilationUnit = false, @ReferenceType = true, @SimpleName = "Transformer", @TypeImage = "Transformer"]
|
||||
+-- ArgumentList[@ArgumentCount = 0]
|
||||
+-- AnonymousClassDeclaration[]
|
||||
+-- ClassOrInterfaceBody[@AnonymousInnerClass = false, @EnumChild = false]
|
||||
+-- ClassOrInterfaceBodyDeclaration[@AnonymousInnerClass = false, @EnumChild = false, @Kind = DeclarationKind.METHOD]
|
||||
+-- MethodDeclaration[@Abstract = false, @Arity = 1, @Default = false, @Final = false, @Image = "transform", @InterfaceMember = false, @Kind = MethodLikeKind.METHOD, @MethodName = "transform", @Modifiers = 1, @Name = "transform", @Native = false, @PackagePrivate = false, @Private = false, @Protected = false, @Public = true, @Static = false, @Strictfp = false, @Synchronized = false, @SyntacticallyAbstract = false, @SyntacticallyPublic = true, @Transient = false, @Varargs = false, @Void = false, @Volatile = false]
|
||||
+-- MarkerAnnotation[@AnnotationName = "Override", @Image = "Override", @SimpleName = "Override"]
|
||||
+-- ResultType[@Void = false, @returnsArray = false]
|
||||
| +-- ClassOrInterfaceType[@AnonymousClass = false, @ArrayDepth = 0, @ArrayType = false, @ClassOrInterfaceType = true, @Image = "Object", @PrimitiveType = false, @ReferenceToClassSameCompilationUnit = false, @ReferenceType = true, @SimpleName = "Object", @TypeImage = "Object"]
|
||||
+-- FormalParameters[@ParameterCount = 1]
|
||||
| +-- FormalParameter[@Abstract = false, @Array = false, @ArrayDepth = 0, @Default = false, @Final = true, @Modifiers = 32, @Native = false, @PackagePrivate = true, @Private = false, @Protected = false, @Public = false, @Static = false, @Strictfp = false, @Synchronized = false, @Transient = false, @TypeInferred = false, @Varargs = false, @Volatile = false]
|
||||
| +-- ClassOrInterfaceType[@AnonymousClass = false, @ArrayDepth = 0, @ArrayType = false, @ClassOrInterfaceType = true, @Image = "Object", @PrimitiveType = false, @ReferenceToClassSameCompilationUnit = false, @ReferenceType = true, @SimpleName = "Object", @TypeImage = "Object"]
|
||||
| +-- VariableDeclaratorId[@Array = false, @ArrayDepth = 0, @ArrayType = false, @EnumConstant = false, @ExceptionBlockParameter = false, @Field = false, @Final = true, @FormalParameter = true, @Image = "obj", @LambdaParameter = false, @LocalVariable = false, @ResourceDeclaration = false, @TypeInferred = false, @VariableName = "obj"]
|
||||
+-- Block[@containsComment = false]
|
||||
+-- LocalVariableDeclaration[@Abstract = false, @Array = false, @ArrayDepth = 0, @Default = false, @Final = true, @Modifiers = 32, @Native = false, @PackagePrivate = true, @Private = false, @Protected = false, @Public = false, @Static = false, @Strictfp = false, @Synchronized = false, @Transient = false, @TypeInferred = false, @VariableName = "key", @Volatile = false]
|
||||
| +-- ClassOrInterfaceType[@AnonymousClass = false, @ArrayDepth = 0, @ArrayType = false, @ClassOrInterfaceType = true, @Image = "String", @PrimitiveType = false, @ReferenceToClassSameCompilationUnit = false, @ReferenceType = true, @SimpleName = "String", @TypeImage = "String"]
|
||||
| +-- VariableDeclarator[@Initializer = true, @Name = "key"]
|
||||
| +-- VariableDeclaratorId[@Array = false, @ArrayDepth = 0, @ArrayType = false, @EnumConstant = false, @ExceptionBlockParameter = false, @Field = false, @Final = true, @FormalParameter = false, @Image = "key", @LambdaParameter = false, @LocalVariable = true, @ResourceDeclaration = false, @TypeInferred = false, @VariableName = "key"]
|
||||
| +-- CastExpression[@CompileTimeConstant = false, @Expression = true, @ParenthesisDepth = 0, @Parenthesized = false]
|
||||
| +-- ClassOrInterfaceType[@AnonymousClass = false, @ArrayDepth = 0, @ArrayType = false, @ClassOrInterfaceType = true, @Image = "String", @PrimitiveType = false, @ReferenceToClassSameCompilationUnit = false, @ReferenceType = true, @SimpleName = "String", @TypeImage = "String"]
|
||||
| +-- VariableAccess[@AccessType = AccessType.READ, @CompileTimeConstant = false, @Expression = true, @Image = "obj", @ParenthesisDepth = 0, @Parenthesized = false, @VariableName = "obj"]
|
||||
+-- LocalVariableDeclaration[@Abstract = false, @Array = false, @ArrayDepth = 0, @Default = false, @Final = true, @Modifiers = 32, @Native = false, @PackagePrivate = true, @Private = false, @Protected = false, @Public = false, @Static = false, @Strictfp = false, @Synchronized = false, @Transient = false, @TypeInferred = false, @VariableName = "value", @Volatile = false]
|
||||
| +-- ClassOrInterfaceType[@AnonymousClass = false, @ArrayDepth = 0, @ArrayType = false, @ClassOrInterfaceType = true, @Image = "String", @PrimitiveType = false, @ReferenceToClassSameCompilationUnit = false, @ReferenceType = true, @SimpleName = "String", @TypeImage = "String"]
|
||||
| +-- VariableDeclarator[@Initializer = true, @Name = "value"]
|
||||
| +-- VariableDeclaratorId[@Array = false, @ArrayDepth = 0, @ArrayType = false, @EnumConstant = false, @ExceptionBlockParameter = false, @Field = false, @Final = true, @FormalParameter = false, @Image = "value", @LambdaParameter = false, @LocalVariable = true, @ResourceDeclaration = false, @TypeInferred = false, @VariableName = "value"]
|
||||
| +-- MethodCall[@CompileTimeConstant = false, @Expression = true, @Image = "get", @MethodName = "get", @ParenthesisDepth = 0, @Parenthesized = false]
|
||||
| +-- FieldAccess[@AccessType = AccessType.READ, @CompileTimeConstant = false, @Expression = true, @FieldName = "attributes", @Image = "attributes", @ParenthesisDepth = 0, @Parenthesized = false]
|
||||
| | +-- ThisExpression[@CompileTimeConstant = false, @Expression = true, @ParenthesisDepth = 0, @Parenthesized = false]
|
||||
| | +-- ClassOrInterfaceType[@AnonymousClass = false, @ArrayDepth = 0, @ArrayType = false, @ClassOrInterfaceType = true, @Image = "HGXLIFFTypeConfiguration", @PrimitiveType = false, @ReferenceToClassSameCompilationUnit = false, @ReferenceType = true, @SimpleName = "HGXLIFFTypeConfiguration", @TypeImage = "HGXLIFFTypeConfiguration"]
|
||||
| +-- ArgumentList[@ArgumentCount = 1]
|
||||
| +-- VariableAccess[@AccessType = AccessType.READ, @CompileTimeConstant = false, @Expression = true, @Image = "key", @ParenthesisDepth = 0, @Parenthesized = false, @VariableName = "key"]
|
||||
+-- 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]
|
||||
| +-- ClassOrInterfaceType[@AnonymousClass = false, @ArrayDepth = 0, @ArrayType = false, @ClassOrInterfaceType = true, @Image = "String", @PrimitiveType = false, @ReferenceToClassSameCompilationUnit = false, @ReferenceType = true, @SimpleName = "String", @TypeImage = "String"]
|
||||
| +-- VariableDeclarator[@Initializer = true, @Name = "result"]
|
||||
| +-- VariableDeclaratorId[@Array = false, @ArrayDepth = 0, @ArrayType = false, @EnumConstant = false, @ExceptionBlockParameter = false, @Field = false, @Final = false, @FormalParameter = false, @Image = "result", @LambdaParameter = false, @LocalVariable = true, @ResourceDeclaration = false, @TypeInferred = false, @VariableName = "result"]
|
||||
| +-- VariableAccess[@AccessType = AccessType.READ, @CompileTimeConstant = false, @Expression = true, @Image = "key", @ParenthesisDepth = 0, @Parenthesized = false, @VariableName = "key"]
|
||||
+-- IfStatement[@Else = false]
|
||||
| +-- MethodCall[@CompileTimeConstant = false, @Expression = true, @Image = "isNotEmpty", @MethodName = "isNotEmpty", @ParenthesisDepth = 0, @Parenthesized = false]
|
||||
| | +-- AmbiguousName[@ArrayDepth = 0, @ArrayType = false, @ClassOrInterfaceType = false, @CompileTimeConstant = false, @Expression = true, @Image = "StringUtils", @Name = "StringUtils", @ParenthesisDepth = 0, @Parenthesized = false, @PrimitiveType = false, @ReferenceType = true, @Segments = null, @TypeImage = "StringUtils"]
|
||||
| | +-- ArgumentList[@ArgumentCount = 1]
|
||||
| | +-- VariableAccess[@AccessType = AccessType.READ, @CompileTimeConstant = false, @Expression = true, @Image = "value", @ParenthesisDepth = 0, @Parenthesized = false, @VariableName = "value"]
|
||||
| +-- Block[@containsComment = false]
|
||||
| +-- ExpressionStatement[]
|
||||
| +-- AssignmentExpression[@CompileTimeConstant = false, @Compound = false, @Expression = true, @Operator = AssignmentOp.ASSIGN, @ParenthesisDepth = 0, @Parenthesized = false]
|
||||
| +-- VariableAccess[@AccessType = AccessType.WRITE, @CompileTimeConstant = false, @Expression = true, @Image = "result", @ParenthesisDepth = 0, @Parenthesized = false, @VariableName = "result"]
|
||||
| +-- MethodCall[@CompileTimeConstant = false, @Expression = true, @Image = "concat", @MethodName = "concat", @ParenthesisDepth = 0, @Parenthesized = false]
|
||||
| +-- MethodCall[@CompileTimeConstant = false, @Expression = true, @Image = "concat", @MethodName = "concat", @ParenthesisDepth = 0, @Parenthesized = false]
|
||||
| | +-- AmbiguousName[@ArrayDepth = 0, @ArrayType = false, @ClassOrInterfaceType = false, @CompileTimeConstant = false, @Expression = true, @Image = "result", @Name = "result", @ParenthesisDepth = 0, @Parenthesized = false, @PrimitiveType = false, @ReferenceType = true, @Segments = null, @TypeImage = "result"]
|
||||
| | +-- ArgumentList[@ArgumentCount = 1]
|
||||
| | +-- StringLiteral[@BooleanLiteral = false, @CharLiteral = false, @CompileTimeConstant = true, @ConstValue = ":", @DoubleLiteral = false, @Expression = true, @FloatLiteral = false, @Image = "":"", @IntLiteral = false, @LongLiteral = false, @NullLiteral = false, @NumericLiteral = false, @ParenthesisDepth = 0, @Parenthesized = false, @StringLiteral = true, @TextBlock = false]
|
||||
| +-- ArgumentList[@ArgumentCount = 1]
|
||||
| +-- VariableAccess[@AccessType = AccessType.READ, @CompileTimeConstant = false, @Expression = true, @Image = "value", @ParenthesisDepth = 0, @Parenthesized = false, @VariableName = "value"]
|
||||
+-- ReturnStatement[]
|
||||
+-- VariableAccess[@AccessType = AccessType.READ, @CompileTimeConstant = false, @Expression = true, @Image = "result", @ParenthesisDepth = 0, @Parenthesized = false, @VariableName = "result"]
|
224
pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/testdata/ParserCornerCases.java
vendored
Normal file
224
pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/testdata/ParserCornerCases.java
vendored
Normal file
@ -0,0 +1,224 @@
|
||||
/**
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is to test the JavaCC java grammar, whether we can parse specific java constructs without
|
||||
* throwing a syntax error.
|
||||
*/
|
||||
|
||||
class Superclass {
|
||||
|
||||
public Superclass() {
|
||||
}
|
||||
|
||||
public <V> Superclass(Class<V> clazz) {
|
||||
}
|
||||
|
||||
<T> T doStuff(T s) {
|
||||
return s;
|
||||
}
|
||||
}
|
||||
|
||||
class Outer {
|
||||
Outer() {
|
||||
System.out.println("Outer constructor");
|
||||
}
|
||||
|
||||
class Inner {
|
||||
Inner() {
|
||||
System.out.println("Inner constructor");
|
||||
}
|
||||
}
|
||||
}
|
||||
class Child extends Outer.Inner {
|
||||
Child(Outer o) {
|
||||
o.super();
|
||||
System.out.println("Child constructor");
|
||||
}
|
||||
}
|
||||
|
||||
public class ParserCornerCases extends Superclass {
|
||||
|
||||
public ParserCornerCases() {
|
||||
super();
|
||||
}
|
||||
|
||||
public ParserCornerCases(int a) {
|
||||
<Integer> this(a, 2);
|
||||
}
|
||||
|
||||
public <W> ParserCornerCases(int a, int b) {
|
||||
<String> super(String.class);
|
||||
}
|
||||
|
||||
public ParserCornerCases(String title) {
|
||||
this();
|
||||
}
|
||||
|
||||
public strictfp void testGeneric() {
|
||||
String o = super.<String> doStuff("foo");
|
||||
String v = this.<String> thisGeneric("bar");
|
||||
}
|
||||
|
||||
<X> X thisGeneric(X x) {
|
||||
return x;
|
||||
}
|
||||
|
||||
Class getByteArrayClass() {
|
||||
return (byte[].class);
|
||||
}
|
||||
|
||||
public void bitwiseOperator() {
|
||||
if ((modifiers & InputEvent.SHIFT_DOWN_MASK) != 0 ) {
|
||||
buf.append("shift ");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test case from http://jira.codehaus.org/browse/MPMD-126
|
||||
*/
|
||||
class PmdTestParent {
|
||||
public PmdTestParent(Object obj) {}
|
||||
}
|
||||
|
||||
class PmdTestChild extends PmdTestParent {
|
||||
|
||||
public PmdTestChild() {
|
||||
// the following line produced a parsing problem
|
||||
super(new Object() {
|
||||
|
||||
public Object create() {
|
||||
|
||||
Object memoryMonitor = null;
|
||||
|
||||
if (memoryMonitor == null) {
|
||||
memoryMonitor = new Object();
|
||||
}
|
||||
|
||||
return memoryMonitor;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Test cases for bug #1020 Parsing Error
|
||||
*/
|
||||
class SimpleBean {
|
||||
String name;
|
||||
}
|
||||
|
||||
class SimpleBeanUser {
|
||||
SimpleBeanUser(SimpleBean o) {
|
||||
|
||||
}
|
||||
|
||||
SimpleBeanUser() {
|
||||
this(new SimpleBean() {{
|
||||
name = "test";
|
||||
}});
|
||||
}
|
||||
}
|
||||
|
||||
class SimpleBeanUser2 extends SimpleBeanUser {
|
||||
SimpleBeanUser2() {
|
||||
super(new SimpleBean(){{
|
||||
name = "test2";
|
||||
}});
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Test case for bug #1007 Parse Exception with annotation
|
||||
*/
|
||||
class TestParseAnnototation {
|
||||
void parse() {
|
||||
for (@SuppressWarnings("unchecked") int i = 0; i < 10; i++) {
|
||||
}
|
||||
for (@SuppressWarnings("unchecked") Iterator it = Fachabteilung.values().iterator(); it.hasNext();) {
|
||||
}
|
||||
List<String> l = new ArrayList<String>();
|
||||
for (@SuppressWarnings("unchecked") String s : l) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Test case for bug #956 PMD Parse Exception
|
||||
*/
|
||||
class FooBlock {}
|
||||
class MyFoo {
|
||||
MyFoo(FooBlock b) {
|
||||
}
|
||||
}
|
||||
class Foo extends MyFoo {
|
||||
public Foo() {
|
||||
super(new FooBlock() {
|
||||
public Object valueOf(Object object) {
|
||||
String fish = "salmon";
|
||||
return fish;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Verifies #1122 parse error at class.super
|
||||
*/
|
||||
class SuperTest {
|
||||
/**
|
||||
* @throws UnsupportedOperationException
|
||||
*/
|
||||
public Iterator<E> iterator() {
|
||||
if (this.mods.contains(Modification.Iterator)) {
|
||||
return new Iterator<E>() {
|
||||
Iterator<E> wrapped = ImmutableSet.super.iterator();
|
||||
|
||||
public boolean hasNext() {
|
||||
return this.wrapped.hasNext();
|
||||
}
|
||||
|
||||
public E next() {
|
||||
return this.wrapped.next();
|
||||
}
|
||||
|
||||
public void remove() {
|
||||
if (ImmutableSet.this.mods.contains(Modification.RemoveIter)) {
|
||||
this.wrapped.remove();
|
||||
}
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
};
|
||||
}
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Test case for #1310 PMD cannot parse int.class
|
||||
*/
|
||||
class ClazzPropertyOfPrimitiveTypes {
|
||||
public void test() {
|
||||
Class<?> c = int.class;
|
||||
c = short.class;
|
||||
c = long.class;
|
||||
c = float.class;
|
||||
c = double.class;
|
||||
c = char.class;
|
||||
c = byte.class;
|
||||
c = void.class;
|
||||
|
||||
if (c == int.class || c == short.class || c == long.class || c == double.class || c == char.class || c == byte.class || c == void.class) {
|
||||
|
||||
}
|
||||
|
||||
if ("a".equals((int.class).getName())) {
|
||||
|
||||
}
|
||||
|
||||
if ((Integer.class.equals(clazz)) || (int.class.equals(clazz))) {
|
||||
}
|
||||
}
|
||||
}
|
606
pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/testdata/ParserCornerCases.txt
vendored
Normal file
606
pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/testdata/ParserCornerCases.txt
vendored
Normal file
File diff suppressed because it is too large
Load Diff
@ -132,7 +132,7 @@
|
||||
<dependency>
|
||||
<groupId>com.github.oowekyala.treeutils</groupId>
|
||||
<artifactId>tree-matchers</artifactId>
|
||||
<version>2.0.1</version>
|
||||
<version>2.1.0</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
package net.sourceforge.pmd.lang.ast.test
|
||||
|
||||
import com.github.oowekyala.treeutils.DoublyLinkedTreeLikeAdapter
|
||||
import com.github.oowekyala.treeutils.TreeLikeAdapter
|
||||
import com.github.oowekyala.treeutils.matchers.MatchingConfig
|
||||
import com.github.oowekyala.treeutils.matchers.TreeNodeWrapper
|
||||
@ -12,10 +13,14 @@ import com.github.oowekyala.treeutils.printers.KotlintestBeanTreePrinter
|
||||
import net.sourceforge.pmd.lang.ast.Node
|
||||
|
||||
/** An adapter for [baseShouldMatchSubtree]. */
|
||||
object NodeTreeLikeAdapter : TreeLikeAdapter<Node> {
|
||||
object NodeTreeLikeAdapter : DoublyLinkedTreeLikeAdapter<Node> {
|
||||
override fun getChildren(node: Node): List<Node> = node.findChildrenOfType(Node::class.java)
|
||||
|
||||
override fun nodeName(type: Class<out Node>): String = type.simpleName.removePrefix("AST")
|
||||
|
||||
override fun getParent(node: Node): Node? = node.parent
|
||||
|
||||
override fun getChild(node: Node, index: Int): Node? = node.safeGetChild(index)
|
||||
}
|
||||
|
||||
/** A subtree matcher written in the DSL documented on [TreeNodeWrapper]. */
|
||||
|
@ -0,0 +1,80 @@
|
||||
/*
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*/
|
||||
|
||||
package net.sourceforge.pmd.lang.ast.test
|
||||
|
||||
import com.github.oowekyala.treeutils.printers.TreePrinter
|
||||
import net.sourceforge.pmd.lang.ast.Node
|
||||
import java.nio.file.Path
|
||||
import java.nio.file.Paths
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
|
||||
/**
|
||||
* Compare a dump of a file against a saved baseline.
|
||||
*
|
||||
* @param printer The node printer used to dump the trees
|
||||
* @param pathToFixtures Path to the test files within the directory of the test case
|
||||
* @param extension Extension that the unparsed source file is supposed to have
|
||||
*/
|
||||
abstract class BaseTreeDumpTest(
|
||||
val printer: TreePrinter<Node>,
|
||||
val pathToFixtures: String,
|
||||
val extension: String
|
||||
) {
|
||||
|
||||
/**
|
||||
* Parses the given string into a node.
|
||||
*/
|
||||
abstract fun parseFile(fileText: String): Node
|
||||
|
||||
|
||||
/**
|
||||
* Executes the test. The test files are looked up in [pathToFixtures],
|
||||
* in the resource directory *of the subclass*.
|
||||
* The reference test file must be named [fileBaseName] + [ExpectedExt].
|
||||
* The source file to parse must be named [fileBaseName] + [extension].
|
||||
*/
|
||||
fun doTest(fileBaseName: String) {
|
||||
val expectedFile = findTestFile(javaClass, "$pathToFixtures/$fileBaseName$ExpectedExt").toFile()
|
||||
val sourceFile = findTestFile(javaClass, "$pathToFixtures/$fileBaseName$extension").toFile()
|
||||
|
||||
assert(sourceFile.isFile) {
|
||||
"Source file $sourceFile is missing"
|
||||
}
|
||||
|
||||
val parsed = parseFile(sourceFile.readText()) // UTF-8
|
||||
val actual = printer.dumpSubtree(parsed)
|
||||
|
||||
if (!expectedFile.exists()) {
|
||||
expectedFile.writeText(actual)
|
||||
throw AssertionError("Reference file $expectedFile doesn't exist, created it anyway")
|
||||
}
|
||||
|
||||
val expected = expectedFile.readText()
|
||||
|
||||
assertEquals(expected, actual, "Tree dump comparison failed, see the reference: $expectedFile")
|
||||
}
|
||||
|
||||
// Outputting a path makes for better error messages
|
||||
private val srcTestResources = let {
|
||||
// this is set from maven surefire
|
||||
System.getProperty("mvn.project.src.test.resources")
|
||||
?.let { Paths.get(it).toAbsolutePath() }
|
||||
// that's for when the tests are run inside the IDE
|
||||
?: Paths.get(javaClass.protectionDomain.codeSource.location.file)
|
||||
// go up from target/test-classes into the project root
|
||||
.resolve("../../src/test/resources").normalize()
|
||||
}
|
||||
|
||||
private fun findTestFile(contextClass: Class<*>, resourcePath: String): Path {
|
||||
val path = contextClass.`package`.name.replace('.', '/')
|
||||
return srcTestResources.resolve("$path/$resourcePath")
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val ExpectedExt = ".txt"
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,83 @@
|
||||
/*
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*/
|
||||
|
||||
package net.sourceforge.pmd.lang.ast.test
|
||||
|
||||
import com.github.oowekyala.treeutils.printers.SimpleTreePrinter
|
||||
import net.sourceforge.pmd.lang.ast.Node
|
||||
import net.sourceforge.pmd.lang.ast.xpath.Attribute
|
||||
import org.apache.commons.lang3.StringEscapeUtils
|
||||
|
||||
/**
|
||||
* Prints just the structure, like so:
|
||||
*
|
||||
* └── LocalVariableDeclaration
|
||||
* ├── Type
|
||||
* │ └── PrimitiveType
|
||||
* └── VariableDeclarator
|
||||
* ├── VariableDeclaratorId
|
||||
* └── VariableInitializer
|
||||
* └── 1 child not shown
|
||||
*
|
||||
*/
|
||||
object SimpleNodePrinter : SimpleTreePrinter<Node>(NodeTreeLikeAdapter, UnicodeStrings)
|
||||
|
||||
/**
|
||||
* Prints all the XPath attributes of the node.
|
||||
*/
|
||||
object FullAttributePrinter : BaseNodeAttributePrinter()
|
||||
|
||||
|
||||
open class RelevantAttributePrinter(stringConfig: StringConfig = UnicodeStrings) : BaseNodeAttributePrinter(stringConfig) {
|
||||
|
||||
private val Ignored = setOf("BeginLine", "EndLine", "BeginColumn", "EndColumn", "FindBoundary", "SingleLine")
|
||||
|
||||
override fun ignoreAttribute(node: Node, attribute: Attribute): Boolean =
|
||||
Ignored.contains(attribute.name) || attribute.name == "Image" && attribute.value == null
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Base attribute printer, subclass to filter attributes.
|
||||
*/
|
||||
open class BaseNodeAttributePrinter(stringConfig: StringConfig = UnicodeStrings) : SimpleTreePrinter<Node>(NodeTreeLikeAdapter, stringConfig) {
|
||||
|
||||
protected open fun ignoreAttribute(node: Node, attribute: Attribute): Boolean = true
|
||||
|
||||
override fun StringBuilder.appendSingleNode(node: Node): StringBuilder {
|
||||
|
||||
append(node.xPathNodeName)
|
||||
|
||||
return node.xPathAttributesIterator
|
||||
.asSequence()
|
||||
// sort to get deterministic results
|
||||
.sortedBy { it.name }
|
||||
.filterNot { ignoreAttribute(node, it) }
|
||||
.joinTo(buffer = this, prefix = "[", postfix = "]") {
|
||||
"@${it.name} = ${valueToString(it.value)}"
|
||||
}
|
||||
}
|
||||
|
||||
protected open fun valueToString(value: Any?): String? {
|
||||
return when (value) {
|
||||
is String -> "\"" + StringEscapeUtils.unescapeJava(value) + "\""
|
||||
is Char -> '\''.toString() + value.toString().replace("'".toRegex(), "\\'") + '\''.toString()
|
||||
is Enum<*> -> value.enumDeclaringClass.simpleName + "." + value.name
|
||||
is Class<*> -> value.canonicalName?.let { "$it.class" }
|
||||
is Number, is Boolean, null -> value.toString()
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
private val Enum<*>.enumDeclaringClass: Class<*>
|
||||
get() = this.javaClass.let {
|
||||
when {
|
||||
it.isEnum -> it
|
||||
else -> it.enclosingClass.takeIf { it.isEnum }
|
||||
?: throw IllegalStateException()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
3
pom.xml
3
pom.xml
@ -256,6 +256,9 @@
|
||||
<configuration>
|
||||
<forkMode>once</forkMode>
|
||||
<runOrder>alphabetical</runOrder>
|
||||
<systemPropertyVariables>
|
||||
<mvn.project.src.test.resources>${project.basedir}/src/test/resources</mvn.project.src.test.resources>
|
||||
</systemPropertyVariables>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
|
Loading…
x
Reference in New Issue
Block a user