Skip to content

Commit 219424f

Browse files
committed
[clang-format] Add new option: WrapNamespaceBodyWithNewlines
1 parent 2847020 commit 219424f

File tree

5 files changed

+343
-1
lines changed

5 files changed

+343
-1
lines changed

clang/docs/ClangFormatStyleOptions.rst

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6652,6 +6652,48 @@ the configuration (without a prefix: ``Auto``).
66526652
66536653
For example: BOOST_PP_STRINGIZE
66546654

6655+
.. _WrapNamespaceBodyWithEmptyLines:
6656+
6657+
**WrapNamespaceBodyWithEmptyLines** (``WrapNamespaceBodyWithEmptyLinesStyle``) :versionbadge:`clang-format 19` :ref:`<WrapNamespaceBodyWithEmptyLines>`
6658+
Controls number of empty lines at the begging and at the end of
6659+
namespace definition.
6660+
6661+
Possible values:
6662+
6663+
* ``WNBWELS_Never`` (in configuration: ``Never``)
6664+
Removes all empty lines at the beginning and at the end of
6665+
namespace definition.
6666+
6667+
.. code-block:: c++
6668+
6669+
namespace N1 {
6670+
namespace N2
6671+
function();
6672+
}
6673+
}
6674+
6675+
* ``WNBWELS_Always`` (in configuration: ``Always``)
6676+
Always adds an empty line at the beginning and at the end of
6677+
namespace definition. MaxEmptyLinesToKeep is also applied, but
6678+
empty lines between consecutive namespace declarations are
6679+
always removed.
6680+
6681+
.. code-block:: c++
6682+
6683+
namespace N1 {
6684+
namespace N2 {
6685+
6686+
function();
6687+
6688+
}
6689+
}
6690+
6691+
* ``WNBWELS_Leave`` (in configuration: ``Leave``)
6692+
Keeps existing newlines at the beginning and at the end of
6693+
namespace definition using MaxEmptyLinesToKeep for formatting.
6694+
6695+
6696+
66556697
.. END_FORMAT_STYLE_OPTIONS
66566698
66576699
Adding additional style options

