Index: docs/ClangFormatStyleOptions.rst =================================================================== --- docs/ClangFormatStyleOptions.rst +++ docs/ClangFormatStyleOptions.rst @@ -1059,6 +1059,52 @@ **BreakStringLiterals** (``bool``) Allow breaking string literals when formatting. +**CaseBlockIndent** (``CaseBlockIndentStyle``) + Control indentation of blocks immediately after case/default label + in switch statements. + + Possible values: + + * ``CBIS_None`` (in configuration: ``None``) + No extra indent, closing-brace in un-indented back to switch + level. + + .. code-block:: c++ + + switch (a) { + case 0: { + f(); + } break; + default: + } + + * ``CBIS_ClosingBrace`` (in configuration: ``ClosingBrace``) + No extra indent, but closing-brace in indented at the same + level as the content of the block. + + .. code-block:: c++ + + switch (a) { + case 0: { + f(); + } break; + default: + } + + * ``CBIS_Block`` (in configuration: ``Block``) + The block adds one extra level of indent. + + .. code-block:: c++ + + switch (a) { + case 0: { + f(); + } break; + default: + } + + + **ColumnLimit** (``unsigned``) The column limit. Index: include/clang/Format/Format.h =================================================================== --- include/clang/Format/Format.h +++ include/clang/Format/Format.h @@ -877,6 +877,46 @@ /// Allow breaking string literals when formatting. bool BreakStringLiterals; + /// Different styles for formatting blocks after case/default label in switch + /// statements. + enum CaseBlockIndentStyle { + /// No extra indent, closing-brace in unindented back to switch level. + /// \code + /// switch (a) { + /// case 0: { + /// f(); + /// } break; + /// default: + /// } + /// \endcode + CBIS_None, + /// No extra indent, but closing-brace in indented at the same level as + /// the content of the block. + /// \code + /// switch (a) { + /// case 0: { + /// f(); + /// } break; + /// default: + /// } + /// \endcode + CBIS_ClosingBrace, + /// The block adds one extra level of indent. + /// \code + /// switch (a) { + /// case 0: { + /// f(); + /// } break; + /// default: + /// } + /// \endcode + CBIS_Block + }; + + /// Control indentation of blocks immediately after case/default label in + /// switch statements. + CaseBlockIndentStyle CaseBlockIndent; + /// The column limit. /// /// A column limit of ``0`` means that there is no column limit. In this case, @@ -1672,6 +1712,7 @@ CompactNamespaces == R.CompactNamespaces && BreakAfterJavaFieldAnnotations == R.BreakAfterJavaFieldAnnotations && BreakStringLiterals == R.BreakStringLiterals && + CaseBlockIndent == R.CaseBlockIndent && ColumnLimit == R.ColumnLimit && CommentPragmas == R.CommentPragmas && BreakBeforeInheritanceComma == R.BreakBeforeInheritanceComma && ConstructorInitializerAllOnOneLineOrOnePerLine == Index: lib/Format/Format.cpp =================================================================== --- lib/Format/Format.cpp +++ lib/Format/Format.cpp @@ -181,6 +181,16 @@ } }; +template<> +struct ScalarEnumerationTraits { + static void + enumeration(IO &IO, FormatStyle::CaseBlockIndentStyle &Value) { + IO.enumCase(Value, "None", FormatStyle::CBIS_None); + IO.enumCase(Value, "ClosingBrace", FormatStyle::CBIS_ClosingBrace); + IO.enumCase(Value, "Block", FormatStyle::CBIS_Block); + } +}; + template <> struct ScalarEnumerationTraits { static void @@ -370,6 +380,7 @@ IO.mapOptional("BreakAfterJavaFieldAnnotations", Style.BreakAfterJavaFieldAnnotations); IO.mapOptional("BreakStringLiterals", Style.BreakStringLiterals); + IO.mapOptional("CaseBlockIndent", Style.CaseBlockIndent); IO.mapOptional("ColumnLimit", Style.ColumnLimit); IO.mapOptional("CommentPragmas", Style.CommentPragmas); IO.mapOptional("CompactNamespaces", Style.CompactNamespaces); @@ -626,6 +637,7 @@ LLVMStyle.BreakConstructorInitializers = FormatStyle::BCIS_BeforeColon; LLVMStyle.BreakBeforeInheritanceComma = false; LLVMStyle.BreakStringLiterals = true; + LLVMStyle.CaseBlockIndent = FormatStyle::CBIS_None; LLVMStyle.ColumnLimit = 80; LLVMStyle.CommentPragmas = "^ IWYU pragma:"; LLVMStyle.CompactNamespaces = false; Index: lib/Format/UnwrappedLineParser.h =================================================================== --- lib/Format/UnwrappedLineParser.h +++ lib/Format/UnwrappedLineParser.h @@ -88,6 +88,10 @@ void parseFile(); void parseLevel(bool HasOpeningBrace); void parseBlock(bool MustBeDeclaration, bool AddLevel = true, + bool MunchSemi = true) { + parseBlock(MustBeDeclaration, AddLevel ? 1 : 0, MunchSemi); + } + void parseBlock(bool MustBeDeclaration, int AddLevel, bool MunchSemi = true); void parseChildBlock(); void parsePPDirective(); Index: lib/Format/UnwrappedLineParser.cpp =================================================================== --- lib/Format/UnwrappedLineParser.cpp +++ lib/Format/UnwrappedLineParser.cpp @@ -515,7 +515,7 @@ return h; } -void UnwrappedLineParser::parseBlock(bool MustBeDeclaration, bool AddLevel, +void UnwrappedLineParser::parseBlock(bool MustBeDeclaration, int AddLevel, bool MunchSemi) { assert(FormatTok->isOneOf(tok::l_brace, TT_MacroBlockBegin) && "'{' or macro block token expected"); @@ -525,7 +525,7 @@ size_t PPStartHash = computePPHash(); unsigned InitialLevel = Line->Level; - nextToken(/*LevelDifference=*/AddLevel ? 1 : 0); + nextToken(/*LevelDifference=*/AddLevel); if (MacroBlock && FormatTok->is(tok::l_paren)) parseParens(); @@ -540,8 +540,7 @@ ScopedDeclarationState DeclarationState(*Line, DeclarationScopeStack, MustBeDeclaration); - if (AddLevel) - ++Line->Level; + Line->Level += static_cast(AddLevel); parseLevel(/*HasOpeningBrace=*/true); if (eof()) @@ -557,7 +556,7 @@ size_t PPEndHash = computePPHash(); // Munch the closing brace. - nextToken(/*LevelDifference=*/AddLevel ? -1 : 0); + nextToken(/*LevelDifference=*/-AddLevel); if (MacroBlock && FormatTok->is(tok::l_paren)) parseParens(); @@ -1879,7 +1878,11 @@ --Line->Level; if (CommentsBeforeNextToken.empty() && FormatTok->Tok.is(tok::l_brace)) { CompoundStatementIndenter Indenter(this, Style, Line->Level); - parseBlock(/*MustBeDeclaration=*/false); + parseBlock(/*MustBeDeclaration=*/false, + /*AddLevel=*/Style.CaseBlockIndent == FormatStyle::CBIS_Block + ? 2 : 1); + if (Style.CaseBlockIndent != FormatStyle::CBIS_None) + Line->Level++; if (FormatTok->Tok.is(tok::kw_break)) { if (Style.BraceWrapping.AfterControlStatement) addUnwrappedLine(); Index: unittests/Format/FormatTest.cpp =================================================================== --- unittests/Format/FormatTest.cpp +++ unittests/Format/FormatTest.cpp @@ -1010,6 +1010,96 @@ " return;\n" "}", getLLVMStyleWithColumns(34)); + + FormatStyle indentClosingBrace = getLLVMStyle(); + indentClosingBrace.CaseBlockIndent = FormatStyle::CBIS_ClosingBrace; + verifyFormat("switch (x) {\n" + "case 1:\n" + " f();\n" + " break;\n" + "}", + indentClosingBrace); + verifyFormat("switch (x) {\n" + "case 1: {\n" + " f();\n" + " break;\n" + " }\n" + "case 2: {\n" + " break;\n" + " }\n" + "}", + indentClosingBrace); + verifyFormat("switch (x) {\n" + "case 1: {\n" + " f();\n" + " } break;\n" + "case 2: {\n" + " } break;\n" + "}", + indentClosingBrace); + verifyFormat("switch (x) {\n" + "case 1: {\n" + " f();\n" + " }\n" + " g();\n" + " break;\n" + "}", + indentClosingBrace); + verifyFormat("switch (x) {\n" + "case 1:\n" + " f();\n" + " {\n" + " g();\n" + " h();\n" + " }\n" + " break;\n" + "}", + indentClosingBrace); + + FormatStyle indentBlock = getLLVMStyle(); + indentBlock.CaseBlockIndent = FormatStyle::CBIS_Block; + verifyFormat("switch (x) {\n" + "case 1:\n" + " f();\n" + " break;\n" + "}", + indentBlock); + verifyFormat("switch (x) {\n" + "case 1: {\n" + " f();\n" + " break;\n" + " }\n" + "case 2: {\n" + " break;\n" + " }\n" + "}", + indentBlock); + verifyFormat("switch (x) {\n" + "case 1: {\n" + " f();\n" + " } break;\n" + "case 2: {\n" + " } break;\n" + "}", + indentBlock); + verifyFormat("switch (x) {\n" + "case 1: {\n" + " f();\n" + " }\n" + " g();\n" + " break;\n" + "}", + indentBlock); + verifyFormat("switch (x) {\n" + "case 1:\n" + " f();\n" + " {\n" + " g();\n" + " h();\n" + " }\n" + " break;\n" + "}", + indentBlock); } TEST_F(FormatTest, CaseRanges) { @@ -10639,6 +10729,13 @@ CHECK_PARSE("AllowShortFunctionsOnASingleLine: true", AllowShortFunctionsOnASingleLine, FormatStyle::SFS_All); + Style.CaseBlockIndent = FormatStyle::CBIS_Block; + CHECK_PARSE("CaseBlockIndent: None", CaseBlockIndent, FormatStyle::CBIS_None); + CHECK_PARSE("CaseBlockIndent: ClosingBrace", CaseBlockIndent, + FormatStyle::CBIS_ClosingBrace); + CHECK_PARSE("CaseBlockIndent: Block", CaseBlockIndent, + FormatStyle::CBIS_Block); + Style.SpaceBeforeParens = FormatStyle::SBPO_Always; CHECK_PARSE("SpaceBeforeParens: Never", SpaceBeforeParens, FormatStyle::SBPO_Never);