Add ability to test an AST dump as cheap regression test

This commit is contained in:
Clément Fournier 2019-05-09 16:35:47 +02:00
parent ac23b2cb3d
commit bb92044a15
11 changed files with 1165 additions and 2 deletions

View File

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

View File

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

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

View 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"]

View 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))) {
}
}
}

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

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

View File

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