Repository: checkstyle/checkstyle

Problem statement:
new Check: NoWhitespaceBeforeCaseDefaultColon
The idea of this check originates from https://github.com/checkstyle/checkstyle/issues/8045
This check should report whitespaces before colon token of switch cases and default.
```
cat Test.java
class Test {
	{
		switch(1) {
			case 1 : // expected violation
				break;
                        case 2:
                                break;
			default : // expected violation
				break;
		}
	}
}

$ cat config.xml
<?xml version="1.0"?>
<!DOCTYPE module PUBLIC
          "-//Puppy Crawl//DTD Check Configuration 1.3//EN"
          "https://checkstyle.org/dtds/configuration_1_3.dtd">
<module name="Checker">
    <property name="charset" value="UTF-8"/>
    <module name="TreeWalker">
       <module name="NoWhitespaceBeforeCaseDefaultColon"/>
    </module>
</module>
/var/tmp $ java $RUN_LOCALE -jar checkstyle-8.31-all.jar -c config.xml TestClass.java
Starting audit...
[ERROR] /var/tmp/Test.java:4: ':' is preceded with whitespace. [NoWhitespaceBeforeCaseDefaultColon]
[ERROR] /var/tmp/Test.java:6: ':' is preceded with whitespace. [NoWhitespaceBeforeCaseDefaultColon]
Audit done.
Checkstyle ends with 2 errors.
```

