From b03e2336477b614e9bd9f6aedbca6f8a1b100453 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Sat, 14 Dec 2019 03:32:17 +0100 Subject: [PATCH] Turn Statement into an interface Remove BlockStatement Introduce LocalClassDeclStatement Introduce EmptyDeclaration (in preparation for PR about declarations) Replace StatementExpression with ExpressionStatement Make YieldStatement, ExplicitConstructorInvocation implement ASTStatement Extract ForeachStatement from ForStatement Rename (ASTWhileStmt, ASTDoStmt, ASTForStmt, ASTIfStmt, ASTAssertStmt)#getGuardExpressionNode() -> getCondition() Rename ASTCatchStatement -> ASTCatchClause Rename ASTFinallyStatement -> ASTFinallyClause Rename ASTTryStatement#getCatchStatements() -> getCatchClauses() Make ASTYieldStatement not a TypeNode Remove ASTTryStatement#hasFinally() Add (ASTThrowStatement, ASTYieldStatement, ASTReturnStatement)#getExpression() Add ASTTryStatement#getBody() --- pmd-java/etc/grammar/Java.jjt | 51 ++--- .../pmd/lang/java/ast/ASTAssertStatement.java | 4 +- .../pmd/lang/java/ast/ASTBlock.java | 24 ++- .../pmd/lang/java/ast/ASTBlockStatement.java | 6 + .../pmd/lang/java/ast/ASTBreakStatement.java | 16 +- ...atchStatement.java => ASTCatchClause.java} | 10 +- .../lang/java/ast/ASTContinueStatement.java | 12 +- .../pmd/lang/java/ast/ASTDoStatement.java | 4 +- .../lang/java/ast/ASTEmptyDeclaration.java | 3 +- .../pmd/lang/java/ast/ASTEmptyStatement.java | 2 +- .../ast/ASTExplicitConstructorInvocation.java | 2 +- .../lang/java/ast/ASTExpressionStatement.java | 46 +++++ ...lyStatement.java => ASTFinallyClause.java} | 23 ++- .../pmd/lang/java/ast/ASTForInit.java | 19 ++ .../pmd/lang/java/ast/ASTForStatement.java | 43 +++-- .../pmd/lang/java/ast/ASTForUpdate.java | 6 + .../lang/java/ast/ASTForeachStatement.java | 65 +++++++ .../pmd/lang/java/ast/ASTFormalParameter.java | 2 +- .../pmd/lang/java/ast/ASTIfStatement.java | 4 +- .../lang/java/ast/ASTLabeledStatement.java | 25 ++- .../lang/java/ast/ASTLocalClassStatement.java | 48 +++++ .../java/ast/ASTLocalVariableDeclaration.java | 22 ++- .../pmd/lang/java/ast/ASTReturnStatement.java | 22 ++- .../pmd/lang/java/ast/ASTStatement.java | 52 +++-- .../lang/java/ast/ASTStatementExpression.java | 5 + .../java/ast/ASTStatementExpressionList.java | 23 ++- .../pmd/lang/java/ast/ASTSwitchStatement.java | 2 +- .../java/ast/ASTSynchronizedStatement.java | 26 ++- .../pmd/lang/java/ast/ASTThrowStatement.java | 6 +- .../pmd/lang/java/ast/ASTTryStatement.java | 29 ++- .../java/ast/ASTVariableDeclaratorId.java | 2 +- .../pmd/lang/java/ast/ASTWhileStatement.java | 6 +- .../pmd/lang/java/ast/ASTYieldStatement.java | 17 +- .../pmd/lang/java/ast/AbstractStatement.java | 16 ++ .../java/ast/JavaParserVisitorAdapter.java | 14 ++ .../ast/internal/LanguageLevelChecker.java | 12 +- .../java/dfa/StatementAndBraceFinder.java | 4 +- .../internal/visitors/CycloVisitor.java | 23 ++- .../internal/visitors/NcssVisitor.java | 12 +- .../pmd/lang/java/rule/AbstractJavaRule.java | 20 ++ .../ForLoopCanBeForeachRule.java | 4 - .../bestpractices/JUnitUseExpectedRule.java | 10 +- .../bestpractices/PreserveStackTraceRule.java | 10 +- .../codestyle/IdenticalCatchBranchesRule.java | 26 +-- .../design/ExceptionAsFlowControlRule.java | 8 +- .../design/StdCyclomaticComplexityRule.java | 8 +- .../AvoidCatchingThrowableRule.java | 6 +- .../rule/errorprone/CloseResourceRule.java | 2 +- .../ConsecutiveLiteralAppendsRule.java | 16 +- .../ScopeAndDeclarationFinder.java | 8 +- .../typeresolution/ClassTypeResolver.java | 11 +- .../resources/category/java/errorprone.xml | 3 +- .../pmd/lang/java/ast/Java13Test.java | 2 +- .../pmd/lang/java/ast/ParserCornersTest.java | 6 +- .../pmd/lang/java/ast/SimpleNodeTest.java | 177 +++++++++--------- .../pmd/lang/java/rule/XPathRuleTest.java | 19 +- .../lang/java/symboltable/AcceptanceTest.java | 4 +- ...StatementTest.kt => ASTCatchClauseTest.kt} | 8 +- .../java/ast/ASTClassOrInterfaceDeclTest.kt | 38 ++-- .../pmd/lang/java/ast/ASTEnumConstantTest.kt | 20 +- .../ASTExplicitConstructorInvocationTest.kt | 16 +- .../pmd/lang/java/ast/ASTStatementsTest.kt | 135 +++++++++++++ .../lang/java/ast/ASTSwitchExpressionTests.kt | 74 +++----- .../pmd/lang/java/ast/KotlinTestingDsl.kt | 46 ++--- .../pmd/lang/java/ast/ParenthesesTest.kt | 6 +- .../pmd/lang/java/ast/TestExtensions.kt | 89 ++++++++- .../pmd/lang/java/ast/TokenUtilsTest.kt | 2 +- 67 files changed, 1044 insertions(+), 438 deletions(-) rename pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/{ASTCatchStatement.java => ASTCatchClause.java} (88%) create mode 100644 pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTExpressionStatement.java rename pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/{ASTFinallyStatement.java => ASTFinallyClause.java} (50%) create mode 100644 pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTForeachStatement.java create mode 100644 pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTLocalClassStatement.java create mode 100644 pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/AbstractStatement.java rename pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/{ASTCatchStatementTest.kt => ASTCatchClauseTest.kt} (90%) create mode 100644 pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTStatementsTest.kt diff --git a/pmd-java/etc/grammar/Java.jjt b/pmd-java/etc/grammar/Java.jjt index 399f7809ed..cc22b2b729 100644 --- a/pmd-java/etc/grammar/Java.jjt +++ b/pmd-java/etc/grammar/Java.jjt @@ -1548,13 +1548,13 @@ TOKEN : ASTCompilationUnit CompilationUnit() : {} { - [ LOOKAHEAD( ( Annotation() )* "package" ) PackageDeclaration() ( EmptyStatement() )* ] - ( ImportDeclaration() ( EmptyStatement() )* )* + [ LOOKAHEAD( ( Annotation() )* "package" ) PackageDeclaration() ( EmptyDeclaration() )* ] + ( ImportDeclaration() ( EmptyDeclaration() )* )* // the module decl lookahead needs to be before the type declaration branch, // looking for annotations + "open" | "module" will fail faster if it's *not* // a module (most common case) - [ LOOKAHEAD(ModuleDeclLahead()) ModuleDeclaration() ( EmptyStatement() )* ] - ( TypeDeclaration() ( EmptyStatement() )* )* + [ LOOKAHEAD(ModuleDeclLahead()) ModuleDeclaration() ( EmptyDeclaration() )* ] + ( TypeDeclaration() ( EmptyDeclaration() )* )* ( < "\u001a" > )? ( < "~[]" > )? // what's this for? Do you mean ( < ~[] > )*, i.e. "any character"? @@ -2654,7 +2654,7 @@ void ArrayDimExpr() #void: * Statement syntax follows. */ -void Statement() : +void Statement() #void: {} { Block() @@ -2675,7 +2675,7 @@ void Statement() : // because they start with a different token | LOOKAHEAD( { isNextTokenAnAssert() } ) AssertStatement() | LOOKAHEAD(2) LabeledStatement() -| StatementExpression() ";" +| ( StatementExpression() ";" ) #ExpressionStatement } void LabeledStatement() : @@ -2692,14 +2692,14 @@ void Block() : ( BlockStatement() )* t = "}" { if (isPrecededByComment(t)) { jjtThis.setContainsComment(); } } } -void BlockStatement(): +void BlockStatement() #void: {} { LOOKAHEAD( { isNextTokenAnAssert() } ) AssertStatement() | LOOKAHEAD({ jdkVersion >= 13 && isKeyword("yield") }) YieldStatement() | LOOKAHEAD(( "final" | Annotation() )* Type() ) - LocalVariableDeclaration() ";" + LocalVariableDeclaration() ";" { ((AbstractJavaNode) jjtree.peekNode()).shiftTokens(0, 1); } | // we need to lookahead until the "class" token, // because a method ref may be annotated @@ -2709,7 +2709,7 @@ void BlockStatement(): Statement() } -void LocalClassDecl() #void: +void LocalClassDecl() #LocalClassStatement: {int mods = 0;} { // this preserves the modifiers of the local class. @@ -2757,7 +2757,13 @@ void EmptyStatement() : ";" } -void StatementExpression() : +void EmptyDeclaration() : +{} +{ + ";" +} + +void StatementExpression() #void: {AssignmentOp op = null;} { PrefixIncrementExpression() @@ -2859,19 +2865,21 @@ void DoStatement() : "do" Statement() "while" "(" Expression() ")" ";" } -void ForStatement() : -{} +void ForStatement() #void: +{Token t;} { - "for" "(" + t="for" "(" ( LOOKAHEAD(LocalVariableDeclaration() ":") - LocalVariableDeclaration() ":" Expression() -| + (LocalVariableDeclaration() ":" Expression() ")" Statement() { jjtThis.jjtSetFirstToken(t); }) #ForeachStatement +| ( [ ForInit() ] ";" [ Expression() ] ";" [ ForUpdate() ] -) ")" Statement() + { jjtThis.jjtSetFirstToken(t); } + ) #ForStatement +) } void ForInit() : @@ -2932,9 +2940,10 @@ void TryStatement() : */ {} { - "try" (ResourceList())? Block() - ( CatchStatement() )* - [ FinallyStatement() ] + "try" (ResourceList())? + Block() + ( CatchClause() )* + [ FinallyClause() ] } void ResourceList(): @@ -2964,7 +2973,7 @@ void Resource() : {} } -void CatchStatement() : +void CatchClause() : {} { "catch" @@ -2972,7 +2981,7 @@ void CatchStatement() : Block() } -void FinallyStatement() : +void FinallyClause() : {} { "finally" Block() diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAssertStatement.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAssertStatement.java index 73f206d203..cfee23c6e2 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAssertStatement.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAssertStatement.java @@ -13,7 +13,7 @@ package net.sourceforge.pmd.lang.java.ast; * * */ -public final class ASTAssertStatement extends AbstractJavaNode { +public final class ASTAssertStatement extends AbstractStatement { ASTAssertStatement(int id) { super(id); @@ -38,7 +38,7 @@ public final class ASTAssertStatement extends AbstractJavaNode { /** * Returns the expression tested by this assert statement. */ - public ASTExpression getGuardExpressionNode() { + public ASTExpression getCondition() { return (ASTExpression) jjtGetChild(0); } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTBlock.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTBlock.java index f0415a6886..3291cdb5e8 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTBlock.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTBlock.java @@ -4,7 +4,19 @@ package net.sourceforge.pmd.lang.java.ast; -public final class ASTBlock extends AbstractJavaNode { +import java.util.Iterator; + +/** + * A block of code. This is a {@linkplain ASTStatement statement} that + * contains other statements. + * + *
+ *
+ * Block ::=  "{" {@link ASTStatement Statement}* "}"
+ *
+ * 
+ */ +public final class ASTBlock extends AbstractStatement implements Iterable { private boolean containsComment; @@ -36,4 +48,14 @@ public final class ASTBlock extends AbstractJavaNode { this.containsComment = true; } + @Override + public Iterator iterator() { + return children(ASTStatement.class).iterator(); + } + + + @Override + public ASTStatement jjtGetChild(int index) { + return (ASTStatement) super.jjtGetChild(index); + } } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTBlockStatement.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTBlockStatement.java index be2e790a03..1fc7a95984 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTBlockStatement.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTBlockStatement.java @@ -4,6 +4,12 @@ package net.sourceforge.pmd.lang.java.ast; +/** + * @deprecated {@link ASTStatement} has been turned into an interface. Usages of BlockStatement can + * either be replaced with Statement if you don't care about the specific statement, or removed if + * you were extracting the contained node anyway. + */ +@Deprecated public final class ASTBlockStatement extends AbstractJavaNode { ASTBlockStatement(int id) { diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTBreakStatement.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTBreakStatement.java index 2db63ff438..f53fbfa5c4 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTBreakStatement.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTBreakStatement.java @@ -4,7 +4,17 @@ package net.sourceforge.pmd.lang.java.ast; -public final class ASTBreakStatement extends AbstractJavaNode { +/** + * A break statement, that jumps to a named label (or exits the current loop). + * + *
+ *
+ * BreakStatement ::= "break" <IDENTIFIER>? ";"
+ *
+ * 
+ * + */ +public final class ASTBreakStatement extends AbstractStatement { ASTBreakStatement(int id) { super(id); @@ -25,6 +35,10 @@ public final class ASTBreakStatement extends AbstractJavaNode { visitor.visit(this, data); } + public String getLabel() { + return getImage(); + } + @Override public String getImage() { String result = super.getImage(); diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTCatchStatement.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTCatchClause.java similarity index 88% rename from pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTCatchStatement.java rename to pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTCatchClause.java index 4b7315f216..880a73a2f2 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTCatchStatement.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTCatchClause.java @@ -9,20 +9,20 @@ import java.util.List; /** - * Catch statement node. + * A "catch" clause of a {@linkplain ASTTryStatement try statement}. * *
  *
- * CatchStatement ::= "catch" "(" {@link ASTFormalParameter FormalParameter} ")" {@link ASTBlock Block}
+ * CatchClause ::= "catch" "(" {@link ASTFormalParameter FormalParameter} ")" {@link ASTBlock Block}
  *
  * 
*/ -public final class ASTCatchStatement extends AbstractJavaNode { - ASTCatchStatement(int id) { +public final class ASTCatchClause extends AbstractJavaNode { + ASTCatchClause(int id) { super(id); } - ASTCatchStatement(JavaParser p, int id) { + ASTCatchClause(JavaParser p, int id) { super(p, id); } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTContinueStatement.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTContinueStatement.java index e3d52e9d2f..6b7605ba25 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTContinueStatement.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTContinueStatement.java @@ -4,7 +4,17 @@ package net.sourceforge.pmd.lang.java.ast; -public final class ASTContinueStatement extends AbstractJavaNode { + +/** + * A continue statement, that jumps to the next iteration of an enclosing loop. + * + *
+ *
+ * ContinueStatement ::= "continue" <IDENTIFIER>? ";"
+ *
+ * 
+ */ +public final class ASTContinueStatement extends AbstractStatement { ASTContinueStatement(int id) { super(id); diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTDoStatement.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTDoStatement.java index dafc5b986c..37163b7931 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTDoStatement.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTDoStatement.java @@ -14,7 +14,7 @@ package net.sourceforge.pmd.lang.java.ast; * * */ -public final class ASTDoStatement extends AbstractJavaNode { +public final class ASTDoStatement extends AbstractStatement { ASTDoStatement(int id) { super(id); @@ -29,7 +29,7 @@ public final class ASTDoStatement extends AbstractJavaNode { * Returns the node that represents the guard of this loop. * This may be any expression of type boolean. */ - public ASTExpression getGuardExpressionNode() { + public ASTExpression getCondition() { return (ASTExpression) jjtGetChild(1); } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTEmptyDeclaration.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTEmptyDeclaration.java index 93249ef1c4..53e04cbd48 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTEmptyDeclaration.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTEmptyDeclaration.java @@ -5,7 +5,8 @@ package net.sourceforge.pmd.lang.java.ast; /** - * An empty declaration (useless). + * An empty declaration (useless). This is kept separate from {@link ASTStatement} + * because they don't occur in the same syntactic contexts. * *
  *
diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTEmptyStatement.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTEmptyStatement.java
index c51f372793..fff2741ccf 100644
--- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTEmptyStatement.java
+++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTEmptyStatement.java
@@ -13,7 +13,7 @@ package net.sourceforge.pmd.lang.java.ast;
  *
  * 
*/ -public final class ASTEmptyStatement extends AbstractJavaNode { +public final class ASTEmptyStatement extends AbstractStatement { ASTEmptyStatement(int id) { super(id); diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTExplicitConstructorInvocation.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTExplicitConstructorInvocation.java index cd644e51e6..e89605d297 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTExplicitConstructorInvocation.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTExplicitConstructorInvocation.java @@ -22,7 +22,7 @@ import net.sourceforge.pmd.lang.java.ast.InternalInterfaces.QualifierOwner; * * */ -public final class ASTExplicitConstructorInvocation extends AbstractJavaNode implements QualifierOwner { +public final class ASTExplicitConstructorInvocation extends AbstractStatement implements QualifierOwner { private boolean isSuper; diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTExpressionStatement.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTExpressionStatement.java new file mode 100644 index 0000000000..52e7bd5e2c --- /dev/null +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTExpressionStatement.java @@ -0,0 +1,46 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java.ast; + +import org.checkerframework.checker.nullness.qual.NonNull; + +/** + * A statement that contains an expression. Note that this is not an + * expression itself. + * + *
+ *
+ * ExpressionStatement ::= {@link ASTExpression StatementExpression} ";"
+ *
+ * 
+ */ +public final class ASTExpressionStatement extends AbstractStatement { + + ASTExpressionStatement(int id) { + super(id); + } + + ASTExpressionStatement(JavaParser p, int id) { + super(p, id); + } + + @Override + public Object jjtAccept(JavaParserVisitor visitor, Object data) { + return visitor.visit(this, data); + } + + + @Override + public void jjtAccept(SideEffectingVisitor visitor, T data) { + visitor.visit(this, data); + } + + + /** Returns the contained expression. */ + @NonNull + public ASTExpression getExpr() { + return (ASTExpression) jjtGetChild(0); + } +} diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTFinallyStatement.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTFinallyClause.java similarity index 50% rename from pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTFinallyStatement.java rename to pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTFinallyClause.java index b95ff39453..22223ffc60 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTFinallyStatement.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTFinallyClause.java @@ -4,13 +4,23 @@ package net.sourceforge.pmd.lang.java.ast; -public final class ASTFinallyStatement extends AbstractJavaNode { +/** + * The "finally" clause of a {@linkplain ASTTryStatement try statement}. + * + * + *
+ *
+ * FinallyClause ::= "finally" {@link ASTBlock Block}
+ *
+ * 
+ */ +public final class ASTFinallyClause extends AbstractJavaNode { - ASTFinallyStatement(int id) { + ASTFinallyClause(int id) { super(id); } - ASTFinallyStatement(JavaParser p, int id) { + ASTFinallyClause(JavaParser p, int id) { super(p, id); } @@ -24,4 +34,11 @@ public final class ASTFinallyStatement extends AbstractJavaNode { public void jjtAccept(SideEffectingVisitor visitor, T data) { visitor.visit(this, data); } + + /** + * Returns the block. + */ + public ASTBlock getBlock() { + return (ASTBlock) jjtGetChild(0); + } } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTForInit.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTForInit.java index 8072f8c1dc..01f8893c96 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTForInit.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTForInit.java @@ -4,6 +4,19 @@ package net.sourceforge.pmd.lang.java.ast; +/** + * The initialization clause of a {@linkplain ASTForStatement for loop}. + * Note: ForInit nodes are necessary in the tree to differentiate them + * from the update clause. They just confer a contextual role to their + * child. + * + *
+ *
+ * ForInit ::= {@link ASTLocalVariableDeclaration LocalVariableDeclaration}
+ *           | {@link ASTStatementExpressionList StatementExpressionList}
+ *
+ * 
+ */ public final class ASTForInit extends AbstractJavaNode { ASTForInit(int id) { @@ -24,4 +37,10 @@ public final class ASTForInit extends AbstractJavaNode { public void jjtAccept(SideEffectingVisitor visitor, T data) { visitor.visit(this, data); } + + /** Returns the statement nested within this node. */ + public ASTStatement getStatement() { + return (ASTStatement) getFirstChild(); + } + } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTForStatement.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTForStatement.java index 6a9ecc8527..c3dc2fa3fd 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTForStatement.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTForStatement.java @@ -4,19 +4,19 @@ package net.sourceforge.pmd.lang.java.ast; +import org.checkerframework.checker.nullness.qual.Nullable; + /** - * Represents a {@code for}-loop, or a foreach loop. + * Represents a {@code for} loop (distinct from {@linkplain ASTForeachStatement foreach loops}). * *
  *
- * ForStatement ::= "for" "(" {@linkplain ASTLocalVariableDeclaration LocalVariableDeclaration} ":" {@linkplain ASTExpression Expression} ")" {@linkplain ASTStatement Statement}
- *                | "for" "(" {@linkplain ASTForInit ForInit}? ";" {@linkplain ASTExpression Expression}? ";" {@linkplain ASTForUpdate ForUpdate}? ")" {@linkplain ASTStatement Statement}
+ * ForStatement ::= "for" "(" {@linkplain ASTForInit ForInit}? ";" {@linkplain ASTExpression Expression}? ";" {@linkplain ASTForUpdate ForUpdate}? ")"
+ *                      {@linkplain ASTStatement Statement}
  *
  * 
*/ -// TODO this should be split into two different nodes, otherwise -// we can't enrich the API without returning null half the time -public final class ASTForStatement extends AbstractJavaNode { +public final class ASTForStatement extends AbstractStatement { ASTForStatement(int id) { super(id); @@ -41,32 +41,35 @@ public final class ASTForStatement extends AbstractJavaNode { /** - * Returns the node that represents the guard of this loop. + * Returns the node that represents the condition of this loop. * This may be any expression of type boolean. * - *

If this node represents a foreach loop, or if there is - * no specified guard, then returns null. + *

If there is no specified guard, then returns null. */ - public ASTExpression getGuardExpressionNode() { - if (isForeach()) { - return null; - } + @Nullable + public ASTExpression getCondition() { return getFirstChildOfType(ASTExpression.class); } - /** - * Returns true if this node represents a foreach loop. + * Returns the statement nested within the {@linkplain ASTForInit init clause}, if it exists. + * This is either a {@linkplain ASTLocalVariableDeclaration local variable declaration} or a + * {@linkplain ASTStatementExpressionList statement expression list}. */ - public boolean isForeach() { - return jjtGetChild(0) instanceof ASTLocalVariableDeclaration; + public @Nullable ASTStatement getInit() { + ASTForInit init = AstImplUtil.getChildAs(this, 0, ASTForInit.class); + return init == null ? null : init.getStatement(); } - /** - * Returns the statement that represents the body of this - * loop. + * Returns the statement nested within the update clause, if it exists. */ + public @Nullable ASTStatementExpressionList getUpdate() { + ASTForUpdate update = getFirstChildOfType(ASTForUpdate.class); + return update == null ? null : update.getExprList(); + } + + /** Returns the statement that represents the body of this loop. */ public ASTStatement getBody() { return (ASTStatement) jjtGetChild(jjtGetNumChildren() - 1); } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTForUpdate.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTForUpdate.java index 75423cff96..1fad2da857 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTForUpdate.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTForUpdate.java @@ -35,4 +35,10 @@ public final class ASTForUpdate extends AbstractJavaNode { public void jjtAccept(SideEffectingVisitor visitor, T data) { visitor.visit(this, data); } + + /** Returns the expression list nested within this node. */ + public ASTStatementExpressionList getExprList() { + return (ASTStatementExpressionList) jjtGetChild(0); + } + } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTForeachStatement.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTForeachStatement.java new file mode 100644 index 0000000000..8025d75b11 --- /dev/null +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTForeachStatement.java @@ -0,0 +1,65 @@ +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java.ast; + +import org.checkerframework.checker.nullness.qual.NonNull; + +/** + * Represents a "foreach"-loop on an {@link Iterable}. + * + *

+ *
+ * ForeachStatement ::= "for" "(" {@linkplain ASTLocalVariableDeclaration LocalVariableDeclaration} ":" {@linkplain ASTExpression Expression} ")" {@linkplain ASTStatement Statement}
+ *
+ * 
+ */ +public final class ASTForeachStatement extends AbstractStatement { + + ASTForeachStatement(int id) { + super(id); + } + + + ASTForeachStatement(JavaParser p, int id) { + super(p, id); + } + + + @Override + public Object jjtAccept(JavaParserVisitor visitor, Object data) { + return visitor.visit(this, data); + } + + + @Override + public void jjtAccept(SideEffectingVisitor visitor, T data) { + visitor.visit(this, data); + } + + + /** Returns the id of the declared variable. */ + @NonNull + public ASTVariableDeclaratorId getVariableId() { + return getFirstChildOfType(ASTLocalVariableDeclaration.class).iterator().next(); + } + + /** + * Returns the expression that evaluates to the {@link Iterable} + * being looped upon. + */ + @NonNull + public ASTExpression getIterableExpr() { + return getFirstChildOfType(ASTExpression.class); + } + + /** + * Returns the statement that represents the body of this + * loop. + */ + public ASTStatement getBody() { + return (ASTStatement) jjtGetChild(jjtGetNumChildren() - 1); + } + +} diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTFormalParameter.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTFormalParameter.java index 496804989f..4b0bc86474 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTFormalParameter.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTFormalParameter.java @@ -11,7 +11,7 @@ import net.sourceforge.pmd.lang.java.typeresolution.typedefinition.JavaTypeDefin /** * Formal parameter node. Used in the {@link ASTFormalParameters} * production of {@link ASTMethodDeclarator} to represent a - * method's formal parameter. Also used in the {@link ASTCatchStatement} + * method's formal parameter. Also used in the {@link ASTCatchClause} * production to represent the declared exception variable. * Also used in LambdaExpressions for the LambdaParameters. * diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTIfStatement.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTIfStatement.java index 508d9299c0..9c25ebf0eb 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTIfStatement.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTIfStatement.java @@ -14,7 +14,7 @@ package net.sourceforge.pmd.lang.java.ast; * * */ -public final class ASTIfStatement extends AbstractJavaNode { +public final class ASTIfStatement extends AbstractStatement { private boolean hasElse; @@ -46,7 +46,7 @@ public final class ASTIfStatement extends AbstractJavaNode { * Returns the node that represents the guard of this conditional. * This may be any expression of type boolean. */ - public ASTExpression getGuardExpressionNode() { + public ASTExpression getCondition() { return (ASTExpression) jjtGetChild(0); } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTLabeledStatement.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTLabeledStatement.java index 52d0c734ee..47c49e6cfb 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTLabeledStatement.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTLabeledStatement.java @@ -4,7 +4,16 @@ package net.sourceforge.pmd.lang.java.ast; -public final class ASTLabeledStatement extends AbstractJavaNode { +/** + * A wrapper around a statement that assigns it a label. + * + *
+ *
+ * LabeledStatement ::= <IDENTIFIER> ":" {@link ASTStatement Statement}
+ *
+ * 
+ */ +public final class ASTLabeledStatement extends AbstractStatement { ASTLabeledStatement(int id) { super(id); @@ -25,4 +34,18 @@ public final class ASTLabeledStatement extends AbstractJavaNode { visitor.visit(this, data); } + /** + * Returns the name of the label. + */ + public String getLabel() { + return getImage(); + } + + /** + * Returned the statement named by this label. + */ + public ASTStatement getStatement() { + return (ASTStatement) jjtGetChild(1); + } + } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTLocalClassStatement.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTLocalClassStatement.java new file mode 100644 index 0000000000..ff2eaac3ab --- /dev/null +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTLocalClassStatement.java @@ -0,0 +1,48 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java.ast; + +import org.checkerframework.checker.nullness.qual.NonNull; + +/** + * A statement that contains a local class declaration. Note that this + * is not a declaration itself. + * + *
+ *
+ * LocalClassStatement ::= {@link ASTClassOrInterfaceDeclaration ClassDeclaration}
+ *
+ * 
+ */ +public final class ASTLocalClassStatement extends AbstractStatement implements LeftRecursiveNode { + + ASTLocalClassStatement(int id) { + super(id); + } + + ASTLocalClassStatement(JavaParser p, int id) { + super(p, id); + } + + @Override + public Object jjtAccept(JavaParserVisitor visitor, Object data) { + return visitor.visit(this, data); + } + + + @Override + public void jjtAccept(SideEffectingVisitor visitor, T data) { + visitor.visit(this, data); + } + + + /** + * Returns the contained declaration. + */ + @NonNull + public ASTClassOrInterfaceDeclaration getDeclaration() { + return (ASTClassOrInterfaceDeclaration) jjtGetChild(0); + } +} diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTLocalVariableDeclaration.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTLocalVariableDeclaration.java index a07fb75b31..4d5b2d0a22 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTLocalVariableDeclaration.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTLocalVariableDeclaration.java @@ -8,13 +8,13 @@ import java.util.Iterator; /** - * Represents a local variable declaration. This is a {@linkplain ASTBlockStatement block statement}, + * Represents a local variable declaration. This is a {@linkplain ASTStatement statement}, * but the node is also used in {@linkplain ASTForInit for-loop initialisers} and * {@linkplain ASTForStatement foreach statements}. * - *

This statement may define several variables, possibly of different types (see {@link - * ASTVariableDeclaratorId#getType()}). - * The nodes corresponding to the declared variables are accessible through {@link #iterator()}. + *

This statement may define several variables, possibly of different types + * (see {@link ASTVariableDeclaratorId#getType()}). The nodes corresponding to + * the declared variables are accessible through {@link #iterator()}. * *

  *
@@ -22,7 +22,8 @@ import java.util.Iterator;
  *
  * 
*/ -public final class ASTLocalVariableDeclaration extends AbstractJavaAccessNode implements Dimensionable, Iterable { +// TODO extend AbstractStatement +public final class ASTLocalVariableDeclaration extends AbstractJavaAccessNode implements Dimensionable, Iterable, ASTStatement { ASTLocalVariableDeclaration(int id) { super(id); @@ -44,6 +45,17 @@ public final class ASTLocalVariableDeclaration extends AbstractJavaAccessNode im } + /** + * Returns true if the local variables declared by this statement + * are final. + */ + @Override + @SuppressWarnings("PMD.UselessOverridingMethod") + public boolean isFinal() { + // TODO unimplement AccessNode, this causes compilation errors because of our current symbol table + return super.isFinal(); + } + /** * If true, this local variable declaration represents a declaration, * which makes use of local variable type inference, e.g. java10 "var". diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTReturnStatement.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTReturnStatement.java index 031d309d39..2e170d52c0 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTReturnStatement.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTReturnStatement.java @@ -4,7 +4,19 @@ package net.sourceforge.pmd.lang.java.ast; -public final class ASTReturnStatement extends AbstractJavaNode { +import org.checkerframework.checker.nullness.qual.Nullable; + +/** + * A return statement in a method or constructor body. + * + * + *
+ *
+ * ReturnStatement ::= "return" {@link ASTExpression Expression}? ";"
+ *
+ * 
+ */ +public final class ASTReturnStatement extends AbstractStatement { ASTReturnStatement(int id) { super(id); @@ -24,4 +36,12 @@ public final class ASTReturnStatement extends AbstractJavaNode { public void jjtAccept(SideEffectingVisitor visitor, T data) { visitor.visit(this, data); } + + /** + * Returns the returned expression, or null if this is a simple return. + */ + @Nullable + public ASTExpression getExpr() { + return AstImplUtil.getChildAs(this, 0, ASTExpression.class); + } } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTStatement.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTStatement.java index 43cdaa66cc..a7d4e194fd 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTStatement.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTStatement.java @@ -4,24 +4,38 @@ package net.sourceforge.pmd.lang.java.ast; -public final class ASTStatement extends AbstractJavaNode { +/** + * Represents a code statement. + * + *
+ *
+ * Statement ::= {@link ASTAssertStatement AssertStatement}
+ *             | {@link ASTBlock Block}
+ *             | {@link ASTBreakStatement BreakStatement}
+ *             | {@link ASTContinueStatement ContinueStatement}
+ *             | {@link ASTDoStatement DoStatement}
+ *             | {@link ASTEmptyStatement EmptyStatement}
+ *             | {@link ASTExplicitConstructorInvocation ExplicitConstructorInvocation}
+ *             | {@link ASTExpressionStatement ExpressionStatement}
+ *             | {@link ASTForeachStatement ForeachStatement}
+ *             | {@link ASTForStatement ForStatement}
+ *             | {@link ASTIfStatement IfStatement}
+ *             | {@link ASTLabeledStatement LabeledStatement}
+ *             | {@link ASTLocalClassStatement LocalClassStatement}
+ *             | {@link ASTLocalVariableDeclaration LocalVariableDeclaration}
+ *             | {@link ASTReturnStatement ReturnStatement}
+ *             | {@link ASTStatementExpressionList StatementExpressionList}
+ *             | {@link ASTSwitchStatement SwitchStatement}
+ *             | {@link ASTSynchronizedStatement SynchronizedStatement}
+ *             | {@link ASTThrowStatement ThrowStatement}
+ *             | {@link ASTTryStatement TryStatement}
+ *             | {@link ASTWhileStatement WhileStatement}
+ *             | {@link ASTYieldStatement YieldStatement}
+ *
+ * 
+ * + * + */ +public interface ASTStatement extends JavaNode { - public ASTStatement(int id) { - super(id); - } - - public ASTStatement(JavaParser p, int id) { - super(p, id); - } - - @Override - public Object jjtAccept(JavaParserVisitor visitor, Object data) { - return visitor.visit(this, data); - } - - - @Override - public void jjtAccept(SideEffectingVisitor visitor, T data) { - visitor.visit(this, data); - } } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTStatementExpression.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTStatementExpression.java index bff70125fe..fc60f78af9 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTStatementExpression.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTStatementExpression.java @@ -4,6 +4,11 @@ package net.sourceforge.pmd.lang.java.ast; +/** + * @deprecated Use {@link ASTExpression} inside {@link ASTStatementExpressionList}, + * or {@link ASTExpressionStatement} inside {@link ASTBlock} + */ +@Deprecated public final class ASTStatementExpression extends AbstractJavaTypeNode { ASTStatementExpression(int id) { diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTStatementExpressionList.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTStatementExpressionList.java index 2772547455..d8b53d56e5 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTStatementExpressionList.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTStatementExpressionList.java @@ -4,7 +4,23 @@ package net.sourceforge.pmd.lang.java.ast; -public final class ASTStatementExpressionList extends AbstractJavaNode { +import java.util.Iterator; + +/** + * A list of statement expressions. Statement expressions are those + * expressions which can appear in an {@linkplain ASTExpressionStatement expression statement}. + * + * + *

Statement expression lists occur only {@link ASTForInit} and {@link ASTForUpdate}. + * To improve the API of {@link ASTForInit}, however, this node implements {@link ASTStatement}. + * + *

+ *
+ * StatementExpressionList ::= {@link ASTExpression Expression} ( "," {@link ASTExpression Expression} )*
+ *
+ * 
+ */ +public final class ASTStatementExpressionList extends AbstractStatement implements Iterable { ASTStatementExpressionList(int id) { super(id); @@ -24,4 +40,9 @@ public final class ASTStatementExpressionList extends AbstractJavaNode { public void jjtAccept(SideEffectingVisitor visitor, T data) { visitor.visit(this, data); } + + @Override + public Iterator iterator() { + return children(ASTExpression.class).iterator(); + } } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTSwitchStatement.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTSwitchStatement.java index 573781af1f..55440472d4 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTSwitchStatement.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTSwitchStatement.java @@ -15,7 +15,7 @@ import org.apache.commons.lang3.EnumUtils; * {@link ASTSwitchExpression SwitchExpression}, though it does not need * to be exhaustive. See the doc of that node for details. */ -public final class ASTSwitchStatement extends AbstractJavaNode implements Iterable { +public final class ASTSwitchStatement extends AbstractStatement implements Iterable { ASTSwitchStatement(int id) { super(id); } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTSynchronizedStatement.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTSynchronizedStatement.java index d700d30e59..604934583c 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTSynchronizedStatement.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTSynchronizedStatement.java @@ -4,7 +4,17 @@ package net.sourceforge.pmd.lang.java.ast; -public final class ASTSynchronizedStatement extends AbstractJavaNode { +/** + * A synchronized statement. + * + *
+ *
+ * SynchronizedStatement ::= "synchronized" "(" {@link ASTExpression Expression} ")" {@link ASTBlock Block}
+ *
+ * 
+ + */ +public final class ASTSynchronizedStatement extends AbstractStatement { ASTSynchronizedStatement(int id) { super(id); @@ -24,4 +34,18 @@ public final class ASTSynchronizedStatement extends AbstractJavaNode { public void jjtAccept(SideEffectingVisitor visitor, T data) { visitor.visit(this, data); } + + /** + * Returns the expression evaluating to the lock object. + */ + public ASTExpression getLockExpression() { + return (ASTExpression) jjtGetChild(0); + } + + /** + * Returns the body of the statement. + */ + public ASTBlock getBody() { + return (ASTBlock) jjtGetChild(1); + } } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTThrowStatement.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTThrowStatement.java index 14756d2024..5eb284c6cd 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTThrowStatement.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTThrowStatement.java @@ -13,7 +13,7 @@ package net.sourceforge.pmd.lang.java.ast; * * */ -public final class ASTThrowStatement extends AbstractJavaNode { +public final class ASTThrowStatement extends AbstractStatement { ASTThrowStatement(int id) { super(id); @@ -34,6 +34,10 @@ public final class ASTThrowStatement extends AbstractJavaNode { visitor.visit(this, data); } + /** Returns the expression for the thrown exception. */ + public ASTExpression getExpr() { + return (ASTExpression) getFirstChild(); + } /** * Gets the image of the first ASTClassOrInterfaceType child or diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTTryStatement.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTTryStatement.java index f62eef5f5b..d51485c29a 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTTryStatement.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTTryStatement.java @@ -20,12 +20,12 @@ import net.sourceforge.pmd.internal.util.IteratorUtil; * * TryStatement ::= "try" {@link ASTResourceList ResourceList}? * {@link ASTBlock Block} - * {@link ASTCatchStatement CatchStatement}* - * {@link ASTFinallyStatement FinallyStatement}? + * {@link ASTCatchClause CatchClause}* + * {@link ASTFinallyClause FinallyClause}? * * */ -public final class ASTTryStatement extends AbstractJavaNode { +public final class ASTTryStatement extends AbstractStatement { ASTTryStatement(int id) { super(id); @@ -66,22 +66,18 @@ public final class ASTTryStatement extends AbstractJavaNode { return list == null ? Collections.emptyList() : IteratorUtil.toList(list.iterator()); } + /** Returns the body of the statement. */ + public ASTBlock getBody() { + return (ASTBlock) jjtGetChild(1); + } + /** * Returns the catch statement nodes of this try statement. * If there are none, returns an empty list. */ - public List getCatchStatements() { - return findChildrenOfType(ASTCatchStatement.class); - } - - - /** - * Returns true if this try statement has a {@code finally} statement, - * in which case {@link #getFinally()} won't return {@code null}. - */ - public boolean hasFinally() { - return getFirstChildOfType(ASTFinallyStatement.class) != null; + public List getCatchClauses() { + return findChildrenOfType(ASTCatchClause.class); } @@ -90,8 +86,9 @@ public final class ASTTryStatement extends AbstractJavaNode { * * @return The finally statement, or null if there is none */ - public ASTFinallyStatement getFinally() { - return getFirstChildOfType(ASTFinallyStatement.class); + @Nullable + public ASTFinallyClause getFinally() { + return AstImplUtil.getChildAs(this, jjtGetNumChildren() - 1, ASTFinallyClause.class); } } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTVariableDeclaratorId.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTVariableDeclaratorId.java index fa836252fa..8afbafd863 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTVariableDeclaratorId.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTVariableDeclaratorId.java @@ -113,7 +113,7 @@ public final class ASTVariableDeclaratorId extends AbstractJavaTypeNode implemen * a {@code catch} statement. */ public boolean isExceptionBlockParameter() { - return jjtGetParent().jjtGetParent() instanceof ASTCatchStatement; + return jjtGetParent().jjtGetParent() instanceof ASTCatchClause; } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTWhileStatement.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTWhileStatement.java index e51ee30528..2324d5fa25 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTWhileStatement.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTWhileStatement.java @@ -5,7 +5,7 @@ package net.sourceforge.pmd.lang.java.ast; /** - * Represents a {@code while} statement. + * Represents a {@code while} loop. * *
  *
@@ -13,7 +13,7 @@ package net.sourceforge.pmd.lang.java.ast;
  *
  * 
*/ -public final class ASTWhileStatement extends AbstractJavaNode { +public final class ASTWhileStatement extends AbstractStatement { ASTWhileStatement(int id) { super(id); @@ -28,7 +28,7 @@ public final class ASTWhileStatement extends AbstractJavaNode { * Returns the node that represents the guard of this loop. * This may be any expression of type boolean. */ - public ASTExpression getGuardExpressionNode() { + public ASTExpression getCondition() { return (ASTExpression) jjtGetChild(0); } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTYieldStatement.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTYieldStatement.java index fca637f634..77947cec17 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTYieldStatement.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTYieldStatement.java @@ -4,7 +4,16 @@ package net.sourceforge.pmd.lang.java.ast; -public class ASTYieldStatement extends AbstractJavaTypeNode { +/** + * A {@code yield} statement in a {@linkplain ASTSwitchExpression switch expression}. + * + *
+ *
+ * YieldStatement ::= "yield" {@link ASTExpression} ";"
+ *
+ * 
+ */ +public class ASTYieldStatement extends AbstractStatement { ASTYieldStatement(int id) { super(id); @@ -26,6 +35,12 @@ public class ASTYieldStatement extends AbstractJavaTypeNode { visitor.visit(this, data); } + /** Returns the yielded expression. */ + public ASTExpression getExpr() { + return (ASTExpression) getFirstChild(); + } + + @Override public String getImage() { String result = super.getImage(); diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/AbstractStatement.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/AbstractStatement.java new file mode 100644 index 0000000000..190e0d8298 --- /dev/null +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/AbstractStatement.java @@ -0,0 +1,16 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java.ast; + +abstract class AbstractStatement extends AbstractJavaNode implements ASTStatement { + + AbstractStatement(int id) { + super(id); + } + + AbstractStatement(JavaParser parser, int id) { + super(parser, id); + } +} diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaParserVisitorAdapter.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaParserVisitorAdapter.java index 0361dfbf08..8d3c389fc3 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaParserVisitorAdapter.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaParserVisitorAdapter.java @@ -253,6 +253,10 @@ public class JavaParserVisitorAdapter implements JavaParserVisitor { } + public Object visit(ASTStatement node, Object data) { + return visit((JavaNode) node, data); + } + // REMOVE ME // deprecated stuff kept for compatibility with existing visitors, not matched by anything @@ -346,4 +350,14 @@ public class JavaParserVisitorAdapter implements JavaParserVisitor { return null; } + @Deprecated + public Object visit(ASTBlockStatement node, Object data) { + return null; + } + + @Deprecated + public Object visit(ASTStatementExpression node, Object data) { + return null; + } + } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/internal/LanguageLevelChecker.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/internal/LanguageLevelChecker.java index e0732c884f..0258fdd3d4 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/internal/LanguageLevelChecker.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/internal/LanguageLevelChecker.java @@ -16,10 +16,10 @@ import net.sourceforge.pmd.lang.java.ast.ASTAnyTypeDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTAssertStatement; import net.sourceforge.pmd.lang.java.ast.ASTBreakStatement; import net.sourceforge.pmd.lang.java.ast.ASTCastExpression; -import net.sourceforge.pmd.lang.java.ast.ASTCatchStatement; +import net.sourceforge.pmd.lang.java.ast.ASTCatchClause; import net.sourceforge.pmd.lang.java.ast.ASTConstructorCall; import net.sourceforge.pmd.lang.java.ast.ASTEnumDeclaration; -import net.sourceforge.pmd.lang.java.ast.ASTForStatement; +import net.sourceforge.pmd.lang.java.ast.ASTForeachStatement; import net.sourceforge.pmd.lang.java.ast.ASTFormalParameter; import net.sourceforge.pmd.lang.java.ast.ASTImportDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTIntersectionType; @@ -173,10 +173,8 @@ public class LanguageLevelChecker { } @Override - public void visit(ASTForStatement node, T data) { - if (node.isForeach()) { - check(node, RegularLanguageFeature.FOREACH_LOOPS, data); - } + public void visit(ASTForeachStatement node, T data) { + check(node, RegularLanguageFeature.FOREACH_LOOPS, data); visitChildren(node, data); } @@ -255,7 +253,7 @@ public class LanguageLevelChecker { } @Override - public void visit(ASTCatchStatement node, T data) { + public void visit(ASTCatchClause node, T data) { if (node.isMulticatchStatement()) { check(node, RegularLanguageFeature.COMPOSITE_CATCH_CLAUSES, data); } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/dfa/StatementAndBraceFinder.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/dfa/StatementAndBraceFinder.java index d3609f8189..111d39d13e 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/dfa/StatementAndBraceFinder.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/dfa/StatementAndBraceFinder.java @@ -20,6 +20,7 @@ import net.sourceforge.pmd.lang.java.ast.ASTConstructorDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTContinueStatement; import net.sourceforge.pmd.lang.java.ast.ASTDoStatement; import net.sourceforge.pmd.lang.java.ast.ASTExpression; +import net.sourceforge.pmd.lang.java.ast.ASTExpressionStatement; import net.sourceforge.pmd.lang.java.ast.ASTForInit; import net.sourceforge.pmd.lang.java.ast.ASTForStatement; import net.sourceforge.pmd.lang.java.ast.ASTForUpdate; @@ -28,7 +29,6 @@ import net.sourceforge.pmd.lang.java.ast.ASTLabeledStatement; import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTReturnStatement; import net.sourceforge.pmd.lang.java.ast.ASTStatement; -import net.sourceforge.pmd.lang.java.ast.ASTStatementExpression; import net.sourceforge.pmd.lang.java.ast.ASTSwitchLabel; import net.sourceforge.pmd.lang.java.ast.ASTSwitchStatement; import net.sourceforge.pmd.lang.java.ast.ASTThrowStatement; @@ -91,7 +91,7 @@ public class StatementAndBraceFinder extends JavaParserVisitorAdapter { } @Override - public Object visit(ASTStatementExpression node, Object data) { + public Object visit(ASTExpressionStatement node, Object data) { if (!(data instanceof Structure)) { return data; } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/metrics/internal/visitors/CycloVisitor.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/metrics/internal/visitors/CycloVisitor.java index edee8381f3..2d7a882cc6 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/metrics/internal/visitors/CycloVisitor.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/metrics/internal/visitors/CycloVisitor.java @@ -8,10 +8,11 @@ import org.apache.commons.lang3.mutable.MutableInt; import net.sourceforge.pmd.lang.java.ast.ASTAssertStatement; import net.sourceforge.pmd.lang.java.ast.ASTBlockStatement; -import net.sourceforge.pmd.lang.java.ast.ASTCatchStatement; +import net.sourceforge.pmd.lang.java.ast.ASTCatchClause; import net.sourceforge.pmd.lang.java.ast.ASTConditionalExpression; import net.sourceforge.pmd.lang.java.ast.ASTDoStatement; import net.sourceforge.pmd.lang.java.ast.ASTForStatement; +import net.sourceforge.pmd.lang.java.ast.ASTForeachStatement; import net.sourceforge.pmd.lang.java.ast.ASTIfStatement; import net.sourceforge.pmd.lang.java.ast.ASTSwitchLabel; import net.sourceforge.pmd.lang.java.ast.ASTSwitchStatement; @@ -90,7 +91,7 @@ public class CycloVisitor extends JavaParserVisitorAdapter { public Object visit(ASTWhileStatement node, Object data) { ((MutableInt) data).increment(); if (considerBooleanPaths) { - ((MutableInt) data).add(CycloMetric.booleanExpressionComplexity(node.getGuardExpressionNode())); + ((MutableInt) data).add(CycloMetric.booleanExpressionComplexity(node.getCondition())); } return super.visit(node, data); } @@ -100,7 +101,7 @@ public class CycloVisitor extends JavaParserVisitorAdapter { public Object visit(ASTIfStatement node, Object data) { ((MutableInt) data).increment(); if (considerBooleanPaths) { - ((MutableInt) data).add(CycloMetric.booleanExpressionComplexity(node.getGuardExpressionNode())); + ((MutableInt) data).add(CycloMetric.booleanExpressionComplexity(node.getCondition())); } return super.visit(node, data); @@ -111,19 +112,25 @@ public class CycloVisitor extends JavaParserVisitorAdapter { public Object visit(ASTForStatement node, Object data) { ((MutableInt) data).increment(); - if (considerBooleanPaths && !node.isForeach()) { - ((MutableInt) data).add(CycloMetric.booleanExpressionComplexity(node.getGuardExpressionNode())); + if (considerBooleanPaths) { + ((MutableInt) data).add(CycloMetric.booleanExpressionComplexity(node.getCondition())); } return super.visit(node, data); } + @Override + public Object visit(ASTForeachStatement node, Object data) { + ((MutableInt) data).increment(); + return super.visit(node, data); + } + @Override public Object visit(ASTDoStatement node, Object data) { ((MutableInt) data).increment(); if (considerBooleanPaths) { - ((MutableInt) data).add(CycloMetric.booleanExpressionComplexity(node.getGuardExpressionNode())); + ((MutableInt) data).add(CycloMetric.booleanExpressionComplexity(node.getCondition())); } return super.visit(node, data); @@ -131,7 +138,7 @@ public class CycloVisitor extends JavaParserVisitorAdapter { @Override - public Object visit(ASTCatchStatement node, Object data) { + public Object visit(ASTCatchClause node, Object data) { ((MutableInt) data).increment(); return super.visit(node, data); } @@ -150,7 +157,7 @@ public class CycloVisitor extends JavaParserVisitorAdapter { ((MutableInt) data).add(2); // equivalent to if (condition) { throw .. } if (considerBooleanPaths) { - ((MutableInt) data).add(CycloMetric.booleanExpressionComplexity(node.getGuardExpressionNode())); + ((MutableInt) data).add(CycloMetric.booleanExpressionComplexity(node.getCondition())); } } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/metrics/internal/visitors/NcssVisitor.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/metrics/internal/visitors/NcssVisitor.java index 1bd55e0e45..24ee81442e 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/metrics/internal/visitors/NcssVisitor.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/metrics/internal/visitors/NcssVisitor.java @@ -11,7 +11,7 @@ import org.apache.commons.lang3.mutable.MutableInt; import net.sourceforge.pmd.lang.java.ast.ASTAnnotationTypeDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTAssertStatement; import net.sourceforge.pmd.lang.java.ast.ASTBreakStatement; -import net.sourceforge.pmd.lang.java.ast.ASTCatchStatement; +import net.sourceforge.pmd.lang.java.ast.ASTCatchClause; import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit; import net.sourceforge.pmd.lang.java.ast.ASTConstructorDeclaration; @@ -19,8 +19,9 @@ import net.sourceforge.pmd.lang.java.ast.ASTContinueStatement; import net.sourceforge.pmd.lang.java.ast.ASTDoStatement; import net.sourceforge.pmd.lang.java.ast.ASTEnumDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTExplicitConstructorInvocation; +import net.sourceforge.pmd.lang.java.ast.ASTExpressionStatement; import net.sourceforge.pmd.lang.java.ast.ASTFieldDeclaration; -import net.sourceforge.pmd.lang.java.ast.ASTFinallyStatement; +import net.sourceforge.pmd.lang.java.ast.ASTFinallyClause; import net.sourceforge.pmd.lang.java.ast.ASTForInit; import net.sourceforge.pmd.lang.java.ast.ASTForStatement; import net.sourceforge.pmd.lang.java.ast.ASTForUpdate; @@ -32,7 +33,6 @@ import net.sourceforge.pmd.lang.java.ast.ASTLocalVariableDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTPackageDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTReturnStatement; -import net.sourceforge.pmd.lang.java.ast.ASTStatementExpression; import net.sourceforge.pmd.lang.java.ast.ASTSwitchLabel; import net.sourceforge.pmd.lang.java.ast.ASTSwitchStatement; import net.sourceforge.pmd.lang.java.ast.ASTSynchronizedStatement; @@ -162,7 +162,7 @@ public class NcssVisitor extends JavaParserVisitorAdapter { @Override - public Object visit(ASTStatementExpression node, Object data) { + public Object visit(ASTExpressionStatement node, Object data) { if (!(node.jjtGetParent().jjtGetParent() instanceof ASTForUpdate)) { ((MutableInt) data).increment(); } @@ -220,7 +220,7 @@ public class NcssVisitor extends JavaParserVisitorAdapter { @Override - public Object visit(ASTCatchStatement node, Object data) { + public Object visit(ASTCatchClause node, Object data) { ((MutableInt) data).increment(); return super.visit(node, data); } @@ -234,7 +234,7 @@ public class NcssVisitor extends JavaParserVisitorAdapter { @Override - public Object visit(ASTFinallyStatement node, Object data) { + public Object visit(ASTFinallyClause node, Object data) { ((MutableInt) data).increment(); return super.visit(node, data); } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/AbstractJavaRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/AbstractJavaRule.java index d69ae5f6e8..35e15e5257 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/AbstractJavaRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/AbstractJavaRule.java @@ -18,6 +18,7 @@ import net.sourceforge.pmd.lang.java.ast.ASTAllocationExpression; import net.sourceforge.pmd.lang.java.ast.ASTAndExpression; import net.sourceforge.pmd.lang.java.ast.ASTAnnotation; import net.sourceforge.pmd.lang.java.ast.ASTArguments; +import net.sourceforge.pmd.lang.java.ast.ASTBlockStatement; import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit; import net.sourceforge.pmd.lang.java.ast.ASTConditionalAndExpression; import net.sourceforge.pmd.lang.java.ast.ASTConditionalOrExpression; @@ -34,9 +35,12 @@ import net.sourceforge.pmd.lang.java.ast.ASTPrimaryPrefix; import net.sourceforge.pmd.lang.java.ast.ASTPrimarySuffix; import net.sourceforge.pmd.lang.java.ast.ASTRelationalExpression; import net.sourceforge.pmd.lang.java.ast.ASTShiftExpression; +import net.sourceforge.pmd.lang.java.ast.ASTStatement; +import net.sourceforge.pmd.lang.java.ast.ASTStatementExpression; import net.sourceforge.pmd.lang.java.ast.ASTTypeArgument; import net.sourceforge.pmd.lang.java.ast.ASTUnaryExpressionNotPlusMinus; import net.sourceforge.pmd.lang.java.ast.ASTWildcardBounds; +import net.sourceforge.pmd.lang.java.ast.JavaNode; import net.sourceforge.pmd.lang.java.ast.JavaParserVisitor; import net.sourceforge.pmd.lang.java.internal.JavaProcessingStage; import net.sourceforge.pmd.lang.rule.AbstractRule; @@ -179,6 +183,10 @@ public abstract class AbstractJavaRule extends AbstractRule implements JavaParse return visit((ASTExpression) node, data); } + public Object visit(ASTStatement node, Object data) { + return visit((JavaNode) node, data); + } + @Deprecated public Object visit(ASTPrimaryPrefix node, Object data) { return JavaParserVisitor.super.visit(node, data); @@ -216,6 +224,17 @@ public abstract class AbstractJavaRule extends AbstractRule implements JavaParse return null; } + @Deprecated + public Object visit(ASTBlockStatement node, Object data) { + return null; + } + + + @Deprecated + public Object visit(ASTStatementExpression node, Object data) { + return null; + } + @Deprecated public Object visit(ASTMethodDeclarator node, Object data) { return null; @@ -225,4 +244,5 @@ public abstract class AbstractJavaRule extends AbstractRule implements JavaParse public Object visit(ASTArguments node, Object data) { return null; } + } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/ForLoopCanBeForeachRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/ForLoopCanBeForeachRule.java index 93eeef41de..2a65e08e05 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/ForLoopCanBeForeachRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/ForLoopCanBeForeachRule.java @@ -49,10 +49,6 @@ public class ForLoopCanBeForeachRule extends AbstractJavaRule { @Override public Object visit(ASTForStatement node, Object data) { - if (node.isForeach()) { - return data; - } - final ASTForInit init = node.getFirstChildOfType(ASTForInit.class); final ASTForUpdate update = node.getFirstChildOfType(ASTForUpdate.class); final ASTExpression guardCondition = node.getFirstChildOfType(ASTExpression.class); diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/JUnitUseExpectedRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/JUnitUseExpectedRule.java index d41e170a7a..ebe8c4c4bb 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/JUnitUseExpectedRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/JUnitUseExpectedRule.java @@ -11,7 +11,7 @@ import net.sourceforge.pmd.lang.ast.Node; import net.sourceforge.pmd.lang.java.ast.ASTAnnotation; import net.sourceforge.pmd.lang.java.ast.ASTBlock; import net.sourceforge.pmd.lang.java.ast.ASTBlockStatement; -import net.sourceforge.pmd.lang.java.ast.ASTCatchStatement; +import net.sourceforge.pmd.lang.java.ast.ASTCatchClause; import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceBodyDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTName; @@ -79,7 +79,7 @@ public class JUnitUseExpectedRule extends AbstractJUnitRule { return found; } for (ASTTryStatement trySt : catches) { - ASTCatchStatement cStatement = getCatch(trySt); + ASTCatchClause cStatement = getCatch(trySt); if (cStatement != null) { ASTBlock block = (ASTBlock) cStatement.jjtGetChild(1); if (block.jjtGetNumChildren() != 0) { @@ -105,10 +105,10 @@ public class JUnitUseExpectedRule extends AbstractJUnitRule { return found; } - private ASTCatchStatement getCatch(Node n) { + private ASTCatchClause getCatch(Node n) { for (int i = 0; i < n.jjtGetNumChildren(); i++) { - if (n.jjtGetChild(i) instanceof ASTCatchStatement) { - return (ASTCatchStatement) n.jjtGetChild(i); + if (n.jjtGetChild(i) instanceof ASTCatchClause) { + return (ASTCatchClause) n.jjtGetChild(i); } } return null; diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/PreserveStackTraceRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/PreserveStackTraceRule.java index 31293bd795..4d3121d8ad 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/PreserveStackTraceRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/PreserveStackTraceRule.java @@ -15,7 +15,7 @@ import net.sourceforge.pmd.lang.java.ast.ASTAdditiveExpression; import net.sourceforge.pmd.lang.java.ast.ASTAllocationExpression; import net.sourceforge.pmd.lang.java.ast.ASTArgumentList; import net.sourceforge.pmd.lang.java.ast.ASTCastExpression; -import net.sourceforge.pmd.lang.java.ast.ASTCatchStatement; +import net.sourceforge.pmd.lang.java.ast.ASTCatchClause; import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceType; import net.sourceforge.pmd.lang.java.ast.ASTName; import net.sourceforge.pmd.lang.java.ast.ASTPrimaryExpression; @@ -38,7 +38,7 @@ public class PreserveStackTraceRule extends AbstractJavaRule { private static final String FILL_IN_STACKTRACE = ".fillInStackTrace"; @Override - public Object visit(ASTCatchStatement catchStmt, Object data) { + public Object visit(ASTCatchClause catchStmt, Object data) { String target = catchStmt.jjtGetChild(0).findChildrenOfType(ASTVariableDeclaratorId.class).get(0).getImage(); // Inspect all the throw stmt inside the catch stmt List lstThrowStatements = catchStmt.findDescendantsOfType(ASTThrowStatement.class); @@ -61,7 +61,7 @@ public class PreserveStackTraceRule extends AbstractJavaRule { // maybe it is used inside a anonymous class ck(data, target, throwStatement, parent); } else { - // Check all arguments used in the throw statement + // Check all arguments used in the throw statement ck(data, target, throwStatement, throwStatement); } } else { @@ -133,7 +133,7 @@ public class PreserveStackTraceRule extends AbstractJavaRule { /** * Checks whether the given target is in the argument list. If this is the * case, then the target (root exception) is used as the cause. - * + * * @param target * @param baseNode */ @@ -155,7 +155,7 @@ public class PreserveStackTraceRule extends AbstractJavaRule { } return match; } - + /** * Checks whether the given childNode is part of an additive expression (String concatenation) limiting search to base Node. * @param childNode diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/IdenticalCatchBranchesRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/IdenticalCatchBranchesRule.java index ba10b3f3c7..b7a635bc1b 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/IdenticalCatchBranchesRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/IdenticalCatchBranchesRule.java @@ -11,7 +11,7 @@ import java.util.Objects; import java.util.Set; import net.sourceforge.pmd.lang.ast.Node; -import net.sourceforge.pmd.lang.java.ast.ASTCatchStatement; +import net.sourceforge.pmd.lang.java.ast.ASTCatchClause; import net.sourceforge.pmd.lang.java.ast.ASTName; import net.sourceforge.pmd.lang.java.ast.ASTPrimaryPrefix; import net.sourceforge.pmd.lang.java.ast.ASTPrimarySuffix; @@ -29,22 +29,22 @@ import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; public class IdenticalCatchBranchesRule extends AbstractJavaRule { - private boolean areEquivalent(ASTCatchStatement st1, ASTCatchStatement st2) { + private boolean areEquivalent(ASTCatchClause st1, ASTCatchClause st2) { return hasSameSubTree(st1.getBlock(), st2.getBlock(), st1.getExceptionName(), st2.getExceptionName()); } - /** groups catch statements by equivalence class, according to the equivalence {@link #areEquivalent(ASTCatchStatement, ASTCatchStatement)}. */ - private Set> equivalenceClasses(List catches) { - Set> result = new HashSet<>(catches.size()); - for (ASTCatchStatement stmt : catches) { + /** groups catch statements by equivalence class, according to the equivalence {@link #areEquivalent(ASTCatchClause, ASTCatchClause)}. */ + private Set> equivalenceClasses(List catches) { + Set> result = new HashSet<>(catches.size()); + for (ASTCatchClause stmt : catches) { if (result.isEmpty()) { result.add(newEquivClass(stmt)); continue; } boolean isNewClass = true; - for (List equivClass : result) { + for (List equivClass : result) { if (areEquivalent(stmt, equivClass.get(0))) { equivClass.add(stmt); isNewClass = false; @@ -61,16 +61,16 @@ public class IdenticalCatchBranchesRule extends AbstractJavaRule { } - private List newEquivClass(ASTCatchStatement stmt) { + private List newEquivClass(ASTCatchClause stmt) { // Each equivalence class is sorted by document order - List result = new ArrayList<>(2); + List result = new ArrayList<>(2); result.add(stmt); return result; } // Gets the representation of the set of catch statements as a single multicatch - private String getCaughtExceptionsAsString(ASTCatchStatement stmt) { + private String getCaughtExceptionsAsString(ASTCatchClause stmt) { StringBuilder sb = new StringBuilder(); @@ -88,10 +88,10 @@ public class IdenticalCatchBranchesRule extends AbstractJavaRule { @Override public Object visit(ASTTryStatement node, Object data) { - List catchStatements = node.getCatchStatements(); - Set> equivClasses = equivalenceClasses(catchStatements); + List catchStatements = node.getCatchClauses(); + Set> equivClasses = equivalenceClasses(catchStatements); - for (List identicalStmts : equivClasses) { + for (List identicalStmts : equivClasses) { if (identicalStmts.size() > 1) { String identicalBranchName = getCaughtExceptionsAsString(identicalStmts.get(0)); diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/ExceptionAsFlowControlRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/ExceptionAsFlowControlRule.java index b1405a45a4..903216af0e 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/ExceptionAsFlowControlRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/ExceptionAsFlowControlRule.java @@ -6,7 +6,7 @@ package net.sourceforge.pmd.lang.java.rule.design; import java.util.List; -import net.sourceforge.pmd.lang.java.ast.ASTCatchStatement; +import net.sourceforge.pmd.lang.java.ast.ASTCatchClause; import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceType; import net.sourceforge.pmd.lang.java.ast.ASTFormalParameter; import net.sourceforge.pmd.lang.java.ast.ASTThrowStatement; @@ -16,7 +16,7 @@ import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; /** * Catches the use of exception statements as a flow control device. - * + * * @author Will Sargent */ public class ExceptionAsFlowControlRule extends AbstractJavaRule { @@ -30,8 +30,8 @@ public class ExceptionAsFlowControlRule extends AbstractJavaRule { for (parent = parent.getFirstParentOfType(ASTTryStatement.class); parent != null; parent = parent .getFirstParentOfType(ASTTryStatement.class)) { - List list = parent.findDescendantsOfType(ASTCatchStatement.class); - for (ASTCatchStatement catchStmt : list) { + List list = parent.findDescendantsOfType(ASTCatchClause.class); + for (ASTCatchClause catchStmt : list) { ASTFormalParameter fp = (ASTFormalParameter) catchStmt.jjtGetChild(0); ASTType type = fp.getFirstDescendantOfType(ASTType.class); ASTClassOrInterfaceType name = type.getFirstDescendantOfType(ASTClassOrInterfaceType.class); diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/StdCyclomaticComplexityRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/StdCyclomaticComplexityRule.java index d659ddf25a..ba6cee9cb1 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/StdCyclomaticComplexityRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/StdCyclomaticComplexityRule.java @@ -11,7 +11,7 @@ import java.util.Deque; import net.sourceforge.pmd.lang.ast.Node; import net.sourceforge.pmd.lang.java.ast.ASTBlockStatement; -import net.sourceforge.pmd.lang.java.ast.ASTCatchStatement; +import net.sourceforge.pmd.lang.java.ast.ASTCatchClause; import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit; import net.sourceforge.pmd.lang.java.ast.ASTConditionalExpression; @@ -36,9 +36,9 @@ import net.sourceforge.pmd.properties.PropertyFactory; *

* Standard rules: +1 for each decision point, including case statements but not * including boolean operators unlike CyclomaticComplexityRule. - * + * * @author Alan Hohn, based on work by Donald A. Leckie - * + * * @since June 18, 2014 */ @Deprecated @@ -107,7 +107,7 @@ public class StdCyclomaticComplexityRule extends AbstractJavaRule { } @Override - public Object visit(ASTCatchStatement node, Object data) { + public Object visit(ASTCatchClause node, Object data) { entryStack.peek().bumpDecisionPoints(); super.visit(node, data); return data; diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/errorprone/AvoidCatchingThrowableRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/errorprone/AvoidCatchingThrowableRule.java index a0012de889..9aeb74d9ca 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/errorprone/AvoidCatchingThrowableRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/errorprone/AvoidCatchingThrowableRule.java @@ -4,7 +4,7 @@ package net.sourceforge.pmd.lang.java.rule.errorprone; -import net.sourceforge.pmd.lang.java.ast.ASTCatchStatement; +import net.sourceforge.pmd.lang.java.ast.ASTCatchClause; import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceType; import net.sourceforge.pmd.lang.java.ast.ASTType; import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; @@ -12,13 +12,13 @@ import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; /** * Finds catch statements containing throwable as the * type definition. - * + * * @author Trond Andersen */ public class AvoidCatchingThrowableRule extends AbstractJavaRule { @Override - public Object visit(ASTCatchStatement node, Object data) { + public Object visit(ASTCatchClause node, Object data) { ASTType type = node.getFirstDescendantOfType(ASTType.class); ASTClassOrInterfaceType name = type.getFirstDescendantOfType(ASTClassOrInterfaceType.class); if (name.hasImageEqualTo("Throwable")) { diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/errorprone/CloseResourceRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/errorprone/CloseResourceRule.java index e7a4c3e164..7e675abb4c 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/errorprone/CloseResourceRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/errorprone/CloseResourceRule.java @@ -363,7 +363,7 @@ public class CloseResourceRule extends AbstractJavaRule { } } - if (t.getBeginLine() > id.getBeginLine() && t.hasFinally()) { + if (t.getBeginLine() > id.getBeginLine() && t.getFinally() != null) { ASTBlock f = (ASTBlock) t.getFinally().jjtGetChild(0); List names = f.findDescendantsOfType(ASTName.class); for (ASTName oName : names) { diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/performance/ConsecutiveLiteralAppendsRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/performance/ConsecutiveLiteralAppendsRule.java index 67644baf83..bb837a82cb 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/performance/ConsecutiveLiteralAppendsRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/performance/ConsecutiveLiteralAppendsRule.java @@ -16,9 +16,9 @@ import net.sourceforge.pmd.lang.ast.Node; import net.sourceforge.pmd.lang.java.ast.ASTAdditiveExpression; import net.sourceforge.pmd.lang.java.ast.ASTAllocationExpression; import net.sourceforge.pmd.lang.java.ast.ASTArgumentList; -import net.sourceforge.pmd.lang.java.ast.ASTCatchStatement; +import net.sourceforge.pmd.lang.java.ast.ASTCatchClause; import net.sourceforge.pmd.lang.java.ast.ASTDoStatement; -import net.sourceforge.pmd.lang.java.ast.ASTFinallyStatement; +import net.sourceforge.pmd.lang.java.ast.ASTFinallyClause; import net.sourceforge.pmd.lang.java.ast.ASTForStatement; import net.sourceforge.pmd.lang.java.ast.ASTIfStatement; import net.sourceforge.pmd.lang.java.ast.ASTLiteral; @@ -45,17 +45,17 @@ import net.sourceforge.pmd.properties.PropertyFactory; * This rule finds concurrent calls to StringBuffer/Builder.append where String * literals are used It would be much better to make these calls using one call * to .append - * + * *

Example:

- * + * *
  * StringBuilder buf = new StringBuilder();
  * buf.append("Hello");
  * buf.append(" ").append("World");
  * 
- * + * *

This would be more eloquently put as:

- * + * *
  * StringBuilder buf = new StringBuilder();
  * buf.append("Hello World");
@@ -76,8 +76,8 @@ public class ConsecutiveLiteralAppendsRule extends AbstractJavaRule {
         BLOCK_PARENTS.add(ASTIfStatement.class);
         BLOCK_PARENTS.add(ASTSwitchStatement.class);
         BLOCK_PARENTS.add(ASTMethodDeclaration.class);
-        BLOCK_PARENTS.add(ASTCatchStatement.class);
-        BLOCK_PARENTS.add(ASTFinallyStatement.class);
+        BLOCK_PARENTS.add(ASTCatchClause.class);
+        BLOCK_PARENTS.add(ASTFinallyClause.class);
     }
 
     private static final PropertyDescriptor THRESHOLD_DESCRIPTOR
diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symboltable/ScopeAndDeclarationFinder.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symboltable/ScopeAndDeclarationFinder.java
index ec45c6bc4b..06fe018b20 100644
--- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symboltable/ScopeAndDeclarationFinder.java
+++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symboltable/ScopeAndDeclarationFinder.java
@@ -10,7 +10,7 @@ import java.util.Deque;
 import net.sourceforge.pmd.lang.java.ast.ASTAnnotationTypeDeclaration;
 import net.sourceforge.pmd.lang.java.ast.ASTAnonymousClassDeclaration;
 import net.sourceforge.pmd.lang.java.ast.ASTBlock;
-import net.sourceforge.pmd.lang.java.ast.ASTCatchStatement;
+import net.sourceforge.pmd.lang.java.ast.ASTCatchClause;
 import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration;
 import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit;
 import net.sourceforge.pmd.lang.java.ast.ASTConstructorDeclaration;
@@ -58,7 +58,7 @@ public class ScopeAndDeclarationFinder extends JavaParserVisitorAdapter {
 
     /**
      * Creates a new {@link ScopeAndDeclarationFinder}.
-     * 
+     *
      * @param classLoader
      *            the class loader to use to resolve types, see
      *            {@link SourceFileScope} and {@link TypeSet}
@@ -201,7 +201,7 @@ public class ScopeAndDeclarationFinder extends JavaParserVisitorAdapter {
         if (node.jjtGetParent() instanceof ASTMethodDeclaration
                 || node.jjtGetParent() instanceof ASTConstructorDeclaration
                 || node.jjtGetParent() instanceof ASTLambdaExpression
-                || node.jjtGetParent() instanceof ASTCatchStatement
+                || node.jjtGetParent() instanceof ASTCatchClause
                 || node.jjtGetParent() instanceof ASTForStatement) {
             super.visit(node, null);
         } else {
@@ -212,7 +212,7 @@ public class ScopeAndDeclarationFinder extends JavaParserVisitorAdapter {
     }
 
     @Override
-    public Object visit(ASTCatchStatement node, Object data) {
+    public Object visit(ASTCatchClause node, Object data) {
         createLocalScope(node);
         cont(node);
         return data;
diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/typeresolution/ClassTypeResolver.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/typeresolution/ClassTypeResolver.java
index 5a400c0c8a..d76d48da89 100644
--- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/typeresolution/ClassTypeResolver.java
+++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/typeresolution/ClassTypeResolver.java
@@ -71,7 +71,6 @@ import net.sourceforge.pmd.lang.java.ast.ASTPrimitiveType;
 import net.sourceforge.pmd.lang.java.ast.ASTReferenceType;
 import net.sourceforge.pmd.lang.java.ast.ASTRelationalExpression;
 import net.sourceforge.pmd.lang.java.ast.ASTShiftExpression;
-import net.sourceforge.pmd.lang.java.ast.ASTStatementExpression;
 import net.sourceforge.pmd.lang.java.ast.ASTSwitchExpression;
 import net.sourceforge.pmd.lang.java.ast.ASTSwitchLabeledRule;
 import net.sourceforge.pmd.lang.java.ast.ASTType;
@@ -222,6 +221,7 @@ public class ClassTypeResolver extends JavaParserVisitorAdapter {
     }
 
 
+
     @Override
     public Object visit(ASTTypeDeclaration node, Object data) {
         super.visit(node, data);
@@ -896,7 +896,7 @@ public class ClassTypeResolver extends JavaParserVisitorAdapter {
         //            if (currentChild.getType() != null) {
         //                // rollup type from the child: PrimaryPrefix -> PrimaryExpression
         //                primaryNodeType = currentChild.getTypeDefinition();
-        //                
+        //
         //                // if this expression is a method call, then make sure, PrimaryPrefix has the type
         //                // on which the method is executed (type of the target reference)
         //                if (currentChild.getFirstChildOfType(ASTArguments.class) != null && previousChild.getFirstChildOfType(ASTName.class) != null) {
@@ -1134,13 +1134,6 @@ public class ClassTypeResolver extends JavaParserVisitorAdapter {
         return data;
     }
 
-    @Override
-    public Object visit(ASTStatementExpression node, Object data) {
-        super.visit(node, data);
-        rollupTypeUnary(node);
-        return data;
-    }
-
     @Override
     public Object visit(ASTSwitchExpression node, Object data) {
         super.visit(node, data);
diff --git a/pmd-java/src/main/resources/category/java/errorprone.xml b/pmd-java/src/main/resources/category/java/errorprone.xml
index 60cee67d46..abbe6c7cb3 100644
--- a/pmd-java/src/main/resources/category/java/errorprone.xml
+++ b/pmd-java/src/main/resources/category/java/errorprone.xml
@@ -1546,8 +1546,7 @@ Empty If Statement finds instances where a condition is checked but nothing is d
             
                 
 
                 
             
diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java13Test.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java13Test.java
index e90ee863af..359828f482 100644
--- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java13Test.java
+++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java13Test.java
@@ -40,7 +40,7 @@ public class Java13Test {
         Assert.assertEquals(1, switchExpression.findChildrenOfType(ASTSwitchLabeledBlock.class).size());
         Assert.assertEquals(1, switchExpression.findDescendantsOfType(ASTYieldStatement.class).size());
         ASTYieldStatement yieldStatement = switchExpression.getFirstDescendantOfType(ASTYieldStatement.class);
-        Assert.assertEquals(Integer.TYPE, yieldStatement.getType());
+        Assert.assertEquals(Integer.TYPE, yieldStatement.getExpr().getType());
     }
 
     @Test
diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/ParserCornersTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/ParserCornersTest.java
index 5accd2d88e..5d0fa458aa 100644
--- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/ParserCornersTest.java
+++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/ParserCornersTest.java
@@ -246,17 +246,17 @@ public class ParserCornersTest {
         String code = "import a;;import b; public class Foo {}";
         ASTCompilationUnit cu = parseJava18(code);
         assertNotNull(cu);
-        Assert.assertEquals(ASTEmptyStatement.class, cu.jjtGetChild(1).getClass());
+        Assert.assertEquals(ASTEmptyDeclaration.class, cu.jjtGetChild(1).getClass());
 
         String code2 = "package c;; import a; import b; public class Foo {}";
         ASTCompilationUnit cu2 = parseJava18(code2);
         assertNotNull(cu2);
-        Assert.assertEquals(ASTEmptyStatement.class, cu2.jjtGetChild(1).getClass());
+        Assert.assertEquals(ASTEmptyDeclaration.class, cu2.jjtGetChild(1).getClass());
 
         String code3 = "package c; import a; import b; public class Foo {};";
         ASTCompilationUnit cu3 = parseJava18(code3);
         assertNotNull(cu3);
-        Assert.assertEquals(ASTEmptyStatement.class, cu3.jjtGetChild(4).getClass());
+        Assert.assertEquals(ASTEmptyDeclaration.class, cu3.jjtGetChild(4).getClass());
     }
 
     @Test
diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/SimpleNodeTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/SimpleNodeTest.java
index 7fe7143609..e64386b2eb 100644
--- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/SimpleNodeTest.java
+++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/SimpleNodeTest.java
@@ -8,7 +8,6 @@ import static net.sourceforge.pmd.lang.java.ParserTstUtil.getNodes;
 import static net.sourceforge.pmd.lang.java.ParserTstUtil.parseJava14;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertSame;
 import static org.junit.Assert.assertTrue;
@@ -102,91 +101,91 @@ public class SimpleNodeTest {
             }
         }
     }
-
-    @Test
-    public void testLineNumbersAreSetOnAllSiblings() {
-        for (ASTBlock b : getNodes(ASTBlock.class, LINE_NUMBERS_ON_SIBLINGS)) {
-            assertTrue(b.getBeginLine() > 0);
-        }
-        for (ASTVariableInitializer b : getNodes(ASTVariableInitializer.class, LINE_NUMBERS_ON_SIBLINGS)) {
-            assertTrue(b.getBeginLine() > 0);
-        }
-        for (ASTExpression b : getNodes(ASTExpression.class, LINE_NUMBERS_ON_SIBLINGS)) {
-            assertTrue(b.getBeginLine() > 0);
-        }
-    }
-
-    @Test
-    public void testFindDescendantsOfType() {
-        ASTBlock block = new ASTBlock(2);
-        block.jjtAddChild(new ASTReturnStatement(1), 0);
-        assertEquals(1, block.findDescendantsOfType(ASTReturnStatement.class).size());
-    }
-
-    @Test
-    public void testFindDescendantsOfTypeMultiple() {
-        ASTBlock block = new ASTBlock(1);
-        block.jjtAddChild(new ASTBlockStatement(2), 0);
-        block.jjtAddChild(new ASTBlockStatement(3), 1);
-        List nodes = block.findDescendantsOfType(ASTBlockStatement.class);
-        assertEquals(2, nodes.size());
-    }
-
-    @Test
-    public void testFindDescendantsOfTypeRecurse() {
-        ASTBlock block = new ASTBlock(1);
-        ASTBlock childBlock = new ASTBlock(2);
-        block.jjtAddChild(childBlock, 0);
-        childBlock.jjtAddChild(new ASTMethodDeclaration(3), 0);
-        List nodes = block.findDescendantsOfType(ASTMethodDeclaration.class);
-        assertEquals(1, nodes.size());
-    }
-
-    @Test
-    public void testGetFirstChild() {
-        ASTBlock block = new ASTBlock(1);
-        ASTStatement x = new ASTStatement(2);
-        block.jjtAddChild(x, 0);
-        block.jjtAddChild(new ASTStatement(3), 1);
-
-        Node n = block.getFirstDescendantOfType(ASTStatement.class);
-        assertNotNull(n);
-        assertTrue(n instanceof ASTStatement);
-        assertEquals(x, n);
-    }
-
-    @Test
-    public void testGetFirstChildNested() {
-        ASTBlock block = new ASTBlock(1);
-        ASTStatement x = new ASTStatement(2);
-        ASTAssignmentOperator x1 = new ASTAssignmentOperator(4);
-        x.jjtAddChild(x1, 0);
-        block.jjtAddChild(x, 0);
-        block.jjtAddChild(new ASTStatement(3), 1);
-
-        Node n = block.getFirstDescendantOfType(ASTAssignmentOperator.class);
-        assertNotNull(n);
-        assertTrue(n instanceof ASTAssignmentOperator);
-        assertEquals(x1, n);
-    }
-
-    @Test
-    public void testGetFirstChildNestedDeeper() {
-        ASTBlock block = new ASTBlock(1);
-        ASTStatement x = new ASTStatement(2);
-        ASTAssignmentOperator x1 = new ASTAssignmentOperator(4);
-        ASTName x2 = new ASTName(5);
-
-        x.jjtAddChild(x1, 0);
-        x1.jjtAddChild(x2, 0);
-        block.jjtAddChild(x, 0);
-        block.jjtAddChild(new ASTStatement(3), 1);
-
-        Node n = block.getFirstDescendantOfType(ASTName.class);
-        assertNotNull(n);
-        assertTrue(n instanceof ASTName);
-        assertEquals(x2, n);
-    }
+    //
+    //    @Test
+    //    public void testLineNumbersAreSetOnAllSiblings() {
+    //        for (ASTBlock b : getNodes(ASTBlock.class, LINE_NUMBERS_ON_SIBLINGS)) {
+    //            assertTrue(b.getBeginLine() > 0);
+    //        }
+    //        for (ASTVariableInitializer b : getNodes(ASTVariableInitializer.class, LINE_NUMBERS_ON_SIBLINGS)) {
+    //            assertTrue(b.getBeginLine() > 0);
+    //        }
+    //        for (ASTExpression b : getNodes(ASTExpression.class, LINE_NUMBERS_ON_SIBLINGS)) {
+    //            assertTrue(b.getBeginLine() > 0);
+    //        }
+    //    }
+    //
+    //    @Test
+    //    public void testFindDescendantsOfType() {
+    //        ASTBlock block = new ASTBlock(2);
+    //        block.jjtAddChild(new ASTReturnStatement(1), 0);
+    //        assertEquals(1, block.findDescendantsOfType(ASTReturnStatement.class).size());
+    //    }
+    //
+    //    @Test
+    //    public void testFindDescendantsOfTypeMultiple() {
+    //        ASTBlock block = new ASTBlock(1);
+    //        block.jjtAddChild(new ASTBlockStatement(2), 0);
+    //        block.jjtAddChild(new ASTBlockStatement(3), 1);
+    //        List nodes = block.findDescendantsOfType(ASTBlockStatement.class);
+    //        assertEquals(2, nodes.size());
+    //    }
+    //
+    //    @Test
+    //    public void testFindDescendantsOfTypeRecurse() {
+    //        ASTBlock block = new ASTBlock(1);
+    //        ASTBlock childBlock = new ASTBlock(2);
+    //        block.jjtAddChild(childBlock, 0);
+    //        childBlock.jjtAddChild(new ASTMethodDeclaration(3), 0);
+    //        List nodes = block.findDescendantsOfType(ASTMethodDeclaration.class);
+    //        assertEquals(1, nodes.size());
+    //    }
+    //
+    //    @Test
+    //    public void testGetFirstChild() {
+    //        ASTBlock block = new ASTBlock(1);
+    //        ASTStatement x = new ASTStatement(2);
+    //        block.jjtAddChild(x, 0);
+    //        block.jjtAddChild(new ASTStatement(3), 1);
+    //
+    //        Node n = block.getFirstDescendantOfType(ASTStatement.class);
+    //        assertNotNull(n);
+    //        assertTrue(n instanceof ASTStatement);
+    //        assertEquals(x, n);
+    //    }
+    //
+    //    @Test
+    //    public void testGetFirstChildNested() {
+    //        ASTBlock block = new ASTBlock(1);
+    //        ASTStatement x = new ASTStatement(2);
+    //        ASTAssignmentOperator x1 = new ASTAssignmentOperator(4);
+    //        x.jjtAddChild(x1, 0);
+    //        block.jjtAddChild(x, 0);
+    //        block.jjtAddChild(new ASTStatement(3), 1);
+    //
+    //        Node n = block.getFirstDescendantOfType(ASTAssignmentOperator.class);
+    //        assertNotNull(n);
+    //        assertTrue(n instanceof ASTAssignmentOperator);
+    //        assertEquals(x1, n);
+    //    }
+    //
+    //    @Test
+    //    public void testGetFirstChildNestedDeeper() {
+    //        ASTBlock block = new ASTBlock(1);
+    //        ASTStatement x = new ASTStatement(2);
+    //        ASTAssignmentOperator x1 = new ASTAssignmentOperator(4);
+    //        ASTName x2 = new ASTName(5);
+    //
+    //        x.jjtAddChild(x1, 0);
+    //        x1.jjtAddChild(x2, 0);
+    //        block.jjtAddChild(x, 0);
+    //        block.jjtAddChild(new ASTStatement(3), 1);
+    //
+    //        Node n = block.getFirstDescendantOfType(ASTName.class);
+    //        assertNotNull(n);
+    //        assertTrue(n instanceof ASTName);
+    //        assertEquals(x2, n);
+    //    }
 
     @Test
     public void testParentMethods() {
@@ -311,9 +310,9 @@ public class SimpleNodeTest {
     private static final String BROKEN_LINE_IN_NAME = "import java.io." + PMD.EOL + "File;" + PMD.EOL
             + "public class Foo{}";
 
-    private static final String LINE_NUMBERS_ON_SIBLINGS = "public class Foo {" + PMD.EOL + " void bar() {" + PMD.EOL
-            + "  try {" + PMD.EOL + "  } catch (Exception1 e) {" + PMD.EOL + "   int x =2;" + PMD.EOL + "  }" + PMD.EOL
-            + " if (x != null) {}" + PMD.EOL + " }" + PMD.EOL + "}";
+    //    private static final String LINE_NUMBERS_ON_SIBLINGS = "public class Foo {" + PMD.EOL + " void bar() {" + PMD.EOL
+    //            + "  try {" + PMD.EOL + "  } catch (Exception1 e) {" + PMD.EOL + "   int x =2;" + PMD.EOL + "  }" + PMD.EOL
+    //            + " if (x != null) {}" + PMD.EOL + " }" + PMD.EOL + "}";
 
     private static final String NO_LOOKAHEAD = "public class Foo { }";
 
diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/XPathRuleTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/XPathRuleTest.java
index 61ed6bd219..87d4ed7039 100644
--- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/XPathRuleTest.java
+++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/XPathRuleTest.java
@@ -169,14 +169,13 @@ public class XPathRuleTest extends RuleTst {
 
     /**
      * Following sibling check: See https://sourceforge.net/p/pmd/bugs/1209/
-     * 
+     *
      * @throws Exception
      *             any error
      */
     @Test
     public void testFollowingSibling() throws Exception {
-        final String SOURCE = "public class dummy {\n" + "  public String toString() {\n"
-                + "    String test = \"bad example\";\n" + "    test = \"a\";\n" + "    return test;\n" + "  }\n" + "}";
+        final String SOURCE = "public interface dummy extends Foo, Bar, Baz {}";
         LanguageVersion language = LanguageRegistry.getLanguage(JavaLanguageModule.NAME).getDefaultVersion();
         ParserOptions parserOptions = language.getLanguageVersionHandler().getDefaultParserOptions();
         Parser parser = language.getLanguageVersionHandler().getParser(parserOptions);
@@ -184,27 +183,27 @@ public class XPathRuleTest extends RuleTst {
         RuleContext ruleContext = new RuleContext();
         ruleContext.setLanguageVersion(language);
 
-        String xpath = "//Block/BlockStatement/following-sibling::BlockStatement";
+        String xpath = "//ExtendsList/ClassOrInterfaceType/following-sibling::ClassOrInterfaceType";
 
         // XPATH version 1.0
         XPathRuleQuery xpathRuleQuery = new JaxenXPathRuleQuery();
         xpathRuleQuery.setXPath(xpath);
-        xpathRuleQuery.setProperties(new HashMap, Object>());
+        xpathRuleQuery.setProperties(new HashMap<>());
         xpathRuleQuery.setVersion(XPathRuleQuery.XPATH_1_0);
         List nodes = xpathRuleQuery.evaluate(cu, ruleContext);
         assertEquals(2, nodes.size());
-        assertEquals(4, nodes.get(0).getBeginLine());
-        assertEquals(5, nodes.get(1).getBeginLine());
+        assertEquals("Bar", nodes.get(0).getImage());
+        assertEquals("Baz", nodes.get(1).getImage());
 
         // XPATH version 2.0
         xpathRuleQuery = new SaxonXPathRuleQuery();
         xpathRuleQuery.setXPath(xpath);
-        xpathRuleQuery.setProperties(new HashMap, Object>());
+        xpathRuleQuery.setProperties(new HashMap<>());
         xpathRuleQuery.setVersion(XPathRuleQuery.XPATH_2_0);
         nodes = xpathRuleQuery.evaluate(cu, ruleContext);
         assertEquals(2, nodes.size());
-        assertEquals(4, nodes.get(0).getBeginLine());
-        assertEquals(5, nodes.get(1).getBeginLine());
+        assertEquals("Bar", nodes.get(0).getImage());
+        assertEquals("Baz", nodes.get(1).getImage());
     }
 
     private static Report getReportForTestString(Rule r, String test) throws PMDException {
diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/symboltable/AcceptanceTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/symboltable/AcceptanceTest.java
index c2df4d47ba..935bcb1e30 100644
--- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/symboltable/AcceptanceTest.java
+++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/symboltable/AcceptanceTest.java
@@ -18,7 +18,7 @@ import org.junit.Test;
 import net.sourceforge.pmd.PMD;
 import net.sourceforge.pmd.lang.ast.Node;
 import net.sourceforge.pmd.lang.java.ast.ASTBlock;
-import net.sourceforge.pmd.lang.java.ast.ASTCatchStatement;
+import net.sourceforge.pmd.lang.java.ast.ASTCatchClause;
 import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration;
 import net.sourceforge.pmd.lang.java.ast.ASTEqualityExpression;
 import net.sourceforge.pmd.lang.java.ast.ASTInitializer;
@@ -48,7 +48,7 @@ public class AcceptanceTest extends STBBaseTst {
     @Test
     public void testCatchBlocks() {
         parseCode(TEST_CATCH_BLOCKS);
-        ASTCatchStatement c = acu.findDescendantsOfType(ASTCatchStatement.class).get(0);
+        ASTCatchClause c = acu.findDescendantsOfType(ASTCatchClause.class).get(0);
         ASTBlock a = c.findDescendantsOfType(ASTBlock.class).get(0);
         Scope s = a.getScope();
         Map> vars = s.getDeclarations();
diff --git a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTCatchStatementTest.kt b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTCatchClauseTest.kt
similarity index 90%
rename from pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTCatchStatementTest.kt
rename to pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTCatchClauseTest.kt
index a4ad3f9fcb..45af65f1ec 100644
--- a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTCatchStatementTest.kt
+++ b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTCatchClauseTest.kt
@@ -8,12 +8,12 @@ import net.sourceforge.pmd.lang.java.ast.JavaVersion.Companion.Latest
 import java.io.IOException
 
 
-class ASTCatchStatementTest : ParserTestSpec({
+class ASTCatchClauseTest : ParserTestSpec({
 
     parserTest("Test crash on multicatch", javaVersions = Earliest..J1_6) {
 
         expectParseException("Composite catch clauses are a feature of Java 1.7, you should select your language version accordingly") {
-            parseAstStatement("try { } catch (IOException | AssertionError e) { }")
+            parseStatement("try { } catch (IOException | AssertionError e) { }")
         }
 
     }
@@ -24,7 +24,7 @@ class ASTCatchStatementTest : ParserTestSpec({
 
         "try { } catch (IOException ioe) { }" should matchStmt {
             child { }
-            child {
+            child {
                 it.isMulticatchStatement shouldBe false
 
                 unspecifiedChildren(2)
@@ -39,7 +39,7 @@ class ASTCatchStatementTest : ParserTestSpec({
 
         "try { } catch (IOException | AssertionError e) { }" should matchStmt {
             child { }
-            child {
+            child {
                 it.isMulticatchStatement shouldBe true
 
                 val types = fromChild> {
diff --git a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTClassOrInterfaceDeclTest.kt b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTClassOrInterfaceDeclTest.kt
index ccbaeceeeb..b7be4d1423 100644
--- a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTClassOrInterfaceDeclTest.kt
+++ b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTClassOrInterfaceDeclTest.kt
@@ -20,18 +20,16 @@ class ASTClassOrInterfaceDeclTest : ParserTestSpec({
 
                }
             """ should parseAs {
+                localClassDecl(simpleName = "Local") {
 
-                child {
-                    classDecl(simpleName = "Local") {
+                    it::isAbstract shouldBe false
+                    it::isFinal shouldBe false
+                    it::isLocal shouldBe true
+                    it::isNested shouldBe false
 
-                        it::isAbstract shouldBe false
-                        it::isFinal shouldBe false
-                        it::isLocal shouldBe true
-                        it::isNested shouldBe false
+                    annotation("F")
 
-                        annotation("F")
-                        classBody {}
-                    }
+                    typeBody()
                 }
             }
 
@@ -41,20 +39,18 @@ class ASTClassOrInterfaceDeclTest : ParserTestSpec({
                }
             """ should parseAs {
 
-                child {
-                    classDecl(simpleName = "Local") {
-                        it::getDeclaredAnnotations shouldBe listOf(
-                                annotation("F"),
-                                annotation("C")
-                        )
+                localClassDecl(simpleName = "Local") {
+                    it::getDeclaredAnnotations shouldBe listOf(
+                            annotation("F"),
+                            annotation("C")
+                    )
 
-                        it::isAbstract shouldBe true
-                        it::isFinal shouldBe false
-                        it::isLocal shouldBe true
-                        it::isNested shouldBe false
+                    it::isAbstract shouldBe true
+                    it::isFinal shouldBe false
+                    it::isLocal shouldBe true
+                    it::isNested shouldBe false
 
-                        classBody {}
-                    }
+                    typeBody()
                 }
             }
         }
diff --git a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTEnumConstantTest.kt b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTEnumConstantTest.kt
index c512f20ed2..614534bc01 100644
--- a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTEnumConstantTest.kt
+++ b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTEnumConstantTest.kt
@@ -12,8 +12,7 @@ class ASTEnumConstantTest : ParserTestSpec({
 
         "enum Foo { A, B }" should matchToplevelType {
 
-            child {
-
+            typeBody {
                 enumConstant("A") {
                     it::isAnonymousClass shouldBe false
 
@@ -36,6 +35,7 @@ class ASTEnumConstantTest : ParserTestSpec({
 
                     it::getArguments shouldBe null
                     it::getAnonymousClass shouldBe null
+
                 }
             }
         }
@@ -45,9 +45,7 @@ class ASTEnumConstantTest : ParserTestSpec({
     parserTest("Enum constants should have an anonymous class node") {
 
         "enum Foo { B { } }" should matchToplevelType {
-
-            child {
-
+            typeBody {
                 enumConstant("B") {
                     it::isAnonymousClass shouldBe true
 
@@ -59,18 +57,19 @@ class ASTEnumConstantTest : ParserTestSpec({
                     it::getArguments shouldBe null
 
                     it::getAnonymousClass shouldBe child {
-                        child {}
+                        typeBody()
                     }
                 }
             }
         }
     }
 
+
     parserTest("Enum constants should contain their annotations") {
 
         "enum Foo { @C B, @A@a C }" should matchToplevelType {
 
-            child {
+            typeBody {
 
                 enumConstant("B") {
                     it::getDeclaredAnnotations shouldBe listOf(annotation("C"))
@@ -93,11 +92,12 @@ class ASTEnumConstantTest : ParserTestSpec({
         }
     }
 
+
     parserTest("Enum constants with arguments") {
 
         "enum Foo { B(\"str\") }" should matchToplevelType {
 
-            child {
+            typeBody {
 
                 enumConstant("B") {
                     it::getId shouldBe variableId("B") {
@@ -116,8 +116,8 @@ class ASTEnumConstantTest : ParserTestSpec({
 
         "enum Foo { B(\"str\") { } }" should matchToplevelType {
 
-            child {
 
+            typeBody {
                 enumConstant("B") {
                     it::getId shouldBe variableId("B") {
                         it::isEnumConstant shouldBe true
@@ -129,7 +129,7 @@ class ASTEnumConstantTest : ParserTestSpec({
                     }
 
                     it::getAnonymousClass shouldBe child {
-                        child {}
+                        typeBody()
                     }
                 }
             }
diff --git a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTExplicitConstructorInvocationTest.kt b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTExplicitConstructorInvocationTest.kt
index 11fe6e59a9..aec45db20d 100644
--- a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTExplicitConstructorInvocationTest.kt
+++ b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTExplicitConstructorInvocationTest.kt
@@ -144,7 +144,7 @@ class ASTExplicitConstructorInvocationTest : ParserTestSpec({
                     it::isQualified shouldBe true
                     it::getArgumentCount shouldBe 0
 
-                it::getQualifier shouldBe child(ignoreChildren = true) { }
+                    it::getQualifier shouldBe child(ignoreChildren = true) { }
 
                     it::getExplicitTypeArguments shouldBe child {
                         classType("String")
@@ -158,8 +158,7 @@ class ASTExplicitConstructorInvocationTest : ParserTestSpec({
         "public TabbedPaneLayout() { MetalTabbedPaneUI.this.super(); }" should matchDeclaration {
 
             child { }
-
-            block {
+            it::getBody shouldBe block {
                 child {
                     it::isThis shouldBe false
                     it::isSuper shouldBe true
@@ -167,7 +166,7 @@ class ASTExplicitConstructorInvocationTest : ParserTestSpec({
                     it::getExplicitTypeArguments shouldBe null
                     it::getArgumentCount shouldBe 0
 
-                it::getQualifier shouldBe child(ignoreChildren = true) { }
+                    it::getQualifier shouldBe child(ignoreChildren = true) { }
 
 
                     it::getArgumentsList shouldBe child { }
@@ -225,7 +224,7 @@ class ASTExplicitConstructorInvocationTest : ParserTestSpec({
             child { }
 
             block {
-                child(ignoreChildren = true) {}
+                exprStatement()
             }
         }
 
@@ -233,8 +232,7 @@ class ASTExplicitConstructorInvocationTest : ParserTestSpec({
 
             child { }
             block {
-
-                child(ignoreChildren = true) {}
+                exprStatement()
             }
         }
 
@@ -243,7 +241,7 @@ class ASTExplicitConstructorInvocationTest : ParserTestSpec({
             child { }
 
             block {
-                child(ignoreChildren = true) {}
+                exprStatement()
             }
         }
 
@@ -253,7 +251,7 @@ class ASTExplicitConstructorInvocationTest : ParserTestSpec({
             child { }
 
             block {
-                child(ignoreChildren = true) {}
+                exprStatement()
             }
         }
 
diff --git a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTStatementsTest.kt b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTStatementsTest.kt
new file mode 100644
index 0000000000..a53c1b59ce
--- /dev/null
+++ b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTStatementsTest.kt
@@ -0,0 +1,135 @@
+/*
+ * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
+ */
+
+
+package net.sourceforge.pmd.lang.java.ast
+
+import net.sourceforge.pmd.lang.ast.test.shouldBe
+import net.sourceforge.pmd.lang.java.ast.ParserTestCtx.Companion.StatementParsingCtx
+
+class ASTStatementsTest : ParserTestSpec({
+
+    parserTest("Foreach loop") {
+
+        inContext(StatementParsingCtx) {
+            """
+                 for (Integer i : new Iter<>()) 
+                    loop();
+            """ should parseAs {
+
+                foreachLoop {
+
+                    it::getVariableId shouldBe fromChild {
+                        it::getTypeNode shouldBe classType("Integer")
+                        fromChild {
+                            variableId("i")
+                        }
+                    }
+
+                    it::getIterableExpr shouldBe constructorCall()
+
+                    exprStatement {
+                        methodCall("loop")
+                    }
+                }
+            }
+            """
+                 for (@Nullable final Integer i : new Iter<>()) {
+                 
+                 
+                 }
+            """ should parseAs {
+
+                foreachLoop {
+
+                    localVarDecl {
+                        annotation("Nullable")
+                        classType("Integer")
+                        variableDeclarator("i")
+                    }
+
+                    it.variableId::isFinal shouldBe true
+
+                    it::getIterableExpr shouldBe constructorCall()
+
+                    block()
+                }
+            }
+        }
+    }
+
+
+    parserTest("For loop") {
+        inContext(StatementParsingCtx) {
+
+            "for (;;) {}" should parseAs {
+                forLoop {
+                    it::getInit shouldBe null
+                    it::getCondition shouldBe null
+                    it::getUpdate shouldBe null
+
+                    block { }
+                }
+            }
+
+            "for (int i = 0; i < 2; i++);" should parseAs {
+                forLoop {
+                    it::getInit shouldBe forInit {
+                        localVarDecl()
+                    }
+                    it::getCondition shouldBe infixExpr(BinaryOp.LT) {
+                        variableAccess("i")
+                        int(2)
+                    }
+                    it::getUpdate shouldBe forUpdate {
+                        statementExprList {
+                            unspecifiedChild()
+                        }
+                    }
+                    emptyStatement()
+                }
+            }
+
+            "for (i = 1, j = 1; ; i *= 2, j += 2);" should parseAs {
+                forLoop {
+                    it::getInit shouldBe forInit {
+                        statementExprList {
+                            assignmentExpr(AssignmentOp.ASSIGN)
+                            assignmentExpr(AssignmentOp.ASSIGN)
+                        }
+                    }
+                    it::getCondition shouldBe null
+                    it::getUpdate shouldBe forUpdate {
+                        statementExprList {
+                            assignmentExpr(AssignmentOp.MUL_ASSIGN)
+                            assignmentExpr(AssignmentOp.ADD_ASSIGN)
+                        }
+                    }
+
+                    emptyStatement()
+                }
+            }
+        }
+    }
+
+    parserTest("Blocks") {
+
+        inContext(StatementParsingCtx) {
+
+            """
+               {
+                 for (;;) {}
+                 for (Integer i : new Iter<>()) loop();
+                 a = 0;
+               }
+            """ should parseAs {
+                block {
+                    forLoop()
+                    foreachLoop()
+                    exprStatement()
+                }
+            }
+        }
+    }
+})
diff --git a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTSwitchExpressionTests.kt b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTSwitchExpressionTests.kt
index 9857986015..fb12385eee 100644
--- a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTSwitchExpressionTests.kt
+++ b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTSwitchExpressionTests.kt
@@ -71,16 +71,10 @@ class ASTSwitchExpressionTests : ParserTestSpec({
                 child {
                     it::isDefault shouldBe true
                 }
-                child {
-                    child(ignoreChildren = true) {}
-                    child(ignoreChildren = true) {}
-                    child {
-                        child {
-                            child {
-                                it::getImage shouldBe "result"
-                            }
-                        }
-                    }
+                block {
+                    localVarDecl()
+                    localVarDecl()
+                    breakStatement(label = "result")
                 }
             }
         }
@@ -240,42 +234,31 @@ class ASTSwitchExpressionTests : ParserTestSpec({
                 child(ignoreChildren = true) {}
 
             }
-            child {
-                child {
-                    child(ignoreChildren = true) {}
-                }
-            }
-            child {
-                child {
-                    child {}
-                }
-            }
+
+            exprStatement()
+            breakStatement()
             child {
                 it::isDefault shouldBe false
 
                 child(ignoreChildren = true) {}
 
             }
-            child {
-                child {
-                    child {
 
-                        it::getTestedExpression shouldBe child(ignoreChildren = true) {}
+            child {
 
-                        child(ignoreChildren = true) {}
-                        child(ignoreChildren = true) {}
+                it::getTestedExpression shouldBe child(ignoreChildren = true) {}
+
+                child(ignoreChildren = true) {}
+                child(ignoreChildren = true) {}
 
-                    }
-                }
             }
+
+
             child {
                 it::isDefault shouldBe true
             }
-            child {
-                child {
-                    child(ignoreChildren = true) {}
-                }
-            }
+
+            exprStatement()
         }
     }
 
@@ -335,14 +318,9 @@ class ASTSwitchExpressionTests : ParserTestSpec({
 
                 variableAccess("TUESDAY")
             }
-            child(ignoreChildren = true) { }
 
-
-            child {
-                child {
-                    child {}
-                }
-            }
+            exprStatement()
+            breakStatement()
 
             child {
                 it::isDefault shouldBe false
@@ -351,24 +329,14 @@ class ASTSwitchExpressionTests : ParserTestSpec({
                 child(ignoreChildren = true) {}
             }
 
-            child(ignoreChildren = true) { }
-
-
-            child {
-                child {
-                    child {}
-                }
-            }
+            exprStatement()
+            breakStatement()
 
             child {
                 it::isDefault shouldBe true
             }
 
-            child {
-                child {
-                    child {}
-                }
-            }
+            breakStatement()
         }
     }
 
diff --git a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/KotlinTestingDsl.kt b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/KotlinTestingDsl.kt
index 1e20de7001..39083d2e39 100644
--- a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/KotlinTestingDsl.kt
+++ b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/KotlinTestingDsl.kt
@@ -94,6 +94,12 @@ private val javaImplicitAssertions: Assertions = {
         it::isParenthesized shouldBe (it.parenthesisDepth > 0)
     }
 
+    if (it is InternalInterfaces.AtLeastOneChild) {
+        assert(it.numChildren > 0) {
+            "Expected at least one child for $it"
+        }
+    }
+
 }
 
 
@@ -112,12 +118,8 @@ inline fun  JavaNode?.shouldMatchNode(ignoreChildren: Boolean
  * Can be used inside of a [ParserTestSpec] with [ParserTestSpec.parserTest].
  *
  * Parsing contexts allow to parse a string containing only the node you're interested
- * in instead of writing up a full class that the parser can handle. See [parseAstExpression],
- * [parseAstStatement].
- *
- * The methods [parseExpression] and [parseStatement] add some sugar to those by skipping
- * some nodes we're not interested in to find the node of interest using their reified type
- * parameter.
+ * in instead of writing up a full class that the parser can handle. See [parseExpression],
+ * [parseStatement].
  *
  * These are implicitly used by [matchExpr] and [matchStmt], which specify a matcher directly
  * on the strings, using their type parameter and the info in this test context to parse, find
@@ -203,7 +205,7 @@ open class ParserTestCtx(val javaVersion: JavaVersion = JavaVersion.Latest,
             makeMatcher(TopLevelTypeDeclarationParsingCtx, ignoreChildren, nodeSpec)
 
     /**
-     * Returns a String matcher that parses the node using [parseBodyDeclaration] with
+     * Returns a String matcher that parses the node using [parseDeclaration] with
      * type param [N], then matches it against the [nodeSpec] using [matchNode].
      *
      * Note that the enclosing type declaration can be customized by changing [genClassHeader].
@@ -248,37 +250,24 @@ open class ParserTestCtx(val javaVersion: JavaVersion = JavaVersion.Latest,
 
     }
 
-
-    fun parseAstExpression(expr: String): ASTExpression = ExpressionParsingCtx.parseNode(expr, this)
-
-    fun parseAstStatement(statement: String): ASTBlockStatement = StatementParsingCtx.parseNode(statement, this)
-
-    fun parseAstType(type: String): ASTType = TypeParsingCtx.parseNode(type, this)
-
-    fun parseToplevelAnyTypeDeclaration(type: String): ASTAnyTypeDeclaration = TopLevelTypeDeclarationParsingCtx.parseNode(type, this)
-
-    fun parseBodyDeclaration(type: String): JavaNode = EnclosedDeclarationParsingCtx.parseNode(type, this)
-
-    // reified shorthands, fetching the node
-
-    inline fun  parseExpression(expr: String): N =
+    inline fun  parseExpression(expr: String): N =
             ExpressionParsingCtx.parseAndFind(expr, this)
 
     // don't forget the semicolon
-    inline fun  parseStatement(stmt: String): N =
+    inline fun  parseStatement(stmt: String): N =
             StatementParsingCtx.parseAndFind(stmt, this)
 
-    inline fun  parseType(type: String): N =
+    inline fun  parseType(type: String): N =
             TypeParsingCtx.parseAndFind(type, this)
 
-    inline fun  parseTypeParameters(typeParams: String): N =
+    inline fun parseTypeParameters(typeParams: String): ASTTypeParameters =
             TypeParametersParsingCtx.parseAndFind(typeParams, this)
 
     inline fun  parseToplevelDeclaration(decl: String): N =
             TopLevelTypeDeclarationParsingCtx.parseAndFind(decl, this)
 
     inline fun  parseDeclaration(decl: String): N =
-            EnclosedDeclarationParsingCtx.parseAndFind(decl, this)
+            EnclosedDeclarationParsingCtx.parseNode(decl, this) as N
 
     companion object {
 
@@ -346,6 +335,7 @@ open class ParserTestCtx(val javaVersion: JavaVersion = JavaVersion.Latest,
                     parseNode(construct, ctx).findFirstNodeOnStraightLine(N::class.java)
                     ?: throw NoSuchElementException("No node of type ${N::class.java.simpleName} in the given $constructName:\n\t$construct")
 
+
             override fun toString(): String = "$constructName context"
         }
 
@@ -366,7 +356,7 @@ ${ctx.genClassHeader} {
             override fun retrieveNode(acu: ASTCompilationUnit): ASTExpression = acu.getFirstDescendantOfType(ASTExpression::class.java)!!
         }
 
-        object StatementParsingCtx : NodeParsingCtx("statement") {
+        object StatementParsingCtx : NodeParsingCtx("statement") {
 
             override fun getTemplate(construct: String, ctx: ParserTestCtx): String =
                 """
@@ -379,7 +369,7 @@ ${ctx.genClassHeader} {
                 """.trimIndent()
 
 
-            override fun retrieveNode(acu: ASTCompilationUnit): ASTBlockStatement = acu.getFirstDescendantOfType(ASTBlockStatement::class.java)
+            override fun retrieveNode(acu: ASTCompilationUnit): ASTStatement = acu.getFirstDescendantOfType(ASTBlock::class.java).jjtGetChild(0)
         }
 
         object EnclosedDeclarationParsingCtx : NodeParsingCtx("enclosed declaration") {
@@ -392,7 +382,7 @@ ${ctx.genClassHeader} {
                 """.trimIndent()
 
             override fun retrieveNode(acu: ASTCompilationUnit): JavaNode =
-                    acu.getFirstDescendantOfType(ASTAnyTypeBodyDeclaration::class.java)!!.declarationNode!!
+                    acu.getFirstDescendantOfType(ASTAnyTypeBodyDeclaration::class.java).declarationNode
         }
 
         object TopLevelTypeDeclarationParsingCtx : NodeParsingCtx("top-level declaration") {
diff --git a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ParenthesesTest.kt b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ParenthesesTest.kt
index 0b8017e6e6..2cfa9ecc8d 100644
--- a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ParenthesesTest.kt
+++ b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ParenthesesTest.kt
@@ -152,8 +152,7 @@ class ParenthesesTest : ParserTestSpec({
         inContext(ExpressionParsingCtx) {
 
             "((String) obj).length()" should parseAs {
-                methodCall {
-                    it::getMethodName shouldBe "length"
+                methodCall("length") {
 
                     it::getQualifier shouldBe parenthesized {
                         castExpr {
@@ -185,8 +184,7 @@ class ParenthesesTest : ParserTestSpec({
             }
 
             "(switch (obj) { case a -> 1; default -> 2; }).length()" should parseAs {
-                methodCall {
-                    it::getMethodName shouldBe "length"
+                methodCall("length") {
 
                     it::getQualifier shouldBe parenthesized {
                         switchExpr()
diff --git a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/TestExtensions.kt b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/TestExtensions.kt
index 5c515495b3..6b82b9af60 100644
--- a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/TestExtensions.kt
+++ b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/TestExtensions.kt
@@ -117,8 +117,9 @@ fun  TreeNodeWrapper.parenthesized(depth:
         }
 
 // this isn't a node anymore
-fun TreeNodeWrapper.methodCall(inside: NodeSpec) =
-        child {
+fun TreeNodeWrapper.methodCall(name: String, inside: NodeSpec = EmptyAssertions) =
+        child(ignoreChildren = inside === EmptyAssertions) {
+            it::getMethodName shouldBe name
             inside()
         }
 
@@ -189,6 +190,84 @@ fun TreeNodeWrapper.block(contents: NodeSpec = EmptyAssertion
             contents()
         }
 
+fun TreeNodeWrapper.emptyStatement(contents: NodeSpec = EmptyAssertions) =
+        child(ignoreChildren = contents == EmptyAssertions) {
+            contents()
+        }
+
+fun TreeNodeWrapper.forLoop(body: ValuedNodeSpec = { null }) =
+        child {
+            val body = body()
+            if (body != null) it::getBody shouldBe body
+            else unspecifiedChildren(it.numChildren)
+        }
+
+fun TreeNodeWrapper.forUpdate(body: ValuedNodeSpec) =
+        fromChild {
+            it::getExprList shouldBe body()
+            it.exprList
+        }
+
+fun TreeNodeWrapper.forInit(body: ValuedNodeSpec) =
+        fromChild {
+            it::getStatement shouldBe body()
+            it.statement
+        }
+
+fun TreeNodeWrapper.statementExprList(body: NodeSpec = EmptyAssertions) =
+        child(ignoreChildren = body === EmptyAssertions) {
+            body()
+        }
+
+fun TreeNodeWrapper.foreachLoop(body: ValuedNodeSpec = { null }) =
+        child {
+            val body = body()
+            if (body != null) it::getBody shouldBe body
+            else unspecifiedChildren(it.numChildren)
+        }
+
+fun TreeNodeWrapper.doLoop(body: ValuedNodeSpec = { null }) =
+        child {
+            val body = body()
+            if (body != null) it::getBody shouldBe body
+            else unspecifiedChildren(it.numChildren)
+        }
+
+fun TreeNodeWrapper.whileLoop(body: ValuedNodeSpec = { null }) =
+        child {
+            val body = body()
+            if (body != null) it::getBody shouldBe body
+            else unspecifiedChildren(it.numChildren)
+        }
+
+fun TreeNodeWrapper.constructorCall(contents: NodeSpec = EmptyAssertions) =
+        child(ignoreChildren = contents == EmptyAssertions) {
+            contents()
+        }
+
+fun TreeNodeWrapper.breakStatement(label: String? = null, contents: NodeSpec = EmptyAssertions) =
+        child(ignoreChildren = contents == EmptyAssertions) {
+            it::getLabel shouldBe label
+            contents()
+        }
+
+fun TreeNodeWrapper.localVarDecl(contents: NodeSpec = EmptyAssertions) =
+        child(ignoreChildren = contents == EmptyAssertions) {
+            contents()
+        }
+
+fun TreeNodeWrapper.localClassDecl(simpleName: String, contents: NodeSpec = EmptyAssertions) =
+        child {
+            it::getDeclaration shouldBe classDecl(simpleName, contents)
+        }
+
+fun TreeNodeWrapper.exprStatement(contents: ValuedNodeSpec = { null }) =
+        child {
+            val expr = contents()
+            if (expr != null) it::getExpr shouldBe expr
+            else unspecifiedChild()
+        }
+
 fun TreeNodeWrapper.fieldDecl(contents: NodeSpec) =
         child {
             contents()
@@ -408,7 +487,7 @@ fun TreeNodeWrapper.classDecl(simpleName: String, assertions: NodeSpec<
             assertions()
         }
 
-fun TreeNodeWrapper.classBody(assertions: NodeSpec = EmptyAssertions) =
-        child(ignoreChildren = assertions == EmptyAssertions) {
-            assertions()
+fun TreeNodeWrapper.typeBody(contents: NodeSpec = EmptyAssertions) =
+        child {
+            contents()
         }
diff --git a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/TokenUtilsTest.kt b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/TokenUtilsTest.kt
index 8fc17f9104..b96b1b8fe8 100644
--- a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/TokenUtilsTest.kt
+++ b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/TokenUtilsTest.kt
@@ -21,7 +21,7 @@ class TokenUtilsTest : FunSpec({
         with(ParserTestCtx(JavaVersion.J11)) {
 
 
-            val decl = parseToplevelAnyTypeDeclaration("""
+            val decl = parseToplevelDeclaration("""
                 class Foo { /* wassup */ abstract void bar(); }
             """.trimIndent())