Skip to content

Commit 84ba993

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

File tree

5 files changed

+140
-1
lines changed

5 files changed

+140
-1
lines changed

clang/docs/ClangFormatStyleOptions.rst

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

6655+
.. _WrapNamespaceBodyWithNewlines:
6656+
6657+
**WrapNamespaceBodyWithNewlines** (``Boolean``) :versionbadge:`clang-format 19` :ref:`<WrapNamespaceBodyWithNewlines>`
6658+
Insert a newline at the begging and at the end of namespace definition
6659+
6660+
.. code-block:: c++
6661+
6662+
false: vs. true:
6663+
6664+
namespace a { namespace a {
6665+
namespace b { namespace b {
6666+
function();
6667+
} function();
6668+
}
6669+
}
6670+
}
6671+
66556672
.. END_FORMAT_STYLE_OPTIONS
66566673
66576674
Adding additional style options

clang/include/clang/Format/Format.h

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

5060+
/// Insert a newline at the begging and at the end of namespace definition
5061+
/// \code
5062+
/// false: vs. true:
5063+
///
5064+
/// namespace a { namespace a {
5065+
/// namespace b { namespace b {
5066+
/// function();
5067+
/// } function();
5068+
/// }
5069+
/// }
5070+
/// }
5071+
/// \endcode
5072+
/// \version 19
5073+
bool WrapNamespaceBodyWithNewlines;
5074+
50605075
bool operator==(const FormatStyle &R) const {
50615076
return AccessModifierOffset == R.AccessModifierOffset &&
50625077
AlignAfterOpenBracket == R.AlignAfterOpenBracket &&
@@ -5234,7 +5249,8 @@ struct FormatStyle {
52345249
TypenameMacros == R.TypenameMacros && UseTab == R.UseTab &&
52355250
VerilogBreakBetweenInstancePorts ==
52365251
R.VerilogBreakBetweenInstancePorts &&
5237-
WhitespaceSensitiveMacros == R.WhitespaceSensitiveMacros;
5252+
WhitespaceSensitiveMacros == R.WhitespaceSensitiveMacros &&
5253+
WrapNamespaceBodyWithNewlines == R.WrapNamespaceBodyWithNewlines;
52385254
}
52395255

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

clang/lib/Format/Format.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1154,6 +1154,8 @@ template <> struct MappingTraits<FormatStyle> {
11541154
Style.VerilogBreakBetweenInstancePorts);
11551155
IO.mapOptional("WhitespaceSensitiveMacros",
11561156
Style.WhitespaceSensitiveMacros);
1157+
IO.mapOptional("WrapNamespaceBodyWithNewlines",
1158+
Style.WrapNamespaceBodyWithNewlines);
11571159

11581160
// If AlwaysBreakAfterDefinitionReturnType was specified but
11591161
// BreakAfterReturnType was not, initialize the latter from the former for
@@ -1623,6 +1625,7 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) {
16231625
LLVMStyle.WhitespaceSensitiveMacros.push_back("NS_SWIFT_NAME");
16241626
LLVMStyle.WhitespaceSensitiveMacros.push_back("PP_STRINGIZE");
16251627
LLVMStyle.WhitespaceSensitiveMacros.push_back("STRINGIZE");
1628+
LLVMStyle.WrapNamespaceBodyWithNewlines = false;
16261629

16271630
LLVMStyle.PenaltyBreakAssignment = prec::Assignment;
16281631
LLVMStyle.PenaltyBreakBeforeFirstCallParameter = 19;

clang/lib/Format/UnwrappedLineFormatter.cpp

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,24 @@ 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 && PreviousLine->Last->is(tok::l_brace) &&
39+
(PreviousLine->startsWithNamespace() ||
40+
(PrevPrevLine && PrevPrevLine->startsWithNamespace() &&
41+
PreviousLine->startsWith(tok::l_brace))) && !Line->startsWithNamespace();
42+
}
43+
44+
bool LineEndsNamespaceScope(const AnnotatedLine *Line,
45+
const SmallVectorImpl<AnnotatedLine*> &Lines) {
46+
const FormatToken* tok = Line->First;
47+
if (!tok || tok->isNot(tok::r_brace)) {
48+
return false;
49+
}
50+
return getNamespaceToken(Line, Lines) != nullptr;
51+
}
52+
3553
/// Tracks the indent level of \c AnnotatedLines across levels.
3654
///
3755
/// \c nextLine must be called for each \c AnnotatedLine, after which \c
@@ -1493,6 +1511,18 @@ static auto computeNewlines(const AnnotatedLine &Line,
14931511
Newlines = 1;
14941512
}
14951513

