Typz created this revision.
Typz added reviewers: krasimir, djasper, klimek.
When a block is started after a case label, clang-format does add extra
indent to the content of this block: the block content is indented one
level (with respect to the switch) while the closing brace is not
indented, and closes at switch level.
This gives the following code:
switch (x) {
case A: {
stuff();
} break;
}
This makes it easy to confuse the closing brace of the 'case' with that
the whole 'switch', especially if more code is added after the brace:
switch (x) {
case A: {
stuff();
}
moreStuff();
break;
}
This patch introduces a new CaseBlockIndent switch, which provides
alternative formatting for these cases:
- `CaseBlockIndent = None` : default behavior, same behavior as before
- `CaseBlockIndent = ClosingBrace` : indent the closing brace to the
same level as its content.
switch (x) {
case A: {
stuff();
} break;
}
- `CaseBlockIndent = Block` : add an extra level of indent for the
content of the block.
switch (x) {
case A: {
stuff();
} break;
}
Repository:
rC Clang
https://reviews.llvm.org/D43183
Files:
include/clang/Format/Format.h
lib/Format/Format.cpp
lib/Format/UnwrappedLineParser.cpp
lib/Format/UnwrappedLineParser.h
unittests/Format/FormatTest.cpp
Index: unittests/Format/FormatTest.cpp
===================================================================
--- unittests/Format/FormatTest.cpp
+++ unittests/Format/FormatTest.cpp
@@ -980,6 +980,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) {
@@ -10413,6 +10503,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);
Index: lib/Format/UnwrappedLineParser.h
===================================================================
--- lib/Format/UnwrappedLineParser.h
+++ lib/Format/UnwrappedLineParser.h
@@ -84,6 +84,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
@@ -508,7 +508,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");
@@ -518,7 +518,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();
@@ -533,8 +533,7 @@
ScopedDeclarationState DeclarationState(*Line, DeclarationScopeStack,
MustBeDeclaration);
- if (AddLevel)
- ++Line->Level;
+ Line->Level += static_cast<unsigned>(AddLevel);
parseLevel(/*HasOpeningBrace=*/true);
if (eof())
@@ -550,7 +549,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();
@@ -1857,7 +1856,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: lib/Format/Format.cpp
===================================================================
--- lib/Format/Format.cpp
+++ lib/Format/Format.cpp
@@ -166,6 +166,16 @@
}
};
+template <>
+struct ScalarEnumerationTraits<FormatStyle::CaseBlockIndentStyle> {
+ 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<FormatStyle::DefinitionReturnTypeBreakingStyle> {
static void
@@ -355,6 +365,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);
@@ -618,6 +629,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: include/clang/Format/Format.h
===================================================================
--- include/clang/Format/Format.h
+++ include/clang/Format/Format.h
@@ -843,6 +843,49 @@
/// \brief Allow breaking string literals when formatting.
bool BreakStringLiterals;
+ /// \brief Different styles for formatting blocks after case/default label
+ /// in switch statements.
+ enum CaseBlockIndentStyle {
+ /// \brief No extra indent, closing-brace in un-indented back to switch
+ /// level.
+ /// \code
+ /// switch (a) {
+ /// case 0: {
+ /// f();
+ /// } break;
+ /// default:
+ /// }
+ /// \endcode
+ CBIS_None,
+
+ /// \brief No extra indent, but closing-brace in indented at the same the
+ /// level as the content of the block.
+ /// \code
+ /// switch (a) {
+ /// case 0: {
+ /// f();
+ /// } break;
+ /// default:
+ /// }
+ /// \endcode
+ CBIS_ClosingBrace,
+
+ /// \brief The block adds one extra level of indent.
+ /// \code
+ /// switch (a) {
+ /// case 0: {
+ /// f();
+ /// } break;
+ /// default:
+ /// }
+ /// \endcode
+ CBIS_Block
+ };
+
+ /// \brief Control indentation of blocks immediately after case/default label
+ /// in switch statements.
+ CaseBlockIndentStyle CaseBlockIndent;
+
/// \brief The column limit.
///
/// A column limit of ``0`` means that there is no column limit. In this case,
@@ -1696,6 +1739,7 @@
CompactNamespaces == R.CompactNamespaces &&
BreakAfterJavaFieldAnnotations == R.BreakAfterJavaFieldAnnotations &&
BreakStringLiterals == R.BreakStringLiterals &&
+ CaseBlockIndent == R.CaseBlockIndent &&
ColumnLimit == R.ColumnLimit && CommentPragmas == R.CommentPragmas &&
BreakBeforeInheritanceComma == R.BreakBeforeInheritanceComma &&
ConstructorInitializerAllOnOneLineOrOnePerLine ==
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits