Merge branch 'java-grammar' into grammar-new-statements
This commit is contained in:
@ -2283,23 +2283,24 @@ void MultiplicativeExpression() #void:
|
||||
void UnaryExpression() #void:
|
||||
{}
|
||||
{
|
||||
(("+" {jjtThis.setImage("+");} | "-" {jjtThis.setImage("-");}) UnaryExpression()) #UnaryExpression
|
||||
(("+" {jjtThis.setOp(UnaryOp.UNARY_PLUS);} | "-" {jjtThis.setOp(UnaryOp.UNARY_MINUS);}) UnaryExpression()) #UnaryExpression
|
||||
| PrefixIncrementExpression()
|
||||
| UnaryExpressionNotPlusMinus()
|
||||
}
|
||||
|
||||
void PrefixIncrementExpression() #IncrementExpression:
|
||||
void PrefixIncrementExpression() #UnaryExpression:
|
||||
{}
|
||||
{
|
||||
( "++" {jjtThis.setIncrement();} | "--" )
|
||||
{ jjtThis.setPrefix(); }
|
||||
("++" {jjtThis.setOp(UnaryOp.PRE_INCREMENT);}
|
||||
| "--" {jjtThis.setOp(UnaryOp.PRE_DECREMENT);}
|
||||
)
|
||||
PrimaryExpression()
|
||||
}
|
||||
|
||||
void UnaryExpressionNotPlusMinus() #void:
|
||||
{}
|
||||
{
|
||||
(( "~" {jjtThis.setImage("~");} | "!" {jjtThis.setImage("!");}) UnaryExpression()) #UnaryExpression
|
||||
(( "~" {jjtThis.setOp(UnaryOp.COMPLEMENT);} | "!" {jjtThis.setOp(UnaryOp.NEGATION);}) UnaryExpression()) #UnaryExpression
|
||||
// There's no separate production for CastExpression, because that would force
|
||||
// us to repeat the lookahead
|
||||
// Those lookaheads are quite expensive, they're run to disambiguate between
|
||||
@ -2328,7 +2329,13 @@ void PostfixExpression() #void:
|
||||
{}
|
||||
{
|
||||
|
||||
PrimaryExpression() [LOOKAHEAD(1) ("++" {jjtThis.setIncrement();} | "--") #IncrementExpression(1) ]
|
||||
PrimaryExpression()
|
||||
[
|
||||
LOOKAHEAD(1)
|
||||
("++" {jjtThis.setOp(UnaryOp.POST_INCREMENT);}
|
||||
| "--" {jjtThis.setOp(UnaryOp.POST_DECREMENT);}
|
||||
) #UnaryExpression(1)
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
|
@ -30,7 +30,7 @@ public interface ASTAssignableExpr extends ASTPrimaryExpression {
|
||||
/**
|
||||
* Returns how this expression is accessed in the enclosing expression.
|
||||
* If this expression occurs as the left-hand-side of an {@linkplain ASTAssignmentExpression assignment},
|
||||
* or as the target of an {@linkplain ASTIncrementExpression increment or decrement expression},
|
||||
* or as the target of an {@linkplain ASTUnaryExpression increment or decrement expression},
|
||||
* this method returns {@link AccessType#WRITE}. Otherwise the value is just {@linkplain AccessType#READ read}.
|
||||
*/
|
||||
@NonNull
|
||||
@ -38,7 +38,7 @@ public interface ASTAssignableExpr extends ASTPrimaryExpression {
|
||||
|
||||
Node parent = this.jjtGetParent();
|
||||
|
||||
if (parent instanceof ASTIncrementExpression
|
||||
if (parent instanceof ASTUnaryExpression && !((ASTUnaryExpression) parent).getOperator().isPure()
|
||||
|| jjtGetChildIndex() == 0 && parent instanceof ASTAssignmentExpression) {
|
||||
return AccessType.WRITE;
|
||||
}
|
||||
|
@ -27,8 +27,8 @@ package net.sourceforge.pmd.lang.java.ast;
|
||||
* | {@link ASTAssignmentExpression AssignmentExpression}
|
||||
* | {@link ASTConditionalExpression ConditionalExpression}
|
||||
* | {@link ASTInfixExpression InfixExpression}
|
||||
* | {@link ASTUnaryExpression UnaryExpression} | {@link ASTIncrementExpression PrefixIncrement} | {@link ASTCastExpression CastExpression}
|
||||
* | {@link ASTIncrementExpression PostfixIncrement}
|
||||
* | {@link ASTUnaryExpression PrefixExpression} | {@link ASTCastExpression CastExpression}
|
||||
* | {@link ASTUnaryExpression PostfixExpression}
|
||||
* | {@link ASTSwitchExpression SwitchExpression}
|
||||
* | {@link ASTPrimaryExpression PrimaryExpression}
|
||||
*
|
||||
|
@ -1,109 +0,0 @@
|
||||
/*
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*/
|
||||
|
||||
package net.sourceforge.pmd.lang.java.ast;
|
||||
|
||||
/**
|
||||
* Represents an increment or decrement operation on a variable. This represents
|
||||
* both the postfix and prefix forms.
|
||||
*
|
||||
* <p>Since 7.0, this node replaces the nodes PostfixExpression, PreDecrementExpression,
|
||||
* and PreIncrementExpression.
|
||||
*
|
||||
* <p>In prefix form, this has the same precedence as {@linkplain ASTUnaryExpression UnaryExpression}.
|
||||
* In postfix form, this has a precedence greater as {@linkplain ASTUnaryExpression UnaryExpression},
|
||||
* and lower as {@linkplain ASTPrimaryExpression PrimaryExpression}.
|
||||
*
|
||||
* <pre class="grammar">
|
||||
*
|
||||
* IncrementExpr ::= {@linkplain ASTAssignableExpr AssignableExpr} ( "++" | "--" )
|
||||
* | ( "++" | "--" ) {@linkplain ASTAssignableExpr AssignableExpr}
|
||||
*
|
||||
* </pre>
|
||||
*/
|
||||
public final class ASTIncrementExpression extends AbstractJavaExpr implements ASTExpression, LeftRecursiveNode {
|
||||
|
||||
private boolean isPrefix;
|
||||
private boolean isIncrement;
|
||||
|
||||
ASTIncrementExpression(int id) {
|
||||
super(id);
|
||||
}
|
||||
|
||||
ASTIncrementExpression(JavaParser p, int id) {
|
||||
super(p, id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object jjtAccept(JavaParserVisitor visitor, Object data) {
|
||||
return visitor.visit(this, data);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public <T> void jjtAccept(SideEffectingVisitor<T> visitor, T data) {
|
||||
visitor.visit(this, data);
|
||||
}
|
||||
|
||||
|
||||
void setPrefix() {
|
||||
this.isPrefix = true;
|
||||
}
|
||||
|
||||
|
||||
void setIncrement() {
|
||||
this.isIncrement = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this a prefix assignment, {@literal e.g.} {@code ++i}, {@code --i}.
|
||||
*/
|
||||
public boolean isPrefix() {
|
||||
return isPrefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this a postfix assignment, {@literal e.g.} {@code i++}, {@code i--}.
|
||||
*/
|
||||
public boolean isPostfix() {
|
||||
return !isPrefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the operator of this expression.
|
||||
*/
|
||||
public IncrementOp getOp() {
|
||||
return isIncrement ? IncrementOp.INCREMENT : IncrementOp.DECREMENT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the operator.
|
||||
*/
|
||||
public String getOpName() {
|
||||
return getOp().name();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this is an increment expression ({@link #getOp()} is {@link IncrementOp#INCREMENT}).
|
||||
*/
|
||||
public boolean isIncrement() {
|
||||
return isIncrement;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this is a decrement expression ({@link #getOp()} is {@link IncrementOp#DECREMENT}).
|
||||
*/
|
||||
public boolean isDecrement() {
|
||||
return !isIncrement;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the expression assigned by this expression.
|
||||
*/
|
||||
public ASTAssignableExpr getOperand() {
|
||||
return (ASTAssignableExpr) jjtGetChild(0);
|
||||
}
|
||||
|
||||
}
|
@ -5,22 +5,22 @@
|
||||
package net.sourceforge.pmd.lang.java.ast;
|
||||
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Represents a unary prefix operation on a value.
|
||||
* This has a precedence greater than {@link ASTInfixExpression}.
|
||||
*
|
||||
* <p>UnaryExpression has the same precedence as the prefix forms of {@linkplain ASTIncrementExpression IncrementExpression},
|
||||
* and {@linkplain ASTCastExpression CastExpression}.
|
||||
* Represents a unary operation on a value. The syntactic form may be
|
||||
* prefix or postfix, which are represented with the same nodes, even
|
||||
* though they have different precedences.
|
||||
*
|
||||
* <pre class="grammar">
|
||||
*
|
||||
* UnaryExpression ::= {@link UnaryOp} {@link ASTExpression Expression}
|
||||
* UnaryExpression ::= PrefixExpression | PostfixExpression
|
||||
*
|
||||
* PrefixExpression ::= {@link UnaryOp PrefixOp} {@link ASTExpression Expression}
|
||||
*
|
||||
* PostfixExpression ::= {@link ASTExpression Expression} {@link UnaryOp PostfixOp}
|
||||
*
|
||||
* </pre>
|
||||
*/
|
||||
public final class ASTUnaryExpression extends AbstractJavaExpr implements ASTExpression {
|
||||
public final class ASTUnaryExpression extends AbstractJavaExpr implements LeftRecursiveNode {
|
||||
|
||||
private UnaryOp operator;
|
||||
|
||||
@ -32,6 +32,7 @@ public final class ASTUnaryExpression extends AbstractJavaExpr implements ASTExp
|
||||
super(p, id);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Object jjtAccept(JavaParserVisitor visitor, Object data) {
|
||||
return visitor.visit(this, data);
|
||||
@ -44,19 +45,29 @@ public final class ASTUnaryExpression extends AbstractJavaExpr implements ASTExp
|
||||
}
|
||||
|
||||
|
||||
/** Returns the expression nested within this expression. */
|
||||
public ASTExpression getOperand() {
|
||||
return (ASTExpression) jjtGetChild(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setImage(String image) {
|
||||
super.setImage(image);
|
||||
this.operator = Objects.requireNonNull(UnaryOp.fromImage(image));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this is a prefix expression.
|
||||
*
|
||||
* @deprecated XPath-attribute only, use {@code getOperator().isPrefix()} in java code.
|
||||
*/
|
||||
@Deprecated
|
||||
public boolean isPrefix() {
|
||||
return getOperator().isPrefix();
|
||||
}
|
||||
|
||||
/** Returns the constant representing the operator of this expression. */
|
||||
public UnaryOp getOperator() {
|
||||
return operator;
|
||||
}
|
||||
|
||||
void setOp(UnaryOp op) {
|
||||
this.operator = op;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,43 +0,0 @@
|
||||
/*
|
||||
* 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.java.ast.InternalInterfaces.OperatorLike;
|
||||
|
||||
/**
|
||||
* An increment operator for {@link ASTIncrementExpression IncrementExpression}.
|
||||
*
|
||||
* <pre class="grammar">
|
||||
*
|
||||
* IncrementOp ::= "++" | "--"
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @see AssignmentOp
|
||||
* @see UnaryOp
|
||||
*/
|
||||
public enum IncrementOp implements OperatorLike {
|
||||
/** "++" */
|
||||
INCREMENT("++"),
|
||||
/** "--" */
|
||||
DECREMENT("--");
|
||||
|
||||
private final String code;
|
||||
|
||||
|
||||
IncrementOp(String code) {
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.code;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getToken() {
|
||||
return code;
|
||||
}
|
||||
}
|
@ -1,55 +1,91 @@
|
||||
/**
|
||||
/*
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*/
|
||||
|
||||
package net.sourceforge.pmd.lang.java.ast;
|
||||
|
||||
import static java.util.stream.Collectors.collectingAndThen;
|
||||
import static java.util.stream.Collectors.toMap;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
/**
|
||||
* A unary operator for {@link ASTUnaryExpression}.
|
||||
* A unary operator, either prefix or postfix. This is used by {@link ASTUnaryExpression UnaryExpression}
|
||||
* to abstract over the syntactic form of the operator.
|
||||
*
|
||||
* <pre class="grammar">
|
||||
*
|
||||
* UnaryOp ::= "+" | "-" | "~" | "!"
|
||||
* UnaryOp ::= PrefixOp | PostfixOp
|
||||
*
|
||||
* </pre>
|
||||
* PrefixOp ::= "+" | "-" | "~" | "!" | "++" | "--"
|
||||
*
|
||||
* PostfixOp ::= "++" | "--"
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @see BinaryOp
|
||||
* @see AssignmentOp
|
||||
*/
|
||||
public enum UnaryOp implements InternalInterfaces.OperatorLike {
|
||||
/** "+" */
|
||||
/** Unary numeric promotion operator {@code "+"}. */
|
||||
UNARY_PLUS("+"),
|
||||
/** "-" */
|
||||
/** Arithmetic negation operation {@code "-"}. */
|
||||
UNARY_MINUS("-"),
|
||||
/** "~" */
|
||||
BITWISE_INVERSE("~"),
|
||||
/** "!" */
|
||||
BOOLEAN_NOT("!");
|
||||
/** Bitwise complement operator {@code "~"}. */
|
||||
COMPLEMENT("~"),
|
||||
/** Logical complement operator {@code "!"}. */
|
||||
NEGATION("!"),
|
||||
|
||||
/** Prefix increment operator {@code "++"}. */
|
||||
PRE_INCREMENT("++"),
|
||||
/** Prefix decrement operator {@code "--"}. */
|
||||
PRE_DECREMENT("--"),
|
||||
|
||||
/** Postfix increment operator {@code "++"}. */
|
||||
POST_INCREMENT("++"),
|
||||
/** Postfix decrement operator {@code "--"}. */
|
||||
POST_DECREMENT("--");
|
||||
|
||||
private static final Map<String, UnaryOp> LOOKUP =
|
||||
Arrays.stream(values())
|
||||
.collect(
|
||||
collectingAndThen(
|
||||
toMap(UnaryOp::getToken, op -> op),
|
||||
Collections::unmodifiableMap
|
||||
)
|
||||
);
|
||||
|
||||
private final String code;
|
||||
|
||||
|
||||
UnaryOp(String code) {
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this operator is pure, ie the evaluation of
|
||||
* the unary expression doesn't produce side-effects. Only increment
|
||||
* and decrement operators are impure.
|
||||
*
|
||||
* <p>This can be used to fetch all increment or decrement operations,
|
||||
* regardless of whether they're postfix or prefix. E.g.
|
||||
* <pre>{@code
|
||||
* node.descendants(ASTUnaryExpression.class)
|
||||
* .filterNot(it -> it.getOperator().isPure())
|
||||
* }</pre>
|
||||
*/
|
||||
public boolean isPure() {
|
||||
return this.ordinal() < PRE_INCREMENT.ordinal();
|
||||
}
|
||||
|
||||
/** Returns true if this is one of {@link #PRE_INCREMENT} or {@link #POST_INCREMENT}. */
|
||||
public boolean isIncrement() {
|
||||
return this == PRE_INCREMENT || this == POST_INCREMENT;
|
||||
}
|
||||
|
||||
/** Returns true if this is one of {@link #PRE_DECREMENT} or {@link #POST_DECREMENT}. */
|
||||
public boolean isDecrement() {
|
||||
return this == PRE_DECREMENT || this == POST_DECREMENT;
|
||||
}
|
||||
|
||||
|
||||
/** Returns true if this is a prefix operator. */
|
||||
public boolean isPrefix() {
|
||||
return this.ordinal() < POST_INCREMENT.ordinal();
|
||||
}
|
||||
|
||||
/** Returns true if this is a postfix operator. */
|
||||
public boolean isPostfix() {
|
||||
return !isPrefix();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getToken() {
|
||||
return code;
|
||||
@ -60,9 +96,4 @@ public enum UnaryOp implements InternalInterfaces.OperatorLike {
|
||||
return this.code;
|
||||
}
|
||||
|
||||
|
||||
// parser only for now
|
||||
static UnaryOp fromImage(String image) {
|
||||
return LOOKUP.get(image);
|
||||
}
|
||||
}
|
||||
|
@ -26,7 +26,6 @@ import net.sourceforge.pmd.lang.java.ast.ASTForInit;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTForStatement;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTForUpdate;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTIfStatement;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTIncrementExpression;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTLocalVariableDeclaration;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTName;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTPrimaryExpression;
|
||||
@ -34,6 +33,7 @@ import net.sourceforge.pmd.lang.java.ast.ASTPrimaryPrefix;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTPrimarySuffix;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTStatement;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTSwitchStatement;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTUnaryExpression;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclaratorId;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTWhileStatement;
|
||||
import net.sourceforge.pmd.lang.java.rule.performance.AbstractOptimizationRule;
|
||||
@ -138,8 +138,8 @@ public class AvoidReassigningLoopVariablesRule extends AbstractOptimizationRule
|
||||
*/
|
||||
private void checkIncrementAndDecrement(Object data, Set<String> loopVariables, ASTStatement loopBody, IgnoreFlags... ignoreFlags) {
|
||||
|
||||
for (ASTIncrementExpression expression : loopBody.findDescendantsOfType(ASTIncrementExpression.class)) {
|
||||
if (ignoreNode(expression, loopBody, ignoreFlags)) {
|
||||
for (ASTUnaryExpression expression : loopBody.findDescendantsOfType(ASTUnaryExpression.class)) {
|
||||
if (expression.getOperator().isPure() || ignoreNode(expression, loopBody, ignoreFlags)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -18,7 +18,6 @@ import net.sourceforge.pmd.lang.java.ast.ASTExpression;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTForInit;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTForStatement;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTForUpdate;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTIncrementExpression;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTLiteral;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTLocalVariableDeclaration;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTName;
|
||||
@ -28,6 +27,8 @@ import net.sourceforge.pmd.lang.java.ast.ASTPrimarySuffix;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTRelationalExpression;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTStatementExpression;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTStatementExpressionList;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTUnaryExpression;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTVariableAccess;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclarator;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTVariableInitializer;
|
||||
import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule;
|
||||
@ -127,11 +128,10 @@ public class ForLoopCanBeForeachRule extends AbstractJavaRule {
|
||||
.children(ASTStatementExpressionList.class)
|
||||
.filter(it -> it.jjtGetNumChildren() == 1)
|
||||
.children(ASTStatementExpression.class)
|
||||
.children(ASTIncrementExpression.class)
|
||||
.filter(ASTIncrementExpression::isIncrement)
|
||||
.children(ASTPrimaryExpression.class)
|
||||
.children(ASTPrimaryPrefix.class)
|
||||
.children(ASTName.class)
|
||||
.children(ASTUnaryExpression.class)
|
||||
.filter(it -> it.getOperator().isIncrement())
|
||||
.map(ASTUnaryExpression::getOperand)
|
||||
.filterIs(ASTVariableAccess.class)
|
||||
.firstOpt()
|
||||
.map(Node::getImage);
|
||||
}
|
||||
|
@ -11,7 +11,7 @@ import net.sourceforge.pmd.lang.java.ast.ASTAssignmentOperator;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTExpression;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTForStatement;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTIfStatement;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTIncrementExpression;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTUnaryExpression;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTWhileStatement;
|
||||
import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule;
|
||||
import net.sourceforge.pmd.properties.PropertyDescriptor;
|
||||
@ -59,8 +59,7 @@ public class AssignmentInOperandRule extends AbstractJavaRule {
|
||||
|| parent instanceof ASTForStatement && parent.jjtGetChild(1) == node
|
||||
&& !getProperty(ALLOW_FOR_DESCRIPTOR))
|
||||
&& (node.hasDescendantOfType(ASTAssignmentOperator.class)
|
||||
|| !getProperty(ALLOW_INCREMENT_DECREMENT_DESCRIPTOR)
|
||||
&& node.hasDescendantOfType(ASTIncrementExpression.class))) {
|
||||
|| !getProperty(ALLOW_INCREMENT_DECREMENT_DESCRIPTOR) && hasIncrement(node))) {
|
||||
|
||||
addViolation(data, node);
|
||||
return data;
|
||||
@ -68,6 +67,11 @@ public class AssignmentInOperandRule extends AbstractJavaRule {
|
||||
return super.visit(node, data);
|
||||
}
|
||||
|
||||
private boolean hasIncrement(ASTExpression node) {
|
||||
// todo use node streams
|
||||
return node.findDescendantsOfType(ASTUnaryExpression.class).stream().anyMatch(it -> !it.getOperator().isPure());
|
||||
}
|
||||
|
||||
public boolean allowsAllAssignments() {
|
||||
return getProperty(ALLOW_IF_DESCRIPTOR) && getProperty(ALLOW_FOR_DESCRIPTOR)
|
||||
&& getProperty(ALLOW_WHILE_DESCRIPTOR) && getProperty(ALLOW_INCREMENT_DECREMENT_DESCRIPTOR);
|
||||
|
@ -7,13 +7,13 @@ package net.sourceforge.pmd.lang.java.symboltable;
|
||||
import net.sourceforge.pmd.lang.ast.Node;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTAssignmentOperator;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTExpression;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTIncrementExpression;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTMethodReference;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTName;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTPrimaryExpression;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTPrimaryPrefix;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTResource;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTStatementExpression;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTUnaryExpression;
|
||||
import net.sourceforge.pmd.lang.java.ast.JavaNode;
|
||||
import net.sourceforge.pmd.lang.symboltable.NameOccurrence;
|
||||
|
||||
@ -120,13 +120,20 @@ public class JavaNameOccurrence implements NameOccurrence {
|
||||
}
|
||||
|
||||
private boolean isStandAlonePostfix(Node primaryExpression) {
|
||||
if (!(primaryExpression instanceof ASTIncrementExpression && ((ASTIncrementExpression) primaryExpression).isPostfix())
|
||||
|| !(primaryExpression.jjtGetParent() instanceof ASTStatementExpression)) {
|
||||
if (!(primaryExpression instanceof ASTUnaryExpression)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ASTUnaryExpression unaryExpr = (ASTUnaryExpression) primaryExpression;
|
||||
|
||||
if (unaryExpr.getOperator().isPure()
|
||||
|| unaryExpr.getOperator().isPrefix()
|
||||
|| !(primaryExpression.jjtGetParent() instanceof ASTStatementExpression)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ASTPrimaryPrefix pf = (ASTPrimaryPrefix) ((ASTPrimaryExpression) primaryExpression.jjtGetChild(0))
|
||||
.jjtGetChild(0);
|
||||
.jjtGetChild(0);
|
||||
if (pf.usesThisModifier()) {
|
||||
return true;
|
||||
}
|
||||
@ -152,7 +159,7 @@ public class JavaNameOccurrence implements NameOccurrence {
|
||||
Node p = l.jjtGetParent();
|
||||
Node gp = p.jjtGetParent();
|
||||
Node node = gp.jjtGetParent();
|
||||
if (node instanceof ASTIncrementExpression) {
|
||||
if (node instanceof ASTUnaryExpression && !((ASTUnaryExpression) node).getOperator().isPure()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -174,7 +181,7 @@ public class JavaNameOccurrence implements NameOccurrence {
|
||||
}
|
||||
|
||||
// catch this.i++ or ++this.i
|
||||
return gp instanceof ASTIncrementExpression;
|
||||
return node instanceof ASTUnaryExpression && !((ASTUnaryExpression) node).getOperator().isPure();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -55,7 +55,6 @@ import net.sourceforge.pmd.lang.java.ast.ASTForStatement;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTFormalParameter;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTImportDeclaration;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTInclusiveOrExpression;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTIncrementExpression;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTInstanceOfExpression;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTIntersectionType;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTLiteral;
|
||||
@ -88,6 +87,7 @@ import net.sourceforge.pmd.lang.java.ast.ASTYieldStatement;
|
||||
import net.sourceforge.pmd.lang.java.ast.InternalApiBridge;
|
||||
import net.sourceforge.pmd.lang.java.ast.JavaParserVisitorAdapter;
|
||||
import net.sourceforge.pmd.lang.java.ast.TypeNode;
|
||||
import net.sourceforge.pmd.lang.java.ast.UnaryOp;
|
||||
import net.sourceforge.pmd.lang.java.symboltable.ClassScope;
|
||||
import net.sourceforge.pmd.lang.java.symboltable.VariableNameDeclaration;
|
||||
import net.sourceforge.pmd.lang.java.typeresolution.typedefinition.JavaTypeDefinition;
|
||||
@ -784,28 +784,17 @@ public class ClassTypeResolver extends JavaParserVisitorAdapter {
|
||||
public Object visit(ASTUnaryExpression node, Object data) {
|
||||
super.visit(node, data);
|
||||
|
||||
switch (node.getOperator()) {
|
||||
case BOOLEAN_NOT:
|
||||
if (node.getOperator() == UnaryOp.NEGATION) {
|
||||
populateType(node, "boolean");
|
||||
break;
|
||||
case BITWISE_INVERSE:
|
||||
} else if (node.getOperator() == UnaryOp.COMPLEMENT) {
|
||||
rollupTypeUnary(node);
|
||||
break;
|
||||
default:
|
||||
} else {
|
||||
rollupTypeUnaryNumericPromotion(node);
|
||||
break;
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visit(ASTIncrementExpression node, Object data) {
|
||||
super.visit(node, data);
|
||||
rollupTypeUnary(node);
|
||||
return data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visit(ASTCastExpression node, Object data) {
|
||||
super.visit(node, data);
|
||||
|
@ -2,10 +2,6 @@
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*/
|
||||
|
||||
/**
|
||||
* 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
|
||||
|
@ -9,6 +9,7 @@ import net.sourceforge.pmd.lang.java.ast.JavaVersion.*
|
||||
import net.sourceforge.pmd.lang.java.ast.JavaVersion.Companion.Earliest
|
||||
import net.sourceforge.pmd.lang.java.ast.JavaVersion.Companion.Latest
|
||||
import net.sourceforge.pmd.lang.java.ast.ParserTestCtx.Companion.ExpressionParsingCtx
|
||||
import net.sourceforge.pmd.lang.java.ast.UnaryOp.UNARY_MINUS
|
||||
|
||||
/**
|
||||
* @author Clément Fournier
|
||||
@ -233,7 +234,7 @@ $delim
|
||||
}
|
||||
|
||||
"-0X0000_000f" should matchExpr<ASTUnaryExpression> {
|
||||
it::getOperator shouldBe UnaryOp.UNARY_MINUS
|
||||
it::getOperator shouldBe UNARY_MINUS
|
||||
it::getOperand shouldBe number(INT) {
|
||||
it::getImage shouldBe "0X0000_000f"
|
||||
it::getValueAsInt shouldBe 15
|
||||
@ -283,7 +284,7 @@ $delim
|
||||
}
|
||||
|
||||
"-3_456.123_456" should matchExpr<ASTUnaryExpression> {
|
||||
it::getOperator shouldBe UnaryOp.UNARY_MINUS
|
||||
it::getOperator shouldBe UNARY_MINUS
|
||||
|
||||
it::getOperand shouldBe number(DOUBLE) {
|
||||
it::getValueAsInt shouldBe 3456
|
||||
@ -361,7 +362,7 @@ $delim
|
||||
"0x0_0__0F" should parseAs(hex15i)
|
||||
|
||||
"-0X0000_000f" should parseAs {
|
||||
unaryExpr(UnaryOp.UNARY_MINUS) {
|
||||
unaryExpr(UNARY_MINUS) {
|
||||
hex15i()
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ package net.sourceforge.pmd.lang.java.ast
|
||||
import net.sourceforge.pmd.lang.ast.test.shouldBe
|
||||
import net.sourceforge.pmd.lang.java.ast.BinaryOp.*
|
||||
import net.sourceforge.pmd.lang.java.ast.ParserTestCtx.Companion.ExpressionParsingCtx
|
||||
import net.sourceforge.pmd.lang.java.ast.UnaryOp.UNARY_MINUS
|
||||
|
||||
|
||||
/**
|
||||
@ -139,7 +140,7 @@ class ASTSwitchExpressionTests : ParserTestSpec({
|
||||
}
|
||||
}
|
||||
"-switch (day) {default -> 6;}" should parseAs {
|
||||
unaryExpr(UnaryOp.UNARY_MINUS) {
|
||||
unaryExpr(UNARY_MINUS) {
|
||||
switchExpr()
|
||||
}
|
||||
}
|
||||
|
@ -1,19 +1,13 @@
|
||||
package net.sourceforge.pmd.lang.java.ast
|
||||
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTPrimitiveType.PrimitiveType
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTAssignableExpr.AccessType.READ
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTAssignableExpr.AccessType.WRITE
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTPrimitiveType.PrimitiveType
|
||||
import net.sourceforge.pmd.lang.java.ast.BinaryOp.ADD
|
||||
import net.sourceforge.pmd.lang.java.ast.IncrementOp.*
|
||||
import net.sourceforge.pmd.lang.java.ast.BinaryOp.SUB
|
||||
import net.sourceforge.pmd.lang.java.ast.ParserTestCtx.Companion.ExpressionParsingCtx
|
||||
import net.sourceforge.pmd.lang.java.ast.UnaryOp.*
|
||||
|
||||
/**
|
||||
* Nodes that previously corresponded to ASTAllocationExpression.
|
||||
*
|
||||
* @author Clément Fournier
|
||||
* @since 7.0.0
|
||||
*/
|
||||
class ASTUnaryExpressionTest : ParserTestSpec({
|
||||
|
||||
parserTest("Simple unary expressions") {
|
||||
@ -75,6 +69,27 @@ class ASTUnaryExpressionTest : ParserTestSpec({
|
||||
}
|
||||
}
|
||||
|
||||
"+(int)-a" should parseAs {
|
||||
unaryExpr(UNARY_PLUS) {
|
||||
castExpr {
|
||||
primitiveType(PrimitiveType.INT)
|
||||
unaryExpr(UNARY_MINUS) {
|
||||
variableAccess("a")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
"+-(int)a" should parseAs {
|
||||
unaryExpr(UNARY_PLUS) {
|
||||
unaryExpr(UNARY_MINUS) {
|
||||
castExpr {
|
||||
primitiveType(PrimitiveType.INT)
|
||||
variableAccess("a")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
"2 ++ 2" shouldNot parse()
|
||||
"2 -- 2" shouldNot parse()
|
||||
}
|
||||
@ -102,7 +117,7 @@ class ASTUnaryExpressionTest : ParserTestSpec({
|
||||
castExpr {
|
||||
classType("p")
|
||||
|
||||
unaryExpr(BITWISE_INVERSE) {
|
||||
unaryExpr(COMPLEMENT) {
|
||||
variableAccess("q", READ)
|
||||
}
|
||||
}
|
||||
@ -112,14 +127,14 @@ class ASTUnaryExpressionTest : ParserTestSpec({
|
||||
castExpr {
|
||||
classType("p")
|
||||
|
||||
unaryExpr(BOOLEAN_NOT) {
|
||||
unaryExpr(NEGATION) {
|
||||
variableAccess("q", READ)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
"(p)++" should parseAs {
|
||||
postfixMutation(INCREMENT) {
|
||||
unaryExpr(POST_INCREMENT) {
|
||||
parenthesized {
|
||||
variableAccess("p", WRITE)
|
||||
}
|
||||
@ -131,15 +146,24 @@ class ASTUnaryExpressionTest : ParserTestSpec({
|
||||
|
||||
"i+++i" should parseAs {
|
||||
additiveExpr(ADD) {
|
||||
postfixMutation(INCREMENT) {
|
||||
unaryExpr(POST_INCREMENT) {
|
||||
variableAccess("i", WRITE)
|
||||
}
|
||||
variableAccess("i", READ)
|
||||
}
|
||||
}
|
||||
|
||||
// "++i++" doesn't compile so don't test it
|
||||
"i---i" should parseAs {
|
||||
additiveExpr(SUB) {
|
||||
unaryExpr(POST_DECREMENT) {
|
||||
variableAccess("i", WRITE)
|
||||
}
|
||||
variableAccess("i", READ)
|
||||
}
|
||||
}
|
||||
|
||||
// "++i++" parses, but doesn't compile, so don't test it
|
||||
// same for eg "p+++++q" (which doesn't parse)
|
||||
|
||||
PrimitiveType
|
||||
.values()
|
||||
@ -170,7 +194,7 @@ class ASTUnaryExpressionTest : ParserTestSpec({
|
||||
castExpr {
|
||||
primitiveType(type)
|
||||
|
||||
prefixMutation(INCREMENT) {
|
||||
unaryExpr(PRE_INCREMENT) {
|
||||
variableAccess("q", WRITE)
|
||||
}
|
||||
}
|
||||
@ -180,7 +204,7 @@ class ASTUnaryExpressionTest : ParserTestSpec({
|
||||
castExpr {
|
||||
primitiveType(type)
|
||||
|
||||
prefixMutation(DECREMENT) {
|
||||
unaryExpr(PRE_DECREMENT) {
|
||||
variableAccess("q", WRITE)
|
||||
}
|
||||
}
|
||||
@ -198,16 +222,16 @@ class ASTUnaryExpressionTest : ParserTestSpec({
|
||||
inContext(ExpressionParsingCtx) {
|
||||
|
||||
"!!true" should parseAs {
|
||||
unaryExpr(BOOLEAN_NOT) {
|
||||
unaryExpr(BOOLEAN_NOT) {
|
||||
unaryExpr(NEGATION) {
|
||||
unaryExpr(NEGATION) {
|
||||
boolean(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
"~~1" should parseAs {
|
||||
unaryExpr(BITWISE_INVERSE) {
|
||||
unaryExpr(BITWISE_INVERSE) {
|
||||
unaryExpr(COMPLEMENT) {
|
||||
unaryExpr(COMPLEMENT) {
|
||||
number()
|
||||
}
|
||||
}
|
||||
@ -215,7 +239,7 @@ class ASTUnaryExpressionTest : ParserTestSpec({
|
||||
|
||||
"-~1" should parseAs {
|
||||
unaryExpr(UNARY_MINUS) {
|
||||
unaryExpr(BITWISE_INVERSE) {
|
||||
unaryExpr(COMPLEMENT) {
|
||||
number()
|
||||
}
|
||||
}
|
||||
|
@ -124,29 +124,13 @@ fun TreeNodeWrapper<Node, *>.methodCall(name: String, inside: NodeSpec<ASTMethod
|
||||
}
|
||||
|
||||
|
||||
fun TreeNodeWrapper<Node, *>.unaryExpr(op: UnaryOp, baseExpr: TreeNodeWrapper<Node, out ASTExpression>.() -> ASTExpression): ASTExpression =
|
||||
fun TreeNodeWrapper<Node, *>.unaryExpr(op: UnaryOp, baseExpr: TreeNodeWrapper<Node, ASTUnaryExpression>.() -> ASTExpression) =
|
||||
child<ASTUnaryExpression> {
|
||||
it::getOperator shouldBe op
|
||||
it::getOperand shouldBe baseExpr()
|
||||
}
|
||||
|
||||
|
||||
fun TreeNodeWrapper<Node, *>.postfixMutation(op: IncrementOp, baseExpr: ValuedNodeSpec<ASTIncrementExpression, ASTPrimaryExpression>) =
|
||||
incrementExpr(op, isPrefix = false, baseExpr = baseExpr)
|
||||
|
||||
fun TreeNodeWrapper<Node, *>.prefixMutation(op: IncrementOp, baseExpr: ValuedNodeSpec<ASTIncrementExpression, ASTPrimaryExpression>) =
|
||||
incrementExpr(op, isPrefix = true, baseExpr = baseExpr)
|
||||
|
||||
fun TreeNodeWrapper<Node, *>.incrementExpr(op: IncrementOp, isPrefix: Boolean, baseExpr: ValuedNodeSpec<ASTIncrementExpression, ASTPrimaryExpression>) =
|
||||
child<ASTIncrementExpression> {
|
||||
it::getOp shouldBe op
|
||||
it::isPostfix shouldBe !isPrefix
|
||||
it::isPrefix shouldBe isPrefix
|
||||
it::isDecrement shouldBe (op == IncrementOp.DECREMENT)
|
||||
it::isIncrement shouldBe (op == IncrementOp.INCREMENT)
|
||||
it::getOperand shouldBe baseExpr()
|
||||
}
|
||||
|
||||
fun TreeNodeWrapper<Node, *>.typeParamList(contents: NodeSpec<ASTTypeParameters>) =
|
||||
child(nodeSpec = contents)
|
||||
|
||||
|
Reference in New Issue
Block a user