1514+
// Insert empty line after "{" that opens namespace scope
1515+
if (Style.WrapNamespaceBodyWithNewlines &&
1516+
LineStartsNamespaceScope(&Line, PreviousLine, PrevPrevLine)) {
1517+
Newlines = 2;
1518+
}
1519+
1520+
// Insert empty line before "}" that closes namespace scope
1521+
if (Style.WrapNamespaceBodyWithNewlines &&
1522+
LineEndsNamespaceScope(&Line, Lines) && !LineEndsNamespaceScope(PreviousLine, Lines)) {
1523+
Newlines = std::max(Newlines, 2u);
1524+
}
1525+
14961526
// Insert or remove empty line before access specifiers.
14971527
if (PreviousLine && RootToken.isAccessSpecifier()) {
14981528
switch (Style.EmptyLineBeforeAccessModifier) {

clang/unittests/Format/FormatTest.cpp

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28084,6 +28084,79 @@ TEST_F(FormatTest, BreakBinaryOperations) {
2808428084
Style);
2808528085
}
2808628086

28087+
TEST_F(FormatTest, WrappingNamespaceBodyWithNewlines) {
28088+
FormatStyle Style = getLLVMStyle();
28089+
Style.FixNamespaceComments = false;
28090+
Style.ShortNamespaceLines = 0;
28091+
Style.WrapNamespaceBodyWithNewlines = true;
28092+
28093+
// Empty namespace
28094+
verifyFormat("namespace N {};", Style);
28095+
28096+
// Single namespace
28097+
verifyFormat("namespace N {\n\n"
28098+
"int f1(int a) { return 2 * a; }\n\n"
28099+
"};", Style);
28100+
28101+
// Nested namespace
28102+
verifyFormat("namespace N1 {\n"
28103+
"namespace N2 {\n"
28104+
"namespace N3 {\n\n"
28105+
"int f1() {\n"
28106+
" int a = 1;\n"
28107+
" return a;\n"
28108+
"}\n\n"
28109+
"}\n"
28110+
"}\n"
28111+
"}", Style);
28112+
28113+
Style.WrapNamespaceBodyWithNewlines = false;
28114+
28115+
// Empty namespace
28116+
verifyFormat("namespace N {};", Style);
28117+
28118+
// Single namespace
28119+
verifyFormat("namespace N {\n"
28120+
"int f1(int a) { return 2 * a; }\n"
28121+
"};", Style);
28122+
28123+
// Nested namespace
28124+
verifyFormat("namespace N1 {\n"
28125+
"namespace N2 {\n"
28126+
"namespace N3 {\n"
28127+
"int f1() {\n"
28128+
" int a = 1;\n"
28129+
" return a;\n"
28130+
"}\n"
28131+
"}\n"
28132+
"}\n"
28133+
"}", Style);
28134+
}
28135+
28136+
TEST_F(FormatTest, WrappingNamespaceBodyWithNewlinesWithCompactNamespaces) {
28137+
FormatStyle Style = getLLVMStyle();
28138+
Style.FixNamespaceComments = false;
28139+
Style.CompactNamespaces = true;
28140+
Style.WrapNamespaceBodyWithNewlines = true;
28141+
28142+
28143+
verifyFormat("namespace N1 { namespace N2 { namespace N3 {\n\n"
28144+
"int f1() {\n"
28145+
" int a = 1;\n"
28146+
" return a;\n"
28147+
"}\n\n"
28148+
"}}}", Style);
28149+
28150+
Style.WrapNamespaceBodyWithNewlines = false;
28151+
28152+
verifyFormat("namespace N1 { namespace N2 { namespace N3 {\n"
28153+
"int f1() {\n"
28154+
" int a = 1;\n"
28155+
" return a;\n"
28156+
"}\n"
28157+
"}}}", Style);
28158+
}
28159+
2808728160
} // namespace
2808828161
} // namespace test
2808928162
} // namespace format

0 commit comments

Comments
 (0)