[clang] [clang-format] Add option to remove leading blank lines (PR #91221)

via cfe-commits cfe-commits at lists.llvm.org
Sun Jun 9 20:15:30 PDT 2024


https://github.com/sstwcw updated https://github.com/llvm/llvm-project/pull/91221

>From 72e15ffb87eff94d51af69c0f804084ab7abe474 Mon Sep 17 00:00:00 2001
From: sstwcw <su3e8a96kzlver at posteo.net>
Date: Mon, 6 May 2024 14:34:08 +0000
Subject: [PATCH 1/4] [clang-format] Add option to remove leading blank lines

---
 clang/docs/ClangFormatStyleOptions.rst      | 5 +++++
 clang/include/clang/Format/Format.h         | 5 +++++
 clang/lib/Format/ContinuationIndenter.cpp   | 3 +++
 clang/lib/Format/Format.cpp                 | 2 ++
 clang/lib/Format/UnwrappedLineFormatter.cpp | 4 +++-
 clang/unittests/Format/ConfigParseTest.cpp  | 1 +
 clang/unittests/Format/FormatTest.cpp       | 7 +++++++
 7 files changed, 26 insertions(+), 1 deletion(-)

diff --git a/clang/docs/ClangFormatStyleOptions.rst b/clang/docs/ClangFormatStyleOptions.rst
index ce9035a2770ee..c81de131f050c 100644
--- a/clang/docs/ClangFormatStyleOptions.rst
+++ b/clang/docs/ClangFormatStyleOptions.rst
@@ -4406,6 +4406,11 @@ the configuration (without a prefix: ``Auto``).
 **KeepEmptyLinesAtEOF** (``Boolean``) :versionbadge:`clang-format 17` :ref:`¶ <KeepEmptyLinesAtEOF>`
   Keep empty lines (up to ``MaxEmptyLinesToKeep``) at end of file.
 
+.. _KeepEmptyLinesAtStart:
+
+**KeepEmptyLinesAtStart** (``Boolean``) :versionbadge:`clang-format 19` :ref:`¶ <KeepEmptyLinesAtStart>`
+  Keep empty lines (up to ``MaxEmptyLinesToKeep``) at start of file.
+
 .. _KeepEmptyLinesAtTheStartOfBlocks:
 
 **KeepEmptyLinesAtTheStartOfBlocks** (``Boolean``) :versionbadge:`clang-format 3.7` :ref:`¶ <KeepEmptyLinesAtTheStartOfBlocks>`
diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h
index 8ebdc86b98329..9a7837b1bac2d 100644
--- a/clang/include/clang/Format/Format.h
+++ b/clang/include/clang/Format/Format.h
@@ -3061,6 +3061,10 @@ struct FormatStyle {
   /// \version 17
   bool KeepEmptyLinesAtEOF;
 
+  /// Keep empty lines (up to ``MaxEmptyLinesToKeep``) at start of file.
+  /// \version 19
+  bool KeepEmptyLinesAtStart;
+
   /// If true, the empty line at the start of blocks is kept.
   /// \code
   ///    true:                                  false:
@@ -4994,6 +4998,7 @@ struct FormatStyle {
            JavaScriptQuotes == R.JavaScriptQuotes &&
            JavaScriptWrapImports == R.JavaScriptWrapImports &&
            KeepEmptyLinesAtEOF == R.KeepEmptyLinesAtEOF &&
+           KeepEmptyLinesAtStart == R.KeepEmptyLinesAtStart &&
            KeepEmptyLinesAtTheStartOfBlocks ==
                R.KeepEmptyLinesAtTheStartOfBlocks &&
            Language == R.Language &&
diff --git a/clang/lib/Format/ContinuationIndenter.cpp b/clang/lib/Format/ContinuationIndenter.cpp
index ad0e2c3c620c3..33dca7b08f998 100644
--- a/clang/lib/Format/ContinuationIndenter.cpp
+++ b/clang/lib/Format/ContinuationIndenter.cpp
@@ -208,6 +208,9 @@ RawStringFormatStyleManager::RawStringFormatStyleManager(
       LanguageStyle = PredefinedStyle;
     }
     LanguageStyle->ColumnLimit = CodeStyle.ColumnLimit;
+    // This way the first line of the string does not have to follow the code
+    // before the string.
+    LanguageStyle->KeepEmptyLinesAtStart = true;
     for (StringRef Delimiter : RawStringFormat.Delimiters)
       DelimiterStyle.insert({Delimiter, *LanguageStyle});
     for (StringRef EnclosingFunction : RawStringFormat.EnclosingFunctions)
diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp
index c8d8ec3afbd99..31ffbf46cdd08 100644
--- a/clang/lib/Format/Format.cpp
+++ b/clang/lib/Format/Format.cpp
@@ -1003,6 +1003,7 @@ template <> struct MappingTraits<FormatStyle> {
     IO.mapOptional("KeepEmptyLinesAtTheStartOfBlocks",
                    Style.KeepEmptyLinesAtTheStartOfBlocks);
     IO.mapOptional("KeepEmptyLinesAtEOF", Style.KeepEmptyLinesAtEOF);
+    IO.mapOptional("KeepEmptyLinesAtStart", Style.KeepEmptyLinesAtStart);
     IO.mapOptional("LambdaBodyIndentation", Style.LambdaBodyIndentation);
     IO.mapOptional("LineEnding", Style.LineEnding);
     IO.mapOptional("MacroBlockBegin", Style.MacroBlockBegin);
@@ -1513,6 +1514,7 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) {
   LLVMStyle.JavaScriptQuotes = FormatStyle::JSQS_Leave;
   LLVMStyle.JavaScriptWrapImports = true;
   LLVMStyle.KeepEmptyLinesAtEOF = false;
+  LLVMStyle.KeepEmptyLinesAtStart = true;
   LLVMStyle.KeepEmptyLinesAtTheStartOfBlocks = true;
   LLVMStyle.LambdaBodyIndentation = FormatStyle::LBI_Signature;
   LLVMStyle.Language = Language;
diff --git a/clang/lib/Format/UnwrappedLineFormatter.cpp b/clang/lib/Format/UnwrappedLineFormatter.cpp
index 4ae54e56331bd..b8485ae2b9197 100644
--- a/clang/lib/Format/UnwrappedLineFormatter.cpp
+++ b/clang/lib/Format/UnwrappedLineFormatter.cpp
@@ -1473,8 +1473,10 @@ static auto computeNewlines(const AnnotatedLine &Line,
     Newlines = std::min(Newlines, 1u);
   if (Newlines == 0 && !RootToken.IsFirst)
     Newlines = 1;
-  if (RootToken.IsFirst && !RootToken.HasUnescapedNewline)
+  if (RootToken.IsFirst &&
+      (!Style.KeepEmptyLinesAtStart || !RootToken.HasUnescapedNewline)) {
     Newlines = 0;
+  }
 
   // Remove empty lines after "{".
   if (!Style.KeepEmptyLinesAtTheStartOfBlocks && PreviousLine &&
diff --git a/clang/unittests/Format/ConfigParseTest.cpp b/clang/unittests/Format/ConfigParseTest.cpp
index 8c74ed2d119a3..004fd750f3e46 100644
--- a/clang/unittests/Format/ConfigParseTest.cpp
+++ b/clang/unittests/Format/ConfigParseTest.cpp
@@ -177,6 +177,7 @@ TEST(ConfigParseTest, ParsesConfigurationBools) {
   CHECK_PARSE_BOOL(InsertBraces);
   CHECK_PARSE_BOOL(InsertNewlineAtEOF);
   CHECK_PARSE_BOOL(KeepEmptyLinesAtEOF);
+  CHECK_PARSE_BOOL(KeepEmptyLinesAtStart);
   CHECK_PARSE_BOOL(KeepEmptyLinesAtTheStartOfBlocks);
   CHECK_PARSE_BOOL(ObjCSpaceAfterProperty);
   CHECK_PARSE_BOOL(ObjCSpaceBeforeProtocolList);
diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp
index e6f8e4a06515e..d76d4b7a7858c 100644
--- a/clang/unittests/Format/FormatTest.cpp
+++ b/clang/unittests/Format/FormatTest.cpp
@@ -45,6 +45,9 @@ TEST_F(FormatTest, FormatsGlobalStatementsAt0) {
   verifyFormat("\nint i;", " \n\t \v \f  int i;");
   verifyFormat("int i;\nint j;", "    int i; int j;");
   verifyFormat("int i;\nint j;", "    int i;\n  int j;");
+  auto Style = getLLVMStyle();
+  Style.KeepEmptyLinesAtStart = false;
+  verifyFormat("int i;", " \n\t \v \f  int i;", Style);
 }
 
 TEST_F(FormatTest, FormatsUnwrappedLinesAtFirstFormat) {
@@ -21898,6 +21901,10 @@ TEST_F(FormatTest, HandlesUTF8BOM) {
   verifyFormat("\xef\xbb\xbf");
   verifyFormat("\xef\xbb\xbf#include <iostream>");
   verifyFormat("\xef\xbb\xbf\n#include <iostream>");
+  auto Style = getLLVMStyle();
+  Style.KeepEmptyLinesAtStart = false;
+  verifyFormat("\xef\xbb\xbf#include <iostream>",
+               "\xef\xbb\xbf\n#include <iostream>", Style);
 }
 
 // FIXME: Encode Cyrillic and CJK characters below to appease MS compilers.

>From 0ccacd600b26a58a75a6b77a370b818d6e9e027a Mon Sep 17 00:00:00 2001
From: sstwcw <su3e8a96kzlver at posteo.net>
Date: Sat, 25 May 2024 03:56:19 +0000
Subject: [PATCH 2/4] Combine configuration options

---
 clang/docs/ClangFormatStyleOptions.rst      | 46 ++++++++++------
 clang/include/clang/Format/Format.h         | 58 +++++++++++++--------
 clang/lib/Format/ContinuationIndenter.cpp   |  2 +-
 clang/lib/Format/Format.cpp                 | 26 ++++++---
 clang/lib/Format/UnwrappedLineFormatter.cpp | 10 ++--
 clang/unittests/Format/ConfigParseTest.cpp  |  9 ++--
 clang/unittests/Format/FormatTest.cpp       | 10 ++--
 7 files changed, 103 insertions(+), 58 deletions(-)

diff --git a/clang/docs/ClangFormatStyleOptions.rst b/clang/docs/ClangFormatStyleOptions.rst
index c81de131f050c..57b3ec326b8fb 100644
--- a/clang/docs/ClangFormatStyleOptions.rst
+++ b/clang/docs/ClangFormatStyleOptions.rst
@@ -4401,28 +4401,44 @@ the configuration (without a prefix: ``Auto``).
      false:
      import {VeryLongImportsAreAnnoying, VeryLongImportsAreAnnoying, VeryLongImportsAreAnnoying,} from "some/module.js"
 
-.. _KeepEmptyLinesAtEOF:
+.. _KeepEmptyLines:
 
-**KeepEmptyLinesAtEOF** (``Boolean``) :versionbadge:`clang-format 17` :ref:`¶ <KeepEmptyLinesAtEOF>`
-  Keep empty lines (up to ``MaxEmptyLinesToKeep``) at end of file.
+**KeepEmptyLines** (``KeepEmptyLinesStyle``) :versionbadge:`clang-format 19` :ref:`¶ <KeepEmptyLines>`
+  Which empty lines are kept.  See ``MaxEmptyLinesToKeep`` for how many
+  consecutive empty lines are kept.
 
-.. _KeepEmptyLinesAtStart:
-
-**KeepEmptyLinesAtStart** (``Boolean``) :versionbadge:`clang-format 19` :ref:`¶ <KeepEmptyLinesAtStart>`
-  Keep empty lines (up to ``MaxEmptyLinesToKeep``) at start of file.
+  Nested configuration flags:
 
-.. _KeepEmptyLinesAtTheStartOfBlocks:
+  Options regarding which empty lines are kept.  Some of the options can
+  also be read as standalone options for backward compatibility.  For
+  example, these configurations do the same thing.
 
-**KeepEmptyLinesAtTheStartOfBlocks** (``Boolean``) :versionbadge:`clang-format 3.7` :ref:`¶ <KeepEmptyLinesAtTheStartOfBlocks>`
-  If true, the empty line at the start of blocks is kept.
 
   .. code-block:: c++
 
-     true:                                  false:
-     if (foo) {                     vs.     if (foo) {
-                                              bar();
-       bar();                               }
-     }
+    KeepEmptyLines:
+      AtEndOfFile: true
+      AtStartOfBlock: true
+
+    KeepEmptyLinesAtEOF: true
+    KeepEmptyLinesAtTheStartOfBlocks: true
+
+  * ``bool AtEndOfFile`` Keep empty lines at end of file.  It can also be read as the standalone
+    option ``KeepEmptyLinesAtEOF``.
+
+  * ``bool AtStartOfBlock`` If true, the empty lines at the start of blocks are kept.  It can also
+    be read as the standalone option ``KeepEmptyLinesAtTheStartOfBlocks``.
+
+    .. code-block:: c++
+
+       true:                                  false:
+       if (foo) {                     vs.     if (foo) {
+                                                bar();
+         bar();                               }
+       }
+
+  * ``bool AtStartOfFile`` Keep empty lines at start of file.
+
 
 .. _LambdaBodyIndentation:
 
diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h
index 9a7837b1bac2d..39d8261186c2e 100644
--- a/clang/include/clang/Format/Format.h
+++ b/clang/include/clang/Format/Format.h
@@ -3057,24 +3057,44 @@ struct FormatStyle {
   bool JavaScriptWrapImports;
   // clang-format on
 
-  /// Keep empty lines (up to ``MaxEmptyLinesToKeep``) at end of file.
-  /// \version 17
-  bool KeepEmptyLinesAtEOF;
-
-  /// Keep empty lines (up to ``MaxEmptyLinesToKeep``) at start of file.
-  /// \version 19
-  bool KeepEmptyLinesAtStart;
-
-  /// If true, the empty line at the start of blocks is kept.
+  /// Options regarding which empty lines are kept.  Some of the options can
+  /// also be read as standalone options for backward compatibility.  For
+  /// example, these configurations do the same thing.
+  ///
   /// \code
-  ///    true:                                  false:
-  ///    if (foo) {                     vs.     if (foo) {
-  ///                                             bar();
-  ///      bar();                               }
-  ///    }
+  ///   KeepEmptyLines:
+  ///     AtEndOfFile: true
+  ///     AtStartOfBlock: true
+  ///
+  ///   KeepEmptyLinesAtEOF: true
+  ///   KeepEmptyLinesAtTheStartOfBlocks: true
   /// \endcode
-  /// \version 3.7
-  bool KeepEmptyLinesAtTheStartOfBlocks;
+  struct KeepEmptyLinesStyle {
+    /// Keep empty lines at end of file.  It can also be read as the standalone
+    /// option ``KeepEmptyLinesAtEOF``.
+    bool AtEndOfFile;
+    /// If true, the empty lines at the start of blocks are kept.  It can also
+    /// be read as the standalone option ``KeepEmptyLinesAtTheStartOfBlocks``.
+    /// \code
+    ///    true:                                  false:
+    ///    if (foo) {                     vs.     if (foo) {
+    ///                                             bar();
+    ///      bar();                               }
+    ///    }
+    /// \endcode
+    bool AtStartOfBlock;
+    /// Keep empty lines at start of file.
+    bool AtStartOfFile;
+    bool operator==(const KeepEmptyLinesStyle &R) const {
+      return AtEndOfFile == R.AtEndOfFile &&
+             AtStartOfBlock == R.AtStartOfBlock &&
+             AtStartOfFile == R.AtStartOfFile;
+    }
+  };
+  /// Which empty lines are kept.  See ``MaxEmptyLinesToKeep`` for how many
+  /// consecutive empty lines are kept.
+  /// \version 19
+  KeepEmptyLinesStyle KeepEmptyLines;
 
   /// Indentation logic for lambda bodies.
   enum LambdaBodyIndentationKind : int8_t {
@@ -4997,11 +5017,7 @@ struct FormatStyle {
            JavaImportGroups == R.JavaImportGroups &&
            JavaScriptQuotes == R.JavaScriptQuotes &&
            JavaScriptWrapImports == R.JavaScriptWrapImports &&
-           KeepEmptyLinesAtEOF == R.KeepEmptyLinesAtEOF &&
-           KeepEmptyLinesAtStart == R.KeepEmptyLinesAtStart &&
-           KeepEmptyLinesAtTheStartOfBlocks ==
-               R.KeepEmptyLinesAtTheStartOfBlocks &&
-           Language == R.Language &&
+           KeepEmptyLines == R.KeepEmptyLines && Language == R.Language &&
            LambdaBodyIndentation == R.LambdaBodyIndentation &&
            LineEnding == R.LineEnding && MacroBlockBegin == R.MacroBlockBegin &&
            MacroBlockEnd == R.MacroBlockEnd && Macros == R.Macros &&
diff --git a/clang/lib/Format/ContinuationIndenter.cpp b/clang/lib/Format/ContinuationIndenter.cpp
index 33dca7b08f998..f3a0b8c478ff2 100644
--- a/clang/lib/Format/ContinuationIndenter.cpp
+++ b/clang/lib/Format/ContinuationIndenter.cpp
@@ -210,7 +210,7 @@ RawStringFormatStyleManager::RawStringFormatStyleManager(
     LanguageStyle->ColumnLimit = CodeStyle.ColumnLimit;
     // This way the first line of the string does not have to follow the code
     // before the string.
-    LanguageStyle->KeepEmptyLinesAtStart = true;
+    LanguageStyle->KeepEmptyLines.AtStartOfFile = true;
     for (StringRef Delimiter : RawStringFormat.Delimiters)
       DelimiterStyle.insert({Delimiter, *LanguageStyle});
     for (StringRef EnclosingFunction : RawStringFormat.EnclosingFunctions)
diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp
index 31ffbf46cdd08..293226af327d5 100644
--- a/clang/lib/Format/Format.cpp
+++ b/clang/lib/Format/Format.cpp
@@ -367,6 +367,14 @@ template <> struct ScalarEnumerationTraits<FormatStyle::JavaScriptQuoteStyle> {
   }
 };
 
+template <> struct MappingTraits<FormatStyle::KeepEmptyLinesStyle> {
+  static void mapping(IO &IO, FormatStyle::KeepEmptyLinesStyle &Value) {
+    IO.mapOptional("AtEndOfFile", Value.AtEndOfFile);
+    IO.mapOptional("AtStartOfBlock", Value.AtStartOfBlock);
+    IO.mapOptional("AtStartOfFile", Value.AtStartOfFile);
+  }
+};
+
 template <> struct ScalarEnumerationTraits<FormatStyle::LanguageKind> {
   static void enumeration(IO &IO, FormatStyle::LanguageKind &Value) {
     IO.enumCase(Value, "Cpp", FormatStyle::LK_Cpp);
@@ -867,6 +875,9 @@ template <> struct MappingTraits<FormatStyle> {
                      OnCurrentLine);
       IO.mapOptional("DeriveLineEnding", DeriveLineEnding);
       IO.mapOptional("DerivePointerBinding", Style.DerivePointerAlignment);
+      IO.mapOptional("KeepEmptyLinesAtEOF", Style.KeepEmptyLines.AtEndOfFile);
+      IO.mapOptional("KeepEmptyLinesAtTheStartOfBlocks",
+                     Style.KeepEmptyLines.AtStartOfBlock);
       IO.mapOptional("IndentFunctionDeclarationAfterType",
                      Style.IndentWrappedFunctionNames);
       IO.mapOptional("IndentRequires", Style.IndentRequiresClause);
@@ -1000,10 +1011,7 @@ template <> struct MappingTraits<FormatStyle> {
     IO.mapOptional("JavaImportGroups", Style.JavaImportGroups);
     IO.mapOptional("JavaScriptQuotes", Style.JavaScriptQuotes);
     IO.mapOptional("JavaScriptWrapImports", Style.JavaScriptWrapImports);
-    IO.mapOptional("KeepEmptyLinesAtTheStartOfBlocks",
-                   Style.KeepEmptyLinesAtTheStartOfBlocks);
-    IO.mapOptional("KeepEmptyLinesAtEOF", Style.KeepEmptyLinesAtEOF);
-    IO.mapOptional("KeepEmptyLinesAtStart", Style.KeepEmptyLinesAtStart);
+    IO.mapOptional("KeepEmptyLines", Style.KeepEmptyLines);
     IO.mapOptional("LambdaBodyIndentation", Style.LambdaBodyIndentation);
     IO.mapOptional("LineEnding", Style.LineEnding);
     IO.mapOptional("MacroBlockBegin", Style.MacroBlockBegin);
@@ -1513,9 +1521,11 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) {
       /*Hex=*/0,     /*HexMinDigits=*/0};
   LLVMStyle.JavaScriptQuotes = FormatStyle::JSQS_Leave;
   LLVMStyle.JavaScriptWrapImports = true;
-  LLVMStyle.KeepEmptyLinesAtEOF = false;
-  LLVMStyle.KeepEmptyLinesAtStart = true;
-  LLVMStyle.KeepEmptyLinesAtTheStartOfBlocks = true;
+  LLVMStyle.KeepEmptyLines = {
+      /*AtEndOfFile=*/false,
+      /*AtStartOfBlock=*/true,
+      /*AtStartOfFile=*/true,
+  };
   LLVMStyle.LambdaBodyIndentation = FormatStyle::LBI_Signature;
   LLVMStyle.Language = Language;
   LLVMStyle.LineEnding = FormatStyle::LE_DeriveLF;
@@ -1638,7 +1648,7 @@ FormatStyle getGoogleStyle(FormatStyle::LanguageKind Language) {
                                                 {".*", 3, 0, false}};
   GoogleStyle.IncludeStyle.IncludeIsMainRegex = "([-_](test|unittest))?$";
   GoogleStyle.IndentCaseLabels = true;
-  GoogleStyle.KeepEmptyLinesAtTheStartOfBlocks = false;
+  GoogleStyle.KeepEmptyLines.AtStartOfBlock = false;
   GoogleStyle.ObjCBinPackProtocolList = FormatStyle::BPS_Never;
   GoogleStyle.ObjCSpaceAfterProperty = false;
   GoogleStyle.ObjCSpaceBeforeProtocolList = true;
diff --git a/clang/lib/Format/UnwrappedLineFormatter.cpp b/clang/lib/Format/UnwrappedLineFormatter.cpp
index b8485ae2b9197..59eea9aedafdd 100644
--- a/clang/lib/Format/UnwrappedLineFormatter.cpp
+++ b/clang/lib/Format/UnwrappedLineFormatter.cpp
@@ -1474,12 +1474,12 @@ static auto computeNewlines(const AnnotatedLine &Line,
   if (Newlines == 0 && !RootToken.IsFirst)
     Newlines = 1;
   if (RootToken.IsFirst &&
-      (!Style.KeepEmptyLinesAtStart || !RootToken.HasUnescapedNewline)) {
+      (!Style.KeepEmptyLines.AtStartOfFile || !RootToken.HasUnescapedNewline)) {
     Newlines = 0;
   }
 
   // Remove empty lines after "{".
-  if (!Style.KeepEmptyLinesAtTheStartOfBlocks && PreviousLine &&
+  if (!Style.KeepEmptyLines.AtStartOfBlock && PreviousLine &&
       PreviousLine->Last->is(tok::l_brace) &&
       !PreviousLine->startsWithNamespace() &&
       !(PrevPrevLine && PrevPrevLine->startsWithNamespace() &&
@@ -1551,9 +1551,9 @@ void UnwrappedLineFormatter::formatFirstToken(
     unsigned NewlineIndent) {
   FormatToken &RootToken = *Line.First;
   if (RootToken.is(tok::eof)) {
-    unsigned Newlines =
-        std::min(RootToken.NewlinesBefore,
-                 Style.KeepEmptyLinesAtEOF ? Style.MaxEmptyLinesToKeep + 1 : 1);
+    unsigned Newlines = std::min(
+        RootToken.NewlinesBefore,
+        Style.KeepEmptyLines.AtEndOfFile ? Style.MaxEmptyLinesToKeep + 1 : 1);
     unsigned TokenIndent = Newlines ? NewlineIndent : 0;
     Whitespaces->replaceWhitespace(RootToken, Newlines, TokenIndent,
                                    TokenIndent);
diff --git a/clang/unittests/Format/ConfigParseTest.cpp b/clang/unittests/Format/ConfigParseTest.cpp
index 004fd750f3e46..0172698ca38f4 100644
--- a/clang/unittests/Format/ConfigParseTest.cpp
+++ b/clang/unittests/Format/ConfigParseTest.cpp
@@ -176,9 +176,9 @@ TEST(ConfigParseTest, ParsesConfigurationBools) {
   CHECK_PARSE_BOOL(IndentWrappedFunctionNames);
   CHECK_PARSE_BOOL(InsertBraces);
   CHECK_PARSE_BOOL(InsertNewlineAtEOF);
-  CHECK_PARSE_BOOL(KeepEmptyLinesAtEOF);
-  CHECK_PARSE_BOOL(KeepEmptyLinesAtStart);
-  CHECK_PARSE_BOOL(KeepEmptyLinesAtTheStartOfBlocks);
+  CHECK_PARSE_BOOL_FIELD(KeepEmptyLines.AtEndOfFile, "KeepEmptyLinesAtEOF");
+  CHECK_PARSE_BOOL_FIELD(KeepEmptyLines.AtStartOfBlock,
+                         "KeepEmptyLinesAtTheStartOfBlocks");
   CHECK_PARSE_BOOL(ObjCSpaceAfterProperty);
   CHECK_PARSE_BOOL(ObjCSpaceBeforeProtocolList);
   CHECK_PARSE_BOOL(Cpp11BracedListStyle);
@@ -224,6 +224,9 @@ TEST(ConfigParseTest, ParsesConfigurationBools) {
   CHECK_PARSE_NESTED_BOOL(BraceWrapping, SplitEmptyFunction);
   CHECK_PARSE_NESTED_BOOL(BraceWrapping, SplitEmptyRecord);
   CHECK_PARSE_NESTED_BOOL(BraceWrapping, SplitEmptyNamespace);
+  CHECK_PARSE_NESTED_BOOL(KeepEmptyLines, AtEndOfFile);
+  CHECK_PARSE_NESTED_BOOL(KeepEmptyLines, AtStartOfBlock);
+  CHECK_PARSE_NESTED_BOOL(KeepEmptyLines, AtStartOfFile);
   CHECK_PARSE_NESTED_BOOL(SpaceBeforeParensOptions, AfterControlStatements);
   CHECK_PARSE_NESTED_BOOL(SpaceBeforeParensOptions, AfterForeachMacros);
   CHECK_PARSE_NESTED_BOOL(SpaceBeforeParensOptions,
diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp
index d76d4b7a7858c..c9fb246eb7912 100644
--- a/clang/unittests/Format/FormatTest.cpp
+++ b/clang/unittests/Format/FormatTest.cpp
@@ -46,7 +46,7 @@ TEST_F(FormatTest, FormatsGlobalStatementsAt0) {
   verifyFormat("int i;\nint j;", "    int i; int j;");
   verifyFormat("int i;\nint j;", "    int i;\n  int j;");
   auto Style = getLLVMStyle();
-  Style.KeepEmptyLinesAtStart = false;
+  Style.KeepEmptyLines.AtStartOfFile = false;
   verifyFormat("int i;", " \n\t \v \f  int i;", Style);
 }
 
@@ -166,7 +166,7 @@ TEST_F(FormatTest, RemovesEmptyLines) {
   auto CustomStyle = getLLVMStyle();
   CustomStyle.BreakBeforeBraces = FormatStyle::BS_Custom;
   CustomStyle.BraceWrapping.AfterNamespace = true;
-  CustomStyle.KeepEmptyLinesAtTheStartOfBlocks = false;
+  CustomStyle.KeepEmptyLines.AtStartOfBlock = false;
   verifyFormat("namespace N\n"
                "{\n"
                "\n"
@@ -392,7 +392,7 @@ TEST_F(FormatTest, RemovesEmptyLines) {
   Style.BreakBeforeBraces = FormatStyle::BS_Custom;
   Style.BraceWrapping.AfterClass = true;
   Style.BraceWrapping.AfterFunction = true;
-  Style.KeepEmptyLinesAtTheStartOfBlocks = false;
+  Style.KeepEmptyLines.AtStartOfBlock = false;
 
   verifyFormat("class Foo\n"
                "{\n"
@@ -21902,7 +21902,7 @@ TEST_F(FormatTest, HandlesUTF8BOM) {
   verifyFormat("\xef\xbb\xbf#include <iostream>");
   verifyFormat("\xef\xbb\xbf\n#include <iostream>");
   auto Style = getLLVMStyle();
-  Style.KeepEmptyLinesAtStart = false;
+  Style.KeepEmptyLines.AtStartOfFile = false;
   verifyFormat("\xef\xbb\xbf#include <iostream>",
                "\xef\xbb\xbf\n#include <iostream>", Style);
 }
@@ -27144,7 +27144,7 @@ TEST_F(FormatTest, InsertNewlineAtEOF) {
 
 TEST_F(FormatTest, KeepEmptyLinesAtEOF) {
   FormatStyle Style = getLLVMStyle();
-  Style.KeepEmptyLinesAtEOF = true;
+  Style.KeepEmptyLines.AtEndOfFile = true;
 
   const StringRef Code{"int i;\n\n"};
   verifyNoChange(Code, Style);

>From 26190ebe702ddcb51cd2bc88c1d1923353d38d8a Mon Sep 17 00:00:00 2001
From: sstwcw <su3e8a96kzlver at posteo.net>
Date: Mon, 10 Jun 2024 03:14:15 +0000
Subject: [PATCH 3/4] Update docs like in e3eca33

---
 clang/docs/ClangFormatStyleOptions.rst | 31 ++++++++++++++++----------
 clang/include/clang/Format/Format.h    | 29 ++++++++++++++----------
 2 files changed, 36 insertions(+), 24 deletions(-)

diff --git a/clang/docs/ClangFormatStyleOptions.rst b/clang/docs/ClangFormatStyleOptions.rst
index 6ab662a855e95..080cba90c4a8b 100644
--- a/clang/docs/ClangFormatStyleOptions.rst
+++ b/clang/docs/ClangFormatStyleOptions.rst
@@ -4451,25 +4451,22 @@ the configuration (without a prefix: ``Auto``).
 
   Nested configuration flags:
 
-  Options regarding which empty lines are kept.  Some of the options can
-  also be read as standalone options for backward compatibility.  For
-  example, these configurations do the same thing.
+  Options regarding which empty lines are kept.
+
+  For example, the config below will remove empty lines at start of the
+  file, end of the file, and start of blocks.
 
 
   .. code-block:: c++
 
     KeepEmptyLines:
-      AtEndOfFile: true
-      AtStartOfBlock: true
-
-    KeepEmptyLinesAtEOF: true
-    KeepEmptyLinesAtTheStartOfBlocks: true
+      AtEndOfFile: false
+      AtStartOfBlock: false
+      AtStartOfFile: false
 
-  * ``bool AtEndOfFile`` Keep empty lines at end of file.  It can also be read as the standalone
-    option ``KeepEmptyLinesAtEOF``.
+  * ``bool AtEndOfFile`` Keep empty lines at end of file.
 
-  * ``bool AtStartOfBlock`` If true, the empty lines at the start of blocks are kept.  It can also
-    be read as the standalone option ``KeepEmptyLinesAtTheStartOfBlocks``.
+  * ``bool AtStartOfBlock`` Keep empty lines at start of a block.
 
     .. code-block:: c++
 
@@ -4482,6 +4479,16 @@ the configuration (without a prefix: ``Auto``).
   * ``bool AtStartOfFile`` Keep empty lines at start of file.
 
 
+.. _KeepEmptyLinesAtEOF:
+
+**KeepEmptyLinesAtEOF** (``Boolean``) :versionbadge:`clang-format 17` :ref:`¶ <KeepEmptyLinesAtEOF>`
+  This option is deprecated. See ``AtEndOfFile`` of ``KeepEmptyLines``.
+
+.. _KeepEmptyLinesAtTheStartOfBlocks:
+
+**KeepEmptyLinesAtTheStartOfBlocks** (``Boolean``) :versionbadge:`clang-format 3.7` :ref:`¶ <KeepEmptyLinesAtTheStartOfBlocks>`
+  This option is deprecated. See ``AtStartOfBlock`` of ``KeepEmptyLines``.
+
 .. _LambdaBodyIndentation:
 
 **LambdaBodyIndentation** (``LambdaBodyIndentationKind``) :versionbadge:`clang-format 13` :ref:`¶ <LambdaBodyIndentation>`
diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h
index d19aba1c1bc84..13e6b4ac16271 100644
--- a/clang/include/clang/Format/Format.h
+++ b/clang/include/clang/Format/Format.h
@@ -3095,24 +3095,21 @@ struct FormatStyle {
   bool JavaScriptWrapImports;
   // clang-format on
 
-  /// Options regarding which empty lines are kept.  Some of the options can
-  /// also be read as standalone options for backward compatibility.  For
-  /// example, these configurations do the same thing.
+  /// Options regarding which empty lines are kept.
+  ///
+  /// For example, the config below will remove empty lines at start of the
+  /// file, end of the file, and start of blocks.
   ///
   /// \code
   ///   KeepEmptyLines:
-  ///     AtEndOfFile: true
-  ///     AtStartOfBlock: true
-  ///
-  ///   KeepEmptyLinesAtEOF: true
-  ///   KeepEmptyLinesAtTheStartOfBlocks: true
+  ///     AtEndOfFile: false
+  ///     AtStartOfBlock: false
+  ///     AtStartOfFile: false
   /// \endcode
   struct KeepEmptyLinesStyle {
-    /// Keep empty lines at end of file.  It can also be read as the standalone
-    /// option ``KeepEmptyLinesAtEOF``.
+    /// Keep empty lines at end of file.
     bool AtEndOfFile;
-    /// If true, the empty lines at the start of blocks are kept.  It can also
-    /// be read as the standalone option ``KeepEmptyLinesAtTheStartOfBlocks``.
+    /// Keep empty lines at start of a block.
     /// \code
     ///    true:                                  false:
     ///    if (foo) {                     vs.     if (foo) {
@@ -3134,6 +3131,14 @@ struct FormatStyle {
   /// \version 19
   KeepEmptyLinesStyle KeepEmptyLines;
 
+  /// This option is deprecated. See ``AtEndOfFile`` of ``KeepEmptyLines``.
+  /// \version 17
+  // bool KeepEmptyLinesAtEOF;
+
+  /// This option is deprecated. See ``AtStartOfBlock`` of ``KeepEmptyLines``.
+  /// \version 3.7
+  // bool KeepEmptyLinesAtTheStartOfBlocks;
+
   /// Indentation logic for lambda bodies.
   enum LambdaBodyIndentationKind : int8_t {
     /// Align lambda body relative to the lambda signature. This is the default.

>From fe11f1c772d2002e83fed9c7e4651989f7d585da Mon Sep 17 00:00:00 2001
From: sstwcw <su3e8a96kzlver at posteo.net>
Date: Mon, 10 Jun 2024 03:15:07 +0000
Subject: [PATCH 4/4] Add release note entry

---
 clang/docs/ReleaseNotes.rst | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index cf1ba02cbc4b2..a1e677821f039 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -1016,6 +1016,8 @@ clang-format
 - Adds ``AllowShortCaseExpressionOnASingleLine`` option.
 - Adds ``AlignCaseArrows`` suboption to ``AlignConsecutiveShortCaseStatements``.
 - Adds ``LeftWithLastLine`` suboption to ``AlignEscapedNewlines``.
+- Adds ``KeepEmptyLines`` option to deprecate ``KeepEmptyLinesAtEOF``
+  and ``KeepEmptyLinesAtTheStartOfBlocks``.
 
 libclang
 --------



More information about the cfe-commits mailing list