Merge branch 'java-grammar' into grammar-new-statements

This commit is contained in:
Clément Fournier
2019-12-15 01:45:08 +01:00
17 changed files with 189 additions and 286 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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