diff --git a/clang/docs/ClangFormatStyleOptions.rst b/clang/docs/ClangFormatStyleOptions.rst --- a/clang/docs/ClangFormatStyleOptions.rst +++ b/clang/docs/ClangFormatStyleOptions.rst @@ -2839,6 +2839,16 @@ int a = 5; vs. int a= 5; a += 42; a+= 42; +**SpaceBeforeCaseColon** (``bool``) + If ``false``, spaces will be removed before case colon. + + .. code-block:: c++ + + true: false + switch (x) { vs. switch (x) { + case 1 : break; case 1: break; + } } + **SpaceBeforeCpp11BracedList** (``bool``) If ``true``, a space will be inserted before a C++11 braced list used to initialize an object (after the preceding identifier or type). diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -289,6 +289,9 @@ - Option ``IndentPragmas`` has been added to allow #pragma to indented with the current scope level. This is especially useful when using #pragma to mark OpenMP sections of code. +- Option ``SpaceBeforeCaseColon`` has been added to add a space before the + colon in a case or default statement. + libclang -------- diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h --- a/clang/include/clang/Format/Format.h +++ b/clang/include/clang/Format/Format.h @@ -2438,6 +2438,15 @@ /// \endcode bool SpaceBeforeAssignmentOperators; + /// If ``false``, spaces will be removed before case colon. + /// \code + /// true: false + /// switch (x) { vs. switch (x) { + /// case 1 : break; case 1: break; + /// } } + /// \endcode + bool SpaceBeforeCaseColon; + /// If ``true``, a space will be inserted before a C++11 braced list /// used to initialize an object (after the preceding identifier or type). /// \code @@ -2820,6 +2829,7 @@ SpaceAfterLogicalNot == R.SpaceAfterLogicalNot && SpaceAfterTemplateKeyword == R.SpaceAfterTemplateKeyword && SpaceBeforeAssignmentOperators == R.SpaceBeforeAssignmentOperators && + SpaceBeforeCaseColon == R.SpaceBeforeCaseColon && SpaceBeforeCpp11BracedList == R.SpaceBeforeCpp11BracedList && SpaceBeforeCtorInitializerColon == R.SpaceBeforeCtorInitializerColon && diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp --- a/clang/lib/Format/Format.cpp +++ b/clang/lib/Format/Format.cpp @@ -608,6 +608,7 @@ Style.SpaceAfterTemplateKeyword); IO.mapOptional("SpaceBeforeAssignmentOperators", Style.SpaceBeforeAssignmentOperators); + IO.mapOptional("SpaceBeforeCaseColon", Style.SpaceBeforeCaseColon); IO.mapOptional("SpaceBeforeCpp11BracedList", Style.SpaceBeforeCpp11BracedList); IO.mapOptional("SpaceBeforeCtorInitializerColon", @@ -958,6 +959,7 @@ LLVMStyle.SpaceAfterLogicalNot = false; LLVMStyle.SpaceAfterTemplateKeyword = true; LLVMStyle.SpaceAroundPointerQualifiers = FormatStyle::SAPQ_Default; + LLVMStyle.SpaceBeforeCaseColon = false; LLVMStyle.SpaceBeforeCtorInitializerColon = true; LLVMStyle.SpaceBeforeInheritanceColon = true; LLVMStyle.SpaceBeforeParens = FormatStyle::SBPO_ControlStatements; diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp --- a/clang/lib/Format/TokenAnnotator.cpp +++ b/clang/lib/Format/TokenAnnotator.cpp @@ -896,7 +896,8 @@ } else if (CurrentToken && CurrentToken->is(tok::numeric_constant)) { Tok->setType(TT_BitFieldColon); } else if (Contexts.size() == 1 && - !Line.First->isOneOf(tok::kw_enum, tok::kw_case)) { + !Line.First->isOneOf(tok::kw_enum, tok::kw_case, + tok::kw_default)) { FormatToken *Prev = Tok->getPreviousNonComment(); if (Prev->isOneOf(tok::r_paren, tok::kw_noexcept)) Tok->setType(TT_CtorInitializerColon); @@ -3340,8 +3341,9 @@ return Style.BitFieldColonSpacing == FormatStyle::BFCS_Both || Style.BitFieldColonSpacing == FormatStyle::BFCS_After; if (Right.is(tok::colon)) { - if (Line.First->isOneOf(tok::kw_case, tok::kw_default) || - !Right.getNextNonComment() || Right.getNextNonComment()->is(tok::semi)) + if (Line.First->isOneOf(tok::kw_default, tok::kw_case)) + return Style.SpaceBeforeCaseColon; + if (!Right.getNextNonComment() || Right.getNextNonComment()->is(tok::semi)) return false; if (Right.is(TT_ObjCMethodExpr)) return false; diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp --- a/clang/unittests/Format/FormatTest.cpp +++ b/clang/unittests/Format/FormatTest.cpp @@ -12077,6 +12077,17 @@ "case 1:\n" "default:\n" "}"); + verifyFormat("switch (allBraces) {\n" + "case 1: {\n" + " break;\n" + "}\n" + "case 2: {\n" + " [[fallthrough]];\n" + "}\n" + "default: {\n" + " break;\n" + "}\n" + "}"); FormatStyle CtorInitializerStyle = getLLVMStyleWithColumns(30); CtorInitializerStyle.SpaceBeforeCtorInitializerColon = false; @@ -12094,6 +12105,18 @@ "default:\n" "}", CtorInitializerStyle); + verifyFormat("switch (allBraces) {\n" + "case 1: {\n" + " break;\n" + "}\n" + "case 2: {\n" + " [[fallthrough]];\n" + "}\n" + "default: {\n" + " break;\n" + "}\n" + "}", + CtorInitializerStyle); CtorInitializerStyle.BreakConstructorInitializers = FormatStyle::BCIS_AfterColon; verifyFormat("Fooooooooooo::Fooooooooooo():\n" @@ -12134,6 +12157,18 @@ "default:\n" "}", InheritanceStyle); + verifyFormat("switch (allBraces) {\n" + "case 1: {\n" + " break;\n" + "}\n" + "case 2: {\n" + " [[fallthrough]];\n" + "}\n" + "default: {\n" + " break;\n" + "}\n" + "}", + InheritanceStyle); InheritanceStyle.BreakInheritanceList = FormatStyle::BILS_AfterColon; verifyFormat("class Foooooooooooooooooooooo:\n" " public aaaaaaaaaaaaaaaaaa,\n" @@ -12174,8 +12209,45 @@ "default:\n" "}", ForLoopStyle); + verifyFormat("switch (allBraces) {\n" + "case 1: {\n" + " break;\n" + "}\n" + "case 2: {\n" + " [[fallthrough]];\n" + "}\n" + "default: {\n" + " break;\n" + "}\n" + "}", + ForLoopStyle); + + FormatStyle CaseStyle = getLLVMStyle(); + CaseStyle.SpaceBeforeCaseColon = true; + verifyFormat("class Foo : public Bar {};", CaseStyle); + verifyFormat("Foo::Foo() : foo(1) {}", CaseStyle); + verifyFormat("for (auto a : b) {\n}", CaseStyle); + verifyFormat("int x = a ? b : c;", CaseStyle); + verifyFormat("switch (x) {\n" + "case 1 :\n" + "default :\n" + "}", + CaseStyle); + verifyFormat("switch (allBraces) {\n" + "case 1 : {\n" + " break;\n" + "}\n" + "case 2 : {\n" + " [[fallthrough]];\n" + "}\n" + "default : {\n" + " break;\n" + "}\n" + "}", + CaseStyle); FormatStyle NoSpaceStyle = getLLVMStyle(); + EXPECT_EQ(NoSpaceStyle.SpaceBeforeCaseColon, false); NoSpaceStyle.SpaceBeforeCtorInitializerColon = false; NoSpaceStyle.SpaceBeforeInheritanceColon = false; NoSpaceStyle.SpaceBeforeRangeBasedForLoopColon = false; @@ -12193,6 +12265,54 @@ "default:\n" "}", NoSpaceStyle); + verifyFormat("switch (allBraces) {\n" + "case 1: {\n" + " break;\n" + "}\n" + "case 2: {\n" + " [[fallthrough]];\n" + "}\n" + "default: {\n" + " break;\n" + "}\n" + "}", + NoSpaceStyle); + + FormatStyle InvertedSpaceStyle = getLLVMStyle(); + InvertedSpaceStyle.SpaceBeforeCaseColon = true; + InvertedSpaceStyle.SpaceBeforeCtorInitializerColon = false; + InvertedSpaceStyle.SpaceBeforeInheritanceColon = false; + InvertedSpaceStyle.SpaceBeforeRangeBasedForLoopColon = false; + verifyFormat("class Foo: public Bar {};", InvertedSpaceStyle); + verifyFormat("Foo::Foo(): foo(1) {}", InvertedSpaceStyle); + verifyFormat("for (auto a: b) {\n}", InvertedSpaceStyle); + verifyFormat("int x = a ? b : c;", InvertedSpaceStyle); + verifyFormat("{\n" + "label3:\n" + " int x = 0;\n" + "}", + InvertedSpaceStyle); + verifyFormat("switch (x) {\n" + "case 1 :\n" + "case 2 : {\n" + " break;\n" + "}\n" + "default :\n" + " break;\n" + "}", + InvertedSpaceStyle); + verifyFormat("switch (allBraces) {\n" + "case 1 : {\n" + " break;\n" + "}\n" + "case 2 : {\n" + " [[fallthrough]];\n" + "}\n" + "default : {\n" + " break;\n" + "}\n" + "}", + InvertedSpaceStyle); } TEST_F(FormatTest, ConfigurableSpaceAroundPointerQualifiers) { @@ -14170,6 +14290,7 @@ CHECK_PARSE_BOOL(SpaceAfterTemplateKeyword); CHECK_PARSE_BOOL(SpaceAfterLogicalNot); CHECK_PARSE_BOOL(SpaceBeforeAssignmentOperators); + CHECK_PARSE_BOOL(SpaceBeforeCaseColon); CHECK_PARSE_BOOL(SpaceBeforeCpp11BracedList); CHECK_PARSE_BOOL(SpaceBeforeCtorInitializerColon); CHECK_PARSE_BOOL(SpaceBeforeInheritanceColon);