Skip to content

Commit 60bf582

Browse files
thezbygHazardyKnusperkeks
authored andcommitted
[clang-format] PR16518 Add flag to suppress empty line insertion before access modifier
Add new option called InsertEmptyLineBeforeAccessModifier. Empty line before access modifier is inerted if this option is set to true (which is the default value, because clang-format always inserts empty lines before access modifiers), otherwise empty lines are removed. Fixes issue #16518. Differential Revision: https://reviews.llvm.org/D93846
1 parent 9aa38a0 commit 60bf582

File tree

6 files changed

+539
-4
lines changed

6 files changed

+539
-4
lines changed

clang/docs/ClangFormatStyleOptions.rst

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2119,6 +2119,75 @@ the configuration (without a prefix: ``Auto``).
21192119
**DisableFormat** (``bool``)
21202120
Disables formatting completely.
21212121

2122+
**EmptyLineBeforeAccessModifier** (``EmptyLineBeforeAccessModifierStyle``)
2123+
Defines in which cases to put empty line before access modifiers.
2124+
2125+
Possible values:
2126+
2127+
* ``ELBAMS_Never`` (in configuration: ``Never``)
2128+
Remove all empty lines before access modifiers.
2129+
2130+
.. code-block:: c++
2131+
2132+
struct foo {
2133+
private:
2134+
int i;
2135+
protected:
2136+
int j;
2137+
/* comment */
2138+
public:
2139+
foo() {}
2140+
private:
2141+
protected:
2142+
};
2143+
2144+
* ``ELBAMS_Leave`` (in configuration: ``Leave``)
2145+
Keep existing empty lines before access modifiers.
2146+
2147+
* ``ELBAMS_LogicalBlock`` (in configuration: ``LogicalBlock``)
2148+
Add empty line only when access modifier starts a new logical block.
2149+
Logical block is a group of one or more member fields or functions.
2150+
2151+
.. code-block:: c++
2152+
2153+
struct foo {
2154+
private:
2155+
int i;
2156+
2157+
protected:
2158+
int j;
2159+
/* comment */
2160+
public:
2161+
foo() {}
2162+
2163+
private:
2164+
protected:
2165+
};
2166+
2167+
* ``ELBAMS_Always`` (in configuration: ``Always``)
2168+
Always add empty line before access modifiers unless access modifier
2169+
is at the start of struct or class definition.
2170+
2171+
.. code-block:: c++
2172+
2173+
struct foo {
2174+
private:
2175+
int i;
2176+
2177+
protected:
2178+
int j;
2179+
/* comment */
2180+
2181+
public:
2182+
foo() {}
2183+
2184+
private:
2185+
2186+
protected:
2187+
};
2188+
2189+
2190+
21222191
**ExperimentalAutoDetectBinPacking** (``bool``)
21232192
If ``true``, clang-format detects whether function calls and
21242193
definitions are formatted with one parameter per line.

