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 1d7051a756..7f30383570 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() ("|" FormalParamType())* // remove this stuff when #2202 is merged + VariableIdWithDims() } + +void FormalParamType() #void: +{} { - ( "final" {jjtThis.setFinal(true);} | Annotation() )* - 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); @@ -2522,11 +2545,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". */ @@ -2534,8 +2556,8 @@ boolean LambdaParameterType() #void : {} { LOOKAHEAD( { jdkVersion >= 11 && isKeyword("var") } ) - { return true; } - | Type() { return false; } + { return true; } + | FormalParamType() { return false; } } void Literal() #void : @@ -3142,7 +3164,7 @@ void AnnotationMethodDeclaration(int modifiers) #MethodDeclaration: Type() #ResultType t= ("(" ")") #FormalParameters(true) - ( "[" "]" )* // TODO use ArrayTypeDims + [ Dims() ] [ DefaultValue() ] ";" { jjtThis.setImage(t.image); 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..9a39d84ec8 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 @@ -4,11 +4,8 @@ package net.sourceforge.pmd.lang.java.ast; -import java.util.Iterator; - 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 +31,11 @@ import net.sourceforge.pmd.lang.java.typeresolution.typedefinition.JavaTypeDefin * * */ -public final class ASTFieldDeclaration extends AbstractJavaAccessTypeNode implements Dimensionable, SignedNode, Iterable { +public final class ASTFieldDeclaration extends AbstractJavaAccessNode + implements SignedNode, + Iterable, + LeftRecursiveNode, + InternalInterfaces.MultiVariableIdOwner { private JavaFieldSignature signature; @@ -138,35 +139,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 @@ -196,39 +168,14 @@ public final class ASTFieldDeclaration extends AbstractJavaAccessTypeNode implem return signature; } + /** + * Returns the type node at the beginning of this field declaration. + * The type of this node is not necessarily the type of the variables, + * see {@link ASTVariableDeclaratorId#getType()}. + */ + @Override public ASTType getTypeNode() { return getFirstChildOfType(ASTType.class); } - - /** - * Returns an iterator over the ids of the fields - * declared in this statement. - */ - @Override - public Iterator iterator() { - return ASTVariableDeclarator.iterateIds(this); - } - - - /** - * @deprecated FieldDeclaration may declare several variables with a different type - * It won't implement TypeNode anymore come 7.0.0 - */ - @Override - @Deprecated - public Class getType() { - return super.getType(); - } - - - /** - * @deprecated FieldDeclaration may declare several variables with a different type - * It won't implement TypeNode anymore come 7.0.0 - */ - @Override - @Deprecated - public JavaTypeDefinition getTypeDefinition() { - return super.getTypeDefinition(); - } } 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 1bc61d4663..7e2a8d58a2 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,23 +4,28 @@ 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. + * 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 ASTVariableDeclaratorId VariableDeclaratorId}
+ * FormalParameter ::= ( "final" | {@link ASTAnnotation Annotation} )* {@link ASTType Type} {@link ASTVariableDeclaratorId VariableDeclaratorId}
+ *
  * 
