From 1eab9448e720a8bf88a70583b272cd3e84fc1af3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Sun, 15 Dec 2019 03:53:10 +0100 Subject: [PATCH] Use ArrayDimensions for VariableDeclaratorId * Remove `Dimensionable`, remove its methods from the former implementations (except from ASTArrayDimsAndInits, which is itself deprecated) * The varargs ellipsis is now represented as an ArrayTypeDim. * This affects FormalParameter and LambdaParameter Closes #997. All forms of type annotations are now supported. --- .../sourceforge/pmd/lang/ast/NodeStream.java | 23 +++- pmd-java/etc/grammar/Java.jjt | 58 +++++--- .../pmd/lang/java/ast/ASTArrayDimensions.java | 20 ++- .../lang/java/ast/ASTArrayDimsAndInits.java | 4 +- .../pmd/lang/java/ast/ASTArrayTypeDim.java | 17 ++- .../pmd/lang/java/ast/ASTEnumConstant.java | 9 +- .../lang/java/ast/ASTFieldDeclaration.java | 48 +++---- .../pmd/lang/java/ast/ASTFormalParameter.java | 63 +++------ .../lang/java/ast/ASTLambdaExpression.java | 16 +++ .../pmd/lang/java/ast/ASTLambdaParameter.java | 12 +- .../java/ast/ASTLocalVariableDeclaration.java | 64 ++------- .../lang/java/ast/ASTMethodDeclaration.java | 12 +- .../lang/java/ast/ASTVariableDeclarator.java | 46 ++----- .../java/ast/ASTVariableDeclaratorId.java | 46 +++---- .../pmd/lang/java/ast/Dimensionable.java | 17 --- .../pmd/lang/java/rule/JavaRuleViolation.java | 4 +- .../ArrayIsStoredDirectlyRule.java | 16 +-- .../documentation/CommentRequiredRule.java | 22 +-- .../rule/errorprone/CloseResourceRule.java | 2 +- .../RedundantFieldInitializerRule.java | 6 +- .../rule/performance/StringToStringRule.java | 2 +- .../UseStringBufferForStringAppendsRule.java | 4 +- .../typeresolution/ClassTypeResolver.java | 8 +- .../java/ast/ASTFieldDeclarationTest.java | 90 ------------- .../ast/ASTLocalVariableDeclarationTest.java | 42 ------ .../typeresolution/ClassTypeResolverTest.java | 8 -- .../pmd/lang/java/ast/ASTEnumConstantTest.kt | 14 +- .../lang/java/ast/ASTFieldDeclarationTest.kt | 87 ++++++++++++ .../lang/java/ast/ASTLambdaExpressionTest.kt | 127 +++++++++++++++++- .../ast/ASTLocalVariableDeclarationTest.kt | 43 ++++++ .../lang/java/ast/ASTMethodDeclarationTest.kt | 81 ++++++++++- .../pmd/lang/java/ast/TestExtensions.kt | 45 ++++++- .../pmd/ast/FullTypeAnnotations.java | 33 +++-- 33 files changed, 641 insertions(+), 448 deletions(-) delete mode 100644 pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/Dimensionable.java delete mode 100644 pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/ASTFieldDeclarationTest.java delete mode 100644 pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/ASTLocalVariableDeclarationTest.java create mode 100644 pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTFieldDeclarationTest.kt create mode 100644 pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTLocalVariableDeclarationTest.kt diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/NodeStream.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/NodeStream.java index 50b972fdac..4c9b329613 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/NodeStream.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/NodeStream.java @@ -7,6 +7,7 @@ package net.sourceforge.pmd.lang.ast; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.NoSuchElementException; import java.util.Objects; import java.util.Optional; import java.util.function.Consumer; @@ -689,7 +690,7 @@ public interface NodeStream extends Iterable<@NonNull T> { * Returns the first element of this stream, or {@code null} if the * stream is empty. * - *

If you'd rather continue processingthe first element as a node + *

If you'd rather continue processing the first element as a node * stream, you can use {@link #take(int) take(1)}. * *