clang/include/clang/Format/Format.h

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1885,6 +1885,68 @@ struct FormatStyle {
18851885
/// Disables formatting completely.
18861886
bool DisableFormat;
18871887

1888+
/// Different styles for empty line before access modifiers.
1889+
enum EmptyLineBeforeAccessModifierStyle : unsigned char {
1890+
/// Remove all empty lines before access modifiers.
1891+
/// \code
1892+
/// struct foo {
1893+
/// private:
1894+
/// int i;
1895+
/// protected:
1896+
/// int j;
1897+
/// /* comment */
1898+
/// public:
1899+
/// foo() {}
1900+
/// private:
1901+
/// protected:
1902+
/// };
1903+
/// \endcode
1904+
ELBAMS_Never,
1905+
/// Keep existing empty lines before access modifiers.
1906+
ELBAMS_Leave,
1907+
/// Add empty line only when access modifier starts a new logical block.
1908+
/// Logical block is a group of one or more member fields or functions.
1909+
/// \code
1910+
/// struct foo {
1911+
/// private:
1912+
/// int i;
1913+
///
1914+
/// protected:
1915+
/// int j;
1916+
/// /* comment */
1917+
/// public:
1918+
/// foo() {}
1919+
///
1920+
/// private:
1921+
/// protected:
1922+
/// };
1923+
/// \endcode
1924+
ELBAMS_LogicalBlock,
1925+
/// Always add empty line before access modifiers unless access modifier
1926+
/// is at the start of struct or class definition.
1927+
/// \code
1928+
/// struct foo {
1929+
/// private:
1930+
/// int i;
1931+
///
1932+
/// protected:
1933+
/// int j;
1934+
/// /* comment */
1935+
///
1936+
/// public:
1937+
/// foo() {}
1938+
///
1939+
/// private:
1940+
///
1941+
/// protected:
1942+
/// };
1943+
/// \endcode
1944+
ELBAMS_Always,
1945+
};
1946+
1947+
/// Defines in which cases to put empty line before access modifiers.
1948+
EmptyLineBeforeAccessModifierStyle EmptyLineBeforeAccessModifier;
1949+
18881950
/// If ``true``, clang-format detects whether function calls and
18891951
/// definitions are formatted with one parameter per line.
18901952
///
@@ -3015,6 +3077,7 @@ struct FormatStyle {
30153077
DeriveLineEnding == R.DeriveLineEnding &&
30163078
DerivePointerAlignment == R.DerivePointerAlignment &&
30173079
DisableFormat == R.DisableFormat &&
3080+
EmptyLineBeforeAccessModifier == R.EmptyLineBeforeAccessModifier &&
30183081
ExperimentalAutoDetectBinPacking ==
30193082
R.ExperimentalAutoDetectBinPacking &&
30203083
FixNamespaceComments == R.FixNamespaceComments &&

clang/lib/Format/Format.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,18 @@ struct ScalarEnumerationTraits<FormatStyle::BreakInheritanceListStyle> {
241241
}
242242
};
243243

244+
template <>
245+
struct ScalarEnumerationTraits<
246+
FormatStyle::EmptyLineBeforeAccessModifierStyle> {
247+
static void
248+
enumeration(IO &IO, FormatStyle::EmptyLineBeforeAccessModifierStyle &Value) {
249+
IO.enumCase(Value, "Never", FormatStyle::ELBAMS_Never);
250+
IO.enumCase(Value, "Leave", FormatStyle::ELBAMS_Leave);
251+
IO.enumCase(Value, "LogicalBlock", FormatStyle::ELBAMS_LogicalBlock);
252+
IO.enumCase(Value, "Always", FormatStyle::ELBAMS_Always);
253+
}
254+
};
255+
244256
template <>
245257
struct ScalarEnumerationTraits<FormatStyle::PPDirectiveIndentStyle> {
246258
static void enumeration(IO &IO, FormatStyle::PPDirectiveIndentStyle &Value) {
@@ -560,6 +572,8 @@ template <> struct MappingTraits<FormatStyle> {
560572
IO.mapOptional("DeriveLineEnding", Style.DeriveLineEnding);
561573
IO.mapOptional("DerivePointerAlignment", Style.DerivePointerAlignment);
562574
IO.mapOptional("DisableFormat", Style.DisableFormat);
575+
IO.mapOptional("EmptyLineBeforeAccessModifier",
576+
Style.EmptyLineBeforeAccessModifier);
563577
IO.mapOptional("ExperimentalAutoDetectBinPacking",
564578
Style.ExperimentalAutoDetectBinPacking);
565579
IO.mapOptional("FixNamespaceComments", Style.FixNamespaceComments);
@@ -931,6 +945,7 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) {
931945
LLVMStyle.Cpp11BracedListStyle = true;
932946
LLVMStyle.DeriveLineEnding = true;
933947
LLVMStyle.DerivePointerAlignment = false;
948+
LLVMStyle.EmptyLineBeforeAccessModifier = FormatStyle::ELBAMS_LogicalBlock;
934949
LLVMStyle.ExperimentalAutoDetectBinPacking = false;
935950
LLVMStyle.FixNamespaceComments = true;
936951
LLVMStyle.ForEachMacros.push_back("foreach");

clang/lib/Format/UnwrappedLineFormatter.cpp

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1245,10 +1245,33 @@ void UnwrappedLineFormatter::formatFirstToken(
12451245
!startsExternCBlock(*PreviousLine))
12461246
Newlines = 1;
12471247

1248-
// Insert extra new line before access specifiers.
1249-
if (PreviousLine && PreviousLine->Last->isOneOf(tok::semi, tok::r_brace) &&
1250-
RootToken.isAccessSpecifier() && RootToken.NewlinesBefore == 1)
1251-
++Newlines;
1248+
// Insert or remove empty line before access specifiers.
1249+
if (PreviousLine && RootToken.isAccessSpecifier()) {
1250+
switch (Style.EmptyLineBeforeAccessModifier) {
1251+
case FormatStyle::ELBAMS_Never:
1252+
if (RootToken.NewlinesBefore > 1)
1253+
Newlines = 1;
1254+
break;
1255+
case FormatStyle::ELBAMS_Leave:
1256+
Newlines = std::max(RootToken.NewlinesBefore, 1u);
1257+
break;
1258+
case FormatStyle::ELBAMS_LogicalBlock:
1259+
if (PreviousLine->Last->isOneOf(tok::semi, tok::r_brace) &&
1260+
RootToken.NewlinesBefore <= 1)
1261+
Newlines = 2;
1262+
break;
1263+
case FormatStyle::ELBAMS_Always: {
1264+
const FormatToken *previousToken;
1265+
if (PreviousLine->Last->is(tok::comment))
1266+
previousToken = PreviousLine->Last->getPreviousNonComment();
1267+
else
1268+
previousToken = PreviousLine->Last;
1269+
if ((!previousToken || !previousToken->is(tok::l_brace)) &&
1270+
RootToken.NewlinesBefore <= 1)
1271+
Newlines = 2;
1272+
} break;
1273+
}
1274+
}
12521275

12531276
// Remove empty lines after access specifiers.
12541277
if (PreviousLine && PreviousLine->First->isAccessSpecifier() &&
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
// RUN: grep -Ev "// *[A-Z-]+:" %s \
2+
// RUN: | clang-format -style="{BasedOnStyle: LLVM, EmptyLineBeforeAccessModifier: LogicalBlock}" -lines=1:14 \
3+
// RUN: | clang-format -style="{BasedOnStyle: LLVM, EmptyLineBeforeAccessModifier: Never}" -lines=14:40 \
4+
// RUN: | FileCheck -strict-whitespace %s
5+
6+
// CHECK: int i
7+
// CHECK-NEXT: {{^$}}
8+
// CHECK-NEXT: {{^private:$}}
9+
// CHECK: }
10+
struct foo1 {
11+
int i;
12+
13+
private:
14+
int j;
15+
};
16+
17+
// CHECK: struct bar1
18+
// CHECK-NEXT: {{^private:$}}
19+
// CHECK: }
20+
struct bar1 {
21+
private:
22+
int i;
23+
int j;
24+
};
25+
26+
// CHECK: int i
27+
// CHECK-NEXT: {{^private:$}}
28+
// CHECK: }
29+
struct foo2 {
30+
int i;
31+
32+
private:
33+
int j;
34+
};
35+
36+
// CHECK: struct bar2
37+
// CHECK-NEXT: {{^private:$}}
38+
// CHECK: }
39+
struct bar2 {
40+
private:
41+
int i;
42+
int j;
43+
};
44+
45+
// CHECK: int j
46+
// CHECK-NEXT: {{^private:$}}
47+
// CHECK: }
48+
struct foo3 {
49+
int i;
50+
int j;
51+
52+
private:
53+
};
54+
55+
// CHECK: struct bar3
56+
// CHECK-NEXT: {{^private:$}}
57+
// CHECK: }
58+
struct bar3 {
59+
60+
private:
61+
int i;
62+
int j;
63+
};

0 commit comments

Comments
 (0)