Skip to content

Commit 9267f8f

Browse files
committed
[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`.
1 parent 4e0a0ea commit 9267f8f

File tree

7 files changed

+124
-41
lines changed

7 files changed

+124
-41
lines changed

clang/docs/ClangFormatStyleOptions.rst

Lines changed: 38 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4443,23 +4443,51 @@ the configuration (without a prefix: ``Auto``).
44434443
false:
44444444
import {VeryLongImportsAreAnnoying, VeryLongImportsAreAnnoying, VeryLongImportsAreAnnoying,} from "some/module.js"
44454445
4446+
.. _KeepEmptyLines:
4447+
4448+
**KeepEmptyLines** (``KeepEmptyLinesStyle``) :versionbadge:`clang-format 19` :ref:`<KeepEmptyLines>`
4449+
Which empty lines are kept. See ``MaxEmptyLinesToKeep`` for how many
4450+
consecutive empty lines are kept.
4451+
4452+
Nested configuration flags:
4453+
4454+
Options regarding which empty lines are kept.
4455+
4456+
For example, the config below will remove empty lines at start of the
4457+
file, end of the file, and start of blocks.
4458+
4459+
4460+
.. code-block:: c++
4461+
4462+
KeepEmptyLines:
4463+
AtEndOfFile: false
4464+
AtStartOfBlock: false
4465+
AtStartOfFile: false
4466+
4467+
* ``bool AtEndOfFile`` Keep empty lines at end of file.
4468+
4469+
* ``bool AtStartOfBlock`` Keep empty lines at start of a block.
4470+
4471+
.. code-block:: c++
4472+
4473+
true: false:
4474+
if (foo) { vs. if (foo) {
4475+
bar();
4476+
bar(); }
4477+
}
4478+
4479+
* ``bool AtStartOfFile`` Keep empty lines at start of file.
4480+
4481+
44464482
.. _KeepEmptyLinesAtEOF:
44474483

44484484
**KeepEmptyLinesAtEOF** (``Boolean``) :versionbadge:`clang-format 17` :ref:`<KeepEmptyLinesAtEOF>`
4449-
Keep empty lines (up to ``MaxEmptyLinesToKeep``) at end of file.
4485+
This option is deprecated. See ``AtEndOfFile`` of ``KeepEmptyLines``.
44504486

44514487
.. _KeepEmptyLinesAtTheStartOfBlocks:
44524488

44534489
**KeepEmptyLinesAtTheStartOfBlocks** (``Boolean``) :versionbadge:`clang-format 3.7` :ref:`<KeepEmptyLinesAtTheStartOfBlocks>`
4454-
If true, the empty line at the start of blocks is kept.
4455-
4456-
.. code-block:: c++
4457-
4458-
true: false:
4459-
if (foo) { vs. if (foo) {
4460-
bar();
4461-
bar(); }
4462-
}
4490+
This option is deprecated. See ``AtStartOfBlock`` of ``KeepEmptyLines``.
44634491

44644492
.. _LambdaBodyIndentation:
44654493

clang/docs/ReleaseNotes.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1110,6 +1110,8 @@ clang-format
11101110
- Adds ``AllowShortCaseExpressionOnASingleLine`` option.
11111111
- Adds ``AlignCaseArrows`` suboption to ``AlignConsecutiveShortCaseStatements``.
11121112
- Adds ``LeftWithLastLine`` suboption to ``AlignEscapedNewlines``.
1113+
- Adds ``KeepEmptyLines`` option to deprecate ``KeepEmptyLinesAtEOF``
1114+
and ``KeepEmptyLinesAtTheStartOfBlocks``.
11131115

11141116
libclang
11151117
--------

clang/include/clang/Format/Format.h

Lines changed: 41 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3095,20 +3095,49 @@ struct FormatStyle {
30953095
bool JavaScriptWrapImports;
30963096
// clang-format on
30973097

3098-
/// Keep empty lines (up to ``MaxEmptyLinesToKeep``) at end of file.
3099-
/// \version 17
3100-
bool KeepEmptyLinesAtEOF;
3101-
3102-
/// If true, the empty line at the start of blocks is kept.
3098+
/// Options regarding which empty lines are kept.
3099+
///
3100+
/// For example, the config below will remove empty lines at start of the
3101+
/// file, end of the file, and start of blocks.
3102+
///
31033103
/// \code
3104-
/// true: false:
3105-
/// if (foo) { vs. if (foo) {
3106-
/// bar();
3107-
/// bar(); }
3108-
/// }
3104+
/// KeepEmptyLines:
3105+
/// AtEndOfFile: false
3106+
/// AtStartOfBlock: false
3107+
/// AtStartOfFile: false
31093108
/// \endcode
3109+
struct KeepEmptyLinesStyle {
3110+
/// Keep empty lines at end of file.
3111+
bool AtEndOfFile;
3112+
/// Keep empty lines at start of a block.
3113+
/// \code
3114+
/// true: false:
3115+
/// if (foo) { vs. if (foo) {
3116+
/// bar();
3117+
/// bar(); }
3118+
/// }
3119+
/// \endcode
3120+
bool AtStartOfBlock;
3121+
/// Keep empty lines at start of file.
3122+
bool AtStartOfFile;
3123+
bool operator==(const KeepEmptyLinesStyle &R) const {
3124+
return AtEndOfFile == R.AtEndOfFile &&
3125+
AtStartOfBlock == R.AtStartOfBlock &&
3126+
AtStartOfFile == R.AtStartOfFile;
3127+
}
3128+
};
3129+
/// Which empty lines are kept. See ``MaxEmptyLinesToKeep`` for how many
3130+
/// consecutive empty lines are kept.
3131+
/// \version 19
3132+
KeepEmptyLinesStyle KeepEmptyLines;
3133+
3134+
/// This option is deprecated. See ``AtEndOfFile`` of ``KeepEmptyLines``.
3135+
/// \version 17
3136+
// bool KeepEmptyLinesAtEOF;
3137+
3138+
/// This option is deprecated. See ``AtStartOfBlock`` of ``KeepEmptyLines``.
31103139
/// \version 3.7
3111-
bool KeepEmptyLinesAtTheStartOfBlocks;
3140+
// bool KeepEmptyLinesAtTheStartOfBlocks;
31123141

31133142
/// Indentation logic for lambda bodies.
31143143
enum LambdaBodyIndentationKind : int8_t {
@@ -5033,10 +5062,7 @@ struct FormatStyle {
50335062
JavaImportGroups == R.JavaImportGroups &&
50345063
JavaScriptQuotes == R.JavaScriptQuotes &&
50355064
JavaScriptWrapImports == R.JavaScriptWrapImports &&
5036-
KeepEmptyLinesAtEOF == R.KeepEmptyLinesAtEOF &&
5037-
KeepEmptyLinesAtTheStartOfBlocks ==
5038-
R.KeepEmptyLinesAtTheStartOfBlocks &&
5039-
Language == R.Language &&
5065+
KeepEmptyLines == R.KeepEmptyLines && Language == R.Language &&
50405066
LambdaBodyIndentation == R.LambdaBodyIndentation &&
50415067
LineEnding == R.LineEnding && MacroBlockBegin == R.MacroBlockBegin &&
50425068
MacroBlockEnd == R.MacroBlockEnd && Macros == R.Macros &&

clang/lib/Format/Format.cpp

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -369,6 +369,14 @@ template <> struct ScalarEnumerationTraits<FormatStyle::JavaScriptQuoteStyle> {
369369
}
370370
};
371371

372+
template <> struct MappingTraits<FormatStyle::KeepEmptyLinesStyle> {
373+
static void mapping(IO &IO, FormatStyle::KeepEmptyLinesStyle &Value) {
374+
IO.mapOptional("AtEndOfFile", Value.AtEndOfFile);
375+
IO.mapOptional("AtStartOfBlock", Value.AtStartOfBlock);
376+
IO.mapOptional("AtStartOfFile", Value.AtStartOfFile);
377+
}
378+
};
379+
372380
template <> struct ScalarEnumerationTraits<FormatStyle::LanguageKind> {
373381
static void enumeration(IO &IO, FormatStyle::LanguageKind &Value) {
374382
IO.enumCase(Value, "Cpp", FormatStyle::LK_Cpp);
@@ -869,6 +877,9 @@ template <> struct MappingTraits<FormatStyle> {
869877
OnCurrentLine);
870878
IO.mapOptional("DeriveLineEnding", DeriveLineEnding);
871879
IO.mapOptional("DerivePointerBinding", Style.DerivePointerAlignment);
880+
IO.mapOptional("KeepEmptyLinesAtEOF", Style.KeepEmptyLines.AtEndOfFile);
881+
IO.mapOptional("KeepEmptyLinesAtTheStartOfBlocks",
882+
Style.KeepEmptyLines.AtStartOfBlock);
872883
IO.mapOptional("IndentFunctionDeclarationAfterType",
873884
Style.IndentWrappedFunctionNames);
874885
IO.mapOptional("IndentRequires", Style.IndentRequiresClause);
@@ -1004,9 +1015,7 @@ template <> struct MappingTraits<FormatStyle> {
10041015
IO.mapOptional("JavaImportGroups", Style.JavaImportGroups);
10051016
IO.mapOptional("JavaScriptQuotes", Style.JavaScriptQuotes);
10061017
IO.mapOptional("JavaScriptWrapImports", Style.JavaScriptWrapImports);
1007-
IO.mapOptional("KeepEmptyLinesAtTheStartOfBlocks",
1008-
Style.KeepEmptyLinesAtTheStartOfBlocks);
1009-
IO.mapOptional("KeepEmptyLinesAtEOF", Style.KeepEmptyLinesAtEOF);
1018+
IO.mapOptional("KeepEmptyLines", Style.KeepEmptyLines);
10101019
IO.mapOptional("LambdaBodyIndentation", Style.LambdaBodyIndentation);
10111020
IO.mapOptional("LineEnding", Style.LineEnding);
10121021
IO.mapOptional("MacroBlockBegin", Style.MacroBlockBegin);
@@ -1517,8 +1526,11 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) {
15171526
/*Hex=*/0, /*HexMinDigits=*/0};
15181527
LLVMStyle.JavaScriptQuotes = FormatStyle::JSQS_Leave;
15191528
LLVMStyle.JavaScriptWrapImports = true;
1520-
LLVMStyle.KeepEmptyLinesAtEOF = false;
1521-
LLVMStyle.KeepEmptyLinesAtTheStartOfBlocks = true;
1529+
LLVMStyle.KeepEmptyLines = {
1530+
/*AtEndOfFile=*/false,
1531+
/*AtStartOfBlock=*/true,
1532+
/*AtStartOfFile=*/true,
1533+
};
15221534
LLVMStyle.LambdaBodyIndentation = FormatStyle::LBI_Signature;
15231535
LLVMStyle.Language = Language;
15241536
LLVMStyle.LineEnding = FormatStyle::LE_DeriveLF;
@@ -1641,7 +1653,7 @@ FormatStyle getGoogleStyle(FormatStyle::LanguageKind Language) {
16411653
{".*", 3, 0, false}};
16421654
GoogleStyle.IncludeStyle.IncludeIsMainRegex = "([-_](test|unittest))?$";
16431655
GoogleStyle.IndentCaseLabels = true;
1644-
GoogleStyle.KeepEmptyLinesAtTheStartOfBlocks = false;
1656+
GoogleStyle.KeepEmptyLines.AtStartOfBlock = false;
16451657
GoogleStyle.ObjCBinPackProtocolList = FormatStyle::BPS_Never;
16461658
GoogleStyle.ObjCSpaceAfterProperty = false;
16471659
GoogleStyle.ObjCSpaceBeforeProtocolList = true;

clang/lib/Format/UnwrappedLineFormatter.cpp

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1478,11 +1478,13 @@ static auto computeNewlines(const AnnotatedLine &Line,
14781478
Newlines = std::min(Newlines, 1u);
14791479
if (Newlines == 0 && !RootToken.IsFirst)
14801480
Newlines = 1;
1481-
if (RootToken.IsFirst && !RootToken.HasUnescapedNewline)
1481+
if (RootToken.IsFirst &&
1482+
(!Style.KeepEmptyLines.AtStartOfFile || !RootToken.HasUnescapedNewline)) {
14821483
Newlines = 0;
1484+
}
14831485

14841486
// Remove empty lines after "{".
1485-
if (!Style.KeepEmptyLinesAtTheStartOfBlocks && PreviousLine &&
1487+
if (!Style.KeepEmptyLines.AtStartOfBlock && PreviousLine &&
14861488
PreviousLine->Last->is(tok::l_brace) &&
14871489
!PreviousLine->startsWithNamespace() &&
14881490
!(PrevPrevLine && PrevPrevLine->startsWithNamespace() &&
@@ -1554,9 +1556,9 @@ void UnwrappedLineFormatter::formatFirstToken(
15541556
unsigned NewlineIndent) {
15551557
FormatToken &RootToken = *Line.First;
15561558
if (RootToken.is(tok::eof)) {
1557-
unsigned Newlines =
1558-
std::min(RootToken.NewlinesBefore,
1559-
Style.KeepEmptyLinesAtEOF ? Style.MaxEmptyLinesToKeep + 1 : 1);
1559+
unsigned Newlines = std::min(
1560+
RootToken.NewlinesBefore,
1561+
Style.KeepEmptyLines.AtEndOfFile ? Style.MaxEmptyLinesToKeep + 1 : 1);
15601562
unsigned TokenIndent = Newlines ? NewlineIndent : 0;
15611563
Whitespaces->replaceWhitespace(RootToken, Newlines, TokenIndent,
15621564
TokenIndent);

clang/unittests/Format/ConfigParseTest.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -178,8 +178,9 @@ TEST(ConfigParseTest, ParsesConfigurationBools) {
178178
CHECK_PARSE_BOOL(IndentWrappedFunctionNames);
179179
CHECK_PARSE_BOOL(InsertBraces);
180180
CHECK_PARSE_BOOL(InsertNewlineAtEOF);
181-
CHECK_PARSE_BOOL(KeepEmptyLinesAtEOF);
182-
CHECK_PARSE_BOOL(KeepEmptyLinesAtTheStartOfBlocks);
181+
CHECK_PARSE_BOOL_FIELD(KeepEmptyLines.AtEndOfFile, "KeepEmptyLinesAtEOF");
182+
CHECK_PARSE_BOOL_FIELD(KeepEmptyLines.AtStartOfBlock,
183+
"KeepEmptyLinesAtTheStartOfBlocks");
183184
CHECK_PARSE_BOOL(ObjCSpaceAfterProperty);
184185
CHECK_PARSE_BOOL(ObjCSpaceBeforeProtocolList);
185186
CHECK_PARSE_BOOL(Cpp11BracedListStyle);
@@ -226,6 +227,9 @@ TEST(ConfigParseTest, ParsesConfigurationBools) {
226227
CHECK_PARSE_NESTED_BOOL(BraceWrapping, SplitEmptyFunction);
227228
CHECK_PARSE_NESTED_BOOL(BraceWrapping, SplitEmptyRecord);
228229
CHECK_PARSE_NESTED_BOOL(BraceWrapping, SplitEmptyNamespace);
230+
CHECK_PARSE_NESTED_BOOL(KeepEmptyLines, AtEndOfFile);
231+
CHECK_PARSE_NESTED_BOOL(KeepEmptyLines, AtStartOfBlock);
232+
CHECK_PARSE_NESTED_BOOL(KeepEmptyLines, AtStartOfFile);
229233
CHECK_PARSE_NESTED_BOOL(SpaceBeforeParensOptions, AfterControlStatements);
230234
CHECK_PARSE_NESTED_BOOL(SpaceBeforeParensOptions, AfterForeachMacros);
231235
CHECK_PARSE_NESTED_BOOL(SpaceBeforeParensOptions,

clang/unittests/Format/FormatTest.cpp

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,10 @@ TEST_F(FormatTest, FormatsGlobalStatementsAt0) {
4545
verifyFormat("\nint i;", " \n\t \v \f int i;");
4646
verifyFormat("int i;\nint j;", " int i; int j;");
4747
verifyFormat("int i;\nint j;", " int i;\n int j;");
48+
49+
auto Style = getLLVMStyle();
50+
Style.KeepEmptyLines.AtStartOfFile = false;
51+
verifyFormat("int i;", " \n\t \v \f int i;", Style);
4852
}
4953

5054
TEST_F(FormatTest, FormatsUnwrappedLinesAtFirstFormat) {
@@ -163,7 +167,7 @@ TEST_F(FormatTest, RemovesEmptyLines) {
163167
auto CustomStyle = getLLVMStyle();
164168
CustomStyle.BreakBeforeBraces = FormatStyle::BS_Custom;
165169
CustomStyle.BraceWrapping.AfterNamespace = true;
166-
CustomStyle.KeepEmptyLinesAtTheStartOfBlocks = false;
170+
CustomStyle.KeepEmptyLines.AtStartOfBlock = false;
167171
verifyFormat("namespace N\n"
168172
"{\n"
169173
"\n"
@@ -389,7 +393,7 @@ TEST_F(FormatTest, RemovesEmptyLines) {
389393
Style.BreakBeforeBraces = FormatStyle::BS_Custom;
390394
Style.BraceWrapping.AfterClass = true;
391395
Style.BraceWrapping.AfterFunction = true;
392-
Style.KeepEmptyLinesAtTheStartOfBlocks = false;
396+
Style.KeepEmptyLines.AtStartOfBlock = false;
393397

394398
verifyFormat("class Foo\n"
395399
"{\n"
@@ -21956,6 +21960,11 @@ TEST_F(FormatTest, HandlesUTF8BOM) {
2195621960
verifyFormat("\xef\xbb\xbf");
2195721961
verifyFormat("\xef\xbb\xbf#include <iostream>");
2195821962
verifyFormat("\xef\xbb\xbf\n#include <iostream>");
21963+
21964+
auto Style = getLLVMStyle();
21965+
Style.KeepEmptyLines.AtStartOfFile = false;
21966+
verifyFormat("\xef\xbb\xbf#include <iostream>",
21967+
"\xef\xbb\xbf\n#include <iostream>", Style);
2195921968
}
2196021969

2196121970
// FIXME: Encode Cyrillic and CJK characters below to appease MS compilers.
@@ -27230,7 +27239,7 @@ TEST_F(FormatTest, InsertNewlineAtEOF) {
2723027239

2723127240
TEST_F(FormatTest, KeepEmptyLinesAtEOF) {
2723227241
FormatStyle Style = getLLVMStyle();
27233-
Style.KeepEmptyLinesAtEOF = true;
27242+
Style.KeepEmptyLines.AtEndOfFile = true;
2723427243

2723527244
const StringRef Code{"int i;\n\n"};
2723627245
verifyNoChange(Code, Style);

0 commit comments

Comments
 (0)