https://github.com/sstwcw updated https://github.com/llvm/llvm-project/pull/91221
>From 9267f8f19a2e502ef5a216c0d52b352b3699d399 Mon Sep 17 00:00:00 2001 From: sstwcw <su3e8a96kzl...@posteo.net> Date: Mon, 6 May 2024 14:34:08 +0000 Subject: [PATCH] [clang-format] Add option to remove leading blank lines (#91221) The options regarding which blank lines are kept are also aggregated. The new option is `KeepEmptyLines`. --- clang/docs/ClangFormatStyleOptions.rst | 48 ++++++++++++++---- clang/docs/ReleaseNotes.rst | 2 + clang/include/clang/Format/Format.h | 56 +++++++++++++++------ clang/lib/Format/Format.cpp | 24 ++++++--- clang/lib/Format/UnwrappedLineFormatter.cpp | 12 +++-- clang/unittests/Format/ConfigParseTest.cpp | 8 ++- clang/unittests/Format/FormatTest.cpp | 15 ++++-- 7 files changed, 124 insertions(+), 41 deletions(-) diff --git a/clang/docs/ClangFormatStyleOptions.rst b/clang/docs/ClangFormatStyleOptions.rst index bb00c20922d361..080cba90c4a8bf 100644 --- a/clang/docs/ClangFormatStyleOptions.rst +++ b/clang/docs/ClangFormatStyleOptions.rst @@ -4443,23 +4443,51 @@ the configuration (without a prefix: ``Auto``). false: import {VeryLongImportsAreAnnoying, VeryLongImportsAreAnnoying, VeryLongImportsAreAnnoying,} from "some/module.js" +.. _KeepEmptyLines: + +**KeepEmptyLines** (``KeepEmptyLinesStyle``) :versionbadge:`clang-format 19` :ref:`¶ <KeepEmptyLines>` + Which empty lines are kept. See ``MaxEmptyLinesToKeep`` for how many + consecutive empty lines are kept. + + Nested configuration flags: + + 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: false + AtStartOfBlock: false + AtStartOfFile: false + + * ``bool AtEndOfFile`` Keep empty lines at end of file. + + * ``bool AtStartOfBlock`` Keep empty lines at start of a block. + + .. code-block:: c++ + + true: false: + if (foo) { vs. if (foo) { + bar(); + bar(); } + } + + * ``bool AtStartOfFile`` Keep empty lines at start of file. + + .. _KeepEmptyLinesAtEOF: **KeepEmptyLinesAtEOF** (``Boolean``) :versionbadge:`clang-format 17` :ref:`¶ <KeepEmptyLinesAtEOF>` - Keep empty lines (up to ``MaxEmptyLinesToKeep``) at end of file. + This option is deprecated. See ``AtEndOfFile`` of ``KeepEmptyLines``. .. _KeepEmptyLinesAtTheStartOfBlocks: **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(); } - } + This option is deprecated. See ``AtStartOfBlock`` of ``KeepEmptyLines``. .. _LambdaBodyIndentation: diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index df579ae398c5ef..9ed3ff4507671c 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -1110,6 +1110,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 -------- diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h index 7d257be10af42c..efc2e450b723fa 100644 --- a/clang/include/clang/Format/Format.h +++ b/clang/include/clang/Format/Format.h @@ -3095,20 +3095,49 @@ struct FormatStyle { bool JavaScriptWrapImports; // clang-format on - /// Keep empty lines (up to ``MaxEmptyLinesToKeep``) at end of file. - /// \version 17 - bool KeepEmptyLinesAtEOF; - - /// If true, the empty line at the start of blocks is kept. + /// 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 - /// true: false: - /// if (foo) { vs. if (foo) { - /// bar(); - /// bar(); } - /// } + /// KeepEmptyLines: + /// AtEndOfFile: false + /// AtStartOfBlock: false + /// AtStartOfFile: false /// \endcode + struct KeepEmptyLinesStyle { + /// Keep empty lines at end of file. + bool AtEndOfFile; + /// Keep empty lines at start of a block. + /// \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; + + /// 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; + // bool KeepEmptyLinesAtTheStartOfBlocks; /// Indentation logic for lambda bodies. enum LambdaBodyIndentationKind : int8_t { @@ -5033,10 +5062,7 @@ struct FormatStyle { JavaImportGroups == R.JavaImportGroups && JavaScriptQuotes == R.JavaScriptQuotes && JavaScriptWrapImports == R.JavaScriptWrapImports && - KeepEmptyLinesAtEOF == R.KeepEmptyLinesAtEOF && - 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/Format.cpp b/clang/lib/Format/Format.cpp index cd21fbb2221ac6..259ef1dd00e3f9 100644 --- a/clang/lib/Format/Format.cpp +++ b/clang/lib/Format/Format.cpp @@ -369,6 +369,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); @@ -869,6 +877,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); @@ -1004,9 +1015,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("KeepEmptyLines", Style.KeepEmptyLines); IO.mapOptional("LambdaBodyIndentation", Style.LambdaBodyIndentation); IO.mapOptional("LineEnding", Style.LineEnding); IO.mapOptional("MacroBlockBegin", Style.MacroBlockBegin); @@ -1517,8 +1526,11 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) { /*Hex=*/0, /*HexMinDigits=*/0}; LLVMStyle.JavaScriptQuotes = FormatStyle::JSQS_Leave; LLVMStyle.JavaScriptWrapImports = true; - LLVMStyle.KeepEmptyLinesAtEOF = false; - LLVMStyle.KeepEmptyLinesAtTheStartOfBlocks = true; + LLVMStyle.KeepEmptyLines = { + /*AtEndOfFile=*/false, + /*AtStartOfBlock=*/true, + /*AtStartOfFile=*/true, + }; LLVMStyle.LambdaBodyIndentation = FormatStyle::LBI_Signature; LLVMStyle.Language = Language; LLVMStyle.LineEnding = FormatStyle::LE_DeriveLF; @@ -1641,7 +1653,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 729f3d78f4a354..1804c1437fd41d 100644 --- a/clang/lib/Format/UnwrappedLineFormatter.cpp +++ b/clang/lib/Format/UnwrappedLineFormatter.cpp @@ -1478,11 +1478,13 @@ 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.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() && @@ -1554,9 +1556,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 aded3ed2a6596e..2466677a3740d3 100644 --- a/clang/unittests/Format/ConfigParseTest.cpp +++ b/clang/unittests/Format/ConfigParseTest.cpp @@ -178,8 +178,9 @@ TEST(ConfigParseTest, ParsesConfigurationBools) { CHECK_PARSE_BOOL(IndentWrappedFunctionNames); CHECK_PARSE_BOOL(InsertBraces); CHECK_PARSE_BOOL(InsertNewlineAtEOF); - CHECK_PARSE_BOOL(KeepEmptyLinesAtEOF); - 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); @@ -226,6 +227,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 db1decb20d626b..5276e79d759812 100644 --- a/clang/unittests/Format/FormatTest.cpp +++ b/clang/unittests/Format/FormatTest.cpp @@ -45,6 +45,10 @@ 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.KeepEmptyLines.AtStartOfFile = false; + verifyFormat("int i;", " \n\t \v \f int i;", Style); } TEST_F(FormatTest, FormatsUnwrappedLinesAtFirstFormat) { @@ -163,7 +167,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" @@ -389,7 +393,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" @@ -21956,6 +21960,11 @@ 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.KeepEmptyLines.AtStartOfFile = 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. @@ -27230,7 +27239,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); _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits