https://github.com/dmasloff created https://github.com/llvm/llvm-project/pull/106145
I would like to suggest a new clang-format option for llvm-project - WrapNamespaceBodyWithNewlines. I think it can be added to upstream since it is used by many popular public repositories, for example, [ytsaurus](https://github.com/ytsaurus/ytsaurus/). You can look through their style guide at this page: https://github.com/ytsaurus/ytsaurus/blob/main/yt/styleguide/cpp.md#namespaces As you can see from the name of the option it wraps the body of namespace with additional newlines turning this code: ``` namespace N { int function(); } ``` into that: ``` namespace N { int function(); } ``` Looking forward to your advices and recommendations >From 84ba9930e4650319265b2fabd2715268a91de614 Mon Sep 17 00:00:00 2001 From: dmasloff <dmaslo...@gmail.com> Date: Mon, 26 Aug 2024 22:11:05 +0300 Subject: [PATCH] [clang-format] Add new option: WrapNamespaceBodyWithNewlines --- clang/docs/ClangFormatStyleOptions.rst | 17 +++++ clang/include/clang/Format/Format.h | 18 ++++- clang/lib/Format/Format.cpp | 3 + clang/lib/Format/UnwrappedLineFormatter.cpp | 30 +++++++++ clang/unittests/Format/FormatTest.cpp | 73 +++++++++++++++++++++ 5 files changed, 140 insertions(+), 1 deletion(-) diff --git a/clang/docs/ClangFormatStyleOptions.rst b/clang/docs/ClangFormatStyleOptions.rst index a427d7cd40fcdd..140787ad9776d9 100644 --- a/clang/docs/ClangFormatStyleOptions.rst +++ b/clang/docs/ClangFormatStyleOptions.rst @@ -6652,6 +6652,23 @@ the configuration (without a prefix: ``Auto``). For example: BOOST_PP_STRINGIZE +.. _WrapNamespaceBodyWithNewlines: + +**WrapNamespaceBodyWithNewlines** (``Boolean``) :versionbadge:`clang-format 19` :ref:`¶ <WrapNamespaceBodyWithNewlines>` + Insert a newline at the begging and at the end of namespace definition + + .. code-block:: c++ + + false: vs. true: + + namespace a { namespace a { + namespace b { namespace b { + function(); + } function(); + } + } + } + .. END_FORMAT_STYLE_OPTIONS Adding additional style options diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h index d8b62c7652a0f6..eb8f198cc8a919 100644 --- a/clang/include/clang/Format/Format.h +++ b/clang/include/clang/Format/Format.h @@ -5057,6 +5057,21 @@ struct FormatStyle { /// \version 11 std::vector<std::string> WhitespaceSensitiveMacros; + /// Insert a newline at the begging and at the end of namespace definition + /// \code + /// false: vs. true: + /// + /// namespace a { namespace a { + /// namespace b { namespace b { + /// function(); + /// } function(); + /// } + /// } + /// } + /// \endcode + /// \version 19 + bool WrapNamespaceBodyWithNewlines; + bool operator==(const FormatStyle &R) const { return AccessModifierOffset == R.AccessModifierOffset && AlignAfterOpenBracket == R.AlignAfterOpenBracket && @@ -5234,7 +5249,8 @@ struct FormatStyle { TypenameMacros == R.TypenameMacros && UseTab == R.UseTab && VerilogBreakBetweenInstancePorts == R.VerilogBreakBetweenInstancePorts && - WhitespaceSensitiveMacros == R.WhitespaceSensitiveMacros; + WhitespaceSensitiveMacros == R.WhitespaceSensitiveMacros && + WrapNamespaceBodyWithNewlines == R.WrapNamespaceBodyWithNewlines; } std::optional<FormatStyle> GetLanguageStyle(LanguageKind Language) const; diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp index d2463b892fbb96..65d7737b397212 100644 --- a/clang/lib/Format/Format.cpp +++ b/clang/lib/Format/Format.cpp @@ -1154,6 +1154,8 @@ template <> struct MappingTraits<FormatStyle> { Style.VerilogBreakBetweenInstancePorts); IO.mapOptional("WhitespaceSensitiveMacros", Style.WhitespaceSensitiveMacros); + IO.mapOptional("WrapNamespaceBodyWithNewlines", + Style.WrapNamespaceBodyWithNewlines); // If AlwaysBreakAfterDefinitionReturnType was specified but // BreakAfterReturnType was not, initialize the latter from the former for @@ -1623,6 +1625,7 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) { LLVMStyle.WhitespaceSensitiveMacros.push_back("NS_SWIFT_NAME"); LLVMStyle.WhitespaceSensitiveMacros.push_back("PP_STRINGIZE"); LLVMStyle.WhitespaceSensitiveMacros.push_back("STRINGIZE"); + LLVMStyle.WrapNamespaceBodyWithNewlines = false; LLVMStyle.PenaltyBreakAssignment = prec::Assignment; LLVMStyle.PenaltyBreakBeforeFirstCallParameter = 19; diff --git a/clang/lib/Format/UnwrappedLineFormatter.cpp b/clang/lib/Format/UnwrappedLineFormatter.cpp index 1804c1437fd41d..f3f76ac227df50 100644 --- a/clang/lib/Format/UnwrappedLineFormatter.cpp +++ b/clang/lib/Format/UnwrappedLineFormatter.cpp @@ -32,6 +32,24 @@ bool isRecordLBrace(const FormatToken &Tok) { TT_StructLBrace, TT_UnionLBrace); } +bool LineStartsNamespaceScope(const AnnotatedLine* Line, + const AnnotatedLine* PreviousLine, + const AnnotatedLine* PrevPrevLine) { + return PreviousLine && PreviousLine->Last->is(tok::l_brace) && + (PreviousLine->startsWithNamespace() || + (PrevPrevLine && PrevPrevLine->startsWithNamespace() && + PreviousLine->startsWith(tok::l_brace))) && !Line->startsWithNamespace(); +} + +bool LineEndsNamespaceScope(const AnnotatedLine *Line, + const SmallVectorImpl<AnnotatedLine*> &Lines) { + const FormatToken* tok = Line->First; + if (!tok || tok->isNot(tok::r_brace)) { + return false; + } + return getNamespaceToken(Line, Lines) != nullptr; +} + /// Tracks the indent level of \c AnnotatedLines across levels. /// /// \c nextLine must be called for each \c AnnotatedLine, after which \c @@ -1493,6 +1511,18 @@ static auto computeNewlines(const AnnotatedLine &Line, Newlines = 1; } + // Insert empty line after "{" that opens namespace scope + if (Style.WrapNamespaceBodyWithNewlines && + LineStartsNamespaceScope(&Line, PreviousLine, PrevPrevLine)) { + Newlines = 2; + } + + // Insert empty line before "}" that closes namespace scope + if (Style.WrapNamespaceBodyWithNewlines && + LineEndsNamespaceScope(&Line, Lines) && !LineEndsNamespaceScope(PreviousLine, Lines)) { + Newlines = std::max(Newlines, 2u); + } + // Insert or remove empty line before access specifiers. if (PreviousLine && RootToken.isAccessSpecifier()) { switch (Style.EmptyLineBeforeAccessModifier) { diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp index a383a624434b1f..94d8d652f80046 100644 --- a/clang/unittests/Format/FormatTest.cpp +++ b/clang/unittests/Format/FormatTest.cpp @@ -28084,6 +28084,79 @@ TEST_F(FormatTest, BreakBinaryOperations) { Style); } +TEST_F(FormatTest, WrappingNamespaceBodyWithNewlines) { + FormatStyle Style = getLLVMStyle(); + Style.FixNamespaceComments = false; + Style.ShortNamespaceLines = 0; + Style.WrapNamespaceBodyWithNewlines = true; + + // Empty namespace + verifyFormat("namespace N {};", Style); + + // Single namespace + verifyFormat("namespace N {\n\n" + "int f1(int a) { return 2 * a; }\n\n" + "};", Style); + + // Nested namespace + verifyFormat("namespace N1 {\n" + "namespace N2 {\n" + "namespace N3 {\n\n" + "int f1() {\n" + " int a = 1;\n" + " return a;\n" + "}\n\n" + "}\n" + "}\n" + "}", Style); + + Style.WrapNamespaceBodyWithNewlines = false; + + // Empty namespace + verifyFormat("namespace N {};", Style); + + // Single namespace + verifyFormat("namespace N {\n" + "int f1(int a) { return 2 * a; }\n" + "};", Style); + + // Nested namespace + verifyFormat("namespace N1 {\n" + "namespace N2 {\n" + "namespace N3 {\n" + "int f1() {\n" + " int a = 1;\n" + " return a;\n" + "}\n" + "}\n" + "}\n" + "}", Style); +} + +TEST_F(FormatTest, WrappingNamespaceBodyWithNewlinesWithCompactNamespaces) { + FormatStyle Style = getLLVMStyle(); + Style.FixNamespaceComments = false; + Style.CompactNamespaces = true; + Style.WrapNamespaceBodyWithNewlines = true; + + + verifyFormat("namespace N1 { namespace N2 { namespace N3 {\n\n" + "int f1() {\n" + " int a = 1;\n" + " return a;\n" + "}\n\n" + "}}}", Style); + + Style.WrapNamespaceBodyWithNewlines = false; + + verifyFormat("namespace N1 { namespace N2 { namespace N3 {\n" + "int f1() {\n" + " int a = 1;\n" + " return a;\n" + "}\n" + "}}}", Style); +} + } // namespace } // namespace test } // namespace format _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits