[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