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

via cfe-commits cfe-commits at lists.llvm.org
Mon May 6 07:40:26 PDT 2024


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

None

>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] [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 ce9035a2770eec..c81de131f050c1 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 8ebdc86b98329c..9a7837b1bac2d2 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 ad0e2c3c620c32..33dca7b08f998d 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 c8d8ec3afbd990..31ffbf46cdd085 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 4ae54e56331bdc..b8485ae2b91975 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 8c74ed2d119a3f..004fd750f3e467 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 e6f8e4a06515ea..d76d4b7a7858c2 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.



More information about the cfe-commits mailing list