Repository: checkstyle/checkstyle

Problem statement:
NeedBraces Check Should violate Switch Expressions with Arrow Syntax That Directly Yields a Value
detected at https://github.com/checkstyle/checkstyle/pull/15321#discussion_r1684288238
I have read check documentation:https://checkstyle.org/checks/blocks/needbraces.html#NeedBraces
I have downloaded the latest checkstyle from: https://checkstyle.org/cmdline.html#Download_and_Run
I have executed the cli and showed it below, as cli describes the problem better than 1,000 words

```
D:\CS\test
javac src/Test.java
D:\CS\test
cat config.xml
<?xml version="1.0"?>
<!DOCTYPE module PUBLIC
          "-//Checkstyle//DTD Checkstyle Configuration 1.3//EN"
          "https://checkstyle.org/dtds/configuration_1_3.dtd">

<module name="Checker">
  <module name="TreeWalker">
    <module name="NeedBraces">
      <property name="tokens" value="LAMBDA, LITERAL_CASE"/>
    </module>
  </module>
</module>
D:\CS\test
cat src/Test.java
import java.util.Arrays;
import java.util.List;

public class Test {
    int test(Object o, String z) {
        List<Integer> numbers = Arrays.asList(1, 2, 3);
        numbers = numbers.stream()
                .map(x -> 0) // violation
                .toList();

        numbers = numbers.stream()
                .map(x -> z.length()) // violation
                .toList();

        return switch (o) {
            case Integer _ -> 5; // should be violation same as the line below and lambda examples above
            case String s -> s.length(); // violation
            default -> 0;
        };
    }
}
D:\CS\test
java  -jar checkstyle-10.17.0-all.jar -c config.xml src/Test.java
Starting audit...
[ERROR] D:\CS\test\src\Test.java:8:24: '->' construct must use '{}'s. [NeedBraces]
[ERROR] D:\CS\test\src\Test.java:12:24: '->' construct must use '{}'s. [NeedBraces]
[ERROR] D:\CS\test\src\Test.java:17:13: 'case' construct must use '{}'s. [NeedBraces]
Audit done.
Checkstyle ends with 3 errors.
z

```

---

**Describe what you expect in detail.**

I expect a violation on line 16. We can add braces and the `yield` keyword. We should be consistent with Lambdas. We violate them and the fix will be add braces and the `return` keyword. If some users don't want to violate these examples they should enable `allowSingleLineStatement`.

 ---



Hints:

