Merge branch 'grammar-dimensions' into java-grammar
This commit is contained in:
@ -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.
|
||||
|
@ -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() ("|" 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") } )
|
||||
<IDENTIFIER> { return true; }
|
||||
| Type() { return false; }
|
||||
<IDENTIFIER> { return true; }
|
||||
| FormalParamType() { return false; }
|
||||
}
|
||||
|
||||
void Literal() #void :
|
||||
@ -3142,7 +3164,7 @@ void AnnotationMethodDeclaration(int modifiers) #MethodDeclaration:
|
||||
Type() #ResultType
|
||||
t=<IDENTIFIER>
|
||||
("(" ")") #FormalParameters(true)
|
||||
( "[" "]" )* // TODO use ArrayTypeDims
|
||||
[ Dims() ]
|
||||
[ DefaultValue() ] ";"
|
||||
{
|
||||
jjtThis.setImage(t.image);
|
||||
|
@ -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.
|
||||
|
@ -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...
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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
|
||||
*
|
||||
* </pre>
|
||||
*/
|
||||
public final class ASTFieldDeclaration extends AbstractJavaAccessTypeNode implements Dimensionable, SignedNode<ASTFieldDeclaration>, Iterable<ASTVariableDeclaratorId> {
|
||||
public final class ASTFieldDeclaration extends AbstractJavaAccessNode
|
||||
implements SignedNode<ASTFieldDeclaration>,
|
||||
Iterable<ASTVariableDeclaratorId>,
|
||||
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 <code>null</code> 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<ASTVariableDeclaratorId> 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();
|
||||
}
|
||||
}
|
||||
|
@ -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}.
|
||||
*
|
||||
* <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 ASTVariableDeclaratorId VariableDeclaratorId}
|
||||
* FormalParameter ::= ( "final" | {@link ASTAnnotation Annotation} )* {@link ASTType Type} {@link ASTVariableDeclaratorId VariableDeclaratorId}
|
||||
*
|
||||
* </pre>
|
||||
*/
|
||||
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();
|
||||
}
|
||||
|
||||
|
||||
|
@ -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() {
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
||||
|
@ -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;
|
||||
*
|
||||
* <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 +20,10 @@ 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,
|
||||
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 <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
|
||||
*/
|
||||
// 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<ASTVariableDeclaratorId> iterator() {
|
||||
return ASTVariableDeclarator.iterateIds(this);
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -33,11 +33,18 @@ 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 ::= <IDENTIFIER> {@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;
|
||||
|
||||
@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();
|
||||
}
|
||||
|
||||
|
||||
|
@ -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();
|
||||
}
|
@ -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<ASTVariableDeclaratorId>, AccessNode {
|
||||
|
||||
/**
|
||||
* Returns a stream of the variable ids declared
|
||||
* by this node.
|
||||
*/
|
||||
default NodeStream<ASTVariableDeclaratorId> getVarIds() {
|
||||
return children(ASTVariableDeclarator.class).children(ASTVariableDeclaratorId.class);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
default Iterator<ASTVariableDeclaratorId> iterator() {
|
||||
return getVarIds().iterator();
|
||||
}
|
||||
|
||||
ASTType getTypeNode();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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 "";
|
||||
}
|
||||
|
@ -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]);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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 <a href="https://docs.oracle.com/javase/7/docs/platform/serialization/spec/serial-arch.html#6250">Oracle docs</a>
|
||||
*/
|
||||
@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
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
|
@ -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<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());
|
||||
}
|
||||
}
|
@ -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}";
|
||||
}
|
@ -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());
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
})
|
@ -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<ASTLambdaExpression> {
|
||||
it::isExpressionBody shouldBe true
|
||||
@ -76,7 +78,7 @@ class ASTLambdaExpressionTest : ParserTestSpec({
|
||||
it::isBlockBody shouldBe false
|
||||
|
||||
it::getParameters shouldBe child {
|
||||
child<ASTLambdaParameter> {
|
||||
lambdaParam {
|
||||
it::isFinal shouldBe true
|
||||
|
||||
it::getTypeNode shouldBe primitiveType(INT)
|
||||
@ -87,7 +89,7 @@ class ASTLambdaExpressionTest : ParserTestSpec({
|
||||
it::isTypeInferred shouldBe false
|
||||
}
|
||||
}
|
||||
child<ASTLambdaParameter> {
|
||||
lambdaParam {
|
||||
annotation()
|
||||
it::getTypeNode shouldBe classType("List")
|
||||
variableId("b") {
|
||||
@ -99,11 +101,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()
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user