Improve switch grammar
This commit is contained in:
@ -2782,49 +2782,36 @@ void SwitchStatement():
|
||||
"switch" "(" Expression() ")" SwitchBlock()
|
||||
}
|
||||
|
||||
void SwitchBlock() #void :
|
||||
void SwitchBlock() #void:
|
||||
{}
|
||||
{
|
||||
"{"
|
||||
(
|
||||
SwitchLabel()
|
||||
(
|
||||
"->" SwitchLabeledRulePart() (SwitchLabeledRule())*
|
||||
|
|
||||
":" (LOOKAHEAD(2) SwitchLabel() ":")*
|
||||
// the lookahead is to prevent choosing BlockStatement when the token is "default",
|
||||
// which could happen as local class declarations accept the "default" modifier.
|
||||
(LOOKAHEAD({shouldStartStatementInSwitch()}) BlockStatement())*
|
||||
(SwitchLabeledStatementGroup())*
|
||||
)
|
||||
)?
|
||||
LOOKAHEAD(SwitchLabel() ":") (SwitchFallthroughBranch())+
|
||||
| (SwitchArrowBranch())*
|
||||
)
|
||||
"}"
|
||||
}
|
||||
|
||||
void SwitchLabeledRule() #void :
|
||||
void SwitchArrowLahead() #void:
|
||||
{}
|
||||
{
|
||||
SwitchLabel() "->" SwitchLabeledRulePart()
|
||||
SwitchLabel() "->"
|
||||
}
|
||||
|
||||
void SwitchLabeledRulePart() #void:
|
||||
void SwitchArrowBranch():
|
||||
{}
|
||||
{
|
||||
( Expression() ";" ) #SwitchLabeledExpression(2)
|
||||
|
|
||||
( Block() ) #SwitchLabeledBlock(2)
|
||||
|
|
||||
( ThrowStatement() ) #SwitchLabeledThrowStatement(2)
|
||||
SwitchLabel() "->" (Expression() ";" | Block() | ThrowStatement())
|
||||
}
|
||||
|
||||
// For PMD 7, make this a real node to group the labels + statements
|
||||
void SwitchLabeledStatementGroup() #void:
|
||||
void SwitchFallthroughBranch():
|
||||
{}
|
||||
{
|
||||
(LOOKAHEAD(2) SwitchLabel() ":")+
|
||||
// the lookahead is to prevent choosing BlockStatement when the token is "default",
|
||||
// which could happen as local class declarations accept the "default" modifier.
|
||||
(LOOKAHEAD({shouldStartStatementInSwitch()}) BlockStatement() )*
|
||||
SwitchLabel() ":"
|
||||
// the lookahead is to prevent choosing BlockStatement when the token is "default",
|
||||
// which could happen as local class declarations accept the "default" modifier.
|
||||
(LOOKAHEAD({shouldStartStatementInSwitch()}) BlockStatement() )*
|
||||
}
|
||||
|
||||
void SwitchLabel() :
|
||||
|
@ -16,7 +16,7 @@ import java.util.Iterator;
|
||||
*
|
||||
* </pre>
|
||||
*/
|
||||
public final class ASTBlock extends AbstractStatement implements Iterable<ASTStatement> {
|
||||
public final class ASTBlock extends AbstractStatement implements Iterable<ASTStatement>, ASTSwitchArrowRHS {
|
||||
|
||||
private boolean containsComment;
|
||||
|
||||
|
@ -36,7 +36,11 @@ import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
*
|
||||
* </pre>
|
||||
*/
|
||||
public interface ASTExpression extends JavaNode, TypeNode, ASTMemberValue {
|
||||
public interface ASTExpression
|
||||
extends JavaNode,
|
||||
TypeNode,
|
||||
ASTMemberValue,
|
||||
ASTSwitchArrowRHS {
|
||||
|
||||
/**
|
||||
* Always returns true. This is to allow XPath queries
|
||||
|
@ -0,0 +1,49 @@
|
||||
/**
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*/
|
||||
|
||||
package net.sourceforge.pmd.lang.java.ast;
|
||||
|
||||
/**
|
||||
* A non-fallthrough switch rule, introduced with switch expressions.
|
||||
* See {@link ASTSwitchLike}.
|
||||
*
|
||||
* <pre class="grammar">
|
||||
*
|
||||
* SwitchLabeledExpression ::= {@link ASTSwitchLabel SwitchLabel} "->" {@link ASTSwitchArrowRHS SwitchArrowRHS}
|
||||
*
|
||||
* </pre>
|
||||
*/
|
||||
public final class ASTSwitchArrowBranch extends AbstractJavaNode implements LeftRecursiveNode {
|
||||
|
||||
ASTSwitchArrowBranch(int id) {
|
||||
super(id);
|
||||
}
|
||||
|
||||
ASTSwitchArrowBranch(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);
|
||||
}
|
||||
|
||||
|
||||
/** Returns the label, which may be compound. */
|
||||
public ASTSwitchLabel getLabel() {
|
||||
return (ASTSwitchLabel) getFirstChild();
|
||||
}
|
||||
|
||||
/** Returns the right hand side of the arrow. */
|
||||
public ASTSwitchArrowRHS getRightHandSide() {
|
||||
return (ASTSwitchArrowRHS) getLastChild();
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
/**
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*/
|
||||
|
||||
package net.sourceforge.pmd.lang.java.ast;
|
||||
|
||||
/**
|
||||
* A node that can appear as the right-hand-side of a {@link ASTSwitchArrowBranch SwitchArrowRule}.
|
||||
*
|
||||
* <pre class="grammar">
|
||||
*
|
||||
* SwitchArrowRightHandSide ::= {@link ASTExpression Expression}
|
||||
* | {@link ASTBlock Block}
|
||||
* | {@link ASTThrowStatement ThrowStatement}
|
||||
*
|
||||
* </pre>
|
||||
*/
|
||||
public interface ASTSwitchArrowRHS extends JavaNode {
|
||||
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
/**
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*/
|
||||
|
||||
package net.sourceforge.pmd.lang.java.ast;
|
||||
|
||||
/**
|
||||
* A branch of a {@link ASTSwitchLike SwitchLike}.
|
||||
*
|
||||
* <pre class="grammar">
|
||||
*
|
||||
* SwitchBranch ::= {@link ASTSwitchArrowBranch SwitchArrowBranch}
|
||||
* | {@link ASTSwitchFallthroughBranch FallthroughBranch}
|
||||
*
|
||||
* </pre>
|
||||
*/
|
||||
public interface ASTSwitchBranch extends JavaNode {
|
||||
|
||||
/**
|
||||
* Returns the label, which may be compound.
|
||||
*/
|
||||
default ASTSwitchLabel getLabel() {
|
||||
return (ASTSwitchLabel) getFirstChild();
|
||||
}
|
||||
|
||||
}
|
@ -6,32 +6,19 @@ package net.sourceforge.pmd.lang.java.ast;
|
||||
|
||||
/**
|
||||
* A switch expression, as introduced in Java 12. This node only occurs
|
||||
* in the contexts where an expression is expected. In particular, if
|
||||
* in the contexts where an expression is expected. In particular,
|
||||
* switch constructs occurring in statement position are parsed as a
|
||||
* {@linkplain ASTSwitchStatement SwitchStatement}, and not a
|
||||
* {@link ASTSwitchExpression SwitchExpression} within a
|
||||
* {@link ASTStatementExpression StatementExpression}. That is
|
||||
* because switch statements are not required to be exhaustive, contrary
|
||||
* {@link ASTExpressionStatement ExpressionStatement}. That is because
|
||||
* switch statements are not required to be exhaustive, contrary
|
||||
* to switch expressions.
|
||||
*
|
||||
* <p>Their syntax is identical though.
|
||||
*
|
||||
* <p>TODO Do we group the statements of a SwitchNormalBlock ? Do we unify
|
||||
* their interface ? SwitchStatement implements Iterator<SwitchLabel>
|
||||
* which seems shitty tbh.
|
||||
*
|
||||
* <pre class="grammar">
|
||||
*
|
||||
* SwitchExpression ::= "switch" "(" {@link ASTExpression Expression} ")" SwitchBlock
|
||||
*
|
||||
* SwitchBlock ::= SwitchArrowBlock | SwitchNormalBlock
|
||||
*
|
||||
* SwitchArrowBlock ::= "{" ( {@link ASTSwitchLabeledRule SwitchLabeledRule} )* "}"
|
||||
* SwitchNormalBlock ::= "{" ( {@linkplain ASTSwitchLabel SwitchLabel} {@linkplain ASTBlockStatement BlockStatement}* )* "}"
|
||||
*
|
||||
* </pre>
|
||||
* <p>Their syntax is identical though, and described on {@link ASTSwitchLike}.
|
||||
*/
|
||||
public final class ASTSwitchExpression extends AbstractJavaExpr implements ASTExpression {
|
||||
public final class ASTSwitchExpression extends AbstractJavaExpr
|
||||
implements ASTExpression,
|
||||
ASTSwitchLike {
|
||||
|
||||
ASTSwitchExpression(int id) {
|
||||
super(id);
|
||||
@ -52,13 +39,4 @@ public final class ASTSwitchExpression extends AbstractJavaExpr implements ASTEx
|
||||
visitor.visit(this, data);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the expression tested by this switch.
|
||||
* This is the expression between the parentheses.
|
||||
*/
|
||||
public ASTExpression getTestedExpression() {
|
||||
return (ASTExpression) jjtGetChild(0);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,65 @@
|
||||
/**
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*/
|
||||
|
||||
package net.sourceforge.pmd.lang.java.ast;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A fallthrough switch branch. This contains exactly one label, and zero
|
||||
* or more statements. Fallthrough must be handled by looking at the siblings.
|
||||
* For example, in the following, the branch for {@code case 1:} has no statements,
|
||||
* while the branch for {@code case 2:} has two.
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* switch (foo) {
|
||||
* case 1:
|
||||
* case 2:
|
||||
* do1Or2();
|
||||
* break;
|
||||
* default:
|
||||
* doDefault();
|
||||
* break;
|
||||
* }
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
*
|
||||
* <pre class="grammar">
|
||||
*
|
||||
* SwitchFallthroughBranch ::= {@link ASTSwitchLabel SwitchLabel} ":" {@link ASTStatement Statement}*
|
||||
*
|
||||
* </pre>
|
||||
*/
|
||||
public final class ASTSwitchFallthroughBranch extends AbstractJavaNode
|
||||
implements LeftRecursiveNode, ASTSwitchBranch {
|
||||
|
||||
ASTSwitchFallthroughBranch(int id) {
|
||||
super(id);
|
||||
}
|
||||
|
||||
ASTSwitchFallthroughBranch(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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of statements dominated by the labels. This list is possibly empty.
|
||||
*/
|
||||
public List<ASTStatement> getStatements() {
|
||||
return findChildrenOfType(ASTStatement.class);
|
||||
}
|
||||
|
||||
}
|
@ -5,6 +5,7 @@
|
||||
package net.sourceforge.pmd.lang.java.ast;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
/**
|
||||
@ -37,10 +38,19 @@ public final class ASTSwitchLabel extends AbstractJavaNode implements Iterable<A
|
||||
isDefault = true;
|
||||
}
|
||||
|
||||
/** Returns true if this is the {@code default} label. */
|
||||
public boolean isDefault() {
|
||||
return isDefault;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the expressions of this label, or an empty list if this
|
||||
* is the default label.
|
||||
*/
|
||||
public List<ASTExpression> getExprList() {
|
||||
return findChildrenOfType(ASTExpression.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object jjtAccept(JavaParserVisitor visitor, Object data) {
|
||||
return visitor.visit(this, data);
|
||||
|
@ -1,36 +0,0 @@
|
||||
/**
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*/
|
||||
|
||||
package net.sourceforge.pmd.lang.java.ast;
|
||||
|
||||
/**
|
||||
* One of the {@linkplain ASTSwitchLabeledRule SwitchLabeledRule}s.
|
||||
*
|
||||
* <pre class="grammar">
|
||||
*
|
||||
* SwitchLabeledBlock ::= {@link ASTSwitchLabel SwitchLabel} "->" {@link ASTBlock Block}
|
||||
*
|
||||
* </pre>
|
||||
*/
|
||||
public final class ASTSwitchLabeledBlock extends AbstractJavaNode implements ASTSwitchLabeledRule {
|
||||
|
||||
ASTSwitchLabeledBlock(int id) {
|
||||
super(id);
|
||||
}
|
||||
|
||||
ASTSwitchLabeledBlock(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);
|
||||
}
|
||||
}
|
@ -1,36 +0,0 @@
|
||||
/**
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*/
|
||||
|
||||
package net.sourceforge.pmd.lang.java.ast;
|
||||
|
||||
/**
|
||||
* One of the {@linkplain ASTSwitchLabeledRule SwitchLabeledRule}s.
|
||||
*
|
||||
* <pre class="grammar">
|
||||
*
|
||||
* SwitchLabeledExpression ::= {@link ASTSwitchLabel SwitchLabel} "->" {@link ASTExpression Expression}
|
||||
*
|
||||
* </pre>
|
||||
*/
|
||||
public final class ASTSwitchLabeledExpression extends AbstractJavaNode implements ASTSwitchLabeledRule {
|
||||
|
||||
ASTSwitchLabeledExpression(int id) {
|
||||
super(id);
|
||||
}
|
||||
|
||||
ASTSwitchLabeledExpression(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);
|
||||
}
|
||||
}
|
@ -1,29 +0,0 @@
|
||||
/**
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*/
|
||||
|
||||
package net.sourceforge.pmd.lang.java.ast;
|
||||
|
||||
/**
|
||||
* A non-fallthrough switch case, written with an arrow ({@code ->})
|
||||
* instead of a colon.
|
||||
*
|
||||
* <pre class="grammar">
|
||||
*
|
||||
* SwitchLabeledRule ::= {@link ASTSwitchLabeledExpression SwitchLabeledExpression}
|
||||
* | {@link ASTSwitchLabeledBlock SwitchLabeledBlock}
|
||||
* | {@link ASTSwitchLabeledThrowStatement SwitchLabeledThrowStatement}
|
||||
*
|
||||
* </pre>
|
||||
*/
|
||||
public interface ASTSwitchLabeledRule extends JavaNode, LeftRecursiveNode {
|
||||
// needs to extend LeftRecursiveNode to fit the text range to the children
|
||||
|
||||
/**
|
||||
* Returns the label of this expression.
|
||||
*/
|
||||
default ASTSwitchLabel getLabel() {
|
||||
return (ASTSwitchLabel) jjtGetChild(0);
|
||||
}
|
||||
|
||||
}
|
@ -1,36 +0,0 @@
|
||||
/**
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*/
|
||||
|
||||
package net.sourceforge.pmd.lang.java.ast;
|
||||
|
||||
/**
|
||||
* One of the {@linkplain ASTSwitchLabeledRule SwitchLabeledRule}s.
|
||||
*
|
||||
* <pre class="grammar">
|
||||
*
|
||||
* SwitchLabeledThrowStatement ::= {@link ASTSwitchLabel SwitchLabel} "->" {@link ASTThrowStatement ThrowStatement}
|
||||
*
|
||||
* </pre>
|
||||
*/
|
||||
public final class ASTSwitchLabeledThrowStatement extends AbstractJavaNode implements ASTSwitchLabeledRule {
|
||||
|
||||
ASTSwitchLabeledThrowStatement(int id) {
|
||||
super(id);
|
||||
}
|
||||
|
||||
ASTSwitchLabeledThrowStatement(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);
|
||||
}
|
||||
}
|
@ -0,0 +1,100 @@
|
||||
/**
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*/
|
||||
|
||||
package net.sourceforge.pmd.lang.java.ast;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.lang3.EnumUtils;
|
||||
|
||||
import net.sourceforge.pmd.lang.ast.NodeStream;
|
||||
|
||||
|
||||
/**
|
||||
* Common supertype for {@linkplain ASTSwitchStatement switch statements}
|
||||
* and {@linkplain ASTSwitchExpression switch expressions}. Their grammar
|
||||
* is identical, and is described below. The difference is that switch
|
||||
* expressions need to be exhaustive.
|
||||
*
|
||||
* <pre class="grammar">
|
||||
*
|
||||
* SwitchLike ::= {@link ASTSwitchExpression SwitchExpression}
|
||||
* | {@link ASTSwitchStatement SwitchStatement}
|
||||
*
|
||||
* ::= "switch" "(" {@link ASTExpression Expression} ")" SwitchBlock
|
||||
*
|
||||
* SwitchBlock ::= SwitchArrowBlock | SwitchNormalBlock
|
||||
*
|
||||
* SwitchArrowBlock ::= "{" {@link ASTSwitchArrowBranch SwitchArrowBranch}* "}"
|
||||
* SwitchNormalBlock ::= "{" {@linkplain ASTSwitchFallthroughBranch SwitchFallthroughBranch}* "}"
|
||||
*
|
||||
* </pre>
|
||||
*/
|
||||
public interface ASTSwitchLike extends JavaNode, Iterable<ASTSwitchBranch> {
|
||||
|
||||
/**
|
||||
* Returns true if this switch has a {@code default} case.
|
||||
*/
|
||||
default boolean hasDefaultCase() {
|
||||
ASTSwitchBranch last = getBranches().last();
|
||||
return last != null && last.getLabel().isDefault();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns a stream of all branches of this switch.
|
||||
*/
|
||||
default NodeStream<ASTSwitchBranch> getBranches() {
|
||||
return children(ASTSwitchBranch.class);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the expression tested by this switch.
|
||||
* This is the expression between the parentheses.
|
||||
*/
|
||||
default ASTExpression getTestedExpression() {
|
||||
return (ASTExpression) jjtGetChild(0);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns true if this switch statement tests an expression
|
||||
* having an enum type and all the constants of this type
|
||||
* are covered by a switch case. Returns false if the type of
|
||||
* the tested expression could not be resolved.
|
||||
*/
|
||||
default boolean isExhaustiveEnumSwitch() {
|
||||
ASTExpression expression = getTestedExpression();
|
||||
|
||||
if (expression.getType() == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Enum.class.isAssignableFrom(expression.getType())) {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
Set<String> constantNames = EnumUtils.getEnumMap((Class<? extends Enum>) expression.getType()).keySet();
|
||||
|
||||
for (ASTSwitchBranch branch : this) {
|
||||
// since this is an enum switch, the labels are necessarily
|
||||
// the simple name of some enum constant.
|
||||
|
||||
constantNames.remove(branch.getLabel().getFirstDescendantOfType(ASTName.class).getImage());
|
||||
|
||||
}
|
||||
|
||||
return constantNames.isEmpty();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
default Iterator<ASTSwitchBranch> iterator() {
|
||||
return children(ASTSwitchBranch.class).iterator();
|
||||
}
|
||||
}
|
@ -4,18 +4,12 @@
|
||||
|
||||
package net.sourceforge.pmd.lang.java.ast;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.lang3.EnumUtils;
|
||||
|
||||
|
||||
/**
|
||||
* Represents a {@code switch} statement. Its syntax is identical to
|
||||
* {@link ASTSwitchExpression SwitchExpression}, though it does not need
|
||||
* to be exhaustive. See the doc of that node for details.
|
||||
* Represents a {@code switch} statement. See {@link ASTSwitchLike} for
|
||||
* its grammar.
|
||||
*/
|
||||
public final class ASTSwitchStatement extends AbstractStatement implements Iterable<ASTSwitchLabel> {
|
||||
public final class ASTSwitchStatement extends AbstractStatement implements ASTSwitchLike {
|
||||
|
||||
ASTSwitchStatement(int id) {
|
||||
super(id);
|
||||
}
|
||||
@ -36,64 +30,4 @@ public final class ASTSwitchStatement extends AbstractStatement implements Itera
|
||||
visitor.visit(this, data);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns true if this switch has a {@code default} case.
|
||||
*/
|
||||
public boolean hasDefaultCase() {
|
||||
for (ASTSwitchLabel label : this) {
|
||||
if (label.isDefault()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the expression tested by this switch.
|
||||
* This is the expression between the parentheses.
|
||||
*/
|
||||
public ASTExpression getTestedExpression() {
|
||||
return (ASTExpression) jjtGetChild(0);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns true if this switch statement tests an expression
|
||||
* having an enum type and all the constants of this type
|
||||
* are covered by a switch case. Returns false if the type of
|
||||
* the tested expression could not be resolved.
|
||||
*/
|
||||
public boolean isExhaustiveEnumSwitch() {
|
||||
ASTExpression expression = getTestedExpression();
|
||||
|
||||
if (expression.getType() == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Enum.class.isAssignableFrom(expression.getType())) {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
Set<String> constantNames = EnumUtils.getEnumMap((Class<? extends Enum>) expression.getType()).keySet();
|
||||
|
||||
for (ASTSwitchLabel label : this) {
|
||||
// since this is an enum switch, the labels are necessarily
|
||||
// the simple name of some enum constant.
|
||||
|
||||
constantNames.remove(label.getFirstDescendantOfType(ASTName.class).getImage());
|
||||
|
||||
}
|
||||
|
||||
return constantNames.isEmpty();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Iterator<ASTSwitchLabel> iterator() {
|
||||
return children(ASTSwitchLabel.class).iterator();
|
||||
}
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ package net.sourceforge.pmd.lang.java.ast;
|
||||
*
|
||||
* </pre>
|
||||
*/
|
||||
public final class ASTThrowStatement extends AbstractStatement {
|
||||
public final class ASTThrowStatement extends AbstractStatement implements ASTSwitchArrowRHS {
|
||||
|
||||
ASTThrowStatement(int id) {
|
||||
super(id);
|
||||
@ -34,7 +34,9 @@ public final class ASTThrowStatement extends AbstractStatement {
|
||||
visitor.visit(this, data);
|
||||
}
|
||||
|
||||
/** Returns the expression for the thrown exception. */
|
||||
/**
|
||||
* Returns the expression for the thrown exception.
|
||||
*/
|
||||
public ASTExpression getExpr() {
|
||||
return (ASTExpression) getFirstChild();
|
||||
}
|
||||
|
@ -23,7 +23,6 @@ public class ASTYieldStatement extends AbstractStatement {
|
||||
super(p, id);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Object jjtAccept(JavaParserVisitor visitor, Object data) {
|
||||
return visitor.visit(this, data);
|
||||
|
@ -37,10 +37,6 @@ public class SideEffectingVisitorAdapter<T> implements SideEffectingVisitor<T> {
|
||||
// TODO delegation
|
||||
|
||||
|
||||
public void visit(ASTSwitchLabeledRule node, T data) {
|
||||
visit((JavaNode) node, data);
|
||||
}
|
||||
|
||||
public void visit(ASTAnyTypeDeclaration node, T data) {
|
||||
visit((JavaNode) node, data);
|
||||
}
|
||||
|
@ -31,9 +31,9 @@ import net.sourceforge.pmd.lang.java.ast.ASTNumericLiteral;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTReceiverParameter;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTResource;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTStringLiteral;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTSwitchArrowBranch;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTSwitchExpression;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTSwitchLabel;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTSwitchLabeledRule;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTTryStatement;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTType;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTTypeArguments;
|
||||
@ -275,7 +275,7 @@ public class LanguageLevelChecker<T> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(ASTSwitchLabeledRule node, T data) {
|
||||
public void visit(ASTSwitchArrowBranch node, T data) {
|
||||
check(node, PreviewFeature.SWITCH_RULES, data);
|
||||
visitChildren(node, data);
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ import net.sourceforge.pmd.lang.java.ast.ASTDoStatement;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTForStatement;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTForeachStatement;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTIfStatement;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTSwitchLabel;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTSwitchBranch;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTSwitchStatement;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTThrowStatement;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTWhileStatement;
|
||||
@ -59,16 +59,16 @@ public class CycloVisitor extends JavaParserVisitorAdapter {
|
||||
((MutableInt) data).add(CycloMetric.booleanExpressionComplexity(node.getTestedExpression()));
|
||||
}
|
||||
|
||||
for (ASTSwitchLabel label : node) {
|
||||
if (label.isDefault()) {
|
||||
for (ASTSwitchBranch branch : node) {
|
||||
if (branch.getLabel().isDefault()) {
|
||||
// like for "else", default is not a decision point
|
||||
continue;
|
||||
}
|
||||
|
||||
if (considerBooleanPaths) {
|
||||
((MutableInt) data).increment();
|
||||
} else if (node.jjtGetNumChildren() > 1 + label.jjtGetChildIndex()
|
||||
&& node.jjtGetChild(label.jjtGetChildIndex() + 1) instanceof ASTBlockStatement) {
|
||||
} else if (node.jjtGetNumChildren() > 1 + branch.jjtGetChildIndex()
|
||||
&& node.jjtGetChild(branch.jjtGetChildIndex() + 1) instanceof ASTBlockStatement) {
|
||||
// an empty label is only counted if we count boolean paths
|
||||
((MutableInt) data).increment();
|
||||
}
|
||||
|
@ -34,9 +34,6 @@ import net.sourceforge.pmd.lang.java.ast.ASTArgumentList;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTArguments;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTArrayDimsAndInits;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTArrayType;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTBlock;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTBlockStatement;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTBreakStatement;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTCastExpression;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTClassLiteral;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration;
|
||||
@ -71,7 +68,6 @@ import net.sourceforge.pmd.lang.java.ast.ASTReferenceType;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTRelationalExpression;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTShiftExpression;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTSwitchExpression;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTSwitchLabeledRule;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTType;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTTypeArgument;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTTypeArguments;
|
||||
@ -83,7 +79,6 @@ import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclarator;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclaratorId;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTVariableInitializer;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTWildcardBounds;
|
||||
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;
|
||||
@ -1135,60 +1130,59 @@ public class ClassTypeResolver extends JavaParserVisitorAdapter {
|
||||
@Override
|
||||
public Object visit(ASTSwitchExpression node, Object data) {
|
||||
super.visit(node, data);
|
||||
|
||||
JavaTypeDefinition type = null;
|
||||
// first try to determine the type based on the first expression/break/yield of a switch rule
|
||||
List<ASTSwitchLabeledRule> rules = node.findChildrenOfType(ASTSwitchLabeledRule.class);
|
||||
for (ASTSwitchLabeledRule rule : rules) {
|
||||
Node body = rule.jjtGetChild(1); // second child is either Expression, Block, ThrowStatement
|
||||
if (body instanceof ASTExpression) {
|
||||
type = ((ASTExpression) body).getTypeDefinition();
|
||||
break;
|
||||
} else if (body instanceof ASTBlock) {
|
||||
List<ASTBreakStatement> breaks = body.findDescendantsOfType(ASTBreakStatement.class);
|
||||
if (!breaks.isEmpty()) {
|
||||
ASTExpression expression = breaks.get(0).getFirstChildOfType(ASTExpression.class);
|
||||
if (expression != null) {
|
||||
type = expression.getTypeDefinition();
|
||||
break;
|
||||
}
|
||||
}
|
||||
List<ASTYieldStatement> yields = body.findDescendantsOfType(ASTYieldStatement.class);
|
||||
if (!yields.isEmpty()) {
|
||||
ASTExpression expression = yields.get(0).getFirstChildOfType(ASTExpression.class);
|
||||
if (expression != null) {
|
||||
type = expression.getTypeDefinition();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (type == null) {
|
||||
// now check the labels and their expressions of break/yield statements
|
||||
for (int i = 0; i < node.jjtGetNumChildren(); i++) {
|
||||
Node child = node.jjtGetChild(i);
|
||||
if (child instanceof ASTBlockStatement) {
|
||||
List<ASTBreakStatement> breaks = child.findDescendantsOfType(ASTBreakStatement.class);
|
||||
if (!breaks.isEmpty()) {
|
||||
ASTExpression expression = breaks.get(0).getFirstChildOfType(ASTExpression.class);
|
||||
if (expression != null) {
|
||||
type = expression.getTypeDefinition();
|
||||
break;
|
||||
}
|
||||
}
|
||||
List<ASTYieldStatement> yields = child.findDescendantsOfType(ASTYieldStatement.class);
|
||||
if (!yields.isEmpty()) {
|
||||
ASTExpression expression = yields.get(0).getFirstChildOfType(ASTExpression.class);
|
||||
if (expression != null && expression.getTypeDefinition() != null) {
|
||||
type = expression.getTypeDefinition();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setTypeDefinition(node, type);
|
||||
//
|
||||
// JavaTypeDefinition type = null;
|
||||
// // first try to determine the type based on the first expression/break/yield of a switch rule
|
||||
// List<ASTSwitchLabeledRule> rules = node.findChildrenOfType(ASTSwitchLabeledRule.class);
|
||||
// for (ASTSwitchLabeledRule rule : rules) {
|
||||
// Node body = rule.jjtGetChild(1); // second child is either Expression, Block, ThrowStatement
|
||||
// if (body instanceof ASTExpression) {
|
||||
// type = ((ASTExpression) body).getTypeDefinition();
|
||||
// break;
|
||||
// } else if (body instanceof ASTBlock) {
|
||||
// List<ASTBreakStatement> breaks = body.findDescendantsOfType(ASTBreakStatement.class);
|
||||
// if (!breaks.isEmpty()) {
|
||||
// ASTExpression expression = breaks.get(0).getFirstChildOfType(ASTExpression.class);
|
||||
// if (expression != null) {
|
||||
// type = expression.getTypeDefinition();
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// List<ASTYieldStatement> yields = body.findDescendantsOfType(ASTYieldStatement.class);
|
||||
// if (!yields.isEmpty()) {
|
||||
// ASTExpression expression = yields.get(0).getFirstChildOfType(ASTExpression.class);
|
||||
// if (expression != null) {
|
||||
// type = expression.getTypeDefinition();
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// if (type == null) {
|
||||
// // now check the labels and their expressions of break/yield statements
|
||||
// for (int i = 0; i < node.jjtGetNumChildren(); i++) {
|
||||
// Node child = node.jjtGetChild(i);
|
||||
// if (child instanceof ASTBlockStatement) {
|
||||
// List<ASTBreakStatement> breaks = child.findDescendantsOfType(ASTBreakStatement.class);
|
||||
// if (!breaks.isEmpty()) {
|
||||
// ASTExpression expression = breaks.get(0).getFirstChildOfType(ASTExpression.class);
|
||||
// if (expression != null) {
|
||||
// type = expression.getTypeDefinition();
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// List<ASTYieldStatement> yields = child.findDescendantsOfType(ASTYieldStatement.class);
|
||||
// if (!yields.isEmpty()) {
|
||||
// ASTExpression expression = yields.get(0).getFirstChildOfType(ASTExpression.class);
|
||||
// if (expression != null && expression.getTypeDefinition() != null) {
|
||||
// type = expression.getTypeDefinition();
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// setTypeDefinition(node, type);
|
||||
return data;
|
||||
}
|
||||
|
||||
|
@ -8,7 +8,6 @@ import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
@ -31,88 +30,15 @@ public class Java12Test {
|
||||
ParserTstUtil.parseAndTypeResolveJava("11", loadSource("MultipleCaseLabels.java"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMultipleCaseLabels() {
|
||||
ASTCompilationUnit compilationUnit = ParserTstUtil.parseAndTypeResolveJava("12-preview",
|
||||
loadSource("MultipleCaseLabels.java"));
|
||||
Assert.assertNotNull(compilationUnit);
|
||||
ASTSwitchStatement switchStatement = compilationUnit.getFirstDescendantOfType(ASTSwitchStatement.class);
|
||||
Assert.assertTrue(switchStatement.jjtGetChild(0) instanceof ASTExpression);
|
||||
Assert.assertTrue(switchStatement.jjtGetChild(1) instanceof ASTSwitchLabel);
|
||||
ASTSwitchLabel switchLabel = switchStatement.getFirstChildOfType(ASTSwitchLabel.class);
|
||||
Assert.assertEquals(3, switchLabel.findChildrenOfType(ASTExpression.class).size());
|
||||
}
|
||||
|
||||
@Test(expected = ParseException.class)
|
||||
public void testSwitchRulesJava11() {
|
||||
ParserTstUtil.parseAndTypeResolveJava("11", loadSource("SwitchRules.java"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSwitchRules() {
|
||||
ASTCompilationUnit compilationUnit = ParserTstUtil.parseAndTypeResolveJava("12-preview",
|
||||
loadSource("SwitchRules.java"));
|
||||
Assert.assertNotNull(compilationUnit);
|
||||
ASTSwitchStatement switchStatement = compilationUnit.getFirstDescendantOfType(ASTSwitchStatement.class);
|
||||
Assert.assertTrue(switchStatement.jjtGetChild(0) instanceof ASTExpression);
|
||||
Assert.assertTrue(switchStatement.jjtGetChild(1) instanceof ASTSwitchLabeledExpression);
|
||||
ASTSwitchLabeledExpression switchLabeledExpression = (ASTSwitchLabeledExpression) switchStatement.jjtGetChild(1);
|
||||
Assert.assertEquals(2, switchLabeledExpression.jjtGetNumChildren());
|
||||
Assert.assertTrue(switchLabeledExpression.jjtGetChild(0) instanceof ASTSwitchLabel);
|
||||
Assert.assertTrue(switchLabeledExpression.jjtGetChild(1) instanceof ASTExpression);
|
||||
|
||||
ASTSwitchLabeledBlock switchLabeledBlock = (ASTSwitchLabeledBlock) switchStatement.jjtGetChild(4);
|
||||
Assert.assertEquals(2, switchLabeledBlock.jjtGetNumChildren());
|
||||
Assert.assertTrue(switchLabeledBlock.jjtGetChild(0) instanceof ASTSwitchLabel);
|
||||
Assert.assertTrue(switchLabeledBlock.jjtGetChild(1) instanceof ASTBlock);
|
||||
|
||||
ASTSwitchLabeledThrowStatement switchLabeledThrowStatement = (ASTSwitchLabeledThrowStatement) switchStatement.jjtGetChild(5);
|
||||
Assert.assertEquals(2, switchLabeledThrowStatement.jjtGetNumChildren());
|
||||
Assert.assertTrue(switchLabeledThrowStatement.jjtGetChild(0) instanceof ASTSwitchLabel);
|
||||
Assert.assertTrue(switchLabeledThrowStatement.jjtGetChild(1) instanceof ASTThrowStatement);
|
||||
}
|
||||
|
||||
@Test(expected = ParseException.class)
|
||||
public void testSwitchExpressionsJava11() {
|
||||
ParserTstUtil.parseAndTypeResolveJava("11", loadSource("SwitchExpressions.java"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSwitchExpressions() {
|
||||
ASTCompilationUnit compilationUnit = ParserTstUtil.parseAndTypeResolveJava("12-preview",
|
||||
loadSource("SwitchExpressions.java"));
|
||||
Assert.assertNotNull(compilationUnit);
|
||||
|
||||
ASTSwitchExpression switchExpression = compilationUnit.getFirstDescendantOfType(ASTSwitchExpression.class);
|
||||
Assert.assertEquals(6, switchExpression.jjtGetNumChildren());
|
||||
Assert.assertTrue(switchExpression.jjtGetChild(0) instanceof ASTExpression);
|
||||
Assert.assertEquals(5, switchExpression.findChildrenOfType(ASTSwitchLabeledRule.class).size());
|
||||
|
||||
ASTLocalVariableDeclaration localVar = compilationUnit.findDescendantsOfType(ASTLocalVariableDeclaration.class).get(1);
|
||||
ASTVariableDeclarator localVarDecl = localVar.getFirstChildOfType(ASTVariableDeclarator.class);
|
||||
Assert.assertEquals(Integer.TYPE, localVarDecl.getType());
|
||||
Assert.assertEquals(Integer.TYPE, switchExpression.getType());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSwitchExpressionsBreak() {
|
||||
ASTCompilationUnit compilationUnit = ParserTstUtil.parseAndTypeResolveJava("12-preview",
|
||||
loadSource("SwitchExpressionsBreak.java"));
|
||||
Assert.assertNotNull(compilationUnit);
|
||||
|
||||
ASTSwitchExpression switchExpression = compilationUnit.getFirstDescendantOfType(ASTSwitchExpression.class);
|
||||
Assert.assertEquals(11, switchExpression.jjtGetNumChildren());
|
||||
Assert.assertTrue(switchExpression.jjtGetChild(0) instanceof ASTExpression);
|
||||
Assert.assertEquals(5, switchExpression.findChildrenOfType(ASTSwitchLabel.class).size());
|
||||
|
||||
ASTBreakStatement breakStatement = switchExpression.getFirstDescendantOfType(ASTBreakStatement.class);
|
||||
Assert.assertEquals("SwitchExpressionsBreak.SIX", breakStatement.getImage());
|
||||
Assert.assertTrue(breakStatement.jjtGetChild(0) instanceof ASTExpression);
|
||||
|
||||
ASTLocalVariableDeclaration localVar = compilationUnit.findDescendantsOfType(ASTLocalVariableDeclaration.class).get(1);
|
||||
ASTVariableDeclarator localVarDecl = localVar.getFirstChildOfType(ASTVariableDeclarator.class);
|
||||
Assert.assertEquals(Integer.TYPE, localVarDecl.getType());
|
||||
Assert.assertEquals(Integer.TYPE, switchExpression.getType());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -8,7 +8,6 @@ import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
@ -27,44 +26,6 @@ public class Java13Test {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSwitchExpressions() {
|
||||
ASTCompilationUnit compilationUnit = ParserTstUtil.parseAndTypeResolveJava("13-preview",
|
||||
loadSource("SwitchExpressions.java"));
|
||||
Assert.assertNotNull(compilationUnit);
|
||||
|
||||
ASTSwitchExpression switchExpression = compilationUnit.getFirstDescendantOfType(ASTSwitchExpression.class);
|
||||
Assert.assertEquals(4, switchExpression.jjtGetNumChildren());
|
||||
Assert.assertTrue(switchExpression.jjtGetChild(0) instanceof ASTExpression);
|
||||
Assert.assertEquals(3, switchExpression.findChildrenOfType(ASTSwitchLabeledRule.class).size());
|
||||
Assert.assertEquals(1, switchExpression.findChildrenOfType(ASTSwitchLabeledBlock.class).size());
|
||||
Assert.assertEquals(1, switchExpression.findDescendantsOfType(ASTYieldStatement.class).size());
|
||||
ASTYieldStatement yieldStatement = switchExpression.getFirstDescendantOfType(ASTYieldStatement.class);
|
||||
Assert.assertEquals(Integer.TYPE, yieldStatement.getExpr().getType());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSwitchExpressionsYield() {
|
||||
ASTCompilationUnit compilationUnit = ParserTstUtil.parseAndTypeResolveJava("13-preview",
|
||||
loadSource("SwitchExpressionsYield.java"));
|
||||
Assert.assertNotNull(compilationUnit);
|
||||
|
||||
ASTSwitchExpression switchExpression = compilationUnit.getFirstDescendantOfType(ASTSwitchExpression.class);
|
||||
Assert.assertEquals(11, switchExpression.jjtGetNumChildren());
|
||||
Assert.assertTrue(switchExpression.jjtGetChild(0) instanceof ASTExpression);
|
||||
Assert.assertEquals(5, switchExpression.findChildrenOfType(ASTSwitchLabel.class).size());
|
||||
|
||||
ASTYieldStatement yieldStatement = switchExpression.getFirstDescendantOfType(ASTYieldStatement.class);
|
||||
Assert.assertEquals("SwitchExpressionsBreak.SIX", yieldStatement.getImage());
|
||||
Assert.assertTrue(yieldStatement.jjtGetChild(0) instanceof ASTExpression);
|
||||
|
||||
ASTLocalVariableDeclaration localVar = compilationUnit.findDescendantsOfType(ASTLocalVariableDeclaration.class)
|
||||
.get(1);
|
||||
ASTVariableDeclarator localVarDecl = localVar.getFirstChildOfType(ASTVariableDeclarator.class);
|
||||
Assert.assertEquals(Integer.TYPE, localVarDecl.getType());
|
||||
Assert.assertEquals(Integer.TYPE, switchExpression.getType());
|
||||
}
|
||||
|
||||
|
||||
@Test(expected = ParseException.class)
|
||||
public void testSwitchExpressionsBeforeJava13() {
|
||||
|
@ -286,7 +286,7 @@ public class ParserCornersTest {
|
||||
ASTCompilationUnit compilationUnit = ParserTstUtil.parseAndTypeResolveJava("11", readAsString("SwitchWithFallthrough.java"));
|
||||
Assert.assertNotNull(compilationUnit);
|
||||
ASTSwitchStatement switchStatement = compilationUnit.getFirstDescendantOfType(ASTSwitchStatement.class);
|
||||
Assert.assertEquals(2, switchStatement.findChildrenOfType(ASTSwitchLabel.class).size());
|
||||
Assert.assertEquals(2, switchStatement.findChildrenOfType(ASTSwitchFallthroughBranch.class).size());
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -294,7 +294,7 @@ public class ParserCornersTest {
|
||||
ASTCompilationUnit compilationUnit = ParserTstUtil.parseAndTypeResolveJava("11", readAsString("SwitchStatements.java"));
|
||||
Assert.assertNotNull(compilationUnit);
|
||||
ASTSwitchStatement switchStatement = compilationUnit.getFirstDescendantOfType(ASTSwitchStatement.class);
|
||||
Assert.assertEquals(2, switchStatement.findChildrenOfType(ASTSwitchLabel.class).size());
|
||||
Assert.assertEquals(2, switchStatement.findChildrenOfType(ASTSwitchBranch.class).size());
|
||||
}
|
||||
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -235,6 +235,19 @@ fun TreeNodeWrapper<Node, *>.breakStatement(label: String? = null, contents: Nod
|
||||
contents()
|
||||
}
|
||||
|
||||
fun TreeNodeWrapper<Node, *>.yieldStatement(contents: ValuedNodeSpec<ASTYieldStatement, ASTExpression?> = {null}) =
|
||||
child<ASTYieldStatement> {
|
||||
val e = contents()
|
||||
if (e != null) it::getExpr shouldBe e
|
||||
else unspecifiedChild()
|
||||
}
|
||||
|
||||
|
||||
fun TreeNodeWrapper<Node, *>.throwStatement(contents: NodeSpec<ASTThrowStatement> = EmptyAssertions) =
|
||||
child<ASTThrowStatement>(ignoreChildren = contents == EmptyAssertions) {
|
||||
contents()
|
||||
}
|
||||
|
||||
fun TreeNodeWrapper<Node, *>.localVarDecl(contents: NodeSpec<ASTLocalVariableDeclaration> = EmptyAssertions) =
|
||||
child<ASTLocalVariableDeclaration>(ignoreChildren = contents == EmptyAssertions) {
|
||||
contents()
|
||||
@ -393,6 +406,34 @@ fun TreeNodeWrapper<Node, *>.switchExpr(assertions: NodeSpec<ASTSwitchExpression
|
||||
child(ignoreChildren = assertions == EmptyAssertions) {
|
||||
assertions()
|
||||
}
|
||||
fun TreeNodeWrapper<Node, *>.switchStmt(assertions: NodeSpec<ASTSwitchStatement> = EmptyAssertions) =
|
||||
child<ASTSwitchStatement>(ignoreChildren = assertions == EmptyAssertions) {
|
||||
assertions()
|
||||
}
|
||||
|
||||
fun TreeNodeWrapper<Node, *>.switchArrow(rhs: ValuedNodeSpec<ASTSwitchArrowBranch, ASTSwitchArrowRHS?> = { null }) =
|
||||
child<ASTSwitchArrowBranch> {
|
||||
val rhs = rhs()
|
||||
if (rhs != null) it::getRightHandSide shouldBe rhs
|
||||
else unspecifiedChildren(2) // label + rhs
|
||||
}
|
||||
|
||||
fun TreeNodeWrapper<Node, *>.switchFallthrough(assertions: NodeSpec<ASTSwitchFallthroughBranch> = EmptyAssertions) =
|
||||
child<ASTSwitchFallthroughBranch>(ignoreChildren = assertions == EmptyAssertions) {
|
||||
assertions()
|
||||
}
|
||||
fun TreeNodeWrapper<Node, *>.switchLabel(assertions: NodeSpec<ASTSwitchLabel> = EmptyAssertions) =
|
||||
child<ASTSwitchLabel>(ignoreChildren = assertions == EmptyAssertions) {
|
||||
it::isDefault shouldBe false
|
||||
assertions()
|
||||
}
|
||||
|
||||
fun TreeNodeWrapper<Node, *>.switchDefaultLabel(assertions: NodeSpec<ASTSwitchLabel> = EmptyAssertions) =
|
||||
child<ASTSwitchLabel>(ignoreChildren = assertions == EmptyAssertions) {
|
||||
it::isDefault shouldBe true
|
||||
it::getExprList shouldBe emptyList()
|
||||
assertions()
|
||||
}
|
||||
|
||||
fun TreeNodeWrapper<Node, *>.number(primitiveType: ASTPrimitiveType.PrimitiveType? = null, assertions: NodeSpec<ASTNumericLiteral> = EmptyAssertions) =
|
||||
child<ASTNumericLiteral> {
|
||||
|
@ -1,41 +0,0 @@
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @see <a href="http://openjdk.java.net/jeps/354">JEP 354: Switch Expressions (Preview)</a>
|
||||
*/
|
||||
public class SwitchExpressions {
|
||||
private enum Day {
|
||||
MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
Day day = Day.FRIDAY;
|
||||
|
||||
int j = switch (day) {
|
||||
case MONDAY -> 0;
|
||||
case TUESDAY -> 1;
|
||||
default -> {
|
||||
int k = day.toString().length();
|
||||
int result = f(k);
|
||||
yield result;
|
||||
}
|
||||
};
|
||||
System.out.printf("j = %d%n", j);
|
||||
|
||||
String s = "Bar";
|
||||
int result = switch (s) {
|
||||
case "Foo":
|
||||
yield 1;
|
||||
case "Bar":
|
||||
yield 2;
|
||||
default:
|
||||
System.out.println("Neither Foo nor Bar, hmmm...");
|
||||
yield 0;
|
||||
};
|
||||
System.out.printf("result = %d%n", result);
|
||||
}
|
||||
|
||||
private static int f(int k) {
|
||||
return k+1;
|
||||
}
|
||||
}
|
@ -1,36 +0,0 @@
|
||||
/**
|
||||
*
|
||||
* @see <a href="https://openjdk.java.net/jeps/325">JEP 325: Switch Expressions (Preview)</a>
|
||||
*/
|
||||
public class SwitchExpressionsYield {
|
||||
private static final int MONDAY = 1;
|
||||
private static final int TUESDAY = 2;
|
||||
private static final int WEDNESDAY = 3;
|
||||
private static final int THURSDAY = 4;
|
||||
private static final int FRIDAY = 5;
|
||||
private static final int SATURDAY = 6;
|
||||
private static final int SUNDAY = 7;
|
||||
|
||||
private static final int SIX = 6;
|
||||
|
||||
public static void main(String[] args) {
|
||||
int day = FRIDAY;
|
||||
|
||||
var numLetters = switch (day) {
|
||||
case MONDAY, FRIDAY, SUNDAY: yield SwitchExpressionsBreak.SIX;
|
||||
case TUESDAY : yield 7;
|
||||
case THURSDAY, SATURDAY : yield 8;
|
||||
case WEDNESDAY : yield 9;
|
||||
default : {
|
||||
int k = day * 2;
|
||||
int result = f(k);
|
||||
yield result;
|
||||
}
|
||||
};
|
||||
System.out.printf("NumLetters: %d%n", numLetters);
|
||||
}
|
||||
|
||||
private static int f(int k) {
|
||||
return k*3;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user