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.
This commit is contained in:
Clément Fournier
2019-12-15 03:53:10 +01:00
parent d4da257dc6
commit 1eab9448e7
33 changed files with 641 additions and 448 deletions

View File

@ -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<T extends Node> extends Iterable<@NonNull T> {
* Returns the first element of this stream, or {@code null} if the
* stream is empty.
*
* <p>If you'd rather continue processingthe first element as a node
* <p>If you'd rather continue processing the first element as a node
* stream, you can use {@link #take(int) take(1)}.
*
* <p>This is equivalent to {@link #get(int) get(0)}.
@ -703,6 +704,26 @@ public interface NodeStream<T extends Node> 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.

View File

@ -1721,7 +1721,7 @@ void ClassOrInterfaceBodyDeclaration():
( LOOKAHEAD(3) ClassOrInterfaceDeclaration(modifiers)
| LOOKAHEAD({isKeyword("enum")}) EnumDeclaration(modifiers)
| LOOKAHEAD( [ TypeParameters() ] <IDENTIFIER> "(" ) ConstructorDeclaration(modifiers)
| LOOKAHEAD( Type() <IDENTIFIER> ( "[" "]" )* ( "," | "=" | ";" ) ) FieldDeclaration(modifiers)
| LOOKAHEAD( Type() <IDENTIFIER> (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() :
{}
{
<IDENTIFIER> { setLastTokenImage(jjtThis); } ( "[" "]" { jjtThis.bumpArrayDepth(); })*
<IDENTIFIER> { setLastTokenImage(jjtThis); }
}
void VariableIdWithDims() #VariableDeclaratorId :
{}
{
<IDENTIFIER> { setLastTokenImage(jjtThis); }
[ Dims() ]
}
void ReceiverParameter():
@ -1777,7 +1783,7 @@ void MethodDeclaration(int modifiers) :
ResultType()
<IDENTIFIER> { 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") } )
<IDENTIFIER> { return true; }
| Type() { return false; }
<IDENTIFIER> { return true; }
| FormalParamType() { return false; }
}
void Literal() #void :

View File

@ -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:
* <ul>
* <li>In an {@linkplain ASTArrayType array type}</li>
* <li>TODO At the end {@linkplain ASTMethodDeclarator method declarator}</li>
* <li>TODO After a {@link ASTVariableDeclaratorId variable declarator id}</li>
* <li>As the {@linkplain ASTMethodDeclaration#getExtraDimensions() extra dimensions of a method declaration},
* after the formal parameter list. For example:
* <pre>public int newIntArray(int length) [];</pre>
* </li>
* <li>As the {@linkplain ASTVariableDeclaratorId#getExtraDimensions() extra dimensions of a variable declarator id},
* in a {@linkplain ASTVariableDeclarator variable declarator}. For example:
* <pre>public int a[], b[][];</pre>
* </li>
* </ul>
*
* <p>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}.
*
* <pre class="grammar">
*
@ -26,7 +32,7 @@ import net.sourceforge.pmd.lang.java.ast.InternalInterfaces.AtLeastOneChild;
*
* </pre>
*/
public final class ASTArrayDimensions extends AbstractJavaTypeNode implements Iterable<ASTArrayTypeDim>, AtLeastOneChild {
public final class ASTArrayDimensions extends AbstractJavaTypeNode implements Iterable<ASTArrayTypeDim>, AtLeastOneChildOfType<ASTArrayTypeDim> {
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.

View File

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

View File

@ -16,10 +16,11 @@ package net.sourceforge.pmd.lang.java.ast;
* ArrayTypeDim ::= {@link ASTAnnotation TypeAnnotation}* "[" "]"
*
* </pre>
*
*/
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);

View File

@ -15,7 +15,9 @@ import org.checkerframework.checker.nullness.qual.Nullable;
*
* </pre>
*/
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();
}
/**

View File

@ -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
*
* </pre>
*/
public final class ASTFieldDeclaration extends AbstractJavaAccessTypeNode implements Dimensionable, SignedNode<ASTFieldDeclaration>, Iterable<ASTVariableDeclaratorId> {
public final class ASTFieldDeclaration extends AbstractJavaAccessTypeNode
implements SignedNode<ASTFieldDeclaration>,
Iterable<ASTVariableDeclaratorId>,
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 <code>null</code> 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<ASTVariableDeclaratorId> 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<ASTVariableDeclaratorId> iterator() {
return ASTVariableDeclarator.iterateIds(this);
return getVariables().iterator();
}

View File

@ -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}.
*
* <p>The varargs ellipsis {@code "..."} is parsed as an {@linkplain ASTArrayTypeDim array dimension}
* in the type node.
*
* <pre class="grammar">
*
* 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}
*
* </pre>
*/
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();
}

View File

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

View File

@ -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
*
* </pre>
*/
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();
}

View File

@ -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;
*
* <p>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()}.
*
* <pre class="grammar">
*
@ -23,7 +25,9 @@ import java.util.Iterator;
* </pre>
*/
// TODO extend AbstractStatement
public final class ASTLocalVariableDeclaration extends AbstractJavaAccessNode implements Dimensionable, Iterable<ASTVariableDeclaratorId>, ASTStatement {
public final class ASTLocalVariableDeclaration extends AbstractJavaAccessNode
implements Iterable<ASTVariableDeclaratorId>,
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 <code>null</code> 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<ASTVariableDeclaratorId> 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<ASTVariableDeclaratorId> iterator() {
return ASTVariableDeclarator.iterateIds(this);
return getVarIds().iterator();
}
}

View File

@ -31,8 +31,8 @@ import net.sourceforge.pmd.lang.dfa.DFAGraphMethod;
* {@link ASTResultType ResultType}
* &lt;IDENTIFIER&gt;
* {@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();
}
}

View File

@ -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;
*
* <pre class="grammar">
*
* VariableDeclarator ::= {@linkplain ASTVariableDeclaratorId VariableDeclaratorId} ( "=" {@linkplain ASTExpression Expression} )?
* VariableDeclarator ::= {@linkplain ASTVariableDeclaratorId VariableDeclaratorId} {@link ASTArrayDimensions ArrayDimensions}? ( "=" {@linkplain ASTExpression Expression} )?
*
* </pre>
*/
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<ASTVariableDeclaratorId> iterateIds(Node parent) {
// TODO this can be made clearer with iterator mapping (Java 8)
final Iterator<ASTVariableDeclarator> declarators = parent.children(ASTVariableDeclarator.class).iterator();
return new Iterator<ASTVariableDeclaratorId>() {
@Override
public boolean hasNext() {
return declarators.hasNext();
}
@Override
public ASTVariableDeclaratorId next() {
return declarators.next().getVariableId();
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
};
}
}

View File

@ -33,9 +33,17 @@ import net.sourceforge.pmd.lang.symboltable.NameOccurrence;
*
* <p>Type resolution assigns the type of the variable to this node. See {@link #getType()}'s
* documentation for the contract of this method.
*
*
* <pre class="grammar">
*
* VariableDeclaratorId ::= &lt;IDENTIFIER&gt; {@link ASTArrayDimensions ArrayDimensions}?
*
* </pre>
*
*/
// @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);

View File

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

View File

@ -111,11 +111,11 @@ public class JavaRuleViolation extends ParametricRuleViolation<JavaNode> {
} 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 "";
}

View File

@ -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<ASTFormalParameter> l = params.findChildrenOfType(ASTFormalParameter.class);
if (l != null && !l.isEmpty()) {
List<ASTFormalParameter> 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]);
}
}

