diff --git a/clang/docs/ClangFormatStyleOptions.rst b/clang/docs/ClangFormatStyleOptions.rst --- a/clang/docs/ClangFormatStyleOptions.rst +++ b/clang/docs/ClangFormatStyleOptions.rst @@ -1610,7 +1610,8 @@ When ``false``, use the same indentation level as for the switch statement. Switch statement body is always indented one level more than - case labels. + case labels (except the first block following the case label, which + itself indents the code - unless IndentCaseBlocks is enabled). .. code-block:: c++ @@ -1623,6 +1624,28 @@ plop(); plop(); } } +**IndentCaseBlocks** (``bool``) + Indent case label blocks one level from the case label. + + When ``false``, the block following the case label uses the same + indentation level as for the case label, treating the case label the same + as an if-statement. + When ``true``, the block gets indented as a scope block. + + .. code-block:: c++ + false: true: + switch (fool) { vs. switch (fool) { + case 1: { case 1: + bar(); { + } break; bar(); + default: { } + plop(); break; + } default: + } { + plop(); + } + } + **IndentGotoLabels** (``bool``) Indent goto labels. 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 @@ -1314,7 +1314,8 @@ /// /// When ``false``, use the same indentation level as for the switch /// statement. Switch statement body is always indented one level more than - /// case labels. + /// case labels (except the first block following the case label, which + /// itself indents the code - unless IndentCaseBlocks is enabled). /// \code /// false: true: /// switch (fool) { vs. switch (fool) { @@ -1327,6 +1328,28 @@ /// \endcode bool IndentCaseLabels; + /// Indent case label blocks one level from the case label. + /// + /// When ``false``, the block following the case label uses the same + /// indentation level as for the case label, treating the case label the same + /// as an if-statement. + /// When ``true``, the block gets indented as a scope block. + /// \code + /// false: true: + /// switch (fool) { vs. switch (fool) { + /// case 1: { case 1: + /// bar(); { + /// } break; bar(); + /// default: { } + /// plop(); break; + /// } default: + /// } { + /// plop(); + /// } + /// } + /// \endcode + bool IndentCaseBlocks; + /// Indent goto labels. /// /// When ``false``, goto labels are flushed left. @@ -2119,6 +2142,7 @@ IncludeStyle.IncludeIsMainSourceRegex == R.IncludeStyle.IncludeIsMainSourceRegex && IndentCaseLabels == R.IndentCaseLabels && + IndentCaseBlocks == R.IndentCaseBlocks && IndentGotoLabels == R.IndentGotoLabels && IndentPPDirectives == R.IndentPPDirectives && IndentWidth == R.IndentWidth && Language == R.Language && 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 @@ -480,6 +480,7 @@ IO.mapOptional("IncludeIsMainSourceRegex", Style.IncludeStyle.IncludeIsMainSourceRegex); IO.mapOptional("IndentCaseLabels", Style.IndentCaseLabels); + IO.mapOptional("IndentCaseBlocks", Style.IndentCaseBlocks); IO.mapOptional("IndentGotoLabels", Style.IndentGotoLabels); IO.mapOptional("IndentPPDirectives", Style.IndentPPDirectives); IO.mapOptional("IndentWidth", Style.IndentWidth); @@ -782,6 +783,7 @@ LLVMStyle.IncludeStyle.IncludeIsMainRegex = "(Test)?$"; LLVMStyle.IncludeStyle.IncludeBlocks = tooling::IncludeStyle::IBS_Preserve; LLVMStyle.IndentCaseLabels = false; + LLVMStyle.IndentCaseBlocks = false; LLVMStyle.IndentGotoLabels = true; LLVMStyle.IndentPPDirectives = FormatStyle::PPDIS_None; LLVMStyle.IndentWrappedFunctionNames = false; diff --git a/clang/lib/Format/UnwrappedLineParser.cpp b/clang/lib/Format/UnwrappedLineParser.cpp --- a/clang/lib/Format/UnwrappedLineParser.cpp +++ b/clang/lib/Format/UnwrappedLineParser.cpp @@ -1985,7 +1985,8 @@ --Line->Level; if (LeftAlignLabel) Line->Level = 0; - if (CommentsBeforeNextToken.empty() && FormatTok->Tok.is(tok::l_brace)) { + if (!Style.IndentCaseBlocks && CommentsBeforeNextToken.empty() && + FormatTok->Tok.is(tok::l_brace)) { CompoundStatementIndenter Indenter(this, Line->Level, Style.BraceWrapping.AfterCaseLabel, Style.BraceWrapping.IndentBraces); 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 @@ -1211,6 +1211,28 @@ " }\n" "}", Style)); + Style.IndentCaseLabels = false; + Style.IndentCaseBlocks = true; + EXPECT_EQ("switch (n)\n" + "{\n" + "case 0:\n" + " {\n" + " return false;\n" + " }\n" + "default:\n" + " {\n" + " return true;\n" + " }\n" + "}", + format("switch (n) {\n" + "case 0: {\n" + " return false;\n" + "}\n" + "default: {\n" + " return true;\n" + "}\n" + "}", + Style)); } TEST_F(FormatTest, CaseRanges) { @@ -12578,6 +12600,7 @@ CHECK_PARSE_BOOL_FIELD(DerivePointerAlignment, "DerivePointerBinding"); CHECK_PARSE_BOOL(DisableFormat); CHECK_PARSE_BOOL(IndentCaseLabels); + CHECK_PARSE_BOOL(IndentCaseBlocks); CHECK_PARSE_BOOL(IndentGotoLabels); CHECK_PARSE_BOOL(IndentWrappedFunctionNames); CHECK_PARSE_BOOL(KeepEmptyLinesAtTheStartOfBlocks);