This is equivalent to {@link #get(int) get(0)}. @@ -703,6 +704,26 @@ public interface NodeStream extends Iterable<@NonNull T> { @Nullable T first(); + /** + * Returns the first element of this stream, or throws a {@link NoSuchElementException} + * if the stream is empty. + * + * @return the first element of this stream + * + * @see #first(Predicate) + * @see #first(Class) + * @see #firstOpt() + */ + @NonNull + default T firstOrThrow() { + T first = first(); + if (first == null) { + throw new NoSuchElementException("Empty node stream"); + } + return first; + } + + /** * Returns an optional containing the first element of this stream, * or an empty optional if the stream is empty. diff --git a/pmd-java/etc/grammar/Java.jjt b/pmd-java/etc/grammar/Java.jjt index c938b8aed5..fbac1bbc4c 100644 --- a/pmd-java/etc/grammar/Java.jjt +++ b/pmd-java/etc/grammar/Java.jjt @@ -1721,7 +1721,7 @@ void ClassOrInterfaceBodyDeclaration(): ( LOOKAHEAD(3) ClassOrInterfaceDeclaration(modifiers) | LOOKAHEAD({isKeyword("enum")}) EnumDeclaration(modifiers) | LOOKAHEAD( [ TypeParameters() ] "(" ) ConstructorDeclaration(modifiers) - | LOOKAHEAD( Type() ( "[" "]" )* ( "," | "=" | ";" ) ) FieldDeclaration(modifiers) + | LOOKAHEAD( Type() (AnnotationList() "[" "]")* ( "," | "=" | ";" ) ) FieldDeclaration(modifiers) | LOOKAHEAD(2) MethodDeclaration(modifiers) | LOOKAHEAD(2) AnnotationTypeDeclaration(modifiers) ) @@ -1739,14 +1739,20 @@ void FieldDeclaration(int modifiers) : void VariableDeclarator() : {} { - VariableDeclaratorId() [ "=" VariableInitializer() ] + VariableIdWithDims() [ "=" VariableInitializer() ] } -// TODO use ArrayDimensions void VariableDeclaratorId() : {} { - { setLastTokenImage(jjtThis); } ( "[" "]" { jjtThis.bumpArrayDepth(); })* + { setLastTokenImage(jjtThis); } +} + +void VariableIdWithDims() #VariableDeclaratorId : +{} +{ + { setLastTokenImage(jjtThis); } + [ Dims() ] } void ReceiverParameter(): @@ -1777,7 +1783,7 @@ void MethodDeclaration(int modifiers) : ResultType() { setLastTokenImage(jjtThis); } FormalParameters() - ( "[" "]" )* // TODO use ArrayDimensions + [ Dims() ] [ ThrowsList() ] ( Block() | ";" ) } @@ -1790,18 +1796,35 @@ void FormalParameters() : } void FormalParameter() : +{boolean isFinal = false;} { + isFinal=LocalVarModifierList() {jjtThis.setFinal(isFinal);} + FormalParamType() + VariableIdWithDims() } + +void FormalParamType() #void: +{} { - ( "final" {jjtThis.setFinal(true);} | Annotation() )* - Type() ("|" Type())* - // TODO there may be annotations before the "..." of the varargs - // the ... is treated analogously to a pair of brackets - // the sensible way to parse it would probably be to push an ArrayType with ArrayTypeDim for the "..." - [ "..." {jjtThis.setVarargs();} ] - VariableDeclaratorId() + PrimitiveType() [ LOOKAHEAD(2) VarargsDimensions() #ArrayType(2) ] + | ClassOrInterfaceType() [ LOOKAHEAD(2) VarargsDimensions() #ArrayType(2) ] } +void VarargsDimensions() #ArrayDimensions: +{} +{ + // like ArrayDimensions but allows for a varargs ellipsis at the end ("...") + LOOKAHEAD(AnnotationList() "[") (LOOKAHEAD(AnnotationList() "[") ArrayTypeDim())+ [ VarargsDim() ] + | VarargsDim() +} + +void VarargsDim() #ArrayTypeDim: +{} +{ + TypeAnnotListNoInject() "..." {jjtThis.setVarargs();} +} + + void ConstructorDeclaration(int modifiers) : {jjtThis.setModifiers(modifiers); JavaccToken t;} @@ -2527,11 +2550,10 @@ void LambdaParameter(): } { [ - isFinal=LocalVarModifierList() {jjtThis.setFinal(isFinal);} - isVarType=LambdaParameterType() { jjtThis.setVarType(); } - [ "..." {jjtThis.setVarargs();} ] + isFinal=LocalVarModifierList() {jjtThis.setFinal(isFinal);} + isVarType=LambdaParameterType() ] - VariableDeclaratorId() + VariableIdWithDims() } /** Returns true if this is "var". */ @@ -2539,8 +2561,8 @@ boolean LambdaParameterType() #void : {} { LOOKAHEAD( { jdkVersion >= 11 && isKeyword("var") } ) - { return true; } - | Type() { return false; } + { return true; } + | FormalParamType() { return false; } } void Literal() #void : diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTArrayDimensions.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTArrayDimensions.java index f8766680e9..e96bce8bfa 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTArrayDimensions.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTArrayDimensions.java @@ -6,19 +6,25 @@ package net.sourceforge.pmd.lang.java.ast; import java.util.Iterator; -import net.sourceforge.pmd.lang.java.ast.InternalInterfaces.AtLeastOneChild; +import net.sourceforge.pmd.lang.java.ast.InternalInterfaces.AtLeastOneChildOfType; /** * Represents array type dimensions. This node may occur in several contexts: *

* *

Some dimensions may be initialized with an expression, but only in - * the array type of an {@link ASTArrayAllocation array allocation expression}. + * the array type of an {@linkplain ASTArrayAllocation array allocation expression}. * *

  *
@@ -26,7 +32,7 @@ import net.sourceforge.pmd.lang.java.ast.InternalInterfaces.AtLeastOneChild;
  *
  * 
*/ -public final class ASTArrayDimensions extends AbstractJavaTypeNode implements Iterable, AtLeastOneChild { +public final class ASTArrayDimensions extends AbstractJavaTypeNode implements Iterable, AtLeastOneChildOfType { ASTArrayDimensions(int id) { super(id); @@ -55,6 +61,10 @@ public final class ASTArrayDimensions extends AbstractJavaTypeNode implements It return children(ASTArrayTypeDim.class).iterator(); } + @Override + public ASTArrayTypeDim jjtGetChild(int index) { + return (ASTArrayTypeDim) super.jjtGetChild(index); + } /** * Returns the number of array dimensions of this type. diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTArrayDimsAndInits.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTArrayDimsAndInits.java index 74b9248462..021d84f338 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTArrayDimsAndInits.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTArrayDimsAndInits.java @@ -8,7 +8,7 @@ package net.sourceforge.pmd.lang.java.ast; * @deprecated Replaced by {@link ASTArrayDimensions} */ @Deprecated -public class ASTArrayDimsAndInits extends AbstractJavaNode implements Dimensionable { +public class ASTArrayDimsAndInits extends AbstractJavaNode { private int arrayDepth; @@ -37,13 +37,11 @@ public class ASTArrayDimsAndInits extends AbstractJavaNode implements Dimensiona arrayDepth++; } - @Override @Deprecated public int getArrayDepth() { return arrayDepth; } - @Override @Deprecated public boolean isArray() { return arrayDepth > 0; // should always be true... diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTArrayTypeDim.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTArrayTypeDim.java index 11d70dfcd5..b2221d8f06 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTArrayTypeDim.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTArrayTypeDim.java @@ -16,10 +16,11 @@ package net.sourceforge.pmd.lang.java.ast; * ArrayTypeDim ::= {@link ASTAnnotation TypeAnnotation}* "[" "]" * * - * */ public class ASTArrayTypeDim extends AbstractJavaNode implements Annotatable { + private boolean isVarargs; + ASTArrayTypeDim(int id) { super(id); } @@ -28,6 +29,20 @@ public class ASTArrayTypeDim extends AbstractJavaNode implements Annotatable { super(p, id); } + /** + * Returns true if this is a varargs dimension. Varargs parameters + * are represented as an array type whose last dimension has this + * attribute set to true. Querying {@link ASTFormalParameter#isVarargs()} + * is more convenient. + */ + public boolean isVarargs() { + return isVarargs; + } + + void setVarargs() { + isVarargs = true; + } + @Override public Object jjtAccept(JavaParserVisitor visitor, Object data) { return visitor.visit(this, data); diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTEnumConstant.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTEnumConstant.java index 0d0d563a56..3a9097b4c6 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTEnumConstant.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTEnumConstant.java @@ -15,7 +15,9 @@ import org.checkerframework.checker.nullness.qual.Nullable; * * */ -public final class ASTEnumConstant extends AbstractJavaNode implements Annotatable { +public final class ASTEnumConstant extends AbstractJavaNode + implements Annotatable, + InternalInterfaces.VariableIdOwner { ASTEnumConstant(int id) { @@ -38,13 +40,14 @@ public final class ASTEnumConstant extends AbstractJavaNode implements Annotatab } - public ASTVariableDeclaratorId getId() { + @Override + public ASTVariableDeclaratorId getVarId() { return getFirstChildOfType(ASTVariableDeclaratorId.class); } @Override public String getImage() { - return getId().getImage(); + return getVarId().getImage(); } /** diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTFieldDeclaration.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTFieldDeclaration.java index b0a7d009ec..deb759a794 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTFieldDeclaration.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTFieldDeclaration.java @@ -6,6 +6,7 @@ package net.sourceforge.pmd.lang.java.ast; import java.util.Iterator; +import net.sourceforge.pmd.lang.ast.NodeStream; import net.sourceforge.pmd.lang.ast.SignedNode; import net.sourceforge.pmd.lang.java.multifile.signature.JavaFieldSignature; import net.sourceforge.pmd.lang.java.typeresolution.typedefinition.JavaTypeDefinition; @@ -34,7 +35,10 @@ import net.sourceforge.pmd.lang.java.typeresolution.typedefinition.JavaTypeDefin * * */ -public final class ASTFieldDeclaration extends AbstractJavaAccessTypeNode implements Dimensionable, SignedNode, Iterable { +public final class ASTFieldDeclaration extends AbstractJavaAccessTypeNode + implements SignedNode, + Iterable, + LeftRecursiveNode { private JavaFieldSignature signature; @@ -138,35 +142,6 @@ public final class ASTFieldDeclaration extends AbstractJavaAccessTypeNode implem return false; } - @Override - @Deprecated - public boolean isArray() { - return checkType() + checkDecl() > 0; - } - - @Override - @Deprecated - public int getArrayDepth() { - if (!isArray()) { - return 0; - } - return checkType() + checkDecl(); - } - - private int checkType() { - if (jjtGetNumChildren() == 0 || !(jjtGetChild(0) instanceof ASTType)) { - return 0; - } - return ((ASTType) jjtGetChild(0)).getArrayDepth(); - } - - private int checkDecl() { - if (jjtGetNumChildren() < 2 || !(jjtGetChild(1) instanceof ASTVariableDeclarator)) { - return 0; - } - return ((ASTVariableDeclaratorId) jjtGetChild(1).jjtGetChild(0)).getArrayDepth(); - } - /** * Gets the variable name of this field. This method searches the first * VariableDeclartorId node and returns its image or null if @@ -200,14 +175,21 @@ public final class ASTFieldDeclaration extends AbstractJavaAccessTypeNode implem return getFirstChildOfType(ASTType.class); } + /** + * Returns a stream of IDs for the fields this node declares. + */ + public NodeStream getVariables() { + return children(ASTVariableDeclarator.class).children(ASTVariableDeclaratorId.class); + } /** - * Returns an iterator over the ids of the fields - * declared in this statement. + * Returns an iterator of IDs for the fields this node declares. + * + * @see #getVariables() */ @Override public Iterator iterator() { - return ASTVariableDeclarator.iterateIds(this); + return getVariables().iterator(); } 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 4b0bc86474..484933a421 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 @@ -4,25 +4,26 @@ package net.sourceforge.pmd.lang.java.ast; +import org.checkerframework.checker.nullness.qual.NonNull; + import net.sourceforge.pmd.annotation.InternalApi; import net.sourceforge.pmd.lang.java.typeresolution.typedefinition.JavaTypeDefinition; /** - * Formal parameter node. Used in the {@link ASTFormalParameters} - * production of {@link ASTMethodDeclarator} to represent a - * method's formal parameter. Also used in the {@link ASTCatchClause} - * production to represent the declared exception variable. - * Also used in LambdaExpressions for the LambdaParameters. + * Formal parameter node for a {@linkplain ASTFormalParameters formal parameter list}. + * This is distinct from {@linkplain ASTLambdaParameter lambda parameters}. + * + *

The varargs ellipsis {@code "..."} is parsed as an {@linkplain ASTArrayTypeDim array dimension} + * in the type node. * *

  *
- * FormalParameter ::= ( "final" | {@link ASTAnnotation Annotation} )* {@link ASTType Type} ( "|" {@link ASTType Type} )* [ "..." ] {@link ASTVariableDeclaratorId VariableDeclaratorId}
+ * FormalParameter ::= ( "final" | {@link ASTAnnotation Annotation} )* {@link ASTType Type} {@link ASTVariableDeclaratorId VariableDeclaratorId}
+ *
  * 
*/ -public class ASTFormalParameter extends AbstractJavaAccessTypeNode implements Dimensionable { - - private boolean isVarargs; +public final class ASTFormalParameter extends AbstractJavaAccessTypeNode implements Annotatable, InternalInterfaces.VariableIdOwner { @InternalApi @Deprecated @@ -34,17 +35,15 @@ public class ASTFormalParameter extends AbstractJavaAccessTypeNode implements Di super(p, id); } - - void setVarargs() { - isVarargs = true; - } - - /** - * Returns true if this node is a varargs parameter. + * Returns true if this node is a varargs parameter. Then, the type + * node is an {@link ASTArrayType ArrayType}, and its last dimension + * {@linkplain ASTArrayTypeDim#isVarargs() is varargs}. */ public boolean isVarargs() { - return isVarargs; + ASTType tn = getTypeNode(); + return tn instanceof ASTArrayType + && ((ASTArrayType) tn).getDimensions().getLastChild().isVarargs(); } @@ -73,33 +72,13 @@ public class ASTFormalParameter extends AbstractJavaAccessTypeNode implements Di /** * Returns the declarator ID of this formal parameter. */ - public ASTVariableDeclaratorId getVariableDeclaratorId() { + @Override + @NonNull + public ASTVariableDeclaratorId getVarId() { return getFirstChildOfType(ASTVariableDeclaratorId.class); } - /** - * Returns true if this formal parameter is of an array type. - * This includes varargs parameters. - */ - @Override - @Deprecated - public boolean isArray() { - return isVarargs() - || getTypeNode() != null && getTypeNode().isArrayType() - || getVariableDeclaratorId().isArray(); - } - - @Override - @Deprecated - public int getArrayDepth() { - if (!isArray()) { - return 0; - } - return getTypeNode().getArrayDepth() + getVariableDeclaratorId().getArrayDepth() + (isVarargs() ? 1 : 0); - } - - /** * Returns the type node of this formal parameter. * The type of that node is not necessarily the type @@ -130,13 +109,13 @@ public class ASTFormalParameter extends AbstractJavaAccessTypeNode implements Di */ @Override public Class getType() { - return getVariableDeclaratorId().getType(); + return getVarId().getType(); } @Override public JavaTypeDefinition getTypeDefinition() { - return getVariableDeclaratorId().getTypeDefinition(); + return getVarId().getTypeDefinition(); } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTLambdaExpression.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTLambdaExpression.java index 2af468eb0f..a796b20fdf 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTLambdaExpression.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTLambdaExpression.java @@ -6,6 +6,7 @@ package net.sourceforge.pmd.lang.java.ast; import org.checkerframework.checker.nullness.qual.Nullable; +import net.sourceforge.pmd.lang.ast.NodeStream; import net.sourceforge.pmd.lang.java.typeresolution.typedefinition.JavaTypeDefinition; @@ -47,6 +48,21 @@ public final class ASTLambdaExpression extends AbstractMethodLikeNode implements return !isBlockBody(); } + /** + * Returns the body of this lambda if it is a block. + */ + public ASTBlock getBlockBody() { + return NodeStream.of(getLastChild()).filterIs(ASTBlock.class).first(); + } + + /** + * Returns the body of this lambda if it is an expression. + */ + public ASTExpression getExpressionBody() { + return NodeStream.of(getLastChild()).filterIs(ASTExpression.class).first(); + } + + // TODO MethodLikeNode should be removed, and this class extend AbstractJavaExpr void bumpParenDepth() { diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTLambdaParameter.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTLambdaParameter.java index 9c051ab6dd..4b80874f92 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTLambdaParameter.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTLambdaParameter.java @@ -4,6 +4,7 @@ package net.sourceforge.pmd.lang.java.ast; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; import net.sourceforge.pmd.lang.java.typeresolution.typedefinition.JavaTypeDefinition; @@ -19,7 +20,8 @@ import net.sourceforge.pmd.lang.java.typeresolution.typedefinition.JavaTypeDefin * * */ -public final class ASTLambdaParameter extends AbstractJavaTypeNode { +public final class ASTLambdaParameter extends AbstractJavaTypeNode + implements InternalInterfaces.VariableIdOwner { private boolean isVarargs; private boolean isFinal; @@ -87,7 +89,9 @@ public final class ASTLambdaParameter extends AbstractJavaTypeNode { /** * Returns the declarator ID of this formal parameter. */ - public ASTVariableDeclaratorId getVariableDeclaratorId() { + @Override + @NonNull + public ASTVariableDeclaratorId getVarId() { return getFirstChildOfType(ASTVariableDeclaratorId.class); } @@ -114,13 +118,13 @@ public final class ASTLambdaParameter extends AbstractJavaTypeNode { */ @Override public Class getType() { - return getVariableDeclaratorId().getType(); + return getVarId().getType(); } @Override public JavaTypeDefinition getTypeDefinition() { - return getVariableDeclaratorId().getTypeDefinition(); + return getVarId().getTypeDefinition(); } 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 4d5b2d0a22..0d88238f28 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 @@ -6,6 +6,8 @@ package net.sourceforge.pmd.lang.java.ast; import java.util.Iterator; +import net.sourceforge.pmd.lang.ast.NodeStream; + /** * Represents a local variable declaration. This is a {@linkplain ASTStatement statement}, @@ -14,7 +16,7 @@ import java.util.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()}. + * the declared variables are accessible through {@link #getVarIds()}. * *

  *
@@ -23,7 +25,9 @@ import java.util.Iterator;
  * 
*/ // TODO extend AbstractStatement -public final class ASTLocalVariableDeclaration extends AbstractJavaAccessNode implements Dimensionable, Iterable, ASTStatement { +public final class ASTLocalVariableDeclaration extends AbstractJavaAccessNode + implements Iterable, + ASTStatement { ASTLocalVariableDeclaration(int id) { super(id); @@ -67,18 +71,6 @@ public final class ASTLocalVariableDeclaration extends AbstractJavaAccessNode im return getTypeNode() == null; } - @Override - @Deprecated - public boolean isArray() { - return getArrayDepth() > 0; - } - - @Override - @Deprecated - public int getArrayDepth() { - return getArrayDimensionOnType() + getArrayDimensionOnDeclaratorId(); - } - /** * Gets the type node for this variable declaration statement. * With Java10 and local variable type inference, there might be @@ -92,50 +84,20 @@ public final class ASTLocalVariableDeclaration extends AbstractJavaAccessNode im return getFirstChildOfType(ASTType.class); } - private int getArrayDimensionOnType() { - ASTType typeNode = getTypeNode(); - if (typeNode != null) { - return typeNode.getArrayDepth(); - } - return 0; - } - - private ASTVariableDeclaratorId getDecl() { - return (ASTVariableDeclaratorId) jjtGetChild(jjtGetNumChildren() - 1).jjtGetChild(0); - } - - private int getArrayDimensionOnDeclaratorId() { - return getDecl().getArrayDepth(); - } - /** - * Gets the variable name of this declaration. This method searches the first - * VariableDeclartorId node and returns it's image or null if - * the child node is not found. - * - * @return a String representing the name of the variable - * - * @deprecated LocalVariableDeclaration may declare several variables, so this is not exhaustive - * Iterate on the {@linkplain ASTVariableDeclaratorId VariableDeclaratorIds} instead + * Returns a stream of IDs for the fields this node declares. */ - // It would be nice to have a way to inform XPath users of the intended replacement - // for a deprecated attribute. We may use another annotation for that. - @Deprecated - public String getVariableName() { - ASTVariableDeclaratorId decl = getFirstDescendantOfType(ASTVariableDeclaratorId.class); - if (decl != null) { - return decl.getImage(); - } - return null; + public NodeStream getVarIds() { + return children(ASTVariableDeclarator.class).children(ASTVariableDeclaratorId.class); } - /** - * Returns an iterator over the ids of the variables - * declared in this statement. + * Returns an iterator of IDs for the fields this node declares. + * + * @see #getVarIds() */ @Override public Iterator iterator() { - return ASTVariableDeclarator.iterateIds(this); + return getVarIds().iterator(); } } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTMethodDeclaration.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTMethodDeclaration.java index 13be4862c0..60e31da4a7 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTMethodDeclaration.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTMethodDeclaration.java @@ -31,8 +31,8 @@ import net.sourceforge.pmd.lang.dfa.DFAGraphMethod; * {@link ASTResultType ResultType} * <IDENTIFIER> * {@link ASTFormalParameters FormalParameters} - * ( "[" "]" )* - * ({@link ASTThrowsList ThrowsList})? + * {@link ASTArrayDimensions ArrayDimensions}? + * {@link ASTThrowsList ThrowsList}? * ({@link ASTBlock Block} | ";" ) * * @@ -173,5 +173,13 @@ public final class ASTMethodDeclaration extends AbstractMethodOrConstructorDecla return MethodLikeKind.METHOD; } + /** + * Returns the extra array dimensions that may be after the + * formal parameters. + */ + @Nullable + public ASTArrayDimensions getExtraDimensions() { + return children(ASTArrayDimensions.class).first(); + } } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTVariableDeclarator.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTVariableDeclarator.java index dcd132e89d..51153bae68 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTVariableDeclarator.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTVariableDeclarator.java @@ -4,9 +4,8 @@ package net.sourceforge.pmd.lang.java.ast; -import java.util.Iterator; - -import net.sourceforge.pmd.lang.ast.Node; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; /** @@ -19,11 +18,11 @@ import net.sourceforge.pmd.lang.ast.Node; * *
  *
- * VariableDeclarator ::= {@linkplain ASTVariableDeclaratorId VariableDeclaratorId} ( "=" {@linkplain ASTExpression Expression} )?
+ * VariableDeclarator ::= {@linkplain ASTVariableDeclaratorId VariableDeclaratorId} {@link ASTArrayDimensions ArrayDimensions}? ( "=" {@linkplain ASTExpression Expression} )?
  *
  * 
*/ -public class ASTVariableDeclarator extends AbstractJavaTypeNode { +public class ASTVariableDeclarator extends AbstractJavaTypeNode implements InternalInterfaces.VariableIdOwner { ASTVariableDeclarator(int id) { super(id); @@ -51,15 +50,16 @@ public class ASTVariableDeclarator extends AbstractJavaTypeNode { * Returns the name of the declared variable. */ public String getName() { - // first child will be VariableDeclaratorId - return jjtGetChild(0).getImage(); + return getVarId().getVariableName(); } /** * Returns the id of the declared variable. */ - public ASTVariableDeclaratorId getVariableId() { + @Override + @NonNull + public ASTVariableDeclaratorId getVarId() { return (ASTVariableDeclaratorId) jjtGetChild(0); } @@ -69,41 +69,17 @@ public class ASTVariableDeclarator extends AbstractJavaTypeNode { * Otherwise, {@link #getInitializer()} returns null. */ public boolean hasInitializer() { - return jjtGetNumChildren() > 1; + return getLastChild() instanceof ASTExpression; } /** * Returns the initializer, of the variable, or null if it doesn't exist. */ + @Nullable public ASTExpression getInitializer() { - return hasInitializer() ? (ASTExpression) jjtGetChild(1) : null; + return hasInitializer() ? (ASTExpression) getLastChild() : null; } - /* only for LocalVarDeclaration and FieldDeclaration */ - static Iterator iterateIds(Node parent) { - // TODO this can be made clearer with iterator mapping (Java 8) - final Iterator declarators = parent.children(ASTVariableDeclarator.class).iterator(); - - return new Iterator() { - @Override - public boolean hasNext() { - return declarators.hasNext(); - } - - - @Override - public ASTVariableDeclaratorId next() { - return declarators.next().getVariableId(); - } - - - @Override - public void remove() { - throw new UnsupportedOperationException(); - } - }; - } - } 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 8afbafd863..a1fef000b4 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 @@ -33,9 +33,17 @@ import net.sourceforge.pmd.lang.symboltable.NameOccurrence; * *

Type resolution assigns the type of the variable to this node. See {@link #getType()}'s * documentation for the contract of this method. + * + * + *

+ *
+ * VariableDeclaratorId ::= <IDENTIFIER> {@link ASTArrayDimensions ArrayDimensions}?
+ *
+ * 
+ * */ // @formatter:on -public final class ASTVariableDeclaratorId extends AbstractJavaTypeNode implements Dimensionable { +public final class ASTVariableDeclaratorId extends AbstractJavaTypeNode { private int arrayDepth; private VariableNameDeclaration nameDeclaration; @@ -76,27 +84,15 @@ public final class ASTVariableDeclaratorId extends AbstractJavaTypeNode implemen return getScope().getDeclarations(VariableNameDeclaration.class).get(nameDeclaration); } - @Deprecated - public void bumpArrayDepth() { - arrayDepth++; - } - - @Override - @Deprecated - public int getArrayDepth() { - return arrayDepth; - } - - /** - * Returns true if the declared variable has an array type. - * - * @deprecated Use {@link #hasArrayType()} + * Returns the extra array dimensions associated with this variable. + * For example in the declaration {@code int a[]}, {@link #getTypeNode()} + * returns {@code int}, and this method returns the dimensions that follow + * the variable ID. Returns null if there are no such dimensions. */ - @Override - @Deprecated - public boolean isArray() { - return arrayDepth > 0; + @Nullable + public ASTArrayDimensions getExtraDimensions() { + return children(ASTArrayDimensions.class).first(); } @@ -104,7 +100,7 @@ public final class ASTVariableDeclaratorId extends AbstractJavaTypeNode implemen * Returns true if the declared variable has an array type. */ public boolean hasArrayType() { - return arrayDepth > 0 || !isTypeInferred() && getTypeNode().isArrayType(); + return getExtraDimensions() != null || getTypeNode() instanceof ASTArrayType; } @@ -113,7 +109,7 @@ public final class ASTVariableDeclaratorId extends AbstractJavaTypeNode implemen * a {@code catch} statement. */ public boolean isExceptionBlockParameter() { - return jjtGetParent().jjtGetParent() instanceof ASTCatchClause; + return jjtGetParent() instanceof ASTCatchParameter; } @@ -122,8 +118,7 @@ public final class ASTVariableDeclaratorId extends AbstractJavaTypeNode implemen * declaration or a lambda expression. */ public boolean isFormalParameter() { - return jjtGetParent() instanceof ASTFormalParameter && !isExceptionBlockParameter() && !isResourceDeclaration() - || isLambdaParameter(); + return jjtGetParent() instanceof ASTFormalParameter || isLambdaParameter(); } @@ -184,6 +179,9 @@ public final class ASTVariableDeclaratorId extends AbstractJavaTypeNode implemen if (jjtGetParent() instanceof ASTFormalParameter) { // This accounts for exception parameters too for now return ((ASTFormalParameter) jjtGetParent()).isFinal(); + } else if (jjtGetParent() instanceof ASTCatchParameter) { + return ((ASTCatchParameter) jjtGetParent()).isMulticatch() + || ((ASTCatchParameter) jjtGetParent()).isFinal(); } Node grandpa = getNthParent(2); diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/Dimensionable.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/Dimensionable.java deleted file mode 100644 index fb0bbac437..0000000000 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/Dimensionable.java +++ /dev/null @@ -1,17 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.java.ast; - -/** - * @deprecated Will be removed with 7.0.0. See https://github.com/pmd/pmd/issues/997 and https://github.com/pmd/pmd/issues/910 - */ -@Deprecated -public interface Dimensionable { - @Deprecated - boolean isArray(); - - @Deprecated - int getArrayDepth(); -} diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/JavaRuleViolation.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/JavaRuleViolation.java index 8b1d88ccc9..0d9ea64887 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/JavaRuleViolation.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/JavaRuleViolation.java @@ -111,11 +111,11 @@ public class JavaRuleViolation extends ParametricRuleViolation { } else if (node instanceof ASTLocalVariableDeclaration) { return getVariableNames((ASTLocalVariableDeclaration) node); } else if (node instanceof ASTVariableDeclarator) { - return ((ASTVariableDeclarator) node).getVariableId().getVariableName(); + return ((ASTVariableDeclarator) node).getVarId().getVariableName(); } else if (node instanceof ASTVariableDeclaratorId) { return ((ASTVariableDeclaratorId) node).getVariableName(); } else if (node instanceof ASTFormalParameter) { - return ((ASTFormalParameter) node).getVariableDeclaratorId().getVariableName(); + return ((ASTFormalParameter) node).getVarId().getVariableName(); } else { return ""; } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/ArrayIsStoredDirectlyRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/ArrayIsStoredDirectlyRule.java index 70be9c5b0d..e1f57d06f4 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/ArrayIsStoredDirectlyRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/ArrayIsStoredDirectlyRule.java @@ -4,7 +4,6 @@ package net.sourceforge.pmd.lang.java.rule.bestpractices; -import java.util.ArrayList; import java.util.List; import net.sourceforge.pmd.lang.ast.Node; @@ -148,17 +147,10 @@ public class ArrayIsStoredDirectlyRule extends AbstractSunSecureRule { } private ASTFormalParameter[] getArrays(ASTFormalParameters params) { - final List l = params.findChildrenOfType(ASTFormalParameter.class); - if (l != null && !l.isEmpty()) { - List l2 = new ArrayList<>(); - for (ASTFormalParameter fp : l) { - if (fp.isArray() || fp.isVarargs()) { - l2.add(fp); - } - } - return l2.toArray(new ASTFormalParameter[0]); - } - return new ASTFormalParameter[0]; + return params.children(ASTFormalParameter.class) + .filter(it -> it.getTypeNode().isArrayType() || it.isVarargs()) + .toList() + .toArray(new ASTFormalParameter[0]); } } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/documentation/CommentRequiredRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/documentation/CommentRequiredRule.java index 0aa317d2c8..87fd87fa09 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/documentation/CommentRequiredRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/documentation/CommentRequiredRule.java @@ -203,10 +203,11 @@ public class CommentRequiredRule extends AbstractCommentRule { private boolean isSerialVersionUID(ASTFieldDeclaration field) { - return "serialVersionUID".equals(field.getVariableName()) - && field.isStatic() - && field.isFinal() - && field.getType() == long.class; + return false; // FIXME, commented out because of incompatibility, needs typeres + // return "serialVersionUID".equals(field.getVariableName()) + // && field.isStatic() + // && field.isFinal() + // && field.getType() == long.class; } /** @@ -220,12 +221,13 @@ public class CommentRequiredRule extends AbstractCommentRule { * @see Oracle docs */ private boolean isSerialPersistentFields(final ASTFieldDeclaration field) { - return "serialPersistentFields".equals(field.getVariableName()) - && field.isPrivate() - && field.isStatic() - && field.isFinal() - && field.isArray() - && "ObjectStreamField".equals(field.jjtGetFirstToken().getImage()); // .getType() returns null + return false; // FIXME, commented out because of incompatibility, needs typeres + // return "serialPersistentFields".equals(field.getVariableName()) + // && field.isPrivate() + // && field.isStatic() + // && field.isFinal() + // && field.isArray() + // && "ObjectStreamField".equals(field.jjtGetFirstToken().getImage()); // .getType() returns null } @Override 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 1e7e895668..e12eb8db5b 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 @@ -179,7 +179,7 @@ public class CloseResourceRule extends AbstractJavaRule { } if (!isAllowedResourceType(type) && !isMethodParameter(var, node)) { - ids.put(var.getVariableId(), type); + ids.put(var.getVarId(), type); } } } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/performance/RedundantFieldInitializerRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/performance/RedundantFieldInitializerRule.java index 578d893b61..8084e4dc35 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/performance/RedundantFieldInitializerRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/performance/RedundantFieldInitializerRule.java @@ -14,7 +14,6 @@ import net.sourceforge.pmd.lang.java.ast.ASTNullLiteral; import net.sourceforge.pmd.lang.java.ast.ASTPrimaryExpression; import net.sourceforge.pmd.lang.java.ast.ASTReferenceType; import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclarator; -import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclaratorId; import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; /** @@ -131,13 +130,12 @@ public class RedundantFieldInitializerRule extends AbstractJavaRule { * otherwise. */ private boolean isRef(ASTFieldDeclaration fieldDeclaration, ASTVariableDeclarator variableDeclarator) { - Node type = fieldDeclaration.jjtGetChild(0).jjtGetChild(0); - if (type instanceof ASTReferenceType) { + if (fieldDeclaration.getTypeNode() instanceof ASTReferenceType) { // Reference type, array or otherwise return true; } else { // Primitive array? - return ((ASTVariableDeclaratorId) variableDeclarator.jjtGetChild(0)).isArray(); + return variableDeclarator.getVarId().getExtraDimensions() != null; } } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/performance/StringToStringRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/performance/StringToStringRule.java index ad9c83f410..33f3d97fe0 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/performance/StringToStringRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/performance/StringToStringRule.java @@ -22,7 +22,7 @@ public class StringToStringRule extends AbstractJavaRule { && !TypeHelper.isExactlyAny(node.getNameDeclaration(), String[].class)) { return data; } - boolean isArray = node.isArray(); + boolean isArray = node.hasArrayType(); for (NameOccurrence occ : node.getUsages()) { JavaNameOccurrence jocc = (JavaNameOccurrence) occ; NameOccurrence qualifier = jocc.getNameForWhichThisIsAQualifier(); diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/performance/UseStringBufferForStringAppendsRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/performance/UseStringBufferForStringAppendsRule.java index 0b04df4054..e1d313e8de 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/performance/UseStringBufferForStringAppendsRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/performance/UseStringBufferForStringAppendsRule.java @@ -21,10 +21,10 @@ import net.sourceforge.pmd.lang.java.typeresolution.TypeHelper; import net.sourceforge.pmd.lang.symboltable.NameOccurrence; public class UseStringBufferForStringAppendsRule extends AbstractJavaRule { - + @Override public Object visit(ASTVariableDeclaratorId node, Object data) { - if (!TypeHelper.isA(node, String.class) || node.isArray()) { + if (!TypeHelper.isA(node, String.class) || node.hasArrayType()) { return data; } Node parent = node.jjtGetParent().jjtGetParent(); 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 075b65c6f8..a2f0b4473f 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 @@ -621,9 +621,9 @@ public class ClassTypeResolver extends JavaParserVisitorAdapter { // Type common to all declarations in the same statement JavaTypeDefinition baseType = node.getTypeNode().getTypeDefinition(); - if (baseType != null) { + if (baseType != null && node.getExtraDimensions() != null) { // add the dimensions specific to the declarator id - setTypeDefinition(node, baseType.withDimensions(node.getArrayDepth())); + setTypeDefinition(node, baseType.withDimensions(node.getExtraDimensions().getSize())); } return super.visit(node, data); } @@ -1196,13 +1196,13 @@ public class ClassTypeResolver extends JavaParserVisitorAdapter { @Override public Object visit(ASTFormalParameter node, Object data) { super.visit(node, data); - JavaTypeDefinition varType = node.getVariableDeclaratorId().getTypeDefinition(); + JavaTypeDefinition varType = node.getVarId().getTypeDefinition(); if (varType != null) { if (node.isVarargs()) { // The type of the formal parameter is defined in terms of the type // of the declarator ID - setTypeDefinition(node.getVariableDeclaratorId(), varType.withDimensions(1)); + setTypeDefinition(node.getVarId(), varType.withDimensions(1)); } } return data; diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/ASTFieldDeclarationTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/ASTFieldDeclarationTest.java deleted file mode 100644 index b90252d2b5..0000000000 --- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/ASTFieldDeclarationTest.java +++ /dev/null @@ -1,90 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.java.ast; - -import static net.sourceforge.pmd.lang.java.ParserTstUtil.parseJava14; -import static net.sourceforge.pmd.lang.java.ParserTstUtil.parseJava15; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -import java.util.List; - -import org.junit.Test; - -import net.sourceforge.pmd.PMD; -import net.sourceforge.pmd.lang.java.ParserTstUtil; -import net.sourceforge.pmd.lang.java.ast.testdata.InterfaceWithNestedClass; - -public class ASTFieldDeclarationTest { - - @Test - public void testIsArray() { - ASTCompilationUnit cu = parseJava14(TEST1); - Dimensionable node = cu.findDescendantsOfType(ASTFieldDeclaration.class).get(0); - assertTrue(node.isArray()); - assertEquals(1, node.getArrayDepth()); - } - - @Test - public void testMultiDimensionalArray() { - ASTCompilationUnit cu = parseJava14(TEST2); - Dimensionable node = cu.findDescendantsOfType(ASTFieldDeclaration.class).get(0); - assertEquals(3, node.getArrayDepth()); - } - - @Test - public void testIsSyntacticallyPublic() { - ASTCompilationUnit cu = parseJava14(TEST3); - ASTFieldDeclaration node = cu.findDescendantsOfType(ASTFieldDeclaration.class).get(0); - assertFalse(node.isSyntacticallyPublic()); - assertFalse(node.isPackagePrivate()); - assertFalse(node.isPrivate()); - assertFalse(node.isProtected()); - assertTrue(node.isFinal()); - assertTrue(node.isStatic()); - assertTrue(node.isPublic()); - } - - @Test - public void testWithEnum() { - ASTCompilationUnit cu = parseJava15(TEST4); - ASTFieldDeclaration node = cu.findDescendantsOfType(ASTFieldDeclaration.class).get(0); - assertFalse(node.isInterfaceMember()); - } - - @Test - public void testWithAnnotation() { - ASTCompilationUnit cu = parseJava15(TEST5); - ASTFieldDeclaration node = cu.findDescendantsOfType(ASTFieldDeclaration.class).get(0); - assertFalse(node.isInterfaceMember()); - assertTrue(node.isAnnotationMember()); - } - - private static final String TEST1 = "class Foo {" + PMD.EOL + " String[] foo;" + PMD.EOL + "}"; - - private static final String TEST2 = "class Foo {" + PMD.EOL + " String[][][] foo;" + PMD.EOL + "}"; - - private static final String TEST3 = "interface Foo {" + PMD.EOL + " int BAR = 6;" + PMD.EOL + "}"; - - private static final String TEST4 = "public enum Foo {" + PMD.EOL + " FOO(1);" + PMD.EOL + " private int x;" - + PMD.EOL + "}"; - - private static final String TEST5 = "public @interface Foo {" + PMD.EOL + " int BAR = 6;" + PMD.EOL + "}"; - - - @Test - public void testPrivateFieldInNestedClassInsideInterface() { - ASTCompilationUnit cu = ParserTstUtil.parseJava10(InterfaceWithNestedClass.class); - List fields = cu.findDescendantsOfType(ASTFieldDeclaration.class, true); - assertEquals(2, fields.size()); - assertEquals("MAPPING", fields.get(0).getFirstDescendantOfType(ASTVariableDeclaratorId.class).getImage()); - assertTrue(fields.get(0).isPublic()); - assertFalse(fields.get(0).isPrivate()); - assertEquals("serialVersionUID", fields.get(1).getFirstDescendantOfType(ASTVariableDeclaratorId.class).getImage()); - assertFalse(fields.get(1).isPublic()); - assertTrue(fields.get(1).isPrivate()); - } -} diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/ASTLocalVariableDeclarationTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/ASTLocalVariableDeclarationTest.java deleted file mode 100644 index 088b64e64f..0000000000 --- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/ASTLocalVariableDeclarationTest.java +++ /dev/null @@ -1,42 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.java.ast; - -import static net.sourceforge.pmd.lang.java.ParserTstUtil.parseJava14; -import static org.junit.Assert.assertEquals; - -import org.junit.Test; - -import net.sourceforge.pmd.PMD; - -public class ASTLocalVariableDeclarationTest { - - @Test - public void testSingleDimArray() { - ASTCompilationUnit cu = parseJava14(TEST1); - ASTLocalVariableDeclaration node = cu.findDescendantsOfType(ASTLocalVariableDeclaration.class).get(0); - assertEquals(1, node.getArrayDepth()); - } - - @Test - public void testMultDimArray() { - ASTCompilationUnit cu = parseJava14(TEST2); - ASTLocalVariableDeclaration node = cu.findDescendantsOfType(ASTLocalVariableDeclaration.class).get(0); - assertEquals(2, node.getArrayDepth()); - } - - @Test - public void testMultDimArraySplitBraces() { - ASTCompilationUnit cu = parseJava14(TEST3); - ASTLocalVariableDeclaration node = cu.findDescendantsOfType(ASTLocalVariableDeclaration.class).get(0); - assertEquals(3, node.getArrayDepth()); - } - - private static final String TEST1 = "class Foo {" + PMD.EOL + " void bar() {int x[] = null;}" + PMD.EOL + "}"; - - private static final String TEST2 = "class Foo {" + PMD.EOL + " void bar() {int x[][] = null;}" + PMD.EOL + "}"; - - private static final String TEST3 = "class Foo {" + PMD.EOL + " void bar() {int[] x[][] = null;}" + PMD.EOL + "}"; -} diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/typeresolution/ClassTypeResolverTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/typeresolution/ClassTypeResolverTest.java index b96cc8260d..552988a067 100644 --- a/pmd-java/src/test/java/net/sourceforge/pmd/typeresolution/ClassTypeResolverTest.java +++ b/pmd-java/src/test/java/net/sourceforge/pmd/typeresolution/ClassTypeResolverTest.java @@ -872,15 +872,11 @@ public class ClassTypeResolverTest { ASTVariableDeclaratorId aID = declaration.getFirstChildOfType(ASTVariableDeclarator.class).getFirstChildOfType(ASTVariableDeclaratorId.class); assertNotNull(aID); assertEquals("a", aID.getImage()); - assertFalse(aID.isArray()); - assertEquals(0, aID.getArrayDepth()); assertEquals(int[].class, aID.getType()); ASTVariableDeclaratorId bID = declaration.findChildrenOfType(ASTVariableDeclarator.class).get(1).getFirstChildOfType(ASTVariableDeclaratorId.class); assertNotNull(bID); assertEquals("b", bID.getImage()); - assertTrue(bID.isArray()); - assertEquals(1, bID.getArrayDepth()); assertEquals(int[][].class, bID.getType()); } @@ -902,15 +898,11 @@ public class ClassTypeResolverTest { ASTVariableDeclaratorId cID = declaration.getFirstChildOfType(ASTVariableDeclarator.class).getFirstChildOfType(ASTVariableDeclaratorId.class); assertNotNull(cID); assertEquals("c", cID.getImage()); - assertFalse(cID.isArray()); - assertEquals(0, cID.getArrayDepth()); assertEquals(String[].class, cID.getType()); ASTVariableDeclaratorId dID = declaration.findChildrenOfType(ASTVariableDeclarator.class).get(1).getFirstChildOfType(ASTVariableDeclaratorId.class); assertNotNull(dID); assertEquals("d", dID.getImage()); - assertTrue(dID.isArray()); - assertEquals(1, dID.getArrayDepth()); assertEquals(String[][].class, dID.getType()); } 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 614534bc01..3d755f2ceb 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 @@ -16,7 +16,7 @@ class ASTEnumConstantTest : ParserTestSpec({ enumConstant("A") { it::isAnonymousClass shouldBe false - it::getId shouldBe variableId("A") { + it::getVarId shouldBe variableId("A") { it::isEnumConstant shouldBe true it::isField shouldBe false } @@ -28,7 +28,7 @@ class ASTEnumConstantTest : ParserTestSpec({ enumConstant("B") { it::isAnonymousClass shouldBe false - it::getId shouldBe variableId("B") { + it::getVarId shouldBe variableId("B") { it::isEnumConstant shouldBe true it::isField shouldBe false } @@ -49,7 +49,7 @@ class ASTEnumConstantTest : ParserTestSpec({ enumConstant("B") { it::isAnonymousClass shouldBe true - it::getId shouldBe variableId("B") { + it::getVarId shouldBe variableId("B") { it::isEnumConstant shouldBe true it::isField shouldBe false } @@ -74,7 +74,7 @@ class ASTEnumConstantTest : ParserTestSpec({ enumConstant("B") { it::getDeclaredAnnotations shouldBe listOf(annotation("C")) - it::getId shouldBe variableId("B") + it::getVarId shouldBe variableId("B") it::getArguments shouldBe null it::getAnonymousClass shouldBe null @@ -83,7 +83,7 @@ class ASTEnumConstantTest : ParserTestSpec({ enumConstant("C") { it::getDeclaredAnnotations shouldBe listOf(annotation("A"), annotation("a")) - it::getId shouldBe variableId("C") + it::getVarId shouldBe variableId("C") it::getArguments shouldBe null it::getAnonymousClass shouldBe null @@ -100,7 +100,7 @@ class ASTEnumConstantTest : ParserTestSpec({ typeBody { enumConstant("B") { - it::getId shouldBe variableId("B") { + it::getVarId shouldBe variableId("B") { it::isEnumConstant shouldBe true it::isField shouldBe false } @@ -119,7 +119,7 @@ class ASTEnumConstantTest : ParserTestSpec({ typeBody { enumConstant("B") { - it::getId shouldBe variableId("B") { + it::getVarId shouldBe variableId("B") { it::isEnumConstant shouldBe true it::isField shouldBe false } diff --git a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTFieldDeclarationTest.kt b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTFieldDeclarationTest.kt new file mode 100644 index 0000000000..67ec1f9bf9 --- /dev/null +++ b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTFieldDeclarationTest.kt @@ -0,0 +1,87 @@ +/* + * 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.ASTPrimitiveType.PrimitiveType.INT +import net.sourceforge.pmd.lang.java.ast.ParserTestCtx.Companion.EnclosedDeclarationParsingCtx + +class ASTFieldDeclarationTest : ParserTestSpec({ + + parserTest("Extra dimensions") { + + inContext(EnclosedDeclarationParsingCtx) { + + // int x[][] = null; + // int[] x[][] = null; + + "int x @A@B[];" should parseAs { + fieldDecl { + + it::isPublic shouldBe false + it::isSyntacticallyPublic shouldBe false + it::isPackagePrivate shouldBe true + + primitiveType(INT) + + varDeclarator { + variableId("x") { + + it::isField shouldBe true + + it::getExtraDimensions shouldBe child { + arrayDim { + annotation("A") + annotation("B") + } + } + } + } + } + } + } + } + + parserTest("In annotation") { + + genClassHeader = "@interface A" + + inContext(EnclosedDeclarationParsingCtx) { + + // int x[][] = null; + // int[] x[][] = null; + + "@A int x[] = { 2 };" should parseAs { + fieldDecl { + + + it::isPublic shouldBe true + it::isSyntacticallyPublic shouldBe false + + + annotation("A") + primitiveType(INT) + + varDeclarator { + variableId("x") { + + it::isField shouldBe true + + it::getExtraDimensions shouldBe child { + arrayDim { } + } + } + + it::getInitializer shouldBe arrayInitializer { + int(2) + } + } + } + } + } + } + +}) diff --git a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTLambdaExpressionTest.kt b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTLambdaExpressionTest.kt index f1a7d2dbfc..81ce9a5942 100644 --- a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTLambdaExpressionTest.kt +++ b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTLambdaExpressionTest.kt @@ -6,13 +6,15 @@ package net.sourceforge.pmd.lang.java.ast import net.sourceforge.pmd.lang.ast.test.shouldBe import net.sourceforge.pmd.lang.java.ast.ASTPrimitiveType.PrimitiveType.INT +import net.sourceforge.pmd.lang.java.ast.JavaVersion.Companion.Latest +import net.sourceforge.pmd.lang.java.ast.JavaVersion.J1_8 import net.sourceforge.pmd.lang.java.ast.ParserTestCtx.Companion.ExpressionParsingCtx import net.sourceforge.pmd.lang.java.ast.ParserTestCtx.Companion.StatementParsingCtx class ASTLambdaExpressionTest : ParserTestSpec({ - parserTest("Simple lambda expressions") { + parserTest("Simple lambda expressions", javaVersions = J1_8..Latest) { "a -> foo()" should matchExpr { it::isExpressionBody shouldBe true @@ -78,7 +80,7 @@ class ASTLambdaExpressionTest : ParserTestSpec({ it::isBlockBody shouldBe false it::getParameters shouldBe child { - child { + lambdaParam { it::isFinal shouldBe true it::getTypeNode shouldBe primitiveType(INT) @@ -89,7 +91,7 @@ class ASTLambdaExpressionTest : ParserTestSpec({ it::isTypeInferred shouldBe false } } - child { + lambdaParam { annotation() it::getTypeNode shouldBe classType("List") variableId("b") { @@ -101,11 +103,128 @@ class ASTLambdaExpressionTest : ParserTestSpec({ } - child(ignoreChildren = true) {} + methodCall("foo") } } + parserTest("Mixed array notation/varargs", javaVersions = J1_8..Latest) { + + inContext(ExpressionParsingCtx) { + "(final int a[]@B[], @F List@a [] b @A []) -> foo()" should parseAs { + + exprLambda { + + it::getParameters shouldBe child { + lambdaParam { + it::isFinal shouldBe true + + it::getTypeNode shouldBe primitiveType(INT) + + variableId("a") { + it::isFinal shouldBe true + it::isLambdaParameter shouldBe true + it::isTypeInferred shouldBe false + + it::getExtraDimensions shouldBe child { + arrayDim {} + arrayDim { + annotation("B") + } + } + } + } + + lambdaParam { + annotation() + it::getTypeNode shouldBe arrayType { + classType("List") + it::getDimensions shouldBe child { + arrayDim { + annotation("a") + } + } + } + variableId("b") { + it::isFinal shouldBe false + it::isLambdaParameter shouldBe true + it::isTypeInferred shouldBe false + + + it::getExtraDimensions shouldBe child { + arrayDim { + annotation("A") + } + } + } + } + } + + + methodCall("foo") + } + } + } + } + + parserTest("Varargs parameter", javaVersions = J1_8..Latest) { + + inContext(ExpressionParsingCtx) { + "(String ... b) -> {}" should parseAs { + + blockLambda { + + it::getParameters shouldBe child { + lambdaParam { + it::getTypeNode shouldBe arrayType { + classType("String") + it::getDimensions shouldBe child { + varargsArrayDim { } + } + } + + variableId("b") { + it::getExtraDimensions shouldBe null + } + } + } + + + block { } + } + } + + "(String @A [] @B ... b) -> {}" should parseAs { + + blockLambda { + + it::getParameters shouldBe child { + lambdaParam { + it::getTypeNode shouldBe arrayType { + classType("String") + it::getDimensions shouldBe child { + arrayDim { + annotation("A") + } + varargsArrayDim { + annotation("B") + } + } + } + + variableId("b") { + it::getExtraDimensions shouldBe null + } + } + } + + + block { } + } + } + } + } + parserTest("Negative lambda contexts") { inContext(StatementParsingCtx) { "a -> {}" shouldNot parse() diff --git a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTLocalVariableDeclarationTest.kt b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTLocalVariableDeclarationTest.kt new file mode 100644 index 0000000000..a12135a804 --- /dev/null +++ b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTLocalVariableDeclarationTest.kt @@ -0,0 +1,43 @@ +/* + * 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.ASTPrimitiveType.PrimitiveType.INT +import net.sourceforge.pmd.lang.java.ast.ParserTestCtx.Companion.StatementParsingCtx + +class ASTLocalVariableDeclarationTest : ParserTestSpec({ + + parserTest("Extra dimensions") { + + inContext(StatementParsingCtx) { + + // int x[][] = null; + // int[] x[][] = null; + + "int x@A[];" should parseAs { + localVarDecl { + + primitiveType(INT) + + varDeclarator { + variableId("x") { + + it::isField shouldBe false + + it::getExtraDimensions shouldBe child { + arrayDim { + annotation("A") + } + } + } + } + } + } + } + } + +}) diff --git a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTMethodDeclarationTest.kt b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTMethodDeclarationTest.kt index 65daa116de..99bf9b7cd6 100644 --- a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTMethodDeclarationTest.kt +++ b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTMethodDeclarationTest.kt @@ -81,7 +81,7 @@ class ASTMethodDeclarationTest : ParserTestSpec({ "void bar() throws IOException, java.io.Bar { }" should matchDeclaration { it::isAbstract shouldBe false - it::getMethodName shouldBe "bar" + it::getName shouldBe "bar" it::getTypeParameters shouldBe null it::isVoid shouldBe true it::getArity shouldBe 0 @@ -129,6 +129,80 @@ class ASTMethodDeclarationTest : ParserTestSpec({ } } + parserTest("Varargs can be annotated") { + + "void bar(@Oha IOException @Aha ... java) { }" should matchDeclaration { + + it::getResultType shouldBe voidResult() + + it::getFormalParameters shouldBe formalsList(1) { + child { + annotation("Oha") + arrayType { + classType("IOException") + it::getDimensions shouldBe child { + varargsArrayDim { + annotation("Aha") + } + } + } + + variableId("java") + } + } + + it::getBody shouldBe block() + } + + + "void bar(@Oha IOException []@O[] @Aha ... java) { }" should matchDeclaration { + + it::getResultType shouldBe voidResult() + + it::getFormalParameters shouldBe formalsList(1) { + child { + annotation("Oha") + arrayType { + classType("IOException") + it::getDimensions shouldBe child { + arrayDim { } + arrayDim { + annotation("O") + } + varargsArrayDim { + annotation("Aha") + } + } + } + + variableId("java") + } + } + + it::getBody shouldBe block() + } + } + + + parserTest("Extra dimensions can be annotated") { + + "void bar() [] @O[] { }" should matchDeclaration { + + it::getResultType shouldBe voidResult() + + it::getFormalParameters shouldBe formalsList(0) + + it::getExtraDimensions shouldBe child { + arrayDim {} + arrayDim { + annotation("O") + } + } + + it::getBody shouldBe block() + } + } + parserTest("Annotation methods") { genClassHeader = "@interface Foo" @@ -195,7 +269,7 @@ class ASTMethodDeclarationTest : ParserTestSpec({ "void bar(@A Foo this);" should matchDeclaration { it::isAbstract shouldBe false - it::getMethodName shouldBe "bar" + it::getName shouldBe "bar" it::getTypeParameters shouldBe null it::isVoid shouldBe true // notice that arity is zero @@ -221,7 +295,7 @@ class ASTMethodDeclarationTest : ParserTestSpec({ "void bar(@A Foo this, int other);" should matchDeclaration { it::isAbstract shouldBe false - it::getMethodName shouldBe "bar" + it::getName shouldBe "bar" it::getTypeParameters shouldBe null it::isVoid shouldBe true it::getArity shouldBe 1 @@ -276,5 +350,4 @@ class ASTMethodDeclarationTest : ParserTestSpec({ block() } } - }) 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 5380f95778..0cd92c12fc 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 @@ -68,15 +68,20 @@ fun TreeNodeWrapper.thisExpr(qualifier: ValuedNodeSpec.variableId(name: String, otherAssertions: (ASTVariableDeclaratorId) -> Unit = {}) = - child(ignoreChildren = true) { +fun TreeNodeWrapper.variableId(name: String, otherAssertions: NodeSpec = EmptyAssertions) = + child(ignoreChildren = otherAssertions == EmptyAssertions) { it::getVariableName shouldBe name - otherAssertions(it) + otherAssertions() } fun TreeNodeWrapper.variableDeclarator(name: String, spec: NodeSpec = EmptyAssertions) = child { - it::getVariableId shouldBe variableId(name) + it::getVarId shouldBe variableId(name) + spec() + } + +fun TreeNodeWrapper.varDeclarator(spec: NodeSpec = EmptyAssertions) = + child { spec() } @@ -361,6 +366,31 @@ fun TreeNodeWrapper.infixExpr(op: BinaryOp, assertions: NodeSpec.blockLambda(assertions: ValuedNodeSpec = {null}) = + child { + it::isBlockBody shouldBe true + it::isExpressionBody shouldBe false + val block = assertions() + if (block == null) unspecifiedChildren(2) + else it::getBlockBody shouldBe block + } + + +fun TreeNodeWrapper.lambdaParam(assertions: NodeSpec = EmptyAssertions) = + child { + assertions() + } + +fun TreeNodeWrapper.exprLambda(assertions: ValuedNodeSpec = {null}) = + child { + it::isBlockBody shouldBe false + it::isExpressionBody shouldBe true + val block = assertions() + if (block == null) unspecifiedChildren(2) + else it::getExpressionBody shouldBe block + } + + fun TreeNodeWrapper.instanceOfExpr(assertions: NodeSpec) = infixExpr(BinaryOp.INSTANCEOF, assertions) @@ -433,6 +463,13 @@ fun TreeNodeWrapper.arrayType(elementType: ValuedNodeSpec.arrayDim(assertions: NodeSpec = EmptyAssertions) = child { + it::isVarargs shouldBe false + assertions() + } + +fun TreeNodeWrapper.varargsArrayDim(assertions: NodeSpec = EmptyAssertions) = + child { + it::isVarargs shouldBe true assertions() } diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/ast/FullTypeAnnotations.java b/pmd-java/src/test/resources/net/sourceforge/pmd/ast/FullTypeAnnotations.java index 2441e84b75..664f9f0673 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/ast/FullTypeAnnotations.java +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/ast/FullTypeAnnotations.java @@ -2,16 +2,8 @@ * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -import java.awt.Button; import java.io.File; -import java.io.FileFilter; -import java.security.PrivilegedAction; -import java.util.Comparator; -import java.util.concurrent.Callable; -import java.util.function.Function; -import java.util.function.IntFunction; import java.util.function.Supplier; -import java.util.stream.Stream; import org.checkerframework.checker.nullness.qual.NonNull; @@ -53,9 +45,9 @@ public class FullTypeAnnotations { class UnmodifiableList implements @Readonly List<@Readonly T> { } - // for throws clauses: TODO unsupported + // for throws clauses: - // void monitorTemperature() throws @Critical TemperatureException { } + void monitorTemperature() throws @Critical TemperatureException { } // for constructor invocationresults(that is, for object creation): @@ -109,15 +101,28 @@ public class FullTypeAnnotations { Document[] @Readonly [] docs3 = new Document[2]@Readonly[12]; // array of read-only arrays of documents // TODO mixed array notation, for now syntax error - // Document [] docs2 @Readonly[] = new Document@Readonly[2][12]; // read-only array of arrays of documents - // Document @Readonly [] docs3[] = new Document[2]@Readonly[12]; // array of read-only arrays of documents + Document[] docs4@Readonly[] = new Document@Readonly[2][12]; // read-only array of arrays of documents + Document @Readonly [] docs5[] = new Document[2]@Readonly[12]; // array of read-only arrays of documents + + { // all of the above for local vars + + @Readonly Document[][] docs1 = new @Readonly Document[2][12]; // array of arrays of read-only documents + Document @Readonly [][] docs2 = new Document@Readonly[2][12]; // read-only array of arrays of documents + Document[] @Readonly [] docs3 = new Document[2]@Readonly[12]; // array of read-only arrays of documents + + // TODO mixed array notation, for now syntax error + Document[] docs4@Readonly[] = new Document@Readonly[2][12]; // read-only array of arrays of documents + Document @Readonly [] docs5[] = new Document[2]@Readonly[12]; // array of read-only arrays of documents + + } + class MyClass { public String toString(@Readonly MyClass this) { } - // TODO unsupported - // public boolean equals(Object @Readonly ... other) { } + public boolean equals(Object @Readonly ... other) { } + MyClass(Object @Readonly ... other) { } }