diff --git a/clang/docs/ClangFormatStyleOptions.rst b/clang/docs/ClangFormatStyleOptions.rst --- a/clang/docs/ClangFormatStyleOptions.rst +++ b/clang/docs/ClangFormatStyleOptions.rst @@ -2195,7 +2195,17 @@ protected: }; +**EmptyLinesAfterAccessModifier** (``unsigned``) + Defines how many lines are put after access modifiers. + .. code-block:: c++ + + 0: 1: + struct Foo { vs. struct Foo { + private: private: + int x; + }; int x; + }; **ExperimentalAutoDetectBinPacking** (``bool``) If ``true``, clang-format detects whether function calls and diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h --- a/clang/include/clang/Format/Format.h +++ b/clang/include/clang/Format/Format.h @@ -1953,6 +1953,9 @@ /// Defines in which cases to put empty line before access modifiers. EmptyLineBeforeAccessModifierStyle EmptyLineBeforeAccessModifier; + /// Defines how many lines are put after access modifiers. + unsigned EmptyLinesAfterAccessModifier; + /// If ``true``, clang-format detects whether function calls and /// definitions are formatted with one parameter per line. /// @@ -3201,6 +3204,7 @@ DerivePointerAlignment == R.DerivePointerAlignment && DisableFormat == R.DisableFormat && EmptyLineBeforeAccessModifier == R.EmptyLineBeforeAccessModifier && + EmptyLinesAfterAccessModifier == R.EmptyLinesAfterAccessModifier && ExperimentalAutoDetectBinPacking == R.ExperimentalAutoDetectBinPacking && FixNamespaceComments == R.FixNamespaceComments && diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp --- a/clang/lib/Format/Format.cpp +++ b/clang/lib/Format/Format.cpp @@ -586,6 +586,8 @@ IO.mapOptional("DisableFormat", Style.DisableFormat); IO.mapOptional("EmptyLineBeforeAccessModifier", Style.EmptyLineBeforeAccessModifier); + IO.mapOptional("EmptyLinesAfterAccessModifier", + Style.EmptyLinesAfterAccessModifier); IO.mapOptional("ExperimentalAutoDetectBinPacking", Style.ExperimentalAutoDetectBinPacking); IO.mapOptional("FixNamespaceComments", Style.FixNamespaceComments); @@ -975,6 +977,7 @@ LLVMStyle.DeriveLineEnding = true; LLVMStyle.DerivePointerAlignment = false; LLVMStyle.EmptyLineBeforeAccessModifier = FormatStyle::ELBAMS_LogicalBlock; + LLVMStyle.EmptyLinesAfterAccessModifier = 0u; LLVMStyle.ExperimentalAutoDetectBinPacking = false; LLVMStyle.FixNamespaceComments = true; LLVMStyle.ForEachMacros.push_back("foreach"); diff --git a/clang/lib/Format/UnwrappedLineFormatter.cpp b/clang/lib/Format/UnwrappedLineFormatter.cpp --- a/clang/lib/Format/UnwrappedLineFormatter.cpp +++ b/clang/lib/Format/UnwrappedLineFormatter.cpp @@ -1281,7 +1281,7 @@ // Remove empty lines after access specifiers. if (PreviousLine && PreviousLine->First->isAccessSpecifier() && (!PreviousLine->InPPDirective || !RootToken.HasUnescapedNewline)) - Newlines = std::min(1u, Newlines); + Newlines = Style.EmptyLinesAfterAccessModifier + 1u; if (Newlines) Indent = NewlineIndent; diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp --- a/clang/unittests/Format/FormatTest.cpp +++ b/clang/unittests/Format/FormatTest.cpp @@ -9179,6 +9179,21 @@ Style); } +TEST_F(FormatTest, FormatsAfterAccessModifiers) { + verifyFormat("class Foo {\n" + "private:\n" + " int i;\n" + "};"); + + FormatStyle StyleWithLine = getLLVMStyle(); + StyleWithLine.EmptyLinesAfterAccessModifier = 1u; + verifyFormat("class Foo {\n" + "private:\n" + "\n" + " int i;\n" + "};", StyleWithLine); +} + TEST_F(FormatTest, FormatsArrays) { verifyFormat("aaaaaaaaaaaaaaaaaaaaaaaaa[aaaaaaaaaaaaaaaaaaaaaaaaa]\n" " [bbbbbbbbbbbbbbbbbbbbbbbbb] = c;");