clang/include/clang/Format/Format.h

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5057,6 +5057,43 @@ struct FormatStyle {
50575057
/// \version 11
50585058
std::vector<std::string> WhitespaceSensitiveMacros;
50595059

5060+
/// Different styles for modify number of empty lines in
5061+
/// the beginning and at the of end of namespaces.
5062+
enum WrapNamespaceBodyWithEmptyLinesStyle : int8_t {
5063+
/// Removes all empty lines at the beginning and at the end of
5064+
/// namespace definition.
5065+
/// \code
5066+
/// namespace N1 {
5067+
/// namespace N2
5068+
/// function();
5069+
/// }
5070+
/// }
5071+
/// \endcode
5072+
WNBWELS_Never,
5073+
/// Always adds an empty line at the beginning and at the end of
5074+
/// namespace definition. MaxEmptyLinesToKeep is also applied, but
5075+
/// empty lines between consecutive namespace declarations are
5076+
/// always removed.
5077+
/// \code
5078+
/// namespace N1 {
5079+
/// namespace N2 {
5080+
///
5081+
/// function();
5082+
///
5083+
/// }
5084+
/// }
5085+
/// \endcode
5086+
WNBWELS_Always,
5087+
/// Keeps existing newlines at the beginning and at the end of
5088+
/// namespace definition using MaxEmptyLinesToKeep for formatting.
5089+
WNBWELS_Leave
5090+
};
5091+
5092+
/// Controls number of empty lines at the begging and at the end of
5093+
/// namespace definition.
5094+
/// \version 19
5095+
WrapNamespaceBodyWithEmptyLinesStyle WrapNamespaceBodyWithEmptyLines;
5096+
50605097
bool operator==(const FormatStyle &R) const {
50615098
return AccessModifierOffset == R.AccessModifierOffset &&
50625099
AlignAfterOpenBracket == R.AlignAfterOpenBracket &&
@@ -5234,7 +5271,8 @@ struct FormatStyle {
52345271
TypenameMacros == R.TypenameMacros && UseTab == R.UseTab &&
52355272
VerilogBreakBetweenInstancePorts ==
52365273
R.VerilogBreakBetweenInstancePorts &&
5237-
WhitespaceSensitiveMacros == R.WhitespaceSensitiveMacros;
5274+
WhitespaceSensitiveMacros == R.WhitespaceSensitiveMacros &&
5275+
WrapNamespaceBodyWithEmptyLines == R.WrapNamespaceBodyWithEmptyLines;
52385276
}
52395277

52405278
std::optional<FormatStyle> GetLanguageStyle(LanguageKind Language) const;

clang/lib/Format/Format.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -829,6 +829,18 @@ template <> struct ScalarEnumerationTraits<FormatStyle::UseTabStyle> {
829829
}
830830
};
831831

832+
template <>
833+
struct ScalarEnumerationTraits<
834+
FormatStyle::WrapNamespaceBodyWithEmptyLinesStyle> {
835+
static void
836+
enumeration(IO &IO,
837+
FormatStyle::WrapNamespaceBodyWithEmptyLinesStyle &Value) {
838+
IO.enumCase(Value, "Never", FormatStyle::WNBWELS_Never);
839+
IO.enumCase(Value, "Always", FormatStyle::WNBWELS_Always);
840+
IO.enumCase(Value, "Leave", FormatStyle::WNBWELS_Leave);
841+
}
842+
};
843+
832844
template <> struct MappingTraits<FormatStyle> {
833845
static void mapping(IO &IO, FormatStyle &Style) {
834846
// When reading, read the language first, we need it for getPredefinedStyle.
@@ -1154,6 +1166,8 @@ template <> struct MappingTraits<FormatStyle> {
11541166
Style.VerilogBreakBetweenInstancePorts);
11551167
IO.mapOptional("WhitespaceSensitiveMacros",
11561168
Style.WhitespaceSensitiveMacros);
1169+
IO.mapOptional("WrapNamespaceBodyWithEmptyLines",
1170+
Style.WrapNamespaceBodyWithEmptyLines);
11571171

11581172
// If AlwaysBreakAfterDefinitionReturnType was specified but
11591173
// BreakAfterReturnType was not, initialize the latter from the former for
@@ -1623,6 +1637,7 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) {
16231637
LLVMStyle.WhitespaceSensitiveMacros.push_back("NS_SWIFT_NAME");
16241638
LLVMStyle.WhitespaceSensitiveMacros.push_back("PP_STRINGIZE");
16251639
LLVMStyle.WhitespaceSensitiveMacros.push_back("STRINGIZE");
1640+
LLVMStyle.WrapNamespaceBodyWithEmptyLines = FormatStyle::WNBWELS_Leave;
16261641

16271642
LLVMStyle.PenaltyBreakAssignment = prec::Assignment;
16281643
LLVMStyle.PenaltyBreakBeforeFirstCallParameter = 19;

clang/lib/Format/UnwrappedLineFormatter.cpp

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,26 @@ bool isRecordLBrace(const FormatToken &Tok) {
3232
TT_StructLBrace, TT_UnionLBrace);
3333
}
3434

35+
bool LineStartsNamespaceScope(const AnnotatedLine *Line,
36+
const AnnotatedLine *PreviousLine,
37+
const AnnotatedLine *PrevPrevLine) {
38+
return PreviousLine &&
39+
((PreviousLine->Last->is(tok::l_brace) &&
40+
PreviousLine->startsWithNamespace()) ||
41+
(PrevPrevLine && PrevPrevLine->startsWithNamespace() &&
42+
PreviousLine->startsWith(tok::l_brace)));
43+
}
44+
45+
bool LineEndsNamespaceScope(const AnnotatedLine *Line,
46+
const SmallVectorImpl<AnnotatedLine *> &Lines) {
47+
if (!Line)
48+
return false;
49+
const FormatToken *tok = Line->First;
50+
if (!tok || tok->isNot(tok::r_brace))
51+
return false;
52+
return getNamespaceToken(Line, Lines) != nullptr;
53+
}
54+
3555
/// Tracks the indent level of \c AnnotatedLines across levels.
3656
///
3757
/// \c nextLine must be called for each \c AnnotatedLine, after which \c
@@ -1493,6 +1513,28 @@ static auto computeNewlines(const AnnotatedLine &Line,
14931513
Newlines = 1;
14941514
}
14951515

1516+
// Modify empty lines after "{" that opens namespace scope.
1517+
if (Style.WrapNamespaceBodyWithEmptyLines != FormatStyle::WNBWELS_Leave &&
1518+
LineStartsNamespaceScope(&Line, PreviousLine, PrevPrevLine)) {
1519+
if (Style.WrapNamespaceBodyWithEmptyLines == FormatStyle::WNBWELS_Never)
1520+
Newlines = std::min(Newlines, 1u);
1521+
else if (!Line.startsWithNamespace())
1522+
Newlines = std::max(Newlines, 2u);
1523+
else
1524+
Newlines = std::min(Newlines, 1u);
1525+
}
1526+
1527+
// Modify empty lines before "}" that closes namespace scope.
1528+
if (Style.WrapNamespaceBodyWithEmptyLines != FormatStyle::WNBWELS_Leave &&
1529+
LineEndsNamespaceScope(&Line, Lines)) {
1530+
if (Style.WrapNamespaceBodyWithEmptyLines == FormatStyle::WNBWELS_Never)
1531+
Newlines = std::min(Newlines, 1u);
1532+
else if (!LineEndsNamespaceScope(PreviousLine, Lines))
1533+
Newlines = std::max(Newlines, 2u);
1534+
else
1535+
Newlines = std::min(Newlines, 1u);
1536+
}
1537+
14961538
// Insert or remove empty line before access specifiers.
14971539
if (PreviousLine && RootToken.isAccessSpecifier()) {
14981540
switch (Style.EmptyLineBeforeAccessModifier) {

0 commit comments

Comments
 (0)