[cfe-dev] clang-format: flush-left goto labels
Christian Neukirchen via cfe-dev
cfe-dev at lists.llvm.org
Thu Sep 10 14:45:10 PDT 2015
Hi,
clang-format is currently lacking an option to specify how to indent
goto labels, they are always outdented one level.
Linux kernel style, OpenBSD style, and many other C projects have the
labels completely flush left, in column 0. The patch below adds
this as "IndentGotoLabels: false". (This indentation style is also
provided by GNU indent and astyle.)
(A less popular, but still common style, is to indent labels always one
space, I don't know how to add that easily.)
Thanks,
diff --git a/docs/ClangFormatStyleOptions.rst b/docs/ClangFormatStyleOptions.rst
index ce6fae1..fb65f4a 100644
--- a/docs/ClangFormatStyleOptions.rst
+++ b/docs/ClangFormatStyleOptions.rst
@@ -343,6 +343,11 @@ the configuration (without a prefix: ``Auto``).
When ``false``, use the same indentation level as for the switch statement.
Switch statement body is always indented one level more than case labels.
+**IndentGotoLabels** (``bool``)
+ Indent goto labels.
+
+ When ``false``, goto labels are flushed left.
+
**IndentWidth** (``unsigned``)
The number of columns to use for indentation.
diff --git a/include/clang/Format/Format.h b/include/clang/Format/Format.h
index 60c54ab..1f43ee8 100644
--- a/include/clang/Format/Format.h
+++ b/include/clang/Format/Format.h
@@ -129,6 +129,11 @@ struct FormatStyle {
/// Switch statement body is always indented one level more than case labels.
bool IndentCaseLabels;
+ /// \brief Indent goto labels.
+ ///
+ /// When \c false, goto labels are flushed left.
+ bool IndentGotoLabels;
+
/// \brief Indent if a function definition or declaration is wrapped after the
/// type.
bool IndentWrappedFunctionNames;
@@ -444,6 +449,7 @@ struct FormatStyle {
ExperimentalAutoDetectBinPacking ==
R.ExperimentalAutoDetectBinPacking &&
IndentCaseLabels == R.IndentCaseLabels &&
+ IndentGotoLabels == R.IndentGotoLabels &&
IndentWrappedFunctionNames == R.IndentWrappedFunctionNames &&
IndentWidth == R.IndentWidth && Language == R.Language &&
MaxEmptyLinesToKeep == R.MaxEmptyLinesToKeep &&
diff --git a/lib/Format/Format.cpp b/lib/Format/Format.cpp
index 2a4721f..323c04d 100644
--- a/lib/Format/Format.cpp
+++ b/lib/Format/Format.cpp
@@ -211,6 +211,7 @@ template <> struct MappingTraits<FormatStyle> {
IO.mapOptional("ExperimentalAutoDetectBinPacking",
Style.ExperimentalAutoDetectBinPacking);
IO.mapOptional("IndentCaseLabels", Style.IndentCaseLabels);
+ IO.mapOptional("IndentGotoLabels", Style.IndentGotoLabels);
IO.mapOptional("IndentWrappedFunctionNames",
Style.IndentWrappedFunctionNames);
IO.mapOptional("IndentFunctionDeclarationAfterType",
@@ -358,6 +359,7 @@ FormatStyle getLLVMStyle() {
LLVMStyle.ForEachMacros.push_back("Q_FOREACH");
LLVMStyle.ForEachMacros.push_back("BOOST_FOREACH");
LLVMStyle.IndentCaseLabels = false;
+ LLVMStyle.IndentGotoLabels = true;
LLVMStyle.IndentWrappedFunctionNames = false;
LLVMStyle.IndentWidth = 2;
LLVMStyle.TabWidth = 8;
diff --git a/lib/Format/UnwrappedLineParser.cpp b/lib/Format/UnwrappedLineParser.cpp
index ec04af5..b615bb6 100644
--- a/lib/Format/UnwrappedLineParser.cpp
+++ b/lib/Format/UnwrappedLineParser.cpp
@@ -817,7 +817,7 @@ void UnwrappedLineParser::parseStructuralElement() {
nextToken();
if (Line->Tokens.size() == 1) {
if (FormatTok->Tok.is(tok::colon)) {
- parseLabel();
+ parseLabel(true);
return;
}
// Recognize function-like macro usages without trailing semicolon as
@@ -1286,11 +1286,13 @@ void UnwrappedLineParser::parseDoWhile() {
parseStructuralElement();
}
-void UnwrappedLineParser::parseLabel() {
+void UnwrappedLineParser::parseLabel(bool GotoLabel) {
nextToken();
unsigned OldLineLevel = Line->Level;
if (Line->Level > 1 || (!Line->InPPDirective && Line->Level > 0))
--Line->Level;
+ if (GotoLabel && !Style.IndentGotoLabels)
+ Line->Level = 0;
if (CommentsBeforeNextToken.empty() && FormatTok->Tok.is(tok::l_brace)) {
CompoundStatementIndenter Indenter(this, Style, Line->Level);
parseBlock(/*MustBeDeclaration=*/false);
diff --git a/lib/Format/UnwrappedLineParser.h b/lib/Format/UnwrappedLineParser.h
index 3218afe..99e3bee 100644
--- a/lib/Format/UnwrappedLineParser.h
+++ b/lib/Format/UnwrappedLineParser.h
@@ -91,7 +91,7 @@ private:
void parseTryCatch();
void parseForOrWhileLoop();
void parseDoWhile();
- void parseLabel();
+ void parseLabel(bool GotoLabel = false);
void parseCaseLabel();
void parseSwitch();
void parseNamespace();
diff --git a/unittests/Format/FormatTest.cpp b/unittests/Format/FormatTest.cpp
index 8e770c2..f468170 100644
--- a/unittests/Format/FormatTest.cpp
+++ b/unittests/Format/FormatTest.cpp
@@ -802,6 +802,20 @@ TEST_F(FormatTest, FormatsLabels) {
verifyFormat("some_code();\n"
"test_label:\n"
"some_other_code();");
+ Style.IndentGotoLabel = false;
+ verifyFormat("void f() {\n"
+ " some_code();\n"
+ "test_label:\n"
+ " some_other_code();\n"
+ " {\n"
+ " some_more_code();\n"
+ "another_label:\n"
+ " some_more_code();\n"
+ " }\n"
+ "}");
+ verifyFormat("some_code();\n"
+ "test_label:\n"
+ "some_other_code();");
}
//===----------------------------------------------------------------------===//
@@ -8700,6 +8714,7 @@ TEST_F(FormatTest, ParsesConfigurationBools) {
CHECK_PARSE_BOOL(DerivePointerAlignment);
CHECK_PARSE_BOOL_FIELD(DerivePointerAlignment, "DerivePointerBinding");
CHECK_PARSE_BOOL(IndentCaseLabels);
+ CHECK_PARSE_BOOL(IndentGotoLabels);
CHECK_PARSE_BOOL(IndentWrappedFunctionNames);
CHECK_PARSE_BOOL(KeepEmptyLinesAtTheStartOfBlocks);
CHECK_PARSE_BOOL(ObjCSpaceAfterProperty);
--
Christian Neukirchen <chneukirchen at gmail.com> http://chneukirchen.org
More information about the cfe-dev
mailing list