diff --git a/src/main/java/com/puppycrawl/tools/checkstyle/checks/metrics/NPathComplexityCheck.java b/src/main/java/com/puppycrawl/tools/checkstyle/checks/metrics/NPathComplexityCheck.java
index 951d61eed29..da17e67d4f9 100644
--- a/src/main/java/com/puppycrawl/tools/checkstyle/checks/metrics/NPathComplexityCheck.java
+++ b/src/main/java/com/puppycrawl/tools/checkstyle/checks/metrics/NPathComplexityCheck.java
@@ -91,6 +91,7 @@
*
NP(for-range) + NP(expr1)+ NP(expr2) + NP(expr3) + 1 |
* switch ([expr]) { case : [case-range] default: [default-range] } |
* S(i=1:i=n)NP(case-range[i]) + NP(default-range) + NP(expr) |
+ * when[expr] | NP(expr) + 1 |
* [expr1] ? [expr2] : [expr3] | NP(expr1) + NP(expr2) + NP(expr3) + 2 |
* goto label | 1 |
break | 1 |
* Expressions |
@@ -220,6 +221,7 @@ public int[] getRequiredTokens() {
TokenTypes.LITERAL_DEFAULT,
TokenTypes.COMPACT_CTOR_DEF,
TokenTypes.SWITCH_RULE,
+ TokenTypes.LITERAL_WHEN,
};
}
@@ -249,6 +251,9 @@ public void visitToken(DetailAST ast) {
case TokenTypes.LITERAL_RETURN:
visitUnitaryOperator(ast, 0);
break;
+ case TokenTypes.LITERAL_WHEN:
+ visitWhenExpression(ast, 1);
+ break;
case TokenTypes.CASE_GROUP:
final int caseNumber = countCaseTokens(ast);
branchVisited = true;
@@ -291,6 +296,7 @@ public void leaveToken(DetailAST ast) {
case TokenTypes.LITERAL_FOR:
case TokenTypes.LITERAL_IF:
case TokenTypes.LITERAL_SWITCH:
+ case TokenTypes.LITERAL_WHEN:
leaveConditional();
break;
case TokenTypes.LITERAL_TRY:
@@ -343,6 +349,19 @@ private void visitConditional(DetailAST ast, int basicBranchingFactor) {
pushValue(expressionValue);
}
+ /**
+ * Visits when expression token. There is no guarantee that when expression will be
+ * bracketed, so we don't use visitConditional method.
+ *
+ * @param ast visited token.
+ * @param basicBranchingFactor default number of branches added.
+ */
+ private void visitWhenExpression(DetailAST ast, int basicBranchingFactor) {
+ final int expressionValue = basicBranchingFactor + countConditionalOperators(ast);
+ processingTokenEnd.setToken(getLastToken(ast));
+ pushValue(expressionValue);
+ }
+
/**
* Visits ternary operator (?:) and return tokens. They differ from those processed by
* visitConditional method in that their expression isn't bracketed.
diff --git a/src/main/resources/com/puppycrawl/tools/checkstyle/meta/checks/metrics/NPathComplexityCheck.xml b/src/main/resources/com/puppycrawl/tools/checkstyle/meta/checks/metrics/NPathComplexityCheck.xml
index cf97e7a6457..8efa3720f18 100644
--- a/src/main/resources/com/puppycrawl/tools/checkstyle/meta/checks/metrics/NPathComplexityCheck.xml
+++ b/src/main/resources/com/puppycrawl/tools/checkstyle/meta/checks/metrics/NPathComplexityCheck.xml
@@ -64,6 +64,7 @@
<td>NP(for-range) + NP(expr1)+ NP(expr2) + NP(expr3) + 1</td></tr>
<tr><td>switch ([expr]) { case : [case-range] default: [default-range] }</td>
<td>S(i=1:i=n)NP(case-range[i]) + NP(default-range) + NP(expr)</td></tr>
+ <tr><td>when[expr]</td><td>NP(expr) + 1</td></tr>
<tr><td>[expr1] ? [expr2] : [expr3]</td><td>NP(expr1) + NP(expr2) + NP(expr3) + 2</td></tr>
<tr><td>goto label</td><td>1</td></tr><tr><td>break</td><td>1</td></tr>
<tr><td>Expressions</td>
diff --git a/src/test/java/com/puppycrawl/tools/checkstyle/checks/metrics/NPathComplexityCheckTest.java b/src/test/java/com/puppycrawl/tools/checkstyle/checks/metrics/NPathComplexityCheckTest.java
index 2733a57950b..fa263cd88fe 100644
--- a/src/test/java/com/puppycrawl/tools/checkstyle/checks/metrics/NPathComplexityCheckTest.java
+++ b/src/test/java/com/puppycrawl/tools/checkstyle/checks/metrics/NPathComplexityCheckTest.java
@@ -257,8 +257,8 @@ public void testPatternMatchingForSwitch() throws Exception {
"23:5: " + getCheckMessage(MSG_KEY, 3, 1),
"32:5: " + getCheckMessage(MSG_KEY, 3, 1),
"41:5: " + getCheckMessage(MSG_KEY, 3, 1),
- "50:5: " + getCheckMessage(MSG_KEY, 3, 1),
- "59:5: " + getCheckMessage(MSG_KEY, 3, 1),
+ "50:5: " + getCheckMessage(MSG_KEY, 5, 1),
+ "59:5: " + getCheckMessage(MSG_KEY, 5, 1),
"68:5: " + getCheckMessage(MSG_KEY, 4, 1),
"76:5: " + getCheckMessage(MSG_KEY, 4, 1),
"86:5: " + getCheckMessage(MSG_KEY, 3, 1),
@@ -271,6 +271,28 @@ public void testPatternMatchingForSwitch() throws Exception {
}
+ @Test
+ public void testWhenExpression() throws Exception {
+
+ final String[] expected = {
+ "14:5: " + getCheckMessage(MSG_KEY, 3, 1),
+ "20:5: " + getCheckMessage(MSG_KEY, 3, 1),
+ "28:5: " + getCheckMessage(MSG_KEY, 3, 1),
+ "36:5: " + getCheckMessage(MSG_KEY, 4, 1),
+ "44:5: " + getCheckMessage(MSG_KEY, 4, 1),
+ "52:5: " + getCheckMessage(MSG_KEY, 5, 1),
+ "60:5: " + getCheckMessage(MSG_KEY, 7, 1),
+ "69:5: " + getCheckMessage(MSG_KEY, 5, 1),
+ "77:5: " + getCheckMessage(MSG_KEY, 5, 1),
+ "85:5: " + getCheckMessage(MSG_KEY, 6, 1),
+ };
+
+ verifyWithInlineConfigParser(
+ getNonCompilablePath("InputNPathComplexityWhenExpression.java"),
+ expected);
+
+ }
+
@Test
public void testGetAcceptableTokens() {
final NPathComplexityCheck npathComplexityCheckObj = new NPathComplexityCheck();
@@ -294,6 +316,7 @@ public void testGetAcceptableTokens() {
TokenTypes.LITERAL_DEFAULT,
TokenTypes.COMPACT_CTOR_DEF,
TokenTypes.SWITCH_RULE,
+ TokenTypes.LITERAL_WHEN,
};
assertWithMessage("Acceptable tokens should not be null")
.that(actual)
@@ -326,6 +349,7 @@ public void testGetRequiredTokens() {
TokenTypes.LITERAL_DEFAULT,
TokenTypes.COMPACT_CTOR_DEF,
TokenTypes.SWITCH_RULE,
+ TokenTypes.LITERAL_WHEN,
};
assertWithMessage("Required tokens should not be null")
.that(actual)
diff --git a/src/test/resources-noncompilable/com/puppycrawl/tools/checkstyle/checks/metrics/npathcomplexity/InputNPathComplexityPatternMatchingForSwitch.java b/src/test/resources-noncompilable/com/puppycrawl/tools/checkstyle/checks/metrics/npathcomplexity/InputNPathComplexityPatternMatchingForSwitch.java
index 4508acae857..41933ccfd37 100644
--- a/src/test/resources-noncompilable/com/puppycrawl/tools/checkstyle/checks/metrics/npathcomplexity/InputNPathComplexityPatternMatchingForSwitch.java
+++ b/src/test/resources-noncompilable/com/puppycrawl/tools/checkstyle/checks/metrics/npathcomplexity/InputNPathComplexityPatternMatchingForSwitch.java
@@ -46,7 +46,7 @@ case B(String s) : {}
}
}
- // violation below, 'NPath Complexity is 3 (max allowed is 1)'
+ // violation below, 'NPath Complexity is 5 (max allowed is 1)'
void testGuardsInRule(Object o) {
switch (o) {
case Integer i when i > 0 -> {}
@@ -55,7 +55,7 @@ void testGuardsInRule(Object o) {
}
}
- // violation below, 'NPath Complexity is 3 (max allowed is 1)'
+ // violation below, 'NPath Complexity is 5 (max allowed is 1)'
void testGuardsInStatement(Object o) {
switch (o) {
case Integer i when i > 0 : {} break;
diff --git a/src/test/resources-noncompilable/com/puppycrawl/tools/checkstyle/checks/metrics/npathcomplexity/InputNPathComplexityWhenExpression.java b/src/test/resources-noncompilable/com/puppycrawl/tools/checkstyle/checks/metrics/npathcomplexity/InputNPathComplexityWhenExpression.java
new file mode 100644
index 00000000000..37d5146c8db
--- /dev/null
+++ b/src/test/resources-noncompilable/com/puppycrawl/tools/checkstyle/checks/metrics/npathcomplexity/InputNPathComplexityWhenExpression.java
@@ -0,0 +1,91 @@
+/*
+NPathComplexity
+max = 1
+
+
+*/
+
+//non-compiled with javac: Compilable with Java21
+package com.puppycrawl.tools.checkstyle.checks.metrics.npathcomplexity;
+
+public class InputNPathComplexityWhenExpression {
+
+ // violation below, 'NPath Complexity is 3 (max allowed is 1)'
+ void m(Object o) {
+
+ if (o instanceof String s && !s.isEmpty()) { }
+ }
+
+ // violation below, 'NPath Complexity is 3 (max allowed is 1)'
+ void m2(Object o) {
+ switch (o) {
+ case String s when !s.isEmpty() -> { }
+ default -> { }
+ }
+ }
+
+ // violation below, 'NPath Complexity is 3 (max allowed is 1)'
+ void m3(Object o) {
+ switch (o) {
+ case String s when (!s.isEmpty()) -> { }
+ default -> { }
+ }
+ }
+
+ // violation below, 'NPath Complexity is 4 (max allowed is 1)'
+ void m4(Object o, boolean b) {
+ switch (o) {
+ case String s when !s.isEmpty() && b -> { }
+ default -> { }
+ }
+ }
+
+ // violation below, 'NPath Complexity is 4 (max allowed is 1)'
+ void m5(Object o, boolean b) {
+ switch (o) {
+ case String s when (!s.isEmpty() && b) -> { }
+ default -> { }
+ }
+ }
+
+ // violation below, 'NPath Complexity is 5 (max allowed is 1)'
+ void m6(Object o, boolean b, boolean c) {
+ switch (o) {
+ case String s when (!s.isEmpty() && b) && c -> { }
+ default -> { }
+ }
+ }
+
+ // violation below, 'NPath Complexity is 7 (max allowed is 1)'
+ void m7(Object o, boolean b, boolean c) {
+ switch (o) {
+ case String s when !s.isEmpty() -> { }
+ case Integer i when (i == 0) && c || b -> { }
+ default -> { }
+ }
+ }
+
+ // violation below, 'NPath Complexity is 5 (max allowed is 1)'
+ void m8(Object o, boolean b, boolean c) {
+ switch (o) {
+ case String s when (b ? true : c) -> { }
+ default -> { }
+ }
+ }
+
+ // violation below, 'NPath Complexity is 5 (max allowed is 1)'
+ void m9(Object o, boolean b, boolean c) {
+ switch (o) {
+ case String s when b ? true : c -> { }
+ default -> { }
+ }
+ }
+
+ // violation below, 'NPath Complexity is 6 (max allowed is 1)'
+ void m10(Object o, boolean b, boolean c) {
+ switch (o) {
+ case String s when (b ? true : c) && c == true -> { }
+ default -> { }
+ }
+ }
+}
diff --git a/src/xdocs/checks/metrics/npathcomplexity.xml b/src/xdocs/checks/metrics/npathcomplexity.xml
index 0feb9d18152..954e988ecc8 100644
--- a/src/xdocs/checks/metrics/npathcomplexity.xml
+++ b/src/xdocs/checks/metrics/npathcomplexity.xml
@@ -75,6 +75,7 @@
switch ([expr]) { case : [case-range] default: [default-range] } |
S(i=1:i=n)NP(case-range[i]) + NP(default-range) + NP(expr) |
+ when[expr] | NP(expr) + 1 |
[expr1] ? [expr2] : [expr3] | NP(expr1) + NP(expr2) + NP(expr3) + 2
|
goto label | 1 |
diff --git a/src/xdocs/checks/metrics/npathcomplexity.xml.template b/src/xdocs/checks/metrics/npathcomplexity.xml.template
index c889e4a3c3a..cdc9e71f678 100644
--- a/src/xdocs/checks/metrics/npathcomplexity.xml.template
+++ b/src/xdocs/checks/metrics/npathcomplexity.xml.template
@@ -75,6 +75,7 @@
switch ([expr]) { case : [case-range] default: [default-range] } |
S(i=1:i=n)NP(case-range[i]) + NP(default-range) + NP(expr) |
+ when[expr] | NP(expr) + 1 |
[expr1] ? [expr2] : [expr3] | NP(expr1) + NP(expr2) + NP(expr3) + 2
|
goto label | 1 |