[java] SwitchStmtsShouldHaveDefault should ignore patterns

Fixes #4813
This commit is contained in:
Andreas Dangel 2024-10-04 16:03:21 +02:00
parent a0818d5ab2
commit 0c858b0a7b
No known key found for this signature in database
GPG Key ID: 93450DF2DF9A3FA3
3 changed files with 83 additions and 0 deletions

View File

@ -32,6 +32,8 @@ The old rule names still work but are deprecated.
### 🐛 Fixed Issues
* java
* [#4532](https://github.com/pmd/pmd/issues/4532): \[java] Rule misnomer for JUnit* rules
* java-bestpractices
* [#4813](https://github.com/pmd/pmd/issues/4813): \[java] SwitchStmtsShouldHaveDefault false positive with pattern matching
* java-errorprone
* [#5067](https://github.com/pmd/pmd/issues/5067): \[java] CloseResource: False positive for FileSystems.getDefault()

View File

@ -1168,12 +1168,18 @@ class SomeTestClass {
easier to follow. This can be achieved by adding a `default` case, or,
if the switch is on an enum type, by ensuring there is one switch branch
for each enum constant.
This rule doesn't consider Switch Statements, that use Pattern Matching, since for these the
compiler already ensures that all cases are covered. The same is true for Switch Expressions,
which are also not considered by this rule.
</description>
<priority>3</priority>
<properties>
<property name="xpath">
<value><![CDATA[
//SwitchStatement[@DefaultCase = false() and @ExhaustiveEnumSwitch = false()]
(: exclude type pattern tests - for these, the compiler will ensure exhaustiveness :)
[not(*/SwitchLabel/TypePattern)]
]]></value>
</property>
</properties>

View File

@ -240,4 +240,79 @@ public enum GradeSystem {
}
]]></code>
</test-code>
<test-code>
<description>[java] SwitchStmtsShouldHaveDefault false positive with pattern matching #4813</description>
<expected-problems>0</expected-problems>
<code><![CDATA[
public sealed interface AcceptableResult permits Success, Warning {
public String message();
}
public final class Success implements AcceptableResult {
@Override
public String message() {
return "Success!";
}
}
public abstract class Failure {
abstract public String message();
}
public non-sealed class Warning extends Failure implements AcceptableResult {
@Override
public String message() {
return "Oopsie";
}
}
public class ProviderWarning extends Warning {
@Override
public String message() {
return "Ohoh";
}
}
public class Example {
public void test(AcceptableResult result) {
switch (result) {
case Warning failure -> System.out.println("WARNING " + failure.message());
case Success success -> System.out.println(success.message());
}
}
public void test2(AcceptableResult result) {
switch (result) {
case ProviderWarning failure: System.out.println("Provider WARNING " + failure.message()); break;
case Warning failure: System.out.println("WARNING " + failure.message()); break;
case Success success: System.out.println(success.message()); break;
}
}
public void test3(AcceptableResult result) {
switch (result) {
case ProviderWarning failure -> System.out.println("Provider WARNING " + failure.message());
case Success success -> System.out.println(success.message());
default -> System.out.println("default case");
}
}
}
]]></code>
</test-code>
<test-code>
<description>[java] SwitchStmtsShouldHaveDefault false positive with pattern matching #4813, example 2</description>
<expected-problems>0</expected-problems>
<code><![CDATA[
sealed interface S permits A, B {}
final class A implements S {}
sealed abstract class B implements S permits C, D {}
final class C extends B {}
final class D extends B {}
public class Example2 {
static int testSealedExhaustive(S s) {
switch(s) {
case A a -> { return 1; }
case C c -> { return 2; }
case D d -> { return 3; }
// case B b -> { return 4; } // not explicitly necessary, but possible
}
}
}
]]></code>
</test-code>
</test-data>