Affects PMD Version:
7.11.0
Rule:
NPathComplexity
Description:
This issue is actually more of a question of why PMD reports switch expressions with an incredibly high NPath complexity.
Code Sample demonstrating the issue:
The following code has an NPathComplexity of 1296:
public static byte toByte(final Register8 r) { return switch (r) { case AL, R8B -> (byte) 0x00; case CL, R9B -> (byte) 0x01; case DL, R10B -> (byte) 0x02; case BL, R11B -> (byte) 0x03; case AH, SPL, R12B -> (byte) 0x04; case CH, BPL, R13B -> (byte) 0x05; case DH, SIL, R14B -> (byte) 0x06; case BH, DIL, R15B -> (byte) 0x07; }; }
The following code (completely equivalent to the first one) has an NPathComplexity of 21:
public static byte toByte(final Register8 r) { if (r == AL || r == R8B) { return (byte) 0x00; } else if (r == CL || r == R9B) { return (byte) 0x01; } else if (r == DL || r == R10B) { return (byte) 0x02; } else if (r == BL || r == R11B) { return (byte) 0x03; } else if (r == AH || r == SPL || r == R12B) { return (byte) 0x04; } else if (r == CH || r == BPL || r == R13B) { return (byte) 0x05; } else if (r == DH || r == SIL || r == R14B) { return (byte) 0x06; } else if (r == BH || r == DIL || r == R15B) { return (byte) 0x07; } else { throw new NullPointerException(); } }
Expected outcome:
I understand where the 1296 comes from: 4 cases with 2 values and 4 cases with 3 values produce 2 * 2 * 2 * 2 * 3 * 3 * 3 * 3 = 1296 possible execution paths. The Register8
enum has only those 20 values (as can be deduced from the switch missing the default
case) so I would expect a complexity of 20 (maybe +1 for the hidden null
case) like in the second example.
In short, I think PMD is doing the wrong calculation. The value of 1296 would make sense if the switch
was a classic one without break
s like the one below. This would explain the use of multiplication in the computation of the NPath complexity but I think in a switch
expression (in which each case has its own scope, AFAIK) that computation should be a simple addition of the complexity of each case.
switch(x) { case 0, 1: // some code... // fallthrough case 2, 3: // some other code... // fallthrough default: return ...; }
Looking around in older issues I found this one which was apparently fixed in PMD 6.26.0, so this issue may be a duplicate.
Running PMD through: Gradle
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4