Rationale: 
The official [google java style guide](https://google.github.io/styleguide/javaguide.html#s4.6-whitespace) does not allow whitespaces before the colon of switch cases and default. Adding this check will improve checkstyle's support for google's java style guide.
Also, we can see in comments of https://github.com/checkstyle/checkstyle/issues/8045 that users are well receptive to the check.


Hints:
Also, no whitespace is expected in [LabeledStatements](https://docs.oracle.com/javase/specs/jls/se8/html/jls-14.html#jls-LabeledStatement):
```java
outer: for(;;) {
   for(;;) {
     break outer;
   }
}
```
If we come up with a good name, we can also handle them.
@pbludov, we handle this already.
See Issue https://github.com/checkstyle/checkstyle/issues/8124 and corresponding PR https://github.com/checkstyle/checkstyle/pull/8125
> @pbludov, we handle this already.
> See Issue #8124 and corresponding PR #8125

Sorry, I missed it. Well, it looks weird: actually, it should be "no whitespace **after** labeled statement." @romani may be it is better to revert #8124 and add this to the new check?
@pbludov I agree with you that it seems weird, but I think the weirdness comes from the tree structure, from the fact that the colon ':' of a labeled statement is not a child of the `LABELED_STAT` token, but instead is the text of `LABELED_STAT` token.

    |      |--LABELED_STAT -> : [4:24]
    |      |  |--IDENT -> mylabel [4:16]
    |      |  |--SINGLE_LINE_COMMENT -> // [4:27]
    |      |  |  `--COMMENT_CONTENT ->  expected violation\n [4:29]

What we wanted in #8124 was a check that reports whitespace *before* the colon of a labeled statement, so it made sense to add that token to `NoWhitespaceBeforeCheck`
I am on it.

Patch:
diff --git a/src/it/java/org/checkstyle/suppressionxpathfilter/XpathRegressionNoWhitespaceBeforeCaseDefaultColonTest.java b/src/it/java/org/checkstyle/suppressionxpathfilter/XpathRegressionNoWhitespaceBeforeCaseDefaultColonTest.java
new file mode 100644
--- /dev/null
+++ b/src/it/java/org/checkstyle/suppressionxpathfilter/XpathRegressionNoWhitespaceBeforeCaseDefaultColonTest.java
@@ -0,0 +1,139 @@
+////////////////////////////////////////////////////////////////////////////////
+// checkstyle: Checks Java source code for adherence to a set of rules.
+// Copyright (C) 2001-2021 the original author or authors.
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+////////////////////////////////////////////////////////////////////////////////
+
+package org.checkstyle.suppressionxpathfilter;
+
+import java.io.File;
+import java.util.Collections;
+import java.util.List;
+
+import org.junit.jupiter.api.Test;
+
+import com.puppycrawl.tools.checkstyle.DefaultConfiguration;
+import com.puppycrawl.tools.checkstyle.checks.whitespace.NoWhitespaceBeforeCaseDefaultColonCheck;
+
+public class XpathRegressionNoWhitespaceBeforeCaseDefaultColonTest
+        extends AbstractXpathTestSupport {
+
+    private final String checkName = NoWhitespaceBeforeCaseDefaultColonCheck.class.getSimpleName();
+
+    @Override
+    protected String getCheckName() {
+        return checkName;
+    }
+
+    @Test
+    public void testOne() throws Exception {
+        final File fileToProcess =
+                new File(getPath(
+                        "SuppressionXpathRegressionNoWhitespaceBeforeCaseDefaultColonOne.java"));
+
+        final DefaultConfiguration moduleConfig =
+                createModuleConfig(NoWhitespaceBeforeCaseDefaultColonCheck.class);
+
+        final String[] expectedViolation = {
+            "6:20: " + getCheckMessage(NoWhitespaceBeforeCaseDefaultColonCheck.class,
+                    NoWhitespaceBeforeCaseDefaultColonCheck.MSG_KEY, ":"),
+        };
+
+        final List<String> expectedXpathQueries = Collections.singletonList(
+            "/CLASS_DEF[./IDENT[@text="
+                    + "'SuppressionXpathRegressionNoWhitespaceBeforeCaseDefaultColonOne']]"
+                    + "/OBJBLOCK/INSTANCE_INIT/SLIST/LITERAL_SWITCH/CASE_GROUP/LITERAL_CASE/COLON"
+        );
+
+        runVerifications(moduleConfig, fileToProcess, expectedViolation,
+                expectedXpathQueries);
+    }
+
+    @Test
+    public void testTwo() throws Exception {
+        final File fileToProcess =
+                new File(getPath(
+                        "SuppressionXpathRegressionNoWhitespaceBeforeCaseDefaultColonTwo.java"));
+
+        final DefaultConfiguration moduleConfig =
+                createModuleConfig(NoWhitespaceBeforeCaseDefaultColonCheck.class);
+
+        final String[] expectedViolation = {
+            "10:21: " + getCheckMessage(NoWhitespaceBeforeCaseDefaultColonCheck.class,
+                    NoWhitespaceBeforeCaseDefaultColonCheck.MSG_KEY, ":"),
+        };
+
+        final List<String> expectedXpathQueries = Collections.singletonList(
+            "/CLASS_DEF[./IDENT[@text="
+                    + "'SuppressionXpathRegressionNoWhitespaceBeforeCaseDefaultColonTwo']]"
+                    + "/OBJBLOCK/INSTANCE_INIT/SLIST/LITERAL_SWITCH/CASE_GROUP"
+                    + "/LITERAL_DEFAULT/COLON"
+        );
+
+        runVerifications(moduleConfig, fileToProcess, expectedViolation,
+                expectedXpathQueries);
+    }
+
+    @Test
+    public void testThree() throws Exception {
+        final File fileToProcess =
+                new File(getPath(
+                        "SuppressionXpathRegressionNoWhitespaceBeforeCaseDefaultColonThree.java"));
+
+        final DefaultConfiguration moduleConfig =
+                createModuleConfig(NoWhitespaceBeforeCaseDefaultColonCheck.class);
+
+        final String[] expectedViolation = {
+            "7:21: " + getCheckMessage(NoWhitespaceBeforeCaseDefaultColonCheck.class,
+                        NoWhitespaceBeforeCaseDefaultColonCheck.MSG_KEY, ":"),
+        };
+
+        final List<String> expectedXpathQueries = Collections.singletonList(
+            "/CLASS_DEF[./IDENT[@text="
+                    + "'SuppressionXpathRegressionNoWhitespaceBeforeCaseDefaultColonThree']]"
+                    + "/OBJBLOCK/INSTANCE_INIT/SLIST/LITERAL_SWITCH/CASE_GROUP"
+                    + "/LITERAL_CASE/COLON"
+        );
+
+        runVerifications(moduleConfig, fileToProcess, expectedViolation,
+                expectedXpathQueries);
+    }
+
+    @Test
+    public void testFour() throws Exception {
+        final File fileToProcess =
+                new File(getPath(
+                        "SuppressionXpathRegressionNoWhitespaceBeforeCaseDefaultColonFour.java"));
+
+        final DefaultConfiguration moduleConfig =
+                createModuleConfig(NoWhitespaceBeforeCaseDefaultColonCheck.class);
+
+        final String[] expectedViolation = {
+            "11:21: " + getCheckMessage(NoWhitespaceBeforeCaseDefaultColonCheck.class,
+                        NoWhitespaceBeforeCaseDefaultColonCheck.MSG_KEY, ":"),
+        };
+
+        final List<String> expectedXpathQueries = Collections.singletonList(
+            "/CLASS_DEF[./IDENT[@text="
+                    + "'SuppressionXpathRegressionNoWhitespaceBeforeCaseDefaultColonFour']]"
+                    + "/OBJBLOCK/INSTANCE_INIT/SLIST/LITERAL_SWITCH/CASE_GROUP"
+                    + "/LITERAL_DEFAULT/COLON"
+        );
+
+        runVerifications(moduleConfig, fileToProcess, expectedViolation,
+                expectedXpathQueries);
+    }
+}
diff --git a/src/it/resources/org/checkstyle/suppressionxpathfilter/nowhitespacebeforecasedefaultcolon/SuppressionXpathRegressionNoWhitespaceBeforeCaseDefaultColonFour.java b/src/it/resources/org/checkstyle/suppressionxpathfilter/nowhitespacebeforecasedefaultcolon/SuppressionXpathRegressionNoWhitespaceBeforeCaseDefaultColonFour.java
new file mode 100644
--- /dev/null
+++ b/src/it/resources/org/checkstyle/suppressionxpathfilter/nowhitespacebeforecasedefaultcolon/SuppressionXpathRegressionNoWhitespaceBeforeCaseDefaultColonFour.java
@@ -0,0 +1,15 @@
+package org.checkstyle.suppressionxpathfilter.nowhitespacebeforecasedefaultcolon;
+
+public class SuppressionXpathRegressionNoWhitespaceBeforeCaseDefaultColonFour {
+    {
+        switch(1) {
+            case 1:
+                break;
+            case 2:
+                break;
+            default
+                    : // warn
+                break;
+        }
+    }
+}
diff --git a/src/it/resources/org/checkstyle/suppressionxpathfilter/nowhitespacebeforecasedefaultcolon/SuppressionXpathRegressionNoWhitespaceBeforeCaseDefaultColonOne.java b/src/it/resources/org/checkstyle/suppressionxpathfilter/nowhitespacebeforecasedefaultcolon/SuppressionXpathRegressionNoWhitespaceBeforeCaseDefaultColonOne.java
new file mode 100644
--- /dev/null
+++ b/src/it/resources/org/checkstyle/suppressionxpathfilter/nowhitespacebeforecasedefaultcolon/SuppressionXpathRegressionNoWhitespaceBeforeCaseDefaultColonOne.java
@@ -0,0 +1,14 @@
+package org.checkstyle.suppressionxpathfilter.nowhitespacebeforecasedefaultcolon;
+
+public class SuppressionXpathRegressionNoWhitespaceBeforeCaseDefaultColonOne {
+    {
+        switch(1) {
+            case 1 : // warn
+                break;
+            case 2:
+                break;
+            default:
+                break;
+        }
+    }
+}
diff --git a/src/it/resources/org/checkstyle/suppressionxpathfilter/nowhitespacebeforecasedefaultcolon/SuppressionXpathRegressionNoWhitespaceBeforeCaseDefaultColonThree.java b/src/it/resources/org/checkstyle/suppressionxpathfilter/nowhitespacebeforecasedefaultcolon/SuppressionXpathRegressionNoWhitespaceBeforeCaseDefaultColonThree.java
new file mode 100644
--- /dev/null
+++ b/src/it/resources/org/checkstyle/suppressionxpathfilter/nowhitespacebeforecasedefaultcolon/SuppressionXpathRegressionNoWhitespaceBeforeCaseDefaultColonThree.java
@@ -0,0 +1,15 @@
+package org.checkstyle.suppressionxpathfilter.nowhitespacebeforecasedefaultcolon;
+
+public class SuppressionXpathRegressionNoWhitespaceBeforeCaseDefaultColonThree {
+    {
+        switch(1) {
+            case 1
+                    : // warn
+                break;
+            case 2:
+                break;
+            default:
+                break;
+        }
+    }
+}
diff --git a/src/it/resources/org/checkstyle/suppressionxpathfilter/nowhitespacebeforecasedefaultcolon/SuppressionXpathRegressionNoWhitespaceBeforeCaseDefaultColonTwo.java b/src/it/resources/org/checkstyle/suppressionxpathfilter/nowhitespacebeforecasedefaultcolon/SuppressionXpathRegressionNoWhitespaceBeforeCaseDefaultColonTwo.java
new file mode 100644
--- /dev/null
+++ b/src/it/resources/org/checkstyle/suppressionxpathfilter/nowhitespacebeforecasedefaultcolon/SuppressionXpathRegressionNoWhitespaceBeforeCaseDefaultColonTwo.java
@@ -0,0 +1,14 @@
+package org.checkstyle.suppressionxpathfilter.nowhitespacebeforecasedefaultcolon;
+
+public class SuppressionXpathRegressionNoWhitespaceBeforeCaseDefaultColonTwo {
+    {
+        switch(1) {
+            case 1:
+                break;
+            case 2:
+                break;
+            default : // warn
+                break;
+        }
+    }
+}
diff --git a/src/main/java/com/puppycrawl/tools/checkstyle/PackageObjectFactory.java b/src/main/java/com/puppycrawl/tools/checkstyle/PackageObjectFactory.java
--- a/src/main/java/com/puppycrawl/tools/checkstyle/PackageObjectFactory.java
+++ b/src/main/java/com/puppycrawl/tools/checkstyle/PackageObjectFactory.java
@@ -829,6 +829,8 @@ private static void fillChecksFromWhitespacePackage() {
                 BASE_PACKAGE + ".checks.whitespace.NoWhitespaceAfterCheck");
         NAME_TO_FULL_MODULE_NAME.put("NoWhitespaceBeforeCheck",
                 BASE_PACKAGE + ".checks.whitespace.NoWhitespaceBeforeCheck");
+        NAME_TO_FULL_MODULE_NAME.put("NoWhitespaceBeforeCaseDefaultColonCheck",
+                BASE_PACKAGE + ".checks.whitespace.NoWhitespaceBeforeCaseDefaultColonCheck");
         NAME_TO_FULL_MODULE_NAME.put("OperatorWrapCheck",
                 BASE_PACKAGE + ".checks.whitespace.OperatorWrapCheck");
         NAME_TO_FULL_MODULE_NAME.put("ParenPadCheck",
diff --git a/src/main/java/com/puppycrawl/tools/checkstyle/checks/whitespace/NoWhitespaceBeforeCaseDefaultColonCheck.java b/src/main/java/com/puppycrawl/tools/checkstyle/checks/whitespace/NoWhitespaceBeforeCaseDefaultColonCheck.java
new file mode 100644
--- /dev/null
+++ b/src/main/java/com/puppycrawl/tools/checkstyle/checks/whitespace/NoWhitespaceBeforeCaseDefaultColonCheck.java
@@ -0,0 +1,220 @@
+////////////////////////////////////////////////////////////////////////////////
+// checkstyle: Checks Java source code for adherence to a set of rules.
+// Copyright (C) 2001-2021 the original author or authors.
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+////////////////////////////////////////////////////////////////////////////////
+
+package com.puppycrawl.tools.checkstyle.checks.whitespace;
+
+import com.puppycrawl.tools.checkstyle.StatelessCheck;
+import com.puppycrawl.tools.checkstyle.api.AbstractCheck;
+import com.puppycrawl.tools.checkstyle.api.DetailAST;
+import com.puppycrawl.tools.checkstyle.api.TokenTypes;
+import com.puppycrawl.tools.checkstyle.utils.TokenUtil;
+
+/**
+ * <p>
+ * Checks that there is no whitespace before the colon in a switch block.
+ * </p>
+ * <p>
+ * To configure the check:
+ * </p>
+ * <pre>
+ * &lt;module name=&quot;NoWhitespaceBeforeCaseDefaultColon&quot;/&gt;
+ * </pre>
+ * <p>Example:</p>
+ * <pre>
+ * class Test {
+ *   {
+ *     switch(1) {
+ *         case 1 : // violation, whitespace before ':' is not allowed here
+ *             break;
+ *         case 2: // ok
+ *             break;
+ *         default : // violation, whitespace before ':' is not allowed here
+ *             break;
+ *     }
+ *
+ *     switch(2) {
+ *         case 2: // ok
+ *             break;
+ *         case 3, 4
+ *                  : break; // violation, whitespace before ':' is not allowed here
+ *         case 4,
+ *               5: break; // ok
+ *         default
+ *               : // violation, whitespace before ':' is not allowed here
+ *             break;
+ *     }
+ *
+ *     switch(day) {
+ *         case MONDAY, FRIDAY, SUNDAY: System.out.println("  6"); break;
+ *         case TUESDAY               : System.out.println("  7"); break; // violation
+ *   }
+ * }
+ * </pre>
+ * <p>
+ * Parent is {@code com.puppycrawl.tools.checkstyle.TreeWalker}
+ * </p>
+ * <p>
+ * Violation Message Keys:
+ * </p>
+ * <ul>
+ * <li>
+ * {@code ws.preceded}
+ * </li>
+ * </ul>
+ *
+ * @since 8.45
+ */
+@StatelessCheck
+public class NoWhitespaceBeforeCaseDefaultColonCheck
+    extends AbstractCheck {
+
+    /**
+     * A key is pointing to the warning message text in "messages.properties"
+     * file.
+     */
+    public static final String MSG_KEY = "ws.preceded";
+
+    @Override
+    public int[] getDefaultTokens() {
+        return getRequiredTokens();
+    }
+
+    @Override
+    public int[] getAcceptableTokens() {
+        return getRequiredTokens();
+    }
+
+    @Override
+    public int[] getRequiredTokens() {
+        return new int[] {TokenTypes.COLON};
+    }
+
+    @Override
+    public boolean isCommentNodesRequired() {
+        return true;
+    }
+
+    @Override
+    public void visitToken(DetailAST ast) {
+        if (isInSwitch(ast) && isWhiteSpaceBeforeColon(ast)) {
+            log(ast, MSG_KEY, ast.getText());
+        }
+    }
+
+    /**
+     * Checks if the colon is inside a switch block.
+     *
+     * @param colonAst DetailAST to check.
+     * @return true, if colon case is inside a switch block.
+     */
+    private static boolean isInSwitch(DetailAST colonAst) {
+        return TokenUtil.isOfType(colonAst.getParent(), TokenTypes.LITERAL_CASE,
+                TokenTypes.LITERAL_DEFAULT);
+    }
+
+    /**
+     * Checks if there is a whitespace before the colon of a switch case or switch default.
+     *
+     * @param colonAst DetailAST to check.
+     * @return true, if there is whitespace preceding colonAst.
+     */
+    private static boolean isWhiteSpaceBeforeColon(DetailAST colonAst) {
+        final DetailAST parent = colonAst.getParent();
+        final boolean result;
+        if (isOnDifferentLineWithPreviousToken(colonAst)) {
+            result = true;
+        }
+        else if (parent.getType() == TokenTypes.LITERAL_CASE) {
+            result = isWhitespaceBeforeColonOfCase(colonAst);
+        }
+        else {
+            result = isWhitespaceBeforeColonOfDefault(colonAst);
+        }
+        return result;
+    }
+
+    /**
+     * Checks if there is a whitespace before the colon of a switch case.
+     *
+     * @param colonAst DetailAST to check.
+     * @return true, if there is whitespace preceding colonAst.
+     */
+    private static boolean isWhitespaceBeforeColonOfCase(DetailAST colonAst) {
+        final DetailAST previousSibling = colonAst.getPreviousSibling();
+        int offset = 0;
+        if (previousSibling.getType() == TokenTypes.BLOCK_COMMENT_BEGIN) {
+            offset = 1;
+        }
+        return colonAst.getColumnNo() != getLastColumnNumberOf(previousSibling) + offset;
+    }
+
+    /**
+     * Checks if there is a whitespace before the colon of a switch default.
+     *
+     * @param colonAst DetailAST to check.
+     * @return true, if there is whitespace preceding colonAst.
+     */
+    private static boolean isWhitespaceBeforeColonOfDefault(DetailAST colonAst) {
+        final boolean result;
+        final DetailAST previousSibling = colonAst.getPreviousSibling();
+        if (previousSibling == null) {
+            final DetailAST literalDefault = colonAst.getParent();
+            result = colonAst.getColumnNo()
+                    != literalDefault.getColumnNo() + literalDefault.getText().length();
+        }
+        else {
+            result =
+                    colonAst.getColumnNo() != getLastColumnNumberOf(previousSibling) + 1;
+        }
+        return result;
+    }
+
+    /**
+     * Checks if the colon is on same line as of case or default.
+     *
+     * @param colonAst DetailAST to check.
+     * @return true, if colon case is in different line as of case or default.
+     */
+    private static boolean isOnDifferentLineWithPreviousToken(DetailAST colonAst) {
+        final DetailAST previousSibling;
+        final DetailAST parent = colonAst.getParent();
+        if (parent.getType() == TokenTypes.LITERAL_CASE) {
+            previousSibling = colonAst.getPreviousSibling();
+        }
+        else {
+            previousSibling = colonAst.getParent();
+        }
+        return !TokenUtil.areOnSameLine(previousSibling, colonAst);
+    }
+
+    /**
+     * Returns the last column number of an ast.
+     *
+     * @param ast DetailAST to check.
+     * @return ast's last column number.
+     */
+    private static int getLastColumnNumberOf(DetailAST ast) {
+        DetailAST lastChild = ast;
+        while (lastChild.hasChildren()) {
+            lastChild = lastChild.getLastChild();
+        }
+        return lastChild.getColumnNo() + lastChild.getText().length();
+    }
+
+}


Test patch:
diff --git a/src/it/java/com/google/checkstyle/test/chapter4formatting/rule462horizontalwhitespace/NoWhitespaceBeforeCaseDefaultColonTest.java b/src/it/java/com/google/checkstyle/test/chapter4formatting/rule462horizontalwhitespace/NoWhitespaceBeforeCaseDefaultColonTest.java
new file mode 100644
--- /dev/null
+++ b/src/it/java/com/google/checkstyle/test/chapter4formatting/rule462horizontalwhitespace/NoWhitespaceBeforeCaseDefaultColonTest.java
@@ -0,0 +1,52 @@
+////////////////////////////////////////////////////////////////////////////////
+// checkstyle: Checks Java source code for adherence to a set of rules.
+// Copyright (C) 2001-2021 the original author or authors.
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+////////////////////////////////////////////////////////////////////////////////
+
+package com.google.checkstyle.test.chapter4formatting.rule462horizontalwhitespace;
+
+import org.junit.jupiter.api.Test;
+
+import com.google.checkstyle.test.base.AbstractGoogleModuleTestSupport;
+import com.puppycrawl.tools.checkstyle.api.Configuration;
+import com.puppycrawl.tools.checkstyle.checks.whitespace.NoWhitespaceBeforeCheck;
+
+public class NoWhitespaceBeforeCaseDefaultColonTest extends AbstractGoogleModuleTestSupport {
+
+    @Override
+    protected String getPackageLocation() {
+        return "com/google/checkstyle/test/chapter4formatting/rule462horizontalwhitespace";
+    }
+
+    @Test
+    public void test() throws Exception {
+        final Class<NoWhitespaceBeforeCheck> clazz = NoWhitespaceBeforeCheck.class;
+        final String messageKeyPreceded = "ws.preceded";
+
+        final String[] expected = {
+            "6:20: " + getCheckMessage(clazz, messageKeyPreceded, ":"),
+            "10:21: " + getCheckMessage(clazz, messageKeyPreceded, ":"),
+        };
+        final Configuration checkConfig = getModuleConfig("NoWhitespaceBeforeCaseDefaultColon");
+        final String filePath = getPath("InputNoWhitespaceBeforeCaseDefaultColon.java");
+
+        final Integer[] warnList = getLinesWithWarn(filePath);
+        verify(checkConfig, filePath, expected, warnList);
+    }
+
+}
+
diff --git a/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule462horizontalwhitespace/InputNoWhitespaceBeforeCaseDefaultColon.java b/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule462horizontalwhitespace/InputNoWhitespaceBeforeCaseDefaultColon.java
new file mode 100644
--- /dev/null
+++ b/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule462horizontalwhitespace/InputNoWhitespaceBeforeCaseDefaultColon.java
@@ -0,0 +1,14 @@
+package com.google.checkstyle.test.chapter4formatting.rule462horizontalwhitespace;
+
+public class InputNoWhitespaceBeforeCaseDefaultColon {
+    {
+        switch(1) {
+            case 1 : // warn
+                break;
+            case 2:
+                break;
+            default : // warn
+                break;
+        }
+    }
+}
diff --git a/src/test/java/com/puppycrawl/tools/checkstyle/checks/whitespace/NoWhitespaceBeforeCaseDefaultColonCheckTest.java b/src/test/java/com/puppycrawl/tools/checkstyle/checks/whitespace/NoWhitespaceBeforeCaseDefaultColonCheckTest.java
new file mode 100644
--- /dev/null
+++ b/src/test/java/com/puppycrawl/tools/checkstyle/checks/whitespace/NoWhitespaceBeforeCaseDefaultColonCheckTest.java
@@ -0,0 +1,90 @@
+////////////////////////////////////////////////////////////////////////////////
+// checkstyle: Checks Java source code for adherence to a set of rules.
+// Copyright (C) 2001-2021 the original author or authors.
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+////////////////////////////////////////////////////////////////////////////////
+
+package com.puppycrawl.tools.checkstyle.checks.whitespace;
+
+import static com.google.common.truth.Truth.assertWithMessage;
+import static com.puppycrawl.tools.checkstyle.checks.whitespace.NoWhitespaceBeforeCaseDefaultColonCheck.MSG_KEY;
+
+import org.junit.jupiter.api.Test;
+
+import com.puppycrawl.tools.checkstyle.AbstractModuleTestSupport;
+import com.puppycrawl.tools.checkstyle.DefaultConfiguration;
+import com.puppycrawl.tools.checkstyle.api.TokenTypes;
+
+public class NoWhitespaceBeforeCaseDefaultColonCheckTest
+    extends AbstractModuleTestSupport {
+
+    @Override
+    protected String getPackageLocation() {
+        return "com/puppycrawl/tools/checkstyle/checks/whitespace"
+                + "/nowhitespacebeforecasedefaultcolon";
+    }
+
+    @Test
+    public void testDefault() throws Exception {
+        final DefaultConfiguration checkConfig = createModuleConfig(
+                NoWhitespaceBeforeCaseDefaultColonCheck.class);
+        final String[] expected = {
+            "15:20: " + getCheckMessage(MSG_KEY, ":"),
+            "19:21: " + getCheckMessage(MSG_KEY, ":"),
+            "32:37: " + getCheckMessage(MSG_KEY, ":"),
+            "40:21: " + getCheckMessage(MSG_KEY, ":"),
+            "44:28: " + getCheckMessage(MSG_KEY, ":"),
+            "47:1: " + getCheckMessage(MSG_KEY, ":"),
+            "50:27: " + getCheckMessage(MSG_KEY, ":"),
+            "61:38: " + getCheckMessage(MSG_KEY, ":"),
+            "66:38: " + getCheckMessage(MSG_KEY, ":"),
+            "79:24: " + getCheckMessage(MSG_KEY, ":"),
+            "82:21: " + getCheckMessage(MSG_KEY, ":"),
+            "89:38: " + getCheckMessage(MSG_KEY, ":"),
+            "92:35: " + getCheckMessage(MSG_KEY, ":"),
+        };
+        verify(checkConfig, getPath("InputNoWhitespaceBeforeCaseDefaultColon.java"),
+                expected);
+    }
+
+    @Test
+    public void testDefaultNonCompilable() throws Exception {
+        final DefaultConfiguration checkConfig = createModuleConfig(
+                NoWhitespaceBeforeCaseDefaultColonCheck.class);
+        final String[] expected = {
+            "33:22: " + getCheckMessage(MSG_KEY, ":"),
+            "36:21: " + getCheckMessage(MSG_KEY, ":"),
+            "39:25: " + getCheckMessage(MSG_KEY, ":"),
+            "58:20: " + getCheckMessage(MSG_KEY, ":"),
+            "71:32: " + getCheckMessage(MSG_KEY, ":"),
+            "88:17: " + getCheckMessage(MSG_KEY, ":"),
+            "91:20: " + getCheckMessage(MSG_KEY, ":"),
+            "94:21: " + getCheckMessage(MSG_KEY, ":"),
+        };
+        verify(checkConfig,
+                getNonCompilablePath("InputNoWhitespaceBeforeCaseDefaultColonEnumAndStrings.java"),
+                expected);
+    }
+
+    @Test
+    public void testAcceptableTokenIsColon() {
+        final NoWhitespaceBeforeCaseDefaultColonCheck check =
+                new NoWhitespaceBeforeCaseDefaultColonCheck();
+        assertWithMessage("Acceptable token should be colon").that(new int[] {TokenTypes.COLON})
+                .isEqualTo(check.getAcceptableTokens());
+    }
+
+}
diff --git a/src/test/resources-noncompilable/com/puppycrawl/tools/checkstyle/checks/whitespace/nowhitespacebeforecasedefaultcolon/InputNoWhitespaceBeforeCaseDefaultColonEnumAndStrings.java b/src/test/resources-noncompilable/com/puppycrawl/tools/checkstyle/checks/whitespace/nowhitespacebeforecasedefaultcolon/InputNoWhitespaceBeforeCaseDefaultColonEnumAndStrings.java
new file mode 100644
--- /dev/null
+++ b/src/test/resources-noncompilable/com/puppycrawl/tools/checkstyle/checks/whitespace/nowhitespacebeforecasedefaultcolon/InputNoWhitespaceBeforeCaseDefaultColonEnumAndStrings.java
@@ -0,0 +1,101 @@
+//non-compiled with javac: Compilable with Java14
+package com.puppycrawl.tools.checkstyle.checks.whitespace.nowhitespacebeforecasedefaultcolon;
+
+/*
+ * Config: default
+ */
+class InputNoWhitespaceBeforeCaseDefaultColonEnumAndStrings {
+
+    enum Day {
+        MON,
+        TUE,
+        WED,
+        THU,
+        FRI,
+        SAT,
+        SUN,
+    }
+
+    String whatIsToday(Day day) {
+        return switch (day) {
+            case SAT, SUN -> "Weekend";
+            case MON, TUE, WED, THU, FRI -> "Working day";
+            default -> throw new IllegalArgumentException("Invalid day: " + day.name());
+        };
+    }
+
+    int assignment(Day day) {
+        int numLetters = -1;
+        switch (day) {
+            case MON,
+                    FRI: numLetters = 6; // ok
+                            break;
+            case TUE : numLetters = 7; // violation
+                       break;
+            case THU, SAT
+                    : numLetters = 8; // violation
+                         break;
+            case WED,
+                    SUN : numLetters = 9; // volation
+                          break;
+        };
+        return numLetters;
+    }
+
+    int complexCase(Day day) {
+        int someInt = -1;
+        return switch (day) {
+            case MON,
+                    TUE: { // ok
+                int l = day.toString().length();
+                yield l + someInt;
+            }
+            case WED: { // ok
+                int l = day.toString().length();
+                yield l + someInt * 2;
+            }
+            default
+                   : { // violation
+                int l = day.toString().length();
+                yield l;
+            }
+        };
+    }
+
+    int numberOfDays(String month) {
+        int days = -1;
+        switch (month) {
+            case "FEB": days = 28; // ok
+                        break;
+            case "JAN", "MAR"
+                       , "MAY" : days = 31; break; // violation
+            case "APR", "JUN": days = 30; // ok
+                                break;
+        };
+        return days;
+    }
+
+    enum T {
+        A, B, C;
+    }
+
+    static {
+        int x;
+        T e = T.B;
+
+        boolean t8 = (switch (e) {
+            case A
+                : // violation
+                x = 1;
+                yield true;
+            case B : // violation
+                yield (x = 1) == 1 || true;
+            default
+                    :yield false; // violation
+        }) && x == 1;
+
+        if (!t8) {
+            throw new IllegalStateException("Unexpected result.");
+        }
+    }
+}
diff --git a/src/test/resources/com/puppycrawl/tools/checkstyle/checks/whitespace/nowhitespacebeforecasedefaultcolon/InputNoWhitespaceBeforeCaseDefaultColon.java b/src/test/resources/com/puppycrawl/tools/checkstyle/checks/whitespace/nowhitespacebeforecasedefaultcolon/InputNoWhitespaceBeforeCaseDefaultColon.java
new file mode 100644
--- /dev/null
+++ b/src/test/resources/com/puppycrawl/tools/checkstyle/checks/whitespace/nowhitespacebeforecasedefaultcolon/InputNoWhitespaceBeforeCaseDefaultColon.java
@@ -0,0 +1,110 @@
+/*
+NoWhitespaceBeforeCaseDefaultColon
+
+
+
+*/
+
+package com.puppycrawl.tools.checkstyle.checks.whitespace.nowhitespacebeforecasedefaultcolon;
+
+import com.puppycrawl.tools.checkstyle.api.TokenTypes;
+
+public class InputNoWhitespaceBeforeCaseDefaultColon {
+    {
+        switch(1) {
+            case 1 : // violation
+                break;
+            case 2:
+                break;
+            default : // violation
+                break;
+        }
+
+        switch(2) {
+            case 2:
+                break;
+            default:
+                break;
+
+        }
+
+        switch(3) {
+            case 3/* space after */ : // violation
+                break;
+            default/* no space after */:
+                break;
+        }
+
+        switch(4) {
+            case 4
+                    : // violation
+                break;
+            default:
+                switch(5) {
+                    case 5 : // violation
+                        break;
+                    case 6
+: // violation
+                        break;
+                    case 7
+                          : // violation
+                        break;
+                    default:
+                        break;
+                }
+                break;
+        }
+
+        switch(8) {
+            case 8/* no space after */:
+                break;
+            default/* space after */ : // violation
+                break;
+        }
+
+        switch (TokenTypes.ABSTRACT) {
+            case TokenTypes.TYPECAST : // violation
+                break;
+            case TokenTypes.ARRAY_DECLARATOR:
+                break;
+            default:
+                break;
+        }
+
+        switch(9) {
+            case
+                    9:
+                break;
+            case
+                    10 : // violation
+                break;
+            default
+                    : // violation
+                break;
+
+        }
+
+        switch(11) {
+            case
+                    /* comment */ 11 : // violation
+                break;
+            default
+                    /* comment */ : // violation
+                break;
+
+        }
+
+         for (int var1 : new int[]{}) {}
+
+         for (int var2: new int[]{}) {}
+
+         int i = true ? 0 : 1;
+
+         int j = false ? 0
+                 : 1;
+
+        for (int t = 10; --t >= 0; ) {
+        }
+
+    }
+}