*/ -public final class ASTFormalParameter extends AbstractJavaAccessTypeNode implements Dimensionable, Annotatable { - - private boolean isVarargs; +public final class ASTFormalParameter extends AbstractJavaAccessTypeNode + implements Annotatable, + InternalInterfaces.VariableIdOwner { @InternalApi @Deprecated @@ -32,17 +37,15 @@ public final class ASTFormalParameter extends AbstractJavaAccessTypeNode impleme 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(); } @@ -61,33 +64,13 @@ public final class ASTFormalParameter extends AbstractJavaAccessTypeNode impleme /** * 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 @@ -110,13 +93,13 @@ public final class ASTFormalParameter extends AbstractJavaAccessTypeNode impleme */ @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..eb25d05fef 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 @@ -4,9 +4,6 @@ package net.sourceforge.pmd.lang.java.ast; -import java.util.Iterator; - - /** * Represents a local variable declaration. This is a {@linkplain ASTStatement statement}, * but the node is also used in {@linkplain ASTForInit for-loop initialisers} and @@ -14,7 +11,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 +20,10 @@ 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, + InternalInterfaces.MultiVariableIdOwner { ASTLocalVariableDeclaration(int id) { super(id); @@ -67,18 +67,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 @@ -88,54 +76,10 @@ public final class ASTLocalVariableDeclaration extends AbstractJavaAccessNode im * * @see #isTypeInferred() */ + @Override public ASTType getTypeNode() { 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 - */ - // 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; - } - - - /** - * Returns an iterator over the ids of the variables - * declared in this statement. - */ - @Override - public Iterator iterator() { - return ASTVariableDeclarator.iterateIds(this); - } } 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 e7f919b501..1c1a55caf3 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,11 +33,18 @@ 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; @InternalApi @@ -76,27 +83,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 +99,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 +108,7 @@ public final class ASTVariableDeclaratorId extends AbstractJavaTypeNode implemen * a {@code catch} statement. */ public boolean isExceptionBlockParameter() { - return jjtGetParent().jjtGetParent() instanceof ASTCatchClause; + return jjtGetParent() instanceof ASTFormalParameter && jjtGetParent().jjtGetParent() instanceof ASTCatchClause; } @@ -122,8 +117,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(); } 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/ast/InternalInterfaces.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/InternalInterfaces.java index 0ce2b8a341..a4a234b99a 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/InternalInterfaces.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/InternalInterfaces.java @@ -5,9 +5,13 @@ package net.sourceforge.pmd.lang.java.ast; +import java.util.Iterator; + import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; +import net.sourceforge.pmd.lang.ast.NodeStream; + /** * Those are some interfaces that are not published, but are used to keep * uniform names on related concepts. Maybe it makes sense to publish some of @@ -126,4 +130,23 @@ final class InternalInterfaces { ASTVariableDeclaratorId getVarId(); } + interface MultiVariableIdOwner extends JavaNode, Iterable, AccessNode { + + /** + * Returns a stream of the variable ids declared + * by this node. + */ + default NodeStream getVarIds() { + return children(ASTVariableDeclarator.class).children(ASTVariableDeclaratorId.class); + } + + + @Override + default Iterator iterator() { + return getVarIds().iterator(); + } + + ASTType getTypeNode(); + } + } 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..0d7b328a1d 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 @@ -202,11 +202,13 @@ public class CommentRequiredRule extends AbstractCommentRule { } + @SuppressWarnings("PMD.UnusedFormalParameter") 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; } /** @@ -219,13 +221,15 @@ public class CommentRequiredRule extends AbstractCommentRule { * @return true if the field is a serialPersistentFields variable, otherwise false * @see Oracle docs */ + @SuppressWarnings("PMD.UnusedFormalParameter") 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..6d26d7f3dc 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 @@ -50,7 +50,6 @@ import net.sourceforge.pmd.lang.java.ast.ASTEqualityExpression; import net.sourceforge.pmd.lang.java.ast.ASTExclusiveOrExpression; import net.sourceforge.pmd.lang.java.ast.ASTExpression; import net.sourceforge.pmd.lang.java.ast.ASTExtendsList; -import net.sourceforge.pmd.lang.java.ast.ASTFieldDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTForStatement; import net.sourceforge.pmd.lang.java.ast.ASTFormalParameter; import net.sourceforge.pmd.lang.java.ast.ASTImportDeclaration; @@ -594,13 +593,6 @@ public class ClassTypeResolver extends JavaParserVisitorAdapter { } - @Override - public Object visit(ASTFieldDeclaration node, Object data) { - super.visit(node, data); - rollupTypeUnary(node); - return data; - } - @Override public Object visit(ASTVariableDeclarator node, Object data) { super.visit(node, data); @@ -621,9 +613,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 +1188,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 b2d7a0c524..0000000000 --- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/ASTFieldDeclarationTest.java +++ /dev/null @@ -1,86 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.java.ast; - -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.lang.java.JavaParsingHelper; -import net.sourceforge.pmd.lang.java.ast.testdata.InterfaceWithNestedClass; - -public class ASTFieldDeclarationTest extends BaseParserTest { - - @Test - public void testIsArray() { - ASTCompilationUnit cu = java.parse(TEST1); - Dimensionable node = cu.findDescendantsOfType(ASTFieldDeclaration.class).get(0); - assertTrue(node.isArray()); - assertEquals(1, node.getArrayDepth()); - } - - @Test - public void testMultiDimensionalArray() { - ASTCompilationUnit cu = java.parse(TEST2); - Dimensionable node = cu.findDescendantsOfType(ASTFieldDeclaration.class).get(0); - assertEquals(3, node.getArrayDepth()); - } - - @Test - public void testIsSyntacticallyPublic() { - ASTCompilationUnit cu = java.parse(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 = java5.parse(TEST4); - ASTFieldDeclaration node = cu.findDescendantsOfType(ASTFieldDeclaration.class).get(0); - assertFalse(node.isInterfaceMember()); - } - - @Test - public void testWithAnnotation() { - ASTCompilationUnit cu = java5.parse(TEST5); - ASTFieldDeclaration node = cu.findDescendantsOfType(ASTFieldDeclaration.class).get(0); - assertFalse(node.isInterfaceMember()); - assertTrue(node.isAnnotationMember()); - } - - private static final String TEST1 = "class Foo {\n String[] foo;\n}"; - - private static final String TEST2 = "class Foo {\n String[][][] foo;\n}"; - - private static final String TEST3 = "interface Foo {\n int BAR = 6;\n}"; - - private static final String TEST4 = "public enum Foo {\n FOO(1);\n private int x;\n}"; - - private static final String TEST5 = "public @interface Foo {\n int BAR = 6;\n}"; - - - @Test - public void testPrivateFieldInNestedClassInsideInterface() { - ASTCompilationUnit cu = JavaParsingHelper.WITH_PROCESSING.parseClass(InterfaceWithNestedClass.class, "10"); - 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 bb16a5dc8a..0000000000 --- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/ASTLocalVariableDeclarationTest.java +++ /dev/null @@ -1,36 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.java.ast; - -import static org.junit.Assert.assertEquals; - -import org.junit.Test; - -public class ASTLocalVariableDeclarationTest extends BaseParserTest { - - @Test - public void testSingleDimArray() { - ASTLocalVariableDeclaration node = java.parse(TEST1).findDescendantsOfType(ASTLocalVariableDeclaration.class).get(0); - assertEquals(1, node.getArrayDepth()); - } - - @Test - public void testMultDimArray() { - ASTLocalVariableDeclaration node = java.parse(TEST2).findDescendantsOfType(ASTLocalVariableDeclaration.class).get(0); - assertEquals(2, node.getArrayDepth()); - } - - @Test - public void testMultDimArraySplitBraces() { - ASTLocalVariableDeclaration node = java.parse(TEST3).findDescendantsOfType(ASTLocalVariableDeclaration.class).get(0); - assertEquals(3, node.getArrayDepth()); - } - - private static final String TEST1 = "class Foo {\n void bar() {int x[] = null;}\n}"; - - private static final String TEST2 = "class Foo {\n void bar() {int x[][] = null;}\n}"; - - private static final String TEST3 = "class Foo {\n void bar() {int[] x[][] = null;}\n}"; -} 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 2214160fe5..d18eab75d4 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 @@ -173,7 +173,6 @@ public class ClassTypeResolverTest { assertEquals(ArrayList.class, acu.getFirstDescendantOfType(ASTType.class).getType()); assertEquals(ArrayList.class, acu.getFirstDescendantOfType(ASTVariableDeclaratorId.class).getType()); assertEquals(ArrayList.class, acu.getFirstDescendantOfType(ASTVariableDeclarator.class).getType()); - assertEquals(ArrayList.class, acu.getFirstDescendantOfType(ASTFieldDeclaration.class).getType()); acu = java5.parseClass(DefaultJavaLangImport.class); assertEquals(String.class, acu.getFirstDescendantOfType(ASTClassOrInterfaceType.class).getType()); @@ -897,15 +896,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()); } @@ -927,15 +922,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..a7a6a06703 --- /dev/null +++ b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTFieldDeclarationTest.kt @@ -0,0 +1,86 @@ +/* + * 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 + +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 951eaba018..07cbe2230c 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,11 +6,13 @@ 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 class ASTLambdaExpressionTest : ParserTestSpec({ - parserTest("Simple lambda expressions") { + parserTest("Simple lambda expressions", javaVersions = J1_8..Latest) { "a -> foo()" should matchExpr { it::isExpressionBody shouldBe true @@ -76,7 +78,7 @@ class ASTLambdaExpressionTest : ParserTestSpec({ it::isBlockBody shouldBe false it::getParameters shouldBe child { - child { + lambdaParam { it::isFinal shouldBe true it::getTypeNode shouldBe primitiveType(INT) @@ -87,7 +89,7 @@ class ASTLambdaExpressionTest : ParserTestSpec({ it::isTypeInferred shouldBe false } } - child { + lambdaParam { annotation() it::getTypeNode shouldBe classType("List") variableId("b") { @@ -99,11 +101,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..2c992b38a2 --- /dev/null +++ b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTLocalVariableDeclarationTest.kt @@ -0,0 +1,42 @@ +/* + * 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 + +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 2bfe8ed63b..9901387387 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 @@ -80,7 +80,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 @@ -128,6 +128,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" @@ -146,6 +220,7 @@ class ASTMethodDeclarationTest : ParserTestSpec({ formalsList(0) } } + "int bar() default 2;" should parseAs { annotationMethod { it::getResultType shouldBe resultType { @@ -157,6 +232,22 @@ class ASTMethodDeclarationTest : ParserTestSpec({ } } + "int bar() @NonZero [];" should parseAs { + annotationMethod { + it::getResultType shouldBe resultType { + primitiveType(PrimitiveType.INT) + } + it::getFormalParameters shouldBe formalsList(0) + + it::getDefaultClause shouldBe null + it::getExtraDimensions shouldBe child { + arrayDim { + annotation("NonZero") + } + } + } + } + "Override bar() default @Override;" should parseAs { annotationMethod { it::getResultType shouldBe resultType { @@ -175,6 +266,9 @@ class ASTMethodDeclarationTest : ParserTestSpec({ } it::getFormalParameters shouldBe formalsList(0) + it::getExtraDimensions shouldBe child { + arrayDim {} + } it::getDefaultClause shouldBe defaultValue { memberValueArray { annotation("Override") @@ -194,7 +288,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 @@ -220,7 +314,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 @@ -275,5 +369,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 40c1a6104d..88f7cb7f56 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 @@ -80,15 +80,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,32 @@ 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.methodRef(methodName: String, assertions: NodeSpec = EmptyAssertions) = child(ignoreChildren = assertions === EmptyAssertions) { it::getMethodName shouldBe methodName @@ -422,6 +453,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..e4f7a995ad 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): @@ -108,16 +100,27 @@ public class FullTypeAnnotations { 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 [] 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 + + 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) @K[][]{ } + MyClass(Object @Readonly [] @ß... other) { } }