View File

@ -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 <a href="https://docs.oracle.com/javase/7/docs/platform/serialization/spec/serial-arch.html#6250">Oracle docs</a>
*/
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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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<ASTLambdaExpression> {
it::isExpressionBody shouldBe true
@ -78,7 +80,7 @@ class ASTLambdaExpressionTest : ParserTestSpec({
it::isBlockBody shouldBe false
it::getParameters shouldBe child {
child<ASTLambdaParameter> {
lambdaParam {
it::isFinal shouldBe true
it::getTypeNode shouldBe primitiveType(INT)
@ -89,7 +91,7 @@ class ASTLambdaExpressionTest : ParserTestSpec({
it::isTypeInferred shouldBe false
}
}
child<ASTLambdaParameter> {
lambdaParam {
annotation()
it::getTypeNode shouldBe classType("List")
variableId("b") {
@ -101,11 +103,128 @@ class ASTLambdaExpressionTest : ParserTestSpec({
}
child<ASTMethodCall>(ignoreChildren = true) {}
methodCall("foo")
}
}
parserTest("Mixed array notation/varargs", javaVersions = J1_8..Latest) {
inContext(ExpressionParsingCtx) {
"(final int a[]@B[], @F List<String>@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()

View File

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

Some files were not shown because too many files have changed in this diff Show More