Patch:
diff --git a/src/main/java/com/puppycrawl/tools/checkstyle/checks/blocks/NeedBracesCheck.java b/src/main/java/com/puppycrawl/tools/checkstyle/checks/blocks/NeedBracesCheck.java
--- a/src/main/java/com/puppycrawl/tools/checkstyle/checks/blocks/NeedBracesCheck.java
+++ b/src/main/java/com/puppycrawl/tools/checkstyle/checks/blocks/NeedBracesCheck.java
@@ -177,8 +177,7 @@ private boolean isBracesNeeded(DetailAST ast) {
                 break;
             case TokenTypes.LITERAL_CASE:
             case TokenTypes.LITERAL_DEFAULT:
-                result = hasUnbracedStatements(ast)
-                    && !isSwitchLabeledExpression(ast);
+                result = hasUnbracedStatements(ast);
                 break;
             case TokenTypes.LITERAL_ELSE:
                 result = ast.findFirstToken(TokenTypes.LITERAL_IF) == null;
@@ -418,35 +417,6 @@ private static boolean isInSwitchRule(DetailAST ast) {
         return ast.getParent().getType() == TokenTypes.SWITCH_RULE;
     }
 
-    /**
-     * Checks if current expression is a switch labeled expression. If so,
-     * braces are not allowed e.g.:
-     * <p>
-     * {@code
-     * case 1 -> 4;
-     * }
-     * </p>
-     *
-     * @param ast the ast to check
-     * @return true if current expression is a switch labeled expression.
-     */
-    private static boolean isSwitchLabeledExpression(DetailAST ast) {
-        final DetailAST parent = ast.getParent();
-        return switchRuleHasSingleExpression(parent);
-    }
-
-    /**
-     * Checks if current switch labeled expression contains only a single expression.
-     *
-     * @param switchRule {@link TokenTypes#SWITCH_RULE}.
-     * @return true if current switch rule has a single expression.
-     */
-    private static boolean switchRuleHasSingleExpression(DetailAST switchRule) {
-        final DetailAST possibleExpression = switchRule.findFirstToken(TokenTypes.EXPR);
-        return possibleExpression != null
-                && possibleExpression.getFirstChild().getFirstChild() == null;
-    }
-
     /**
      * Checks if switch member (case or default statement) in a switch rule or
      * case group is on a single-line.


Test patch:
diff --git a/src/test/java/com/puppycrawl/tools/checkstyle/checks/blocks/NeedBracesCheckTest.java b/src/test/java/com/puppycrawl/tools/checkstyle/checks/blocks/NeedBracesCheckTest.java
--- a/src/test/java/com/puppycrawl/tools/checkstyle/checks/blocks/NeedBracesCheckTest.java
+++ b/src/test/java/com/puppycrawl/tools/checkstyle/checks/blocks/NeedBracesCheckTest.java
@@ -246,7 +246,10 @@ public void testNeedBracesSwitchExpressionNoSingleLine() throws Exception {
             "59:13: " + getCheckMessage(MSG_KEY_NEED_BRACES, "default"),
             "73:47: " + getCheckMessage(MSG_KEY_NEED_BRACES, "->"),
             "80:13: " + getCheckMessage(MSG_KEY_NEED_BRACES, "default"),
-            };
+            "87:13: " + getCheckMessage(MSG_KEY_NEED_BRACES, "case"),
+            "88:13: " + getCheckMessage(MSG_KEY_NEED_BRACES, "case"),
+            "89:13: " + getCheckMessage(MSG_KEY_NEED_BRACES, "case"),
+        };
         verifyWithInlineConfigParser(
                 getNonCompilablePath("InputNeedBracesTestSwitchExpressionNoSingleLine.java"),
             expected);
@@ -291,8 +294,10 @@ public void testPatternMatchingForSwitch() throws Exception {
             "78:13: " + getCheckMessage(MSG_KEY_NEED_BRACES, "case"),
             "80:13: " + getCheckMessage(MSG_KEY_NEED_BRACES, "case"),
             "83:13: " + getCheckMessage(MSG_KEY_NEED_BRACES, "default"),
+            "88:13: " + getCheckMessage(MSG_KEY_NEED_BRACES, "case"),
+            "89:13: " + getCheckMessage(MSG_KEY_NEED_BRACES, "case"),
             "90:13: " + getCheckMessage(MSG_KEY_NEED_BRACES, "case"),
-            "91:13: " + getCheckMessage(MSG_KEY_NEED_BRACES, "case"),
+            "96:13: " + getCheckMessage(MSG_KEY_NEED_BRACES, "default"),
         };
         verifyWithInlineConfigParser(
                 getNonCompilablePath("InputNeedBracesPatternMatchingForSwitch.java"),
@@ -320,4 +325,37 @@ public void testPatternMatchingForSwitchAllowSingleLine() throws Exception {
             expected);
     }
 
+    @Test
+    public void testNeedBracesSwitchExpressionAndLambda() throws Exception {
+        final String[] expected = {
+            "21:24: " + getCheckMessage(MSG_KEY_NEED_BRACES, "->"),
+            "24:24: " + getCheckMessage(MSG_KEY_NEED_BRACES, "->"),
+            "27:24: " + getCheckMessage(MSG_KEY_NEED_BRACES, "->"),
+            "50:13: " + getCheckMessage(MSG_KEY_NEED_BRACES, "case"),
+            "51:13: " + getCheckMessage(MSG_KEY_NEED_BRACES, "default"),
+            "56:13: " + getCheckMessage(MSG_KEY_NEED_BRACES, "case"),
+            "58:13: " + getCheckMessage(MSG_KEY_NEED_BRACES, "default"),
+            "62:13: " + getCheckMessage(MSG_KEY_NEED_BRACES, "case"),
+            "63:13: " + getCheckMessage(MSG_KEY_NEED_BRACES, "case"),
+            "65:13: " + getCheckMessage(MSG_KEY_NEED_BRACES, "case"),
+            "66:13: " + getCheckMessage(MSG_KEY_NEED_BRACES, "default"),
+        };
+        verifyWithInlineConfigParser(
+                getNonCompilablePath("InputNeedBracesSwitchExpressionAndLambda.java"),
+            expected);
+    }
+
+    @Test
+    public void testNeedBracesSwitchExpressionAndLambdaAllowSingleLine() throws Exception {
+        final String[] expected = {
+            "27:24: " + getCheckMessage(MSG_KEY_NEED_BRACES, "->"),
+            "46:13: " + getCheckMessage(MSG_KEY_NEED_BRACES, "case"),
+            "53:13: " + getCheckMessage(MSG_KEY_NEED_BRACES, "case"),
+        };
+        verifyWithInlineConfigParser(
+                getNonCompilablePath(
+                        "InputNeedBracesSwitchExpressionAndLambdaAllowSingleLine.java"),
+            expected);
+    }
+
 }
diff --git a/src/test/resources-noncompilable/com/puppycrawl/tools/checkstyle/checks/blocks/needbraces/InputNeedBracesPatternMatchingForSwitch.java b/src/test/resources-noncompilable/com/puppycrawl/tools/checkstyle/checks/blocks/needbraces/InputNeedBracesPatternMatchingForSwitch.java
--- a/src/test/resources-noncompilable/com/puppycrawl/tools/checkstyle/checks/blocks/needbraces/InputNeedBracesPatternMatchingForSwitch.java
+++ b/src/test/resources-noncompilable/com/puppycrawl/tools/checkstyle/checks/blocks/needbraces/InputNeedBracesPatternMatchingForSwitch.java
@@ -85,16 +85,15 @@ case Point(int x, int y ) when (x>=0 && y >=0) :  // violation
         };
 
         int b =  switch (o) {
-            case Integer i when (i == 0) -> i;
-            // until https://github.com/checkstyle/checkstyle/issues/15322
-            case String s when (s.equals("a")) -> s.length();  // violation
-            case Point(int x, int y ) when (x>=0 && y >=0) ->  // violation
+            case Integer i when (i == 0) -> i; // violation
+            case String s when (s.equals("a")) -> s.length(); // violation
+            case Point(int x, int y ) when (x>=0 && y >=0) -> // violation
                 x + y;
             case Integer i when (i == 9) -> {
                 int n = i;
                 yield n;
             }
-            default -> 0;
+            default -> 0; // violation
         };
     }
     record Point(int x, int y) {}
diff --git a/src/test/resources-noncompilable/com/puppycrawl/tools/checkstyle/checks/blocks/needbraces/InputNeedBracesPatternMatchingForSwitchAllowSingleLine.java b/src/test/resources-noncompilable/com/puppycrawl/tools/checkstyle/checks/blocks/needbraces/InputNeedBracesPatternMatchingForSwitchAllowSingleLine.java
--- a/src/test/resources-noncompilable/com/puppycrawl/tools/checkstyle/checks/blocks/needbraces/InputNeedBracesPatternMatchingForSwitchAllowSingleLine.java
+++ b/src/test/resources-noncompilable/com/puppycrawl/tools/checkstyle/checks/blocks/needbraces/InputNeedBracesPatternMatchingForSwitchAllowSingleLine.java
@@ -84,10 +84,10 @@ case Point(int x, int y ) when (x>=0 && y >=0) :  // violation
                 yield 0;
         };
 
-        int b =  switch (o) {
+        int b = switch (o) {
             case Integer i when (i == 0) -> i;
             case String s when (s.equals("a")) -> s.length();
-            case Point(int x, int y ) when (x>=0 && y >=0) ->  // violation
+            case Point(int x, int y ) when (x>=0 && y >=0) -> // violation
                 x + y;
             case Integer i when (i == 9) -> {
                 int n = i;
diff --git a/src/test/resources-noncompilable/com/puppycrawl/tools/checkstyle/checks/blocks/needbraces/InputNeedBracesSwitchExpressionAndLambda.java b/src/test/resources-noncompilable/com/puppycrawl/tools/checkstyle/checks/blocks/needbraces/InputNeedBracesSwitchExpressionAndLambda.java
new file mode 100644
--- /dev/null
+++ b/src/test/resources-noncompilable/com/puppycrawl/tools/checkstyle/checks/blocks/needbraces/InputNeedBracesSwitchExpressionAndLambda.java
@@ -0,0 +1,105 @@
+/*
+NeedBraces
+allowSingleLineStatement = false
+allowEmptyLoopBody = (default)false
+tokens = LITERAL_CASE, LITERAL_DEFAULT, LAMBDA
+
+
+*/
+
+//non-compiled with javac: Compilable with Java21
+package com.puppycrawl.tools.checkstyle.checks.blocks.needbraces;
+
+import java.util.Arrays;
+import java.util.List;
+
+public class InputNeedBracesSwitchExpressionAndLambda {
+
+    public void testLambda(String x, String y, String z) {
+        List<Integer> numbers = Arrays.asList(1, 2, 3);
+        numbers = numbers.stream()
+                .map(i -> 0).toList(); // violation
+
+        numbers = numbers.stream()
+                .map(i -> x.length()).toList(); // violation
+
+        numbers = numbers.stream()
+                .map(i -> x.length() + y.length() // violation
+                        + z.length()
+                ).toList();
+
+        numbers = numbers.stream()
+                .map(i -> {
+                    return 0;
+                }).toList();
+
+        numbers = numbers.stream()
+                .map(i -> {
+                    return x.length();
+                }).toList();
+
+        numbers = numbers.stream()
+                .map(i -> {
+                    return x.length() + y.length()
+                            + z.length();
+                }).toList();
+    }
+
+    public void testSwitchExpression(int x, String s, Object o) {
+        int a = switch (x) {
+            case 1 -> 1; // violation
+            default -> 0; // violation
+        };
+
+        int b;
+        b = switch (x) {
+            case 1 -> 1 + 2 // violation
+                    + 3 + 4 * 5;
+            default -> throw new IllegalStateException(); // violation
+        };
+
+        int c = switch (o) {
+            case Integer i -> i; // violation
+            case String str when x == 1 -> str.length() // violation
+                    + str.length() * 5 + str.lastIndexOf("a");
+            case String str -> str.length(); // violation
+            default -> 0; // violation
+        };
+
+        int aa = switch (x) {
+            case 1 -> {
+                yield 1;
+            }
+            default -> {
+                yield 0;
+            }
+        };
+
+        int bb;
+        bb = switch (x) {
+            case 1 -> {
+                yield 1 + 2
+                        + 3 + 4 * 5;
+            }
+            default -> {
+                throw new IllegalStateException();
+            }
+        };
+
+        int cc = switch (o) {
+            case Integer i -> {
+                yield i;
+            }
+            case String str when x == 1 -> {
+                yield str.length()
+                        + str.length() * 5 + str.lastIndexOf("a");
+            }
+            case String str -> {
+                yield str.length();
+            }
+            default -> {
+                yield 0;
+            }
+        };
+    }
+}
diff --git a/src/test/resources-noncompilable/com/puppycrawl/tools/checkstyle/checks/blocks/needbraces/InputNeedBracesSwitchExpressionAndLambdaAllowSingleLine.java b/src/test/resources-noncompilable/com/puppycrawl/tools/checkstyle/checks/blocks/needbraces/InputNeedBracesSwitchExpressionAndLambdaAllowSingleLine.java
new file mode 100644
--- /dev/null
+++ b/src/test/resources-noncompilable/com/puppycrawl/tools/checkstyle/checks/blocks/needbraces/InputNeedBracesSwitchExpressionAndLambdaAllowSingleLine.java
@@ -0,0 +1,78 @@
+/*
+NeedBraces
+allowSingleLineStatement = true
+allowEmptyLoopBody = (default)false
+tokens = LITERAL_CASE, LITERAL_DEFAULT, LAMBDA
+
+
+*/
+
+//non-compiled with javac: Compilable with Java21
+package com.puppycrawl.tools.checkstyle.checks.blocks.needbraces;
+
+import java.util.Arrays;
+import java.util.List;
+
+public class InputNeedBracesSwitchExpressionAndLambdaAllowSingleLine {
+
+    public void testLambda(String x, String y, String z) {
+        List<Integer> numbers = Arrays.asList(1, 2, 3);
+        numbers = numbers.stream()
+                .map(i -> 0).toList();
+
+        numbers = numbers.stream()
+                .map(i -> x.length()).toList();
+
+        numbers = numbers.stream()
+                .map(i -> x.length() + y.length() // violation
+                        + z.length()
+                ).toList();
+
+        numbers = numbers.stream()
+                .map(i -> {
+                    return x.length() + y.length()
+                            + z.length();
+                }).toList();
+    }
+
+    public void testSwitchExpression(int x, String s, Object o) {
+        int a = switch (x) {
+            case 1 -> 1;
+            default -> 0;
+        };
+
+        int b;
+        b = switch (x) {
+            case 1 -> 1 + 2 // violation
+                    + 3 + 4 * 5;
+            default -> throw new IllegalStateException();
+        };
+
+        int c = switch (o) {
+            case Integer i -> i;
+            case String str when x == 1 -> str.length() // violation
+                    + str.length() * 5 + str.lastIndexOf("a");
+            case String str -> str.length();
+            default -> 0;
+        };
+
+        int bb;
+        bb = switch (x) {
+            case 1 -> {
+                yield 1 + 2
+                        + 3 + 4 * 5;
+            }
+            default -> throw new IllegalStateException();
+        };
+
+        int cc = switch (o) {
+            case Integer i -> i;
+            case String str when x == 1 -> {
+                yield str.length()
+                        + str.length() * 5 + str.lastIndexOf("a");
+            }
+            case String str -> str.length();
+            default -> 0;
+        };
+    }
+}
diff --git a/src/test/resources-noncompilable/com/puppycrawl/tools/checkstyle/checks/blocks/needbraces/InputNeedBracesTestSwitchExpressionNoSingleLine.java b/src/test/resources-noncompilable/com/puppycrawl/tools/checkstyle/checks/blocks/needbraces/InputNeedBracesTestSwitchExpressionNoSingleLine.java
--- a/src/test/resources-noncompilable/com/puppycrawl/tools/checkstyle/checks/blocks/needbraces/InputNeedBracesTestSwitchExpressionNoSingleLine.java
+++ b/src/test/resources-noncompilable/com/puppycrawl/tools/checkstyle/checks/blocks/needbraces/InputNeedBracesTestSwitchExpressionNoSingleLine.java
@@ -82,14 +82,11 @@ int howMany4(Nums k) {
         };
     }
 
-    /**
-     * Braces not allowed in switch expression with switch labeled expression
-     */
     int howMany5(Nums k) {
         return switch (k) {
-            case ONE -> 1; // braces not allowed, ok
-            case TWO, THREE -> 3; // braces not allowed, ok
-            case FOUR -> 4; // braces not allowed, ok
+            case ONE -> 1; // violation
+            case TWO, THREE -> 3; // violation
+            case FOUR -> 4; // violation
             default -> {
                 throw new IllegalStateException("Not a Nums");
             }