https://github.com/DaanDeMeyer updated https://github.com/llvm/llvm-project/pull/169160
>From 072d1ab13b478c7e92a698e00fbd76e14ee1542b Mon Sep 17 00:00:00 2001 From: Daan De Meyer <[email protected]> Date: Fri, 21 Nov 2025 23:11:45 +0100 Subject: [PATCH 1/3] [clang-format][NFC] Upgrade PointerAlignment option to a struct This allows adding other suboptions e.g. ReturnType for #136597. --- clang/docs/ClangFormatStyleOptions.rst | 107 +++++++++++++------ clang/include/clang/Format/Format.h | 59 ++++++++++- clang/lib/Format/Format.cpp | 63 +++++++++-- clang/lib/Format/TokenAnnotator.cpp | 16 +-- clang/lib/Format/WhitespaceManager.cpp | 10 +- clang/unittests/Format/ConfigParseTest.cpp | 34 +++--- clang/unittests/Format/FormatTest.cpp | 118 ++++++++++----------- 7 files changed, 281 insertions(+), 126 deletions(-) diff --git a/clang/docs/ClangFormatStyleOptions.rst b/clang/docs/ClangFormatStyleOptions.rst index 94d6f0d27619f..ab21290260005 100644 --- a/clang/docs/ClangFormatStyleOptions.rst +++ b/clang/docs/ClangFormatStyleOptions.rst @@ -5668,31 +5668,54 @@ the configuration (without a prefix: ``Auto``). .. _PointerAlignment: -**PointerAlignment** (``PointerAlignmentStyle``) :versionbadge:`clang-format 3.7` :ref:`¶ <PointerAlignment>` +**PointerAlignment** (``PointerAlignmentOptions``) :versionbadge:`clang-format 3.7` :ref:`¶ <PointerAlignment>` Pointer and reference alignment style. - Possible values: + Acceptable values (configured as a single string or with suboptions): + * ``Left`` + * ``Right`` + * ``Middle`` - * ``PAS_Left`` (in configuration: ``Left``) - Align pointer to the left. + For example, to configure left pointer alignment: - .. code-block:: c++ + .. code-block:: yaml - int* a; + PointerAlignment: Left - * ``PAS_Right`` (in configuration: ``Right``) - Align pointer to the right. + # or - .. code-block:: c++ + PointerAlignment: + Default: Left + + Nested configuration flags: - int *a; + Pointer and reference alignment options. - * ``PAS_Middle`` (in configuration: ``Middle``) - Align pointer in the middle. + * ``PointerAlignmentStyle Default`` + The default alignment for pointers and references. - .. code-block:: c++ + Possible values: + + * ``PAS_Left`` (in configuration: ``Left``) + Align pointer to the left. + + .. code-block:: c++ + + int* a; + + * ``PAS_Right`` (in configuration: ``Right``) + Align pointer to the right. + + .. code-block:: c++ + + int *a; + + * ``PAS_Middle`` (in configuration: ``Middle``) + Align pointer in the middle. + + .. code-block:: c++ - int * a; + int * a; @@ -5824,34 +5847,58 @@ the configuration (without a prefix: ``Auto``). .. _ReferenceAlignment: -**ReferenceAlignment** (``ReferenceAlignmentStyle``) :versionbadge:`clang-format 13` :ref:`¶ <ReferenceAlignment>` +**ReferenceAlignment** (``ReferenceAlignmentOptions``) :versionbadge:`clang-format 13` :ref:`¶ <ReferenceAlignment>` Reference alignment style (overrides ``PointerAlignment`` for references). - Possible values: + Acceptable values (configured as a single string or with suboptions): + * ``Pointer`` + * ``Left`` + * ``Right`` + * ``Middle`` - * ``RAS_Pointer`` (in configuration: ``Pointer``) - Align reference like ``PointerAlignment``. + For example, to configure right reference alignment: - * ``RAS_Left`` (in configuration: ``Left``) - Align reference to the left. + .. code-block:: yaml - .. code-block:: c++ + ReferenceAlignment: Right - int& a; + # or - * ``RAS_Right`` (in configuration: ``Right``) - Align reference to the right. + ReferenceAlignment: + Default: Right - .. code-block:: c++ + Nested configuration flags: - int &a; + Reference alignment options. - * ``RAS_Middle`` (in configuration: ``Middle``) - Align reference in the middle. + * ``ReferenceAlignmentStyle Default`` + The default alignment for references. - .. code-block:: c++ + Possible values: + + * ``RAS_Pointer`` (in configuration: ``Pointer``) + Align reference like ``PointerAlignment``. + + * ``RAS_Left`` (in configuration: ``Left``) + Align reference to the left. + + .. code-block:: c++ + + int& a; + + * ``RAS_Right`` (in configuration: ``Right``) + Align reference to the right. + + .. code-block:: c++ + + int &a; + + * ``RAS_Middle`` (in configuration: ``Middle``) + Align reference in the middle. + + .. code-block:: c++ - int & a; + int & a; diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h index b6f124f948b59..2cd446366cfa4 100644 --- a/clang/include/clang/Format/Format.h +++ b/clang/include/clang/Format/Format.h @@ -4036,9 +4036,36 @@ struct FormatStyle { PAS_Middle }; + /// Pointer and reference alignment options. + struct PointerAlignmentOptions { + /// The default alignment for pointers and references. + PointerAlignmentStyle Default; + bool operator==(const PointerAlignmentOptions &R) const { + return Default == R.Default; + } + bool operator!=(const PointerAlignmentOptions &R) const { + return !(*this == R); + } + }; + /// Pointer and reference alignment style. + /// + /// Acceptable values (configured as a single string or with suboptions): + /// * ``Left`` + /// * ``Right`` + /// * ``Middle`` + /// + /// For example, to configure left pointer alignment: + /// \code{.yaml} + /// PointerAlignment: Left + /// + /// # or + /// + /// PointerAlignment: + /// Default: Left + /// \endcode /// \version 3.7 - PointerAlignmentStyle PointerAlignment; + PointerAlignmentOptions PointerAlignment; /// The number of columns to use for indentation of preprocessor statements. /// When set to -1 (default) ``IndentWidth`` is used also for preprocessor @@ -4208,9 +4235,37 @@ struct FormatStyle { RAS_Middle }; + /// Reference alignment options. + struct ReferenceAlignmentOptions { + /// The default alignment for references. + ReferenceAlignmentStyle Default; + bool operator==(const ReferenceAlignmentOptions &R) const { + return Default == R.Default; + } + bool operator!=(const ReferenceAlignmentOptions &R) const { + return !(*this == R); + } + }; + /// Reference alignment style (overrides ``PointerAlignment`` for references). + /// + /// Acceptable values (configured as a single string or with suboptions): + /// * ``Pointer`` + /// * ``Left`` + /// * ``Right`` + /// * ``Middle`` + /// + /// For example, to configure right reference alignment: + /// \code{.yaml} + /// ReferenceAlignment: Right + /// + /// # or + /// + /// ReferenceAlignment: + /// Default: Right + /// \endcode /// \version 13 - ReferenceAlignmentStyle ReferenceAlignment; + ReferenceAlignmentOptions ReferenceAlignment; // clang-format off /// Types of comment reflow style. diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp index 9bbb33cb14502..2140cf66cd5af 100644 --- a/clang/lib/Format/Format.cpp +++ b/clang/lib/Format/Format.cpp @@ -541,10 +541,32 @@ template <> struct ScalarEnumerationTraits<FormatStyle::PointerAlignmentStyle> { IO.enumCase(Value, "Middle", FormatStyle::PAS_Middle); IO.enumCase(Value, "Left", FormatStyle::PAS_Left); IO.enumCase(Value, "Right", FormatStyle::PAS_Right); + } +}; + +template <> struct MappingTraits<FormatStyle::PointerAlignmentOptions> { + static void enumInput(IO &IO, FormatStyle::PointerAlignmentOptions &Value) { + IO.enumCase(Value, "Middle", + FormatStyle::PointerAlignmentOptions( + {/*Default=*/FormatStyle::PAS_Middle})); + IO.enumCase(Value, "Left", + FormatStyle::PointerAlignmentOptions( + {/*Default=*/FormatStyle::PAS_Left})); + IO.enumCase(Value, "Right", + FormatStyle::PointerAlignmentOptions( + {/*Default=*/FormatStyle::PAS_Right})); // For backward compatibility. - IO.enumCase(Value, "true", FormatStyle::PAS_Left); - IO.enumCase(Value, "false", FormatStyle::PAS_Right); + IO.enumCase(Value, "true", + FormatStyle::PointerAlignmentOptions( + {/*Default=*/FormatStyle::PAS_Left})); + IO.enumCase(Value, "false", + FormatStyle::PointerAlignmentOptions( + {/*Default=*/FormatStyle::PAS_Right})); + } + + static void mapping(IO &IO, FormatStyle::PointerAlignmentOptions &Value) { + IO.mapOptional("Default", Value.Default); } }; @@ -589,6 +611,27 @@ template <> struct ScalarEnumerationTraits<FormatStyle::ReflowCommentsStyle> { } }; +template <> struct MappingTraits<FormatStyle::ReferenceAlignmentOptions> { + static void enumInput(IO &IO, FormatStyle::ReferenceAlignmentOptions &Value) { + IO.enumCase(Value, "Pointer", + FormatStyle::ReferenceAlignmentOptions( + {/*Default=*/FormatStyle::RAS_Pointer})); + IO.enumCase(Value, "Middle", + FormatStyle::ReferenceAlignmentOptions( + {/*Default=*/FormatStyle::RAS_Middle})); + IO.enumCase(Value, "Left", + FormatStyle::ReferenceAlignmentOptions( + {/*Default=*/FormatStyle::RAS_Left})); + IO.enumCase(Value, "Right", + FormatStyle::ReferenceAlignmentOptions( + {/*Default=*/FormatStyle::RAS_Right})); + } + + static void mapping(IO &IO, FormatStyle::ReferenceAlignmentOptions &Value) { + IO.mapOptional("Default", Value.Default); + } +}; + template <> struct ScalarEnumerationTraits<FormatStyle::ReferenceAlignmentStyle> { static void enumeration(IO &IO, FormatStyle::ReferenceAlignmentStyle &Value) { @@ -1785,10 +1828,10 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) { LLVMStyle.ObjCSpaceAfterProperty = false; LLVMStyle.ObjCSpaceBeforeProtocolList = true; LLVMStyle.PackConstructorInitializers = FormatStyle::PCIS_BinPack; - LLVMStyle.PointerAlignment = FormatStyle::PAS_Right; + LLVMStyle.PointerAlignment = {/*Default=*/FormatStyle::PAS_Right}; LLVMStyle.PPIndentWidth = -1; LLVMStyle.QualifierAlignment = FormatStyle::QAS_Leave; - LLVMStyle.ReferenceAlignment = FormatStyle::RAS_Pointer; + LLVMStyle.ReferenceAlignment = {/*Default=*/FormatStyle::RAS_Pointer}; LLVMStyle.ReflowComments = FormatStyle::RCS_Always; LLVMStyle.RemoveBracesLLVM = false; LLVMStyle.RemoveEmptyLinesInUnwrappedLines = false; @@ -1910,7 +1953,7 @@ FormatStyle getGoogleStyle(FormatStyle::LanguageKind Language) { GoogleStyle.ObjCSpaceAfterProperty = false; GoogleStyle.ObjCSpaceBeforeProtocolList = true; GoogleStyle.PackConstructorInitializers = FormatStyle::PCIS_NextLine; - GoogleStyle.PointerAlignment = FormatStyle::PAS_Left; + GoogleStyle.PointerAlignment.Default = FormatStyle::PAS_Left; GoogleStyle.RawStringFormats = { { FormatStyle::LK_Cpp, @@ -2105,7 +2148,7 @@ FormatStyle getMozillaStyle() { MozillaStyle.ObjCSpaceAfterProperty = true; MozillaStyle.ObjCSpaceBeforeProtocolList = false; MozillaStyle.PenaltyReturnTypeOnItsOwnLine = 200; - MozillaStyle.PointerAlignment = FormatStyle::PAS_Left; + MozillaStyle.PointerAlignment.Default = FormatStyle::PAS_Left; MozillaStyle.SpaceAfterTemplateKeyword = false; return MozillaStyle; } @@ -2128,7 +2171,7 @@ FormatStyle getWebKitStyle() { Style.NamespaceIndentation = FormatStyle::NI_Inner; Style.ObjCBlockIndentWidth = 4; Style.ObjCSpaceAfterProperty = true; - Style.PointerAlignment = FormatStyle::PAS_Left; + Style.PointerAlignment.Default = FormatStyle::PAS_Left; Style.SpaceBeforeCpp11BracedList = true; Style.SpaceInEmptyBraces = FormatStyle::SIEB_Always; return Style; @@ -2862,10 +2905,10 @@ class Formatter : public TokenAnalyzer { if (Style.DerivePointerAlignment) { const auto NetRightCount = countVariableAlignments(AnnotatedLines); if (NetRightCount > 0) - Style.PointerAlignment = FormatStyle::PAS_Right; + Style.PointerAlignment.Default = FormatStyle::PAS_Right; else if (NetRightCount < 0) - Style.PointerAlignment = FormatStyle::PAS_Left; - Style.ReferenceAlignment = FormatStyle::RAS_Pointer; + Style.PointerAlignment.Default = FormatStyle::PAS_Left; + Style.ReferenceAlignment.Default = FormatStyle::RAS_Pointer; } if (Style.Standard == FormatStyle::LS_Auto) { Style.Standard = hasCpp03IncompatibleFormat(AnnotatedLines) diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp index cb41756c56bf7..f48a02c49c562 100644 --- a/clang/lib/Format/TokenAnnotator.cpp +++ b/clang/lib/Format/TokenAnnotator.cpp @@ -4732,7 +4732,7 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line, if (BeforeLeft->is(tok::coloncolon)) { if (Left.isNot(tok::star)) return false; - assert(Style.PointerAlignment != FormatStyle::PAS_Right); + assert(Style.PointerAlignment.Default != FormatStyle::PAS_Right); if (!Right.startsSequence(tok::identifier, tok::r_paren)) return true; assert(Right.Next); @@ -4744,7 +4744,7 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line, // Ensure right pointer alignment with ellipsis e.g. int *...P if (Left.is(tok::ellipsis) && BeforeLeft && BeforeLeft->isPointerOrReference()) { - return Style.PointerAlignment != FormatStyle::PAS_Right; + return Style.PointerAlignment.Default != FormatStyle::PAS_Right; } if (Right.is(tok::star) && Left.is(tok::l_paren)) @@ -4782,9 +4782,9 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line, // dependent on PointerAlignment style. if (Previous) { if (Previous->endsSequence(tok::kw_operator)) - return Style.PointerAlignment != FormatStyle::PAS_Left; + return Style.PointerAlignment.Default != FormatStyle::PAS_Left; if (Previous->isOneOf(tok::kw_const, tok::kw_volatile)) { - return (Style.PointerAlignment != FormatStyle::PAS_Left) || + return (Style.PointerAlignment.Default != FormatStyle::PAS_Left) || (Style.SpaceAroundPointerQualifiers == FormatStyle::SAPQ_After) || (Style.SpaceAroundPointerQualifiers == FormatStyle::SAPQ_Both); @@ -6543,9 +6543,9 @@ void TokenAnnotator::printDebugInfo(const AnnotatedLine &Line) const { FormatStyle::PointerAlignmentStyle TokenAnnotator::getTokenReferenceAlignment(const FormatToken &Reference) const { assert(Reference.isOneOf(tok::amp, tok::ampamp)); - switch (Style.ReferenceAlignment) { + switch (Style.ReferenceAlignment.Default) { case FormatStyle::RAS_Pointer: - return Style.PointerAlignment; + return Style.PointerAlignment.Default; case FormatStyle::RAS_Left: return FormatStyle::PAS_Left; case FormatStyle::RAS_Right: @@ -6554,7 +6554,7 @@ TokenAnnotator::getTokenReferenceAlignment(const FormatToken &Reference) const { return FormatStyle::PAS_Middle; } assert(0); //"Unhandled value of ReferenceAlignment" - return Style.PointerAlignment; + return Style.PointerAlignment.Default; } FormatStyle::PointerAlignmentStyle @@ -6563,7 +6563,7 @@ TokenAnnotator::getTokenPointerOrReferenceAlignment( if (PointerOrReference.isOneOf(tok::amp, tok::ampamp)) return getTokenReferenceAlignment(PointerOrReference); assert(PointerOrReference.is(tok::star)); - return Style.PointerAlignment; + return Style.PointerAlignment.Default; } } // namespace format diff --git a/clang/lib/Format/WhitespaceManager.cpp b/clang/lib/Format/WhitespaceManager.cpp index 94ccf9eb7842a..3834f3ca743d6 100644 --- a/clang/lib/Format/WhitespaceManager.cpp +++ b/clang/lib/Format/WhitespaceManager.cpp @@ -384,14 +384,14 @@ AlignTokenSequence(const FormatStyle &Style, unsigned Start, unsigned End, // If PointerAlignment is PAS_Right, keep *s or &s next to the token, // except if the token is equal, then a space is needed. - if ((Style.PointerAlignment == FormatStyle::PAS_Right || - Style.ReferenceAlignment == FormatStyle::RAS_Right) && + if ((Style.PointerAlignment.Default == FormatStyle::PAS_Right || + Style.ReferenceAlignment.Default == FormatStyle::RAS_Right) && CurrentChange.Spaces != 0 && CurrentChange.Tok->isNoneOf(tok::equal, tok::r_paren, TT_TemplateCloser)) { const bool ReferenceNotRightAligned = - Style.ReferenceAlignment != FormatStyle::RAS_Right && - Style.ReferenceAlignment != FormatStyle::RAS_Pointer; + Style.ReferenceAlignment.Default != FormatStyle::RAS_Right && + Style.ReferenceAlignment.Default != FormatStyle::RAS_Pointer; for (int Previous = i - 1; Previous >= 0 && Changes[Previous].Tok->is(TT_PointerOrReference); --Previous) { @@ -399,7 +399,7 @@ AlignTokenSequence(const FormatStyle &Style, unsigned Start, unsigned End, if (Changes[Previous].Tok->isNot(tok::star)) { if (ReferenceNotRightAligned) continue; - } else if (Style.PointerAlignment != FormatStyle::PAS_Right) { + } else if (Style.PointerAlignment.Default != FormatStyle::PAS_Right) { continue; } Changes[Previous + 1].Spaces -= Shift; diff --git a/clang/unittests/Format/ConfigParseTest.cpp b/clang/unittests/Format/ConfigParseTest.cpp index d578fa7a1a1e8..882f7b1342cc4 100644 --- a/clang/unittests/Format/ConfigParseTest.cpp +++ b/clang/unittests/Format/ConfigParseTest.cpp @@ -391,29 +391,39 @@ TEST(ConfigParseTest, ParsesConfiguration) { #undef CHECK_ALIGN_CONSECUTIVE - Style.PointerAlignment = FormatStyle::PAS_Middle; + Style.PointerAlignment = {/*Default=*/FormatStyle::PAS_Middle}; CHECK_PARSE("PointerAlignment: Left", PointerAlignment, - FormatStyle::PAS_Left); + FormatStyle::PointerAlignmentOptions( + {/*Default=*/FormatStyle::PAS_Left})); CHECK_PARSE("PointerAlignment: Right", PointerAlignment, - FormatStyle::PAS_Right); + FormatStyle::PointerAlignmentOptions( + {/*Default=*/FormatStyle::PAS_Right})); CHECK_PARSE("PointerAlignment: Middle", PointerAlignment, - FormatStyle::PAS_Middle); - Style.ReferenceAlignment = FormatStyle::RAS_Middle; + FormatStyle::PointerAlignmentOptions( + {/*Default=*/FormatStyle::PAS_Middle})); + Style.ReferenceAlignment = {/*Default=*/FormatStyle::RAS_Middle}; CHECK_PARSE("ReferenceAlignment: Pointer", ReferenceAlignment, - FormatStyle::RAS_Pointer); + FormatStyle::ReferenceAlignmentOptions( + {/*Default=*/FormatStyle::RAS_Pointer})); CHECK_PARSE("ReferenceAlignment: Left", ReferenceAlignment, - FormatStyle::RAS_Left); + FormatStyle::ReferenceAlignmentOptions( + {/*Default=*/FormatStyle::RAS_Left})); CHECK_PARSE("ReferenceAlignment: Right", ReferenceAlignment, - FormatStyle::RAS_Right); + FormatStyle::ReferenceAlignmentOptions( + {/*Default=*/FormatStyle::RAS_Right})); CHECK_PARSE("ReferenceAlignment: Middle", ReferenceAlignment, - FormatStyle::RAS_Middle); + FormatStyle::ReferenceAlignmentOptions( + {/*Default=*/FormatStyle::RAS_Middle})); // For backward compatibility: CHECK_PARSE("PointerBindsToType: Left", PointerAlignment, - FormatStyle::PAS_Left); + FormatStyle::PointerAlignmentOptions( + {/*Default=*/FormatStyle::PAS_Left})); CHECK_PARSE("PointerBindsToType: Right", PointerAlignment, - FormatStyle::PAS_Right); + FormatStyle::PointerAlignmentOptions( + {/*Default=*/FormatStyle::PAS_Right})); CHECK_PARSE("PointerBindsToType: Middle", PointerAlignment, - FormatStyle::PAS_Middle); + FormatStyle::PointerAlignmentOptions( + {/*Default=*/FormatStyle::PAS_Middle})); Style.ReflowComments = FormatStyle::RCS_Always; CHECK_PARSE("ReflowComments: Never", ReflowComments, FormatStyle::RCS_Never); diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp index 81fa7d1d11aa4..4ebcd428a0685 100644 --- a/clang/unittests/Format/FormatTest.cpp +++ b/clang/unittests/Format/FormatTest.cpp @@ -2047,8 +2047,8 @@ TEST_F(FormatTest, ElseIf) { TEST_F(FormatTest, SeparatePointerReferenceAlignment) { FormatStyle Style = getLLVMStyle(); - EXPECT_EQ(Style.PointerAlignment, FormatStyle::PAS_Right); - EXPECT_EQ(Style.ReferenceAlignment, FormatStyle::RAS_Pointer); + EXPECT_EQ(Style.PointerAlignment.Default, FormatStyle::PAS_Right); + EXPECT_EQ(Style.ReferenceAlignment.Default, FormatStyle::RAS_Pointer); verifyFormat("int *f1(int *a, int &b, int &&c);", Style); verifyFormat("int &f2(int &&c, int *a, int &b);", Style); verifyFormat("int &&f3(int &b, int &&c, int *a);", Style); @@ -2104,7 +2104,7 @@ TEST_F(FormatTest, SeparatePointerReferenceAlignment) { "Const unsigned h;", Style); - Style.PointerAlignment = FormatStyle::PAS_Left; + Style.PointerAlignment.Default = FormatStyle::PAS_Left; verifyFormat("int* f1(int* a, int& b, int&& c);", Style); verifyFormat("int& f2(int&& c, int* a, int& b);", Style); verifyFormat("int&& f3(int& b, int&& c, int* a);", Style); @@ -2162,8 +2162,8 @@ TEST_F(FormatTest, SeparatePointerReferenceAlignment) { "Const unsigned h;", Style); - Style.PointerAlignment = FormatStyle::PAS_Right; - Style.ReferenceAlignment = FormatStyle::RAS_Left; + Style.PointerAlignment.Default = FormatStyle::PAS_Right; + Style.ReferenceAlignment.Default = FormatStyle::RAS_Left; verifyFormat("int *f1(int *a, int& b, int&& c);", Style); verifyFormat("int& f2(int&& c, int *a, int& b);", Style); verifyFormat("int&& f3(int& b, int&& c, int *a);", Style); @@ -2200,8 +2200,8 @@ TEST_F(FormatTest, SeparatePointerReferenceAlignment) { "Const unsigned h;", Style); - Style.PointerAlignment = FormatStyle::PAS_Left; - Style.ReferenceAlignment = FormatStyle::RAS_Middle; + Style.PointerAlignment.Default = FormatStyle::PAS_Left; + Style.ReferenceAlignment.Default = FormatStyle::RAS_Middle; verifyFormat("int* f1(int* a, int & b, int && c);", Style); verifyFormat("int & f2(int && c, int* a, int & b);", Style); verifyFormat("int && f3(int & b, int && c, int* a);", Style); @@ -2253,8 +2253,8 @@ TEST_F(FormatTest, SeparatePointerReferenceAlignment) { "Const unsigned h;", Style); - Style.PointerAlignment = FormatStyle::PAS_Middle; - Style.ReferenceAlignment = FormatStyle::RAS_Right; + Style.PointerAlignment.Default = FormatStyle::PAS_Middle; + Style.ReferenceAlignment.Default = FormatStyle::RAS_Right; verifyFormat("int * f1(int * a, int &b, int &&c);", Style); verifyFormat("int &f2(int &&c, int * a, int &b);", Style); verifyFormat("int &&f3(int &b, int &&c, int * a);", Style); @@ -2376,7 +2376,7 @@ TEST_F(FormatTest, FormatsForLoop) { NoBinPacking); FormatStyle AlignLeft = getLLVMStyle(); - AlignLeft.PointerAlignment = FormatStyle::PAS_Left; + AlignLeft.PointerAlignment.Default = FormatStyle::PAS_Left; verifyFormat("for (A* a = start; a < end; ++a, ++value) {\n}", AlignLeft); } @@ -8638,7 +8638,7 @@ TEST_F(FormatTest, BreaksFunctionDeclarations) { " void f();"); auto Style = getLLVMStyle(); - Style.PointerAlignment = FormatStyle::PAS_Left; + Style.PointerAlignment.Default = FormatStyle::PAS_Left; verifyFormat("void aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(\n" " aaaaaaaaaaaaaaaaaaaaaaaaa* const aaaaaaaaaaaa) {}", Style); @@ -9975,7 +9975,7 @@ TEST_F(FormatTest, DeclarationsOfMultipleVariables) { " ***c = ccccccccccccccccccc, ***d = ddddddddddddddd;"); FormatStyle Style = getGoogleStyle(); - Style.PointerAlignment = FormatStyle::PAS_Left; + Style.PointerAlignment.Default = FormatStyle::PAS_Left; Style.DerivePointerAlignment = false; verifyFormat("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n" " *aaaaaaaaaaaaaaaaaaaaaaaaaaaaa = aaaaaaaaaaaaaaaaaaa,\n" @@ -11465,15 +11465,15 @@ TEST_F(FormatTest, UnderstandsPointersToMembers) { " aaaaaaaaaaaaaaaaaaaaaaaaaaa(aaaaaaaaaaaaaaaaaaaaaaaaaaa));"); FormatStyle Style = getLLVMStyle(); - EXPECT_EQ(Style.PointerAlignment, FormatStyle::PAS_Right); + EXPECT_EQ(Style.PointerAlignment.Default, FormatStyle::PAS_Right); verifyFormat("typedef bool *(Class::*Member)() const;", Style); verifyFormat("void f(int A::*p) { int A::*v = &A::B; }", Style); - Style.PointerAlignment = FormatStyle::PAS_Left; + Style.PointerAlignment.Default = FormatStyle::PAS_Left; verifyFormat("typedef bool* (Class::*Member)() const;", Style); verifyFormat("void f(int A::* p) { int A::* v = &A::B; }", Style); - Style.PointerAlignment = FormatStyle::PAS_Middle; + Style.PointerAlignment.Default = FormatStyle::PAS_Middle; verifyFormat("typedef bool * (Class::*Member)() const;", Style); verifyFormat("void f(int A::* p) { int A::* v = &A::B; }", Style); } @@ -11533,7 +11533,7 @@ TEST_F(FormatTest, UnderstandsUnaryOperators) { // Check that * is not treated as a binary operator when we set // PointerAlignment as PAS_Left after a keyword and not a declaration. FormatStyle PASLeftStyle = getLLVMStyle(); - PASLeftStyle.PointerAlignment = FormatStyle::PAS_Left; + PASLeftStyle.PointerAlignment.Default = FormatStyle::PAS_Left; verifyFormat("co_return *a;", PASLeftStyle); verifyFormat("co_await *a;", PASLeftStyle); verifyFormat("co_yield *a", PASLeftStyle); @@ -11661,7 +11661,7 @@ TEST_F(FormatTest, UnderstandsFunctionRefQualification) { verifyFormat("template <typename T> void operator=(T) && {}"); FormatStyle AlignLeft = getLLVMStyle(); - AlignLeft.PointerAlignment = FormatStyle::PAS_Left; + AlignLeft.PointerAlignment.Default = FormatStyle::PAS_Left; verifyFormat("void A::b() && {}", AlignLeft); verifyFormat("void A::b() && noexcept {}", AlignLeft); verifyFormat("Deleted& operator=(const Deleted&) & = default;", AlignLeft); @@ -11693,7 +11693,7 @@ TEST_F(FormatTest, UnderstandsFunctionRefQualification) { verifyFormat("for (foo<void() &&>& cb : X)", AlignLeft); FormatStyle AlignMiddle = getLLVMStyle(); - AlignMiddle.PointerAlignment = FormatStyle::PAS_Middle; + AlignMiddle.PointerAlignment.Default = FormatStyle::PAS_Middle; verifyFormat("void A::b() && {}", AlignMiddle); verifyFormat("void A::b() && noexcept {}", AlignMiddle); verifyFormat("Deleted & operator=(const Deleted &) & = default;", @@ -11776,7 +11776,7 @@ TEST_F(FormatTest, UnderstandsFunctionRefQualification) { FormatStyle AlignLeftBreakTemplate = getLLVMStyle(); AlignLeftBreakTemplate.BreakTemplateDeclarations = FormatStyle::BTDS_Yes; - AlignLeftBreakTemplate.PointerAlignment = FormatStyle::PAS_Left; + AlignLeftBreakTemplate.PointerAlignment.Default = FormatStyle::PAS_Left; verifyFormat("struct f {\n" " template <class T>\n" @@ -11860,19 +11860,19 @@ TEST_F(FormatTest, PointerAlignmentFallback) { "int *q;\n" "int * r;"); - EXPECT_EQ(Style.PointerAlignment, FormatStyle::PAS_Right); + EXPECT_EQ(Style.PointerAlignment.Default, FormatStyle::PAS_Right); verifyFormat("int *p;\n" "int *q;\n" "int *r;", Code, Style); - Style.PointerAlignment = FormatStyle::PAS_Left; + Style.PointerAlignment.Default = FormatStyle::PAS_Left; verifyFormat("int* p;\n" "int* q;\n" "int* r;", Code, Style); - Style.PointerAlignment = FormatStyle::PAS_Middle; + Style.PointerAlignment.Default = FormatStyle::PAS_Middle; verifyFormat("int * p;\n" "int * q;\n" "int * r;", @@ -12068,7 +12068,7 @@ TEST_F(FormatTest, UnderstandsUsesOfStarAndAmp) { "void f(int i = 0, SomeType** temps = NULL);"); FormatStyle Left = getLLVMStyle(); - Left.PointerAlignment = FormatStyle::PAS_Left; + Left.PointerAlignment.Default = FormatStyle::PAS_Left; verifyFormat("x = *a(x) = *a(y);", Left); verifyFormat("for (;; *a = b) {\n}", Left); verifyFormat("return *this += 1;", Left); @@ -12214,7 +12214,7 @@ TEST_F(FormatTest, UnderstandsUsesOfStarAndAmp) { getGoogleStyleWithColumns(68)); FormatStyle Style = getLLVMStyle(); - Style.PointerAlignment = FormatStyle::PAS_Left; + Style.PointerAlignment.Default = FormatStyle::PAS_Left; verifyFormat("struct {\n" "}* ptr;", Style); @@ -12238,7 +12238,7 @@ TEST_F(FormatTest, UnderstandsUsesOfStarAndAmp) { Style); verifyFormat("bool b = 3 == int{3} && true;"); - Style.PointerAlignment = FormatStyle::PAS_Middle; + Style.PointerAlignment.Default = FormatStyle::PAS_Middle; verifyFormat("struct {\n" "} * ptr;", Style); @@ -12258,7 +12258,7 @@ TEST_F(FormatTest, UnderstandsUsesOfStarAndAmp) { "} && ptr = {};", Style); - Style.PointerAlignment = FormatStyle::PAS_Right; + Style.PointerAlignment.Default = FormatStyle::PAS_Right; verifyFormat("struct {\n" "} *ptr;", Style); @@ -12278,7 +12278,7 @@ TEST_F(FormatTest, UnderstandsUsesOfStarAndAmp) { "} &&ptr = {};", Style); - Style.PointerAlignment = FormatStyle::PAS_Left; + Style.PointerAlignment.Default = FormatStyle::PAS_Left; verifyFormat("delete[] *ptr;", Style); verifyFormat("delete[] **ptr;", Style); verifyFormat("delete[] *(ptr);", Style); @@ -12369,7 +12369,7 @@ TEST_F(FormatTest, UnderstandsUsesOfStarAndAmp) { verifyFormat("foo<a<b && c> d> v;"); FormatStyle PointerMiddle = getLLVMStyle(); - PointerMiddle.PointerAlignment = FormatStyle::PAS_Middle; + PointerMiddle.PointerAlignment.Default = FormatStyle::PAS_Middle; verifyFormat("delete *x;", PointerMiddle); verifyFormat("int * x;", PointerMiddle); verifyFormat("int *[] x;", PointerMiddle); @@ -12476,7 +12476,7 @@ TEST_F(FormatTest, UnderstandsAttributes) { auto Style = getLLVMStyleWithColumns(60); Style.AttributeMacros.push_back("my_fancy_attr"); - Style.PointerAlignment = FormatStyle::PAS_Left; + Style.PointerAlignment.Default = FormatStyle::PAS_Left; verifyFormat("void foo(const MyLongTypeNameeeeeeeeeeeee* my_fancy_attr\n" " testttttttttt);", Style); @@ -12504,7 +12504,7 @@ TEST_F(FormatTest, UnderstandsPointerQualifiersInCast) { // determine that the expression is a cast to a pointer type. FormatStyle LongPointerRight = getLLVMStyleWithColumns(999); FormatStyle LongPointerLeft = getLLVMStyleWithColumns(999); - LongPointerLeft.PointerAlignment = FormatStyle::PAS_Left; + LongPointerLeft.PointerAlignment.Default = FormatStyle::PAS_Left; StringRef AllQualifiers = "const volatile restrict __attribute__((foo)) _Nonnull _Null_unspecified " "_Nullable [[clang::attr]] __ptr32 __ptr64 __capability"; @@ -12640,12 +12640,12 @@ TEST_F(FormatTest, UnderstandsEllipsis) { verifyFormat("template <int *...PP> a;", Style); - Style.PointerAlignment = FormatStyle::PAS_Left; + Style.PointerAlignment.Default = FormatStyle::PAS_Left; verifyFormat("template <class... Ts> void Foo(Ts*... ts) {}", Style); verifyFormat("template <int*... PP> a;", Style); - Style.PointerAlignment = FormatStyle::PAS_Middle; + Style.PointerAlignment.Default = FormatStyle::PAS_Middle; verifyFormat("template <int *... PP> a;", Style); } @@ -16253,15 +16253,15 @@ TEST_F(FormatTest, ConfigurableUseOfTab) { FormatStyle TabAlignment = Tab; TabAlignment.AlignConsecutiveDeclarations.Enabled = true; - TabAlignment.PointerAlignment = FormatStyle::PAS_Left; + TabAlignment.PointerAlignment.Default = FormatStyle::PAS_Left; verifyFormat("unsigned long long big;\n" "char*\t\t ptr;", TabAlignment); - TabAlignment.PointerAlignment = FormatStyle::PAS_Middle; + TabAlignment.PointerAlignment.Default = FormatStyle::PAS_Middle; verifyFormat("unsigned long long big;\n" "char *\t\t ptr;", TabAlignment); - TabAlignment.PointerAlignment = FormatStyle::PAS_Right; + TabAlignment.PointerAlignment.Default = FormatStyle::PAS_Right; verifyFormat("unsigned long long big;\n" "char\t\t *ptr;", TabAlignment); @@ -16309,19 +16309,19 @@ TEST_F(FormatTest, ConfigurableUseOfTab) { Tab); TabAlignment.UseTab = FormatStyle::UT_ForIndentation; - TabAlignment.PointerAlignment = FormatStyle::PAS_Left; + TabAlignment.PointerAlignment.Default = FormatStyle::PAS_Left; verifyFormat("void f() {\n" "\tunsigned long long big;\n" "\tchar* ptr;\n" "}", TabAlignment); - TabAlignment.PointerAlignment = FormatStyle::PAS_Middle; + TabAlignment.PointerAlignment.Default = FormatStyle::PAS_Middle; verifyFormat("void f() {\n" "\tunsigned long long big;\n" "\tchar * ptr;\n" "}", TabAlignment); - TabAlignment.PointerAlignment = FormatStyle::PAS_Right; + TabAlignment.PointerAlignment.Default = FormatStyle::PAS_Right; verifyFormat("void f() {\n" "\tunsigned long long big;\n" "\tchar *ptr;\n" @@ -18227,13 +18227,13 @@ TEST_F(FormatTest, ConfigurableSpaceBeforeColon) { TEST_F(FormatTest, ConfigurableSpaceAroundPointerQualifiers) { FormatStyle Style = getLLVMStyle(); - Style.PointerAlignment = FormatStyle::PAS_Left; + Style.PointerAlignment.Default = FormatStyle::PAS_Left; Style.SpaceAroundPointerQualifiers = FormatStyle::SAPQ_Default; verifyFormat("void* const* x = NULL;", Style); #define verifyQualifierSpaces(Code, Pointers, Qualifiers) \ do { \ - Style.PointerAlignment = FormatStyle::Pointers; \ + Style.PointerAlignment.Default = FormatStyle::Pointers; \ Style.SpaceAroundPointerQualifiers = FormatStyle::Qualifiers; \ verifyFormat(Code, Style); \ } while (false) @@ -18279,7 +18279,7 @@ TEST_F(FormatTest, ConfigurableSpaceAroundPointerQualifiers) { FormatStyle Spaces = getLLVMStyle(); Spaces.AttributeMacros.push_back("qualified"); - Spaces.PointerAlignment = FormatStyle::PAS_Right; + Spaces.PointerAlignment.Default = FormatStyle::PAS_Right; Spaces.SpaceAroundPointerQualifiers = FormatStyle::SAPQ_Default; verifyFormat("SomeType *volatile *a = NULL;", Spaces); verifyFormat("SomeType *__attribute__((attr)) *a = NULL;", Spaces); @@ -18294,7 +18294,7 @@ TEST_F(FormatTest, ConfigurableSpaceAroundPointerQualifiers) { verifyFormat("std::vector<SomeVar * NotAQualifier> x;", Spaces); // Check that SAPQ_Before doesn't result in extra spaces for PAS_Left. - Spaces.PointerAlignment = FormatStyle::PAS_Left; + Spaces.PointerAlignment.Default = FormatStyle::PAS_Left; Spaces.SpaceAroundPointerQualifiers = FormatStyle::SAPQ_Before; verifyFormat("SomeType* volatile* a = NULL;", Spaces); verifyFormat("SomeType* __attribute__((attr))* a = NULL;", Spaces); @@ -18310,7 +18310,7 @@ TEST_F(FormatTest, ConfigurableSpaceAroundPointerQualifiers) { verifyFormat("std::vector<SomeVar * NotAQualifier> x;", Spaces); // PAS_Middle should not have any noticeable changes even for SAPQ_Both - Spaces.PointerAlignment = FormatStyle::PAS_Middle; + Spaces.PointerAlignment.Default = FormatStyle::PAS_Middle; Spaces.SpaceAroundPointerQualifiers = FormatStyle::SAPQ_After; verifyFormat("SomeType * volatile * a = NULL;", Spaces); verifyFormat("SomeType * __attribute__((attr)) * a = NULL;", Spaces); @@ -19756,7 +19756,7 @@ TEST_F(FormatTest, AlignConsecutiveBitFields) { TEST_F(FormatTest, AlignConsecutiveDeclarations) { FormatStyle Alignment = getLLVMStyle(); Alignment.AlignConsecutiveMacros.Enabled = true; - Alignment.PointerAlignment = FormatStyle::PAS_Right; + Alignment.PointerAlignment.Default = FormatStyle::PAS_Right; verifyFormat("float const a = 5;\n" "int oneTwoThree = 123;", Alignment); @@ -20023,7 +20023,7 @@ TEST_F(FormatTest, AlignConsecutiveDeclarations) { // PAS_Left FormatStyle AlignmentLeft = Alignment; - AlignmentLeft.PointerAlignment = FormatStyle::PAS_Left; + AlignmentLeft.PointerAlignment.Default = FormatStyle::PAS_Left; verifyFormat("void SomeFunction(int parameter = 0) {\n" " int const i = 1;\n" " int* j = 2;\n" @@ -20097,7 +20097,7 @@ TEST_F(FormatTest, AlignConsecutiveDeclarations) { // PAS_Middle FormatStyle AlignmentMiddle = Alignment; - AlignmentMiddle.PointerAlignment = FormatStyle::PAS_Middle; + AlignmentMiddle.PointerAlignment.Default = FormatStyle::PAS_Middle; verifyFormat("void SomeFunction(int parameter = 0) {\n" " int const i = 1;\n" " int * j = 2;\n" @@ -20313,14 +20313,14 @@ TEST_F(FormatTest, AlignConsecutiveDeclarations) { Alignment.ColumnLimit = 80; // Bug 33507 - Alignment.PointerAlignment = FormatStyle::PAS_Middle; + Alignment.PointerAlignment.Default = FormatStyle::PAS_Middle; verifyFormat( "auto found = range::find_if(vsProducts, [&](auto * aProduct) {\n" " static const Version verVs2017;\n" " return true;\n" "});", Alignment); - Alignment.PointerAlignment = FormatStyle::PAS_Right; + Alignment.PointerAlignment.Default = FormatStyle::PAS_Right; // See llvm.org/PR35641 Alignment.AlignConsecutiveDeclarations.Enabled = true; @@ -20337,7 +20337,7 @@ TEST_F(FormatTest, AlignConsecutiveDeclarations) { "foo(int a);", "DECOR1 /**/ int8_t /**/ DECOR2 /**/ foo (int a);", Style); - Alignment.PointerAlignment = FormatStyle::PAS_Left; + Alignment.PointerAlignment.Default = FormatStyle::PAS_Left; verifyFormat("unsigned int* a;\n" "int* b;\n" "unsigned int Const* c;\n" @@ -20353,7 +20353,7 @@ TEST_F(FormatTest, AlignConsecutiveDeclarations) { "Const unsigned h;", Alignment); - Alignment.PointerAlignment = FormatStyle::PAS_Middle; + Alignment.PointerAlignment.Default = FormatStyle::PAS_Middle; verifyFormat("unsigned int * a;\n" "int * b;\n" "unsigned int Const * c;\n" @@ -25086,7 +25086,7 @@ TEST_F(FormatTest, StructuredBindings) { // Make sure we don't mistake structured bindings for lambdas. FormatStyle PointerMiddle = getLLVMStyle(); - PointerMiddle.PointerAlignment = FormatStyle::PAS_Middle; + PointerMiddle.PointerAlignment.Default = FormatStyle::PAS_Middle; verifyGoogleFormat("auto [a1, b]{A * i};"); verifyFormat("auto [a2, b]{A * i};"); verifyFormat("auto [a3, b]{A * i};", PointerMiddle); @@ -25330,7 +25330,7 @@ TEST_F(FormatTest, TypenameMacros) { verifyFormat("vector<LIST(uint64_t) *attr> x;", Macros); verifyFormat("vector<LIST(uint64_t) *const> f(LIST(uint64_t) *arg);", Macros); - Macros.PointerAlignment = FormatStyle::PAS_Left; + Macros.PointerAlignment.Default = FormatStyle::PAS_Left; verifyFormat("STACK_OF(int)* a;", Macros); verifyFormat("STACK_OF(int*)* a;", Macros); verifyFormat("x = (STACK_OF(uint64_t))*a;", Macros); @@ -25361,7 +25361,7 @@ TEST_F(FormatTest, AtomicQualifier) { verifyFormat("_Atomic(uint64_t) *s(InitValue);"); verifyFormat("_Atomic(uint64_t) *s{InitValue};"); FormatStyle Style = getLLVMStyle(); - Style.PointerAlignment = FormatStyle::PAS_Left; + Style.PointerAlignment.Default = FormatStyle::PAS_Left; verifyFormat("_Atomic(uint64_t)* s(InitValue);", Style); verifyFormat("_Atomic(uint64_t)* s{InitValue};", Style); verifyFormat("_Atomic(int)* a;", Style); @@ -25424,9 +25424,9 @@ TEST_F(FormatTest, C11Generic) { TEST_F(FormatTest, AmbersandInLamda) { // Test case reported in https://bugs.llvm.org/show_bug.cgi?id=41899 FormatStyle AlignStyle = getLLVMStyle(); - AlignStyle.PointerAlignment = FormatStyle::PAS_Left; + AlignStyle.PointerAlignment.Default = FormatStyle::PAS_Left; verifyFormat("auto lambda = [&a = a]() { a = 2; };", AlignStyle); - AlignStyle.PointerAlignment = FormatStyle::PAS_Right; + AlignStyle.PointerAlignment.Default = FormatStyle::PAS_Right; verifyFormat("auto lambda = [&a = a]() { a = 2; };", AlignStyle); } @@ -25554,7 +25554,7 @@ TEST_F(FormatTest, STLWhileNotDefineChed) { TEST_F(FormatTest, OperatorSpacing) { FormatStyle Style = getLLVMStyle(); - Style.PointerAlignment = FormatStyle::PAS_Right; + Style.PointerAlignment.Default = FormatStyle::PAS_Right; verifyFormat("Foo::operator*();", Style); verifyFormat("Foo::operator void *();", Style); verifyFormat("Foo::operator void **();", Style); @@ -25610,7 +25610,7 @@ TEST_F(FormatTest, OperatorSpacing) { verifyFormat("operator const FooRight<Object> *&()", Style); verifyFormat("operator const FooRight<Object> *&&()", Style); - Style.PointerAlignment = FormatStyle::PAS_Left; + Style.PointerAlignment.Default = FormatStyle::PAS_Left; verifyFormat("Foo::operator*();", Style); verifyFormat("Foo::operator**();", Style); verifyFormat("Foo::operator void*();", Style); @@ -25681,7 +25681,7 @@ TEST_F(FormatTest, OperatorSpacing) { verifyFormat("operator/*a*/ const /*b*/ Foo /*c*/<X> /*d*/ ::Bar<Y>*();", Style); - Style.PointerAlignment = FormatStyle::PAS_Middle; + Style.PointerAlignment.Default = FormatStyle::PAS_Middle; verifyFormat("Foo::operator*();", Style); verifyFormat("Foo::operator void *();", Style); verifyFormat("Foo::operator()(void *);", Style); @@ -27940,7 +27940,7 @@ TEST_F(FormatTest, BreakAfterAttributes) { "Foo &operator-(Foo &);", Style); - Style.ReferenceAlignment = FormatStyle::RAS_Left; + Style.ReferenceAlignment.Default = FormatStyle::RAS_Left; verifyFormat("[[nodiscard]]\n" "Foo& operator-(Foo&);", Style); >From a4ca42e69ed638969ec78c66781fbb09c986e42e Mon Sep 17 00:00:00 2001 From: Daan De Meyer <[email protected]> Date: Sat, 22 Nov 2025 11:35:28 +0100 Subject: [PATCH 2/3] [clang-format] Allow custom pointer/ref alignment in return types I would like to adopt clang-format in systemd (https://github.com/systemd/systemd). One major blocker is that systemd right-aligns pointers by default, except in function return types, where they are left-aligned. Let's introduce a ReturnType customization for PointerAlignment and ReferenceAlignment that allows overriding the alignment used in return types. systemd style guide: https://github.com/systemd/systemd/blob/main/docs/CODING_STYLE.md Fixes #136597 --- clang/docs/ClangFormatStyleOptions.rst | 60 +++++++ clang/include/clang/Format/Format.h | 29 ++- clang/lib/Format/Format.cpp | 46 +++-- clang/lib/Format/TokenAnnotator.cpp | 76 +++++++- clang/unittests/Format/ConfigParseTest.cpp | 52 ++++-- clang/unittests/Format/FormatTest.cpp | 200 +++++++++++++++++++++ 6 files changed, 436 insertions(+), 27 deletions(-) diff --git a/clang/docs/ClangFormatStyleOptions.rst b/clang/docs/ClangFormatStyleOptions.rst index ab21290260005..119685d39d347 100644 --- a/clang/docs/ClangFormatStyleOptions.rst +++ b/clang/docs/ClangFormatStyleOptions.rst @@ -5718,6 +5718,36 @@ the configuration (without a prefix: ``Auto``). int * a; + * ``ReturnTypeAlignmentStyle ReturnType`` + The alignment for pointers in function return types. + + Possible values: + + * ``RTAS_Default`` (in configuration: ``Default``) + Use default alignment. + + * ``RTAS_Left`` (in configuration: ``Left``) + Align pointer/reference to the left. + + .. code-block:: c++ + + int* a(void); + + * ``RTAS_Right`` (in configuration: ``Right``) + Align pointer/reference to the right. + + .. code-block:: c++ + + int *a(void); + + * ``RTAS_Middle`` (in configuration: ``Middle``) + Align pointer/reference in the middle. + + .. code-block:: c++ + + int * a(void); + + .. _QualifierAlignment: @@ -5901,6 +5931,36 @@ the configuration (without a prefix: ``Auto``). int & a; + * ``ReturnTypeAlignmentStyle ReturnType`` + The alignment for references in function return types. + + Possible values: + + * ``RTAS_Default`` (in configuration: ``Default``) + Use default alignment. + + * ``RTAS_Left`` (in configuration: ``Left``) + Align pointer/reference to the left. + + .. code-block:: c++ + + int* a(void); + + * ``RTAS_Right`` (in configuration: ``Right``) + Align pointer/reference to the right. + + .. code-block:: c++ + + int *a(void); + + * ``RTAS_Middle`` (in configuration: ``Middle``) + Align pointer/reference in the middle. + + .. code-block:: c++ + + int * a(void); + + .. _ReflowComments: diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h index 2cd446366cfa4..3919c1d0bc8b3 100644 --- a/clang/include/clang/Format/Format.h +++ b/clang/include/clang/Format/Format.h @@ -4036,12 +4036,35 @@ struct FormatStyle { PAS_Middle }; + /// \brief The pointer/reference alignment style for function return types. + enum ReturnTypeAlignmentStyle : int8_t { + /// Use default alignment. + RTAS_Default, + /// Align pointer/reference to the left. + /// \code + /// int* a(void); + /// \endcode + RTAS_Left, + /// Align pointer/reference to the right. + /// \code + /// int *a(void); + /// \endcode + RTAS_Right, + /// Align pointer/reference in the middle. + /// \code + /// int * a(void); + /// \endcode + RTAS_Middle + }; + /// Pointer and reference alignment options. struct PointerAlignmentOptions { /// The default alignment for pointers and references. PointerAlignmentStyle Default; + /// The alignment for pointers in function return types. + ReturnTypeAlignmentStyle ReturnType; bool operator==(const PointerAlignmentOptions &R) const { - return Default == R.Default; + return Default == R.Default && ReturnType == R.ReturnType; } bool operator!=(const PointerAlignmentOptions &R) const { return !(*this == R); @@ -4239,8 +4262,10 @@ struct FormatStyle { struct ReferenceAlignmentOptions { /// The default alignment for references. ReferenceAlignmentStyle Default; + /// The alignment for references in function return types. + ReturnTypeAlignmentStyle ReturnType; bool operator==(const ReferenceAlignmentOptions &R) const { - return Default == R.Default; + return Default == R.Default && ReturnType == R.ReturnType; } bool operator!=(const ReferenceAlignmentOptions &R) const { return !(*this == R); diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp index 2140cf66cd5af..f950d64b29436 100644 --- a/clang/lib/Format/Format.cpp +++ b/clang/lib/Format/Format.cpp @@ -544,29 +544,46 @@ template <> struct ScalarEnumerationTraits<FormatStyle::PointerAlignmentStyle> { } }; +template <> +struct ScalarEnumerationTraits<FormatStyle::ReturnTypeAlignmentStyle> { + static void enumeration(IO &IO, + FormatStyle::ReturnTypeAlignmentStyle &Value) { + IO.enumCase(Value, "Default", FormatStyle::RTAS_Default); + IO.enumCase(Value, "Middle", FormatStyle::RTAS_Middle); + IO.enumCase(Value, "Left", FormatStyle::RTAS_Left); + IO.enumCase(Value, "Right", FormatStyle::RTAS_Right); + } +}; + template <> struct MappingTraits<FormatStyle::PointerAlignmentOptions> { static void enumInput(IO &IO, FormatStyle::PointerAlignmentOptions &Value) { IO.enumCase(Value, "Middle", FormatStyle::PointerAlignmentOptions( - {/*Default=*/FormatStyle::PAS_Middle})); + {/*Default=*/FormatStyle::PAS_Middle, + /*ReturnType=*/FormatStyle::RTAS_Default})); IO.enumCase(Value, "Left", FormatStyle::PointerAlignmentOptions( - {/*Default=*/FormatStyle::PAS_Left})); + {/*Default=*/FormatStyle::PAS_Left, + /*ReturnType=*/FormatStyle::RTAS_Default})); IO.enumCase(Value, "Right", FormatStyle::PointerAlignmentOptions( - {/*Default=*/FormatStyle::PAS_Right})); + {/*Default=*/FormatStyle::PAS_Right, + /*ReturnType=*/FormatStyle::RTAS_Default})); // For backward compatibility. IO.enumCase(Value, "true", FormatStyle::PointerAlignmentOptions( - {/*Default=*/FormatStyle::PAS_Left})); + {/*Default=*/FormatStyle::PAS_Left, + /*ReturnType=*/FormatStyle::RTAS_Default})); IO.enumCase(Value, "false", FormatStyle::PointerAlignmentOptions( - {/*Default=*/FormatStyle::PAS_Right})); + {/*Default=*/FormatStyle::PAS_Right, + /*ReturnType=*/FormatStyle::RTAS_Default})); } static void mapping(IO &IO, FormatStyle::PointerAlignmentOptions &Value) { IO.mapOptional("Default", Value.Default); + IO.mapOptional("ReturnType", Value.ReturnType); } }; @@ -615,20 +632,25 @@ template <> struct MappingTraits<FormatStyle::ReferenceAlignmentOptions> { static void enumInput(IO &IO, FormatStyle::ReferenceAlignmentOptions &Value) { IO.enumCase(Value, "Pointer", FormatStyle::ReferenceAlignmentOptions( - {/*Default=*/FormatStyle::RAS_Pointer})); + {/*Default=*/FormatStyle::RAS_Pointer, + /*ReturnType=*/FormatStyle::RTAS_Default})); IO.enumCase(Value, "Middle", FormatStyle::ReferenceAlignmentOptions( - {/*Default=*/FormatStyle::RAS_Middle})); + {/*Default=*/FormatStyle::RAS_Middle, + /*ReturnType=*/FormatStyle::RTAS_Default})); IO.enumCase(Value, "Left", FormatStyle::ReferenceAlignmentOptions( - {/*Default=*/FormatStyle::RAS_Left})); + {/*Default=*/FormatStyle::RAS_Left, + /*ReturnType=*/FormatStyle::RTAS_Default})); IO.enumCase(Value, "Right", FormatStyle::ReferenceAlignmentOptions( - {/*Default=*/FormatStyle::RAS_Right})); + {/*Default=*/FormatStyle::RAS_Right, + /*ReturnType=*/FormatStyle::RTAS_Default})); } static void mapping(IO &IO, FormatStyle::ReferenceAlignmentOptions &Value) { IO.mapOptional("Default", Value.Default); + IO.mapOptional("ReturnType", Value.ReturnType); } }; @@ -1828,10 +1850,12 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) { LLVMStyle.ObjCSpaceAfterProperty = false; LLVMStyle.ObjCSpaceBeforeProtocolList = true; LLVMStyle.PackConstructorInitializers = FormatStyle::PCIS_BinPack; - LLVMStyle.PointerAlignment = {/*Default=*/FormatStyle::PAS_Right}; + LLVMStyle.PointerAlignment = {/*Default=*/FormatStyle::PAS_Right, + /*ReturnType=*/FormatStyle::RTAS_Default}; LLVMStyle.PPIndentWidth = -1; LLVMStyle.QualifierAlignment = FormatStyle::QAS_Leave; - LLVMStyle.ReferenceAlignment = {/*Default=*/FormatStyle::RAS_Pointer}; + LLVMStyle.ReferenceAlignment = {/*Default=*/FormatStyle::RAS_Pointer, + /*ReturnType=*/FormatStyle::RTAS_Default}; LLVMStyle.ReflowComments = FormatStyle::RCS_Always; LLVMStyle.RemoveBracesLLVM = false; LLVMStyle.RemoveEmptyLinesInUnwrappedLines = false; diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp index f48a02c49c562..fe53d70eb12d7 100644 --- a/clang/lib/Format/TokenAnnotator.cpp +++ b/clang/lib/Format/TokenAnnotator.cpp @@ -6540,9 +6540,76 @@ void TokenAnnotator::printDebugInfo(const AnnotatedLine &Line) const { llvm::errs() << "----\n"; } +static bool isReturnType(const FormatToken &Tok, const LangOptions &LangOpts) { + // Look forward to see if there's a function declaration paren. + for (const FormatToken *Next = Tok.Next; Next; + Next = Next->getNextNonComment()) { + if (Next->isOneOf(TT_FunctionDeclarationName, TT_FunctionDeclarationLParen, + TT_FunctionTypeLParen)) { + return true; + } + + if (Next->is(TT_TemplateOpener) && Next->MatchingParen) { + Next = Next->MatchingParen; + continue; + } + + if (Next->isPointerOrReference() || Next->isTypeName(LangOpts) || + Next->isOneOf(tok::identifier, tok::coloncolon) || + Next->canBePointerOrReferenceQualifier()) { + continue; + } + + break; + } + + // Look backward to see if there's a trailing return arrow. + for (const FormatToken *Prev = Tok.Previous; Prev; + Prev = Prev->getPreviousNonComment()) { + if (Prev->is(TT_TrailingReturnArrow)) + return true; + + if (Prev->is(TT_TemplateCloser) && Prev->MatchingParen) { + Prev = Prev->MatchingParen; + continue; + } + + if (Prev->isPointerOrReference() || Prev->isTypeName(LangOpts) || + Prev->isOneOf(tok::identifier, tok::coloncolon) || + Prev->canBePointerOrReferenceQualifier()) { + continue; + } + + break; + } + + return false; +} + +static FormatStyle::PointerAlignmentStyle +mapReturnTypeAlignmentStyle(FormatStyle::ReturnTypeAlignmentStyle Style) { + switch (Style) { + case FormatStyle::RTAS_Left: + return FormatStyle::PAS_Left; + case FormatStyle::RTAS_Right: + return FormatStyle::PAS_Right; + case FormatStyle::RTAS_Middle: + return FormatStyle::PAS_Middle; + case FormatStyle::RTAS_Default: + assert(false); + } + llvm_unreachable("Unknown FormatStyle::ReturnTypeAlignmentStyle enum"); +} + FormatStyle::PointerAlignmentStyle TokenAnnotator::getTokenReferenceAlignment(const FormatToken &Reference) const { assert(Reference.isOneOf(tok::amp, tok::ampamp)); + + if (Style.ReferenceAlignment.ReturnType != FormatStyle::RTAS_Default && + isReturnType(Reference, LangOpts)) { + return mapReturnTypeAlignmentStyle(Style.ReferenceAlignment.ReturnType); + } + switch (Style.ReferenceAlignment.Default) { case FormatStyle::RAS_Pointer: return Style.PointerAlignment.Default; @@ -6553,8 +6620,7 @@ TokenAnnotator::getTokenReferenceAlignment(const FormatToken &Reference) const { case FormatStyle::RAS_Middle: return FormatStyle::PAS_Middle; } - assert(0); //"Unhandled value of ReferenceAlignment" - return Style.PointerAlignment.Default; + llvm_unreachable("Unknown FormatStyle::ReferenceAlignmentStyle enum"); } FormatStyle::PointerAlignmentStyle @@ -6563,6 +6629,12 @@ TokenAnnotator::getTokenPointerOrReferenceAlignment( if (PointerOrReference.isOneOf(tok::amp, tok::ampamp)) return getTokenReferenceAlignment(PointerOrReference); assert(PointerOrReference.is(tok::star)); + + if (Style.PointerAlignment.ReturnType != FormatStyle::RTAS_Default && + isReturnType(PointerOrReference, LangOpts)) { + return mapReturnTypeAlignmentStyle(Style.PointerAlignment.ReturnType); + } + return Style.PointerAlignment.Default; } diff --git a/clang/unittests/Format/ConfigParseTest.cpp b/clang/unittests/Format/ConfigParseTest.cpp index 882f7b1342cc4..cf54b79bcf8a6 100644 --- a/clang/unittests/Format/ConfigParseTest.cpp +++ b/clang/unittests/Format/ConfigParseTest.cpp @@ -391,39 +391,67 @@ TEST(ConfigParseTest, ParsesConfiguration) { #undef CHECK_ALIGN_CONSECUTIVE - Style.PointerAlignment = {/*Default=*/FormatStyle::PAS_Middle}; + Style.PointerAlignment = {/*Default=*/FormatStyle::PAS_Middle, + /*ReturnType=*/FormatStyle::RTAS_Default}; CHECK_PARSE("PointerAlignment: Left", PointerAlignment, FormatStyle::PointerAlignmentOptions( - {/*Default=*/FormatStyle::PAS_Left})); + {/*Default=*/FormatStyle::PAS_Left, + /*ReturnType=*/FormatStyle::RTAS_Default})); CHECK_PARSE("PointerAlignment: Right", PointerAlignment, FormatStyle::PointerAlignmentOptions( - {/*Default=*/FormatStyle::PAS_Right})); + {/*Default=*/FormatStyle::PAS_Right, + /*ReturnType=*/FormatStyle::RTAS_Default})); CHECK_PARSE("PointerAlignment: Middle", PointerAlignment, FormatStyle::PointerAlignmentOptions( - {/*Default=*/FormatStyle::PAS_Middle})); - Style.ReferenceAlignment = {/*Default=*/FormatStyle::RAS_Middle}; + {/*Default=*/FormatStyle::PAS_Middle, + /*ReturnType=*/FormatStyle::RTAS_Default})); + CHECK_PARSE("PointerAlignment:\n" + " Default: Right\n" + " ReturnType: Left", + PointerAlignment, + FormatStyle::PointerAlignmentOptions( + {/*Default=*/FormatStyle::PAS_Right, + /*ReturnType=*/FormatStyle::RTAS_Left})); + + Style.ReferenceAlignment = {/*Default=*/FormatStyle::RAS_Middle, + /*ReturnType=*/FormatStyle::RTAS_Default}; CHECK_PARSE("ReferenceAlignment: Pointer", ReferenceAlignment, FormatStyle::ReferenceAlignmentOptions( - {/*Default=*/FormatStyle::RAS_Pointer})); + {/*Default=*/FormatStyle::RAS_Pointer, + /*ReturnType=*/FormatStyle::RTAS_Default})); CHECK_PARSE("ReferenceAlignment: Left", ReferenceAlignment, FormatStyle::ReferenceAlignmentOptions( - {/*Default=*/FormatStyle::RAS_Left})); + {/*Default=*/FormatStyle::RAS_Left, + /*ReturnType=*/FormatStyle::RTAS_Default})); CHECK_PARSE("ReferenceAlignment: Right", ReferenceAlignment, FormatStyle::ReferenceAlignmentOptions( - {/*Default=*/FormatStyle::RAS_Right})); + {/*Default=*/FormatStyle::RAS_Right, + /*ReturnType=*/FormatStyle::RTAS_Default})); CHECK_PARSE("ReferenceAlignment: Middle", ReferenceAlignment, FormatStyle::ReferenceAlignmentOptions( - {/*Default=*/FormatStyle::RAS_Middle})); + {/*Default=*/FormatStyle::RAS_Middle, + /*ReturnType=*/FormatStyle::RTAS_Default})); + CHECK_PARSE("ReferenceAlignment:\n" + " Default: Right\n" + " ReturnType: Left", + ReferenceAlignment, + FormatStyle::ReferenceAlignmentOptions( + {/*Default=*/FormatStyle::RAS_Right, + /*ReturnType=*/FormatStyle::RTAS_Left})); + // For backward compatibility: CHECK_PARSE("PointerBindsToType: Left", PointerAlignment, FormatStyle::PointerAlignmentOptions( - {/*Default=*/FormatStyle::PAS_Left})); + {/*Default=*/FormatStyle::PAS_Left, + /*ReturnType=*/FormatStyle::RTAS_Default})); CHECK_PARSE("PointerBindsToType: Right", PointerAlignment, FormatStyle::PointerAlignmentOptions( - {/*Default=*/FormatStyle::PAS_Right})); + {/*Default=*/FormatStyle::PAS_Right, + /*ReturnType=*/FormatStyle::RTAS_Default})); CHECK_PARSE("PointerBindsToType: Middle", PointerAlignment, FormatStyle::PointerAlignmentOptions( - {/*Default=*/FormatStyle::PAS_Middle})); + {/*Default=*/FormatStyle::PAS_Middle, + /*ReturnType=*/FormatStyle::RTAS_Default})); Style.ReflowComments = FormatStyle::RCS_Always; CHECK_PARSE("ReflowComments: Never", ReflowComments, FormatStyle::RCS_Never); diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp index 4ebcd428a0685..ad14e7d1f0429 100644 --- a/clang/unittests/Format/FormatTest.cpp +++ b/clang/unittests/Format/FormatTest.cpp @@ -2296,6 +2296,206 @@ TEST_F(FormatTest, SeparatePointerReferenceAlignment) { // verifyFormat("int Add2(BTree * &Root, char * szToAdd)", Style); } +TEST_F(FormatTest, ReturnTypeAlignment) { + // Test that ReturnType overrides PointerAlignment for return types + FormatStyle Style = getLLVMStyle(); + Style.PointerAlignment.Default = FormatStyle::PAS_Right; + Style.PointerAlignment.ReturnType = FormatStyle::RTAS_Left; + Style.ReferenceAlignment.Default = FormatStyle::RAS_Pointer; + Style.ReferenceAlignment.ReturnType = FormatStyle::RTAS_Left; + + // Return type pointers should be left-aligned despite PAS_Right + verifyFormat("int* f1(int *a, int *b);", Style); + verifyFormat("int& f2(int &a, int &b);", Style); + verifyFormat("int&& f3(int &&a, int &&b);", Style); + + // Multiple pointers in return type + verifyFormat("int** f4(int **a);", Style); + verifyFormat("const int* f5(const int *a);", Style); + verifyFormat("int*** f6(int ***a);", Style); + + // Multiple pointers with const qualifiers + verifyFormat("const int** f7(const int **a);", Style); + verifyFormat("int* const* f8(int *const *a);", Style); + verifyFormat("const int* const* f9(const int *const *a);", Style); + verifyFormat("int** const f10(int **const a);", Style); + verifyFormat("const int** const f11(const int **const a);", Style); + + // Complex return types + verifyFormat("std::vector<int>* f16(std::vector<int> *a);", Style); + verifyFormat("const char* f17(const char *str);", Style); + verifyFormat("const char** f18(const char **argv);", Style); + verifyFormat("char* const* f19(char *const *envp);", Style); + + // Member functions + verifyFormat("int* Class::method(int *a);", Style); + verifyFormat("int& Class::method(int &a);", Style); + verifyFormat("int* (*f8())(int *a);", Style); + + // Variables should still follow the default alignment + verifyFormat("int *a = nullptr;", Style); + verifyFormat("int *b = f1(a, a);", Style); + + // Now test with PAS_Left base and RTAS_Right return type + Style.PointerAlignment.Default = FormatStyle::PAS_Left; + Style.PointerAlignment.ReturnType = FormatStyle::RTAS_Right; + Style.ReferenceAlignment.Default = FormatStyle::RAS_Pointer; + Style.ReferenceAlignment.ReturnType = FormatStyle::RTAS_Right; + + // Return type pointers should be right-aligned despite PAS_Left + verifyFormat("int *f1(int* a, int* b);", Style); + verifyFormat("int &f2(int& a, int& b);", Style); + verifyFormat("int &&f3(int&& a, int&& b);", Style); + + // Multiple pointers with right alignment in return type + verifyFormat("int **f4(int** a);", Style); + verifyFormat("const int *f5(const int* a);", Style); + verifyFormat("int ***f6(int*** a);", Style); + + // Multiple pointers with const qualifiers, right-aligned return type + verifyFormat("const int **f7(const int** a);", Style); + verifyFormat("int *const *f8(int* const* a);", Style); + verifyFormat("const int *const *f9(const int* const* a);", Style); + verifyFormat("int **const f10(int** const a);", Style); + verifyFormat("const char **f11(const char** argv);", Style); + + // Variables should still follow PointerAlignment (PAS_Left) + verifyFormat("int* a = nullptr;", Style); + verifyFormat("int* b = f1(a, a);", Style); + + // Test with RTAS_Middle + Style.PointerAlignment.Default = FormatStyle::PAS_Right; + Style.PointerAlignment.ReturnType = FormatStyle::RTAS_Middle; + Style.ReferenceAlignment.Default = FormatStyle::RAS_Pointer; + Style.ReferenceAlignment.ReturnType = FormatStyle::RTAS_Middle; + + verifyFormat("int * f1(int *a, int *b);", Style); + verifyFormat("int & f2(int &a, int &b);", Style); + verifyFormat("int && f3(int &&a, int &&b);", Style); + + // Multiple pointers with const qualifiers, middle-aligned return type + verifyFormat("const int * f6(const int *a);", Style); + verifyFormat("const int ** f7(const int **a);", Style); + verifyFormat("int * const * f8(int *const *a);", Style); + verifyFormat("const int * const * f9(const int *const *a);", Style); + verifyFormat("int ** const f10(int **const a);", Style); + verifyFormat("const char ** f11(const char **argv);", Style); + + // Variables should still follow PointerAlignment (PAS_Right) + verifyFormat("int *a = nullptr;", Style); + + // Test that default alignment is used when ReturnType is RTAS_Default + Style.PointerAlignment.Default = FormatStyle::PAS_Left; + Style.PointerAlignment.ReturnType = FormatStyle::RTAS_Default; + Style.ReferenceAlignment.Default = FormatStyle::RAS_Pointer; + Style.ReferenceAlignment.ReturnType = FormatStyle::RTAS_Default; + + verifyFormat("int* f1(int* a, int* b);", Style); + verifyFormat("int& f2(int& a, int& b);", Style); + + // Test with ReferenceAlignment override + Style.PointerAlignment.Default = FormatStyle::PAS_Right; + Style.PointerAlignment.ReturnType = FormatStyle::RTAS_Left; + Style.ReferenceAlignment.Default = FormatStyle::RAS_Pointer; + Style.ReferenceAlignment.ReturnType = FormatStyle::RTAS_Right; + + verifyFormat("int* f1(int *a, int &b);", Style); + verifyFormat("int &f2(int &a, int *b);", Style); + verifyFormat("int &&f3(int &&a, int *b);", Style); + + // Test trailing return types with PAS_Right and RTAS_Left + Style.PointerAlignment.Default = FormatStyle::PAS_Right; + Style.PointerAlignment.ReturnType = FormatStyle::RTAS_Left; + Style.ReferenceAlignment.Default = FormatStyle::RAS_Pointer; + Style.ReferenceAlignment.ReturnType = FormatStyle::RTAS_Left; + + verifyFormat("auto f1(int *a, int *b) -> int*;", Style); + verifyFormat("auto f2(int &a, int &b) -> int&;", Style); + verifyFormat("auto f3(int &&a, int &&b) -> int&&;", Style); + + // Multiple pointers in trailing return type + verifyFormat("auto f4(int **a) -> int**;", Style); + verifyFormat("auto f5(const int *a) -> const int*;", Style); + verifyFormat("auto f6(int ***a) -> int***;", Style); + + // Multiple pointers with const qualifiers + verifyFormat("auto f7(const int **a) -> const int**;", Style); + verifyFormat("auto f8(int *const *a) -> int* const*;", Style); + verifyFormat("auto f9(const int *const *a) -> const int* const*;", Style); + verifyFormat("auto f10(int **const a) -> int** const;", Style); + verifyFormat("auto f11(const int **const a) -> const int** const;", Style); + + // Complex trailing return types + verifyFormat("auto f16(std::vector<int> *a) -> std::vector<int>*;", Style); + verifyFormat("auto f17(const char *str) -> const char*;", Style); + verifyFormat("auto f18(const char **argv) -> const char**;", Style); + verifyFormat("auto f19(char *const *envp) -> char* const*;", Style); + + // Member functions with trailing return types + verifyFormat("auto Class::method(int *a) -> int*;", Style); + verifyFormat("auto Class::method(int &a) -> int&;", Style); + + // Now test with PAS_Left base and RTAS_Right trailing return type + Style.PointerAlignment.Default = FormatStyle::PAS_Left; + Style.PointerAlignment.ReturnType = FormatStyle::RTAS_Right; + Style.ReferenceAlignment.Default = FormatStyle::RAS_Pointer; + Style.ReferenceAlignment.ReturnType = FormatStyle::RTAS_Right; + + verifyFormat("auto f1(int* a, int* b) -> int *;", Style); + verifyFormat("auto f2(int& a, int& b) -> int &;", Style); + verifyFormat("auto f3(int&& a, int&& b) -> int &&;", Style); + + // Multiple pointers with right alignment in trailing return type + verifyFormat("auto f4(int** a) -> int **;", Style); + verifyFormat("auto f5(const int* a) -> const int *;", Style); + verifyFormat("auto f6(int*** a) -> int ***;", Style); + + // Multiple pointers with const qualifiers, right-aligned trailing return type + verifyFormat("auto f7(const int** a) -> const int **;", Style); + verifyFormat("auto f8(int* const* a) -> int *const *;", Style); + verifyFormat("auto f9(const int* const* a) -> const int *const *;", Style); + verifyFormat("auto f10(int** const a) -> int **const;", Style); + verifyFormat("auto f11(const char** argv) -> const char **;", Style); + + // Test with RTAS_Middle trailing return type + Style.PointerAlignment.Default = FormatStyle::PAS_Right; + Style.PointerAlignment.ReturnType = FormatStyle::RTAS_Middle; + Style.ReferenceAlignment.Default = FormatStyle::RAS_Pointer; + Style.ReferenceAlignment.ReturnType = FormatStyle::RTAS_Middle; + + verifyFormat("auto f1(int *a, int *b) -> int *;", Style); + verifyFormat("auto f2(int &a, int &b) -> int &;", Style); + verifyFormat("auto f3(int &&a, int &&b) -> int &&;", Style); + + // Multiple pointers with const qualifiers, middle-aligned trailing return + // type + verifyFormat("auto f6(const int *a) -> const int *;", Style); + verifyFormat("auto f7(const int **a) -> const int **;", Style); + verifyFormat("auto f8(int *const *a) -> int * const *;", Style); + verifyFormat("auto f9(const int *const *a) -> const int * const *;", Style); + verifyFormat("auto f10(int **const a) -> int ** const;", Style); + verifyFormat("auto f11(const char **argv) -> const char **;", Style); + + // Test that default alignment is used when ReturnType is RTAS_Default + Style.PointerAlignment.Default = FormatStyle::PAS_Left; + Style.PointerAlignment.ReturnType = FormatStyle::RTAS_Default; + Style.ReferenceAlignment.Default = FormatStyle::RAS_Pointer; + Style.ReferenceAlignment.ReturnType = FormatStyle::RTAS_Default; + + verifyFormat("auto f1(int* a, int* b) -> int*;", Style); + verifyFormat("auto f2(int& a, int& b) -> int&;", Style); + + // Test with ReferenceAlignment override for trailing return types + Style.PointerAlignment.Default = FormatStyle::PAS_Right; + Style.PointerAlignment.ReturnType = FormatStyle::RTAS_Left; + Style.ReferenceAlignment.Default = FormatStyle::RAS_Pointer; + Style.ReferenceAlignment.ReturnType = FormatStyle::RTAS_Right; + + verifyFormat("auto f1(int *a, int &b) -> int*;", Style); + verifyFormat("auto f2(int &a, int *b) -> int &;", Style); + verifyFormat("auto f3(int &&a, int *b) -> int &&;", Style); +} + TEST_F(FormatTest, FormatsForLoop) { verifyFormat( "for (int VeryVeryLongLoopVariable = 0; VeryVeryLongLoopVariable < 10;\n" >From 3f29d19b98117c5699cd141bb78cbaa7ea6e6d84 Mon Sep 17 00:00:00 2001 From: Daan De Meyer <[email protected]> Date: Sat, 22 Nov 2025 21:10:04 +0100 Subject: [PATCH 3/3] [clang-format] Allow custom pointer/ref alignment for C-style casts I would like to adopt clang-format in systemd (https://github.com/systemd/systemd). One major blocker is that systemd right-aligns pointers by default, except in function return types and c-style casts, where they are left-aligned. Let's introduce a CStyleCast customization for PointerAlignment and ReferenceAlignment that allows overriding the alignment used for C-style casts. systemd style guide: https://github.com/systemd/systemd/blob/main/docs/CODING_STYLE.md --- clang/docs/ClangFormatStyleOptions.rst | 46 ++++++++++ clang/include/clang/Format/Format.h | 26 +++++- clang/lib/Format/Format.cpp | 43 +++++++--- clang/lib/Format/TokenAnnotator.cpp | 45 ++++++++++ clang/unittests/Format/ConfigParseTest.cpp | 58 +++++++++---- clang/unittests/Format/FormatTest.cpp | 98 ++++++++++++++++++++++ 6 files changed, 287 insertions(+), 29 deletions(-) diff --git a/clang/docs/ClangFormatStyleOptions.rst b/clang/docs/ClangFormatStyleOptions.rst index 119685d39d347..9a523bfe5fea3 100644 --- a/clang/docs/ClangFormatStyleOptions.rst +++ b/clang/docs/ClangFormatStyleOptions.rst @@ -5748,6 +5748,29 @@ the configuration (without a prefix: ``Auto``). int * a(void); + * ``CastAlignmentStyle CStyleCast`` + The alignment for pointers in C-style casts. + + Possible values: + + * ``CAS_Default`` (in configuration: ``Default``) + Use default alignment. + + * ``CAS_Left`` (in configuration: ``Left``) + Align pointer/reference to the left. + + .. code-block:: c++ + + (char*)s; + + * ``CAS_Right`` (in configuration: ``Right``) + Align pointer/reference to the right. + + .. code-block:: c++ + + (char *)s; + + .. _QualifierAlignment: @@ -5961,6 +5984,29 @@ the configuration (without a prefix: ``Auto``). int * a(void); + * ``CastAlignmentStyle CStyleCast`` + The alignment for references in C-style casts. + + Possible values: + + * ``CAS_Default`` (in configuration: ``Default``) + Use default alignment. + + * ``CAS_Left`` (in configuration: ``Left``) + Align pointer/reference to the left. + + .. code-block:: c++ + + (char*)s; + + * ``CAS_Right`` (in configuration: ``Right``) + Align pointer/reference to the right. + + .. code-block:: c++ + + (char *)s; + + .. _ReflowComments: diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h index 3919c1d0bc8b3..5a611a1141582 100644 --- a/clang/include/clang/Format/Format.h +++ b/clang/include/clang/Format/Format.h @@ -4057,14 +4057,33 @@ struct FormatStyle { RTAS_Middle }; + /// \brief The pointer/reference alignment style for C-style casts. + enum CastAlignmentStyle : int8_t { + /// Use default alignment. + CAS_Default, + /// Align pointer/reference to the left. + /// \code + /// (char*)s; + /// \endcode + CAS_Left, + /// Align pointer/reference to the right. + /// \code + /// (char *)s; + /// \endcode + CAS_Right, + }; + /// Pointer and reference alignment options. struct PointerAlignmentOptions { /// The default alignment for pointers and references. PointerAlignmentStyle Default; /// The alignment for pointers in function return types. ReturnTypeAlignmentStyle ReturnType; + /// The alignment for pointers in C-style casts. + CastAlignmentStyle CStyleCast; bool operator==(const PointerAlignmentOptions &R) const { - return Default == R.Default && ReturnType == R.ReturnType; + return Default == R.Default && ReturnType == R.ReturnType && + CStyleCast == R.CStyleCast; } bool operator!=(const PointerAlignmentOptions &R) const { return !(*this == R); @@ -4264,8 +4283,11 @@ struct FormatStyle { ReferenceAlignmentStyle Default; /// The alignment for references in function return types. ReturnTypeAlignmentStyle ReturnType; + /// The alignment for references in C-style casts. + CastAlignmentStyle CStyleCast; bool operator==(const ReferenceAlignmentOptions &R) const { - return Default == R.Default && ReturnType == R.ReturnType; + return Default == R.Default && ReturnType == R.ReturnType && + CStyleCast == R.CStyleCast; } bool operator!=(const ReferenceAlignmentOptions &R) const { return !(*this == R); diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp index f950d64b29436..057fe92ccc966 100644 --- a/clang/lib/Format/Format.cpp +++ b/clang/lib/Format/Format.cpp @@ -555,35 +555,49 @@ struct ScalarEnumerationTraits<FormatStyle::ReturnTypeAlignmentStyle> { } }; +template <> struct ScalarEnumerationTraits<FormatStyle::CastAlignmentStyle> { + static void enumeration(IO &IO, FormatStyle::CastAlignmentStyle &Value) { + IO.enumCase(Value, "Default", FormatStyle::CAS_Default); + IO.enumCase(Value, "Left", FormatStyle::CAS_Left); + IO.enumCase(Value, "Right", FormatStyle::CAS_Right); + } +}; + template <> struct MappingTraits<FormatStyle::PointerAlignmentOptions> { static void enumInput(IO &IO, FormatStyle::PointerAlignmentOptions &Value) { IO.enumCase(Value, "Middle", FormatStyle::PointerAlignmentOptions( {/*Default=*/FormatStyle::PAS_Middle, - /*ReturnType=*/FormatStyle::RTAS_Default})); + /*ReturnType=*/FormatStyle::RTAS_Default, + /*CStyleCast=*/FormatStyle::CAS_Default})); IO.enumCase(Value, "Left", FormatStyle::PointerAlignmentOptions( {/*Default=*/FormatStyle::PAS_Left, - /*ReturnType=*/FormatStyle::RTAS_Default})); + /*ReturnType=*/FormatStyle::RTAS_Default, + /*CStyleCast=*/FormatStyle::CAS_Default})); IO.enumCase(Value, "Right", FormatStyle::PointerAlignmentOptions( {/*Default=*/FormatStyle::PAS_Right, - /*ReturnType=*/FormatStyle::RTAS_Default})); + /*ReturnType=*/FormatStyle::RTAS_Default, + /*CStyleCast=*/FormatStyle::CAS_Default})); // For backward compatibility. IO.enumCase(Value, "true", FormatStyle::PointerAlignmentOptions( {/*Default=*/FormatStyle::PAS_Left, - /*ReturnType=*/FormatStyle::RTAS_Default})); + /*ReturnType=*/FormatStyle::RTAS_Default, + /*CStyleCast=*/FormatStyle::CAS_Default})); IO.enumCase(Value, "false", FormatStyle::PointerAlignmentOptions( {/*Default=*/FormatStyle::PAS_Right, - /*ReturnType=*/FormatStyle::RTAS_Default})); + /*ReturnType=*/FormatStyle::RTAS_Default, + /*CStyleCast=*/FormatStyle::CAS_Default})); } static void mapping(IO &IO, FormatStyle::PointerAlignmentOptions &Value) { IO.mapOptional("Default", Value.Default); IO.mapOptional("ReturnType", Value.ReturnType); + IO.mapOptional("CStyleCast", Value.CStyleCast); } }; @@ -633,24 +647,29 @@ template <> struct MappingTraits<FormatStyle::ReferenceAlignmentOptions> { IO.enumCase(Value, "Pointer", FormatStyle::ReferenceAlignmentOptions( {/*Default=*/FormatStyle::RAS_Pointer, - /*ReturnType=*/FormatStyle::RTAS_Default})); + /*ReturnType=*/FormatStyle::RTAS_Default, + /*CStyleCast=*/FormatStyle::CAS_Default})); IO.enumCase(Value, "Middle", FormatStyle::ReferenceAlignmentOptions( {/*Default=*/FormatStyle::RAS_Middle, - /*ReturnType=*/FormatStyle::RTAS_Default})); + /*ReturnType=*/FormatStyle::RTAS_Default, + /*CStyleCast=*/FormatStyle::CAS_Default})); IO.enumCase(Value, "Left", FormatStyle::ReferenceAlignmentOptions( {/*Default=*/FormatStyle::RAS_Left, - /*ReturnType=*/FormatStyle::RTAS_Default})); + /*ReturnType=*/FormatStyle::RTAS_Default, + /*CStyleCast=*/FormatStyle::CAS_Default})); IO.enumCase(Value, "Right", FormatStyle::ReferenceAlignmentOptions( {/*Default=*/FormatStyle::RAS_Right, - /*ReturnType=*/FormatStyle::RTAS_Default})); + /*ReturnType=*/FormatStyle::RTAS_Default, + /*CStyleCast=*/FormatStyle::CAS_Default})); } static void mapping(IO &IO, FormatStyle::ReferenceAlignmentOptions &Value) { IO.mapOptional("Default", Value.Default); IO.mapOptional("ReturnType", Value.ReturnType); + IO.mapOptional("CStyleCast", Value.CStyleCast); } }; @@ -1851,11 +1870,13 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) { LLVMStyle.ObjCSpaceBeforeProtocolList = true; LLVMStyle.PackConstructorInitializers = FormatStyle::PCIS_BinPack; LLVMStyle.PointerAlignment = {/*Default=*/FormatStyle::PAS_Right, - /*ReturnType=*/FormatStyle::RTAS_Default}; + /*ReturnType=*/FormatStyle::RTAS_Default, + /*CStyleCast=*/FormatStyle::CAS_Default}; LLVMStyle.PPIndentWidth = -1; LLVMStyle.QualifierAlignment = FormatStyle::QAS_Leave; LLVMStyle.ReferenceAlignment = {/*Default=*/FormatStyle::RAS_Pointer, - /*ReturnType=*/FormatStyle::RTAS_Default}; + /*ReturnType=*/FormatStyle::RTAS_Default, + /*CStyleCast=*/FormatStyle::CAS_Default}; LLVMStyle.ReflowComments = FormatStyle::RCS_Always; LLVMStyle.RemoveBracesLLVM = false; LLVMStyle.RemoveEmptyLinesInUnwrappedLines = false; diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp index fe53d70eb12d7..a7c00e19352cf 100644 --- a/clang/lib/Format/TokenAnnotator.cpp +++ b/clang/lib/Format/TokenAnnotator.cpp @@ -6586,6 +6586,28 @@ static bool isReturnType(const FormatToken &Tok, const LangOptions &LangOpts) { return false; } +static bool isCStyleCast(const FormatToken &Tok, const LangOptions &LangOpts) { + // Look forward to see if there's a TT_CastRParen. + for (const FormatToken *Next = Tok.Next; Next; + Next = Next->getNextNonComment()) { + if (Next->is(TT_CastRParen)) + return true; + + if (Next->is(TT_TemplateOpener) && Next->MatchingParen) { + Next = Next->MatchingParen; + continue; + } + + if (Next->isPointerOrReference() || Next->isTypeName(LangOpts) || + Next->canBePointerOrReferenceQualifier()) { + continue; + } + + break; + } + return false; +} + static FormatStyle::PointerAlignmentStyle mapReturnTypeAlignmentStyle(FormatStyle::ReturnTypeAlignmentStyle Style) { switch (Style) { @@ -6601,6 +6623,19 @@ mapReturnTypeAlignmentStyle(FormatStyle::ReturnTypeAlignmentStyle Style) { llvm_unreachable("Unknown FormatStyle::ReturnTypeAlignmentStyle enum"); } +static FormatStyle::PointerAlignmentStyle +mapCastAlignmentStyle(FormatStyle::CastAlignmentStyle Style) { + switch (Style) { + case FormatStyle::CAS_Left: + return FormatStyle::PAS_Left; + case FormatStyle::CAS_Right: + return FormatStyle::PAS_Right; + case FormatStyle::CAS_Default: + assert(false); + } + llvm_unreachable("Unknown FormatStyle::CastAlignmentStyle enum"); +} + FormatStyle::PointerAlignmentStyle TokenAnnotator::getTokenReferenceAlignment(const FormatToken &Reference) const { assert(Reference.isOneOf(tok::amp, tok::ampamp)); @@ -6610,6 +6645,11 @@ TokenAnnotator::getTokenReferenceAlignment(const FormatToken &Reference) const { return mapReturnTypeAlignmentStyle(Style.ReferenceAlignment.ReturnType); } + if (Style.ReferenceAlignment.CStyleCast != FormatStyle::CAS_Default && + isCStyleCast(Reference, LangOpts)) { + return mapCastAlignmentStyle(Style.ReferenceAlignment.CStyleCast); + } + switch (Style.ReferenceAlignment.Default) { case FormatStyle::RAS_Pointer: return Style.PointerAlignment.Default; @@ -6635,6 +6675,11 @@ TokenAnnotator::getTokenPointerOrReferenceAlignment( return mapReturnTypeAlignmentStyle(Style.PointerAlignment.ReturnType); } + if (Style.PointerAlignment.CStyleCast != FormatStyle::CAS_Default && + isCStyleCast(PointerOrReference, LangOpts)) { + return mapCastAlignmentStyle(Style.PointerAlignment.CStyleCast); + } + return Style.PointerAlignment.Default; } diff --git a/clang/unittests/Format/ConfigParseTest.cpp b/clang/unittests/Format/ConfigParseTest.cpp index cf54b79bcf8a6..825487628ccfe 100644 --- a/clang/unittests/Format/ConfigParseTest.cpp +++ b/clang/unittests/Format/ConfigParseTest.cpp @@ -392,66 +392,92 @@ TEST(ConfigParseTest, ParsesConfiguration) { #undef CHECK_ALIGN_CONSECUTIVE Style.PointerAlignment = {/*Default=*/FormatStyle::PAS_Middle, - /*ReturnType=*/FormatStyle::RTAS_Default}; + /*ReturnType=*/FormatStyle::RTAS_Default, + /*CStyleCast=*/FormatStyle::CAS_Default}; CHECK_PARSE("PointerAlignment: Left", PointerAlignment, FormatStyle::PointerAlignmentOptions( {/*Default=*/FormatStyle::PAS_Left, - /*ReturnType=*/FormatStyle::RTAS_Default})); + /*ReturnType=*/FormatStyle::RTAS_Default, + /*CStyleCast=*/FormatStyle::CAS_Default})); CHECK_PARSE("PointerAlignment: Right", PointerAlignment, FormatStyle::PointerAlignmentOptions( {/*Default=*/FormatStyle::PAS_Right, - /*ReturnType=*/FormatStyle::RTAS_Default})); + /*ReturnType=*/FormatStyle::RTAS_Default, + /*CStyleCast=*/FormatStyle::CAS_Default})); CHECK_PARSE("PointerAlignment: Middle", PointerAlignment, FormatStyle::PointerAlignmentOptions( {/*Default=*/FormatStyle::PAS_Middle, - /*ReturnType=*/FormatStyle::RTAS_Default})); + /*ReturnType=*/FormatStyle::RTAS_Default, + /*CStyleCast=*/FormatStyle::CAS_Default})); CHECK_PARSE("PointerAlignment:\n" " Default: Right\n" " ReturnType: Left", PointerAlignment, FormatStyle::PointerAlignmentOptions( {/*Default=*/FormatStyle::PAS_Right, - /*ReturnType=*/FormatStyle::RTAS_Left})); - - Style.ReferenceAlignment = {/*Default=*/FormatStyle::RAS_Middle, - /*ReturnType=*/FormatStyle::RTAS_Default}; + /*ReturnType=*/FormatStyle::RTAS_Left, + /*CStyleCast=*/FormatStyle::CAS_Default})); + CHECK_PARSE("PointerAlignment:\n" + " Default: Right\n" + " CStyleCast: Left", + PointerAlignment, + FormatStyle::PointerAlignmentOptions( + {/*Default=*/FormatStyle::PAS_Right, + /*ReturnType=*/FormatStyle::RTAS_Left, + /*CStyleCast=*/FormatStyle::CAS_Left})); CHECK_PARSE("ReferenceAlignment: Pointer", ReferenceAlignment, FormatStyle::ReferenceAlignmentOptions( {/*Default=*/FormatStyle::RAS_Pointer, - /*ReturnType=*/FormatStyle::RTAS_Default})); + /*ReturnType=*/FormatStyle::RTAS_Default, + /*CStyleCast=*/FormatStyle::CAS_Default})); CHECK_PARSE("ReferenceAlignment: Left", ReferenceAlignment, FormatStyle::ReferenceAlignmentOptions( {/*Default=*/FormatStyle::RAS_Left, - /*ReturnType=*/FormatStyle::RTAS_Default})); + /*ReturnType=*/FormatStyle::RTAS_Default, + /*CStyleCast=*/FormatStyle::CAS_Default})); CHECK_PARSE("ReferenceAlignment: Right", ReferenceAlignment, FormatStyle::ReferenceAlignmentOptions( {/*Default=*/FormatStyle::RAS_Right, - /*ReturnType=*/FormatStyle::RTAS_Default})); + /*ReturnType=*/FormatStyle::RTAS_Default, + /*CStyleCast=*/FormatStyle::CAS_Default})); CHECK_PARSE("ReferenceAlignment: Middle", ReferenceAlignment, FormatStyle::ReferenceAlignmentOptions( {/*Default=*/FormatStyle::RAS_Middle, - /*ReturnType=*/FormatStyle::RTAS_Default})); + /*ReturnType=*/FormatStyle::RTAS_Default, + /*CStyleCast=*/FormatStyle::CAS_Default})); CHECK_PARSE("ReferenceAlignment:\n" " Default: Right\n" " ReturnType: Left", ReferenceAlignment, FormatStyle::ReferenceAlignmentOptions( {/*Default=*/FormatStyle::RAS_Right, - /*ReturnType=*/FormatStyle::RTAS_Left})); + /*ReturnType=*/FormatStyle::RTAS_Left, + /*CStyleCast=*/FormatStyle::CAS_Default})); + CHECK_PARSE("ReferenceAlignment:\n" + " Default: Right\n" + " CStyleCast: Left", + ReferenceAlignment, + FormatStyle::ReferenceAlignmentOptions( + {/*Default=*/FormatStyle::RAS_Right, + /*ReturnType=*/FormatStyle::RTAS_Left, + /*CStyleCast=*/FormatStyle::CAS_Left})); // For backward compatibility: CHECK_PARSE("PointerBindsToType: Left", PointerAlignment, FormatStyle::PointerAlignmentOptions( {/*Default=*/FormatStyle::PAS_Left, - /*ReturnType=*/FormatStyle::RTAS_Default})); + /*ReturnType=*/FormatStyle::RTAS_Default, + /*CStyleCast=*/FormatStyle::CAS_Default})); CHECK_PARSE("PointerBindsToType: Right", PointerAlignment, FormatStyle::PointerAlignmentOptions( {/*Default=*/FormatStyle::PAS_Right, - /*ReturnType=*/FormatStyle::RTAS_Default})); + /*ReturnType=*/FormatStyle::RTAS_Default, + /*CStyleCast=*/FormatStyle::CAS_Default})); CHECK_PARSE("PointerBindsToType: Middle", PointerAlignment, FormatStyle::PointerAlignmentOptions( {/*Default=*/FormatStyle::PAS_Middle, - /*ReturnType=*/FormatStyle::RTAS_Default})); + /*ReturnType=*/FormatStyle::RTAS_Default, + /*CStyleCast=*/FormatStyle::CAS_Default})); Style.ReflowComments = FormatStyle::RCS_Always; CHECK_PARSE("ReflowComments: Never", ReflowComments, FormatStyle::RCS_Never); diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp index ad14e7d1f0429..5cd2ad8947fbe 100644 --- a/clang/unittests/Format/FormatTest.cpp +++ b/clang/unittests/Format/FormatTest.cpp @@ -2496,6 +2496,104 @@ TEST_F(FormatTest, ReturnTypeAlignment) { verifyFormat("auto f3(int &&a, int *b) -> int &&;", Style); } +TEST_F(FormatTest, CStyleCastAlignment) { + // Test that CStyleCast overrides PointerAlignment for C-style casts + FormatStyle Style = getLLVMStyle(); + Style.PointerAlignment.Default = FormatStyle::PAS_Right; + Style.PointerAlignment.CStyleCast = FormatStyle::CAS_Left; + Style.ReferenceAlignment.Default = FormatStyle::RAS_Pointer; + Style.ReferenceAlignment.CStyleCast = FormatStyle::CAS_Left; + + // Basic C-style casts with pointers should be left-aligned despite PAS_Right + verifyFormat("int *a = (int*)b;", Style); + verifyFormat("int &c = (int&)d;", Style); + verifyFormat("int &&e = (int&&)f;", Style); + + // Multiple pointers in C-style casts + verifyFormat("int **a = (int**)b;", Style); + verifyFormat("const int *c = (const int*)d;", Style); + verifyFormat("int ***e = (int***)f;", Style); + + // Multiple pointers with const qualifiers + verifyFormat("const int **a = (const int**)b;", Style); + verifyFormat("int *const *c = (int* const*)d;", Style); + verifyFormat("const int *const *e = (const int* const*)f;", Style); + verifyFormat("int **const g = (int** const)h;", Style); + verifyFormat("const int **const i = (const int** const)j;", Style); + + // Complex types in C-style casts + verifyFormat("std::vector<int> *a = (std::vector<int>*)b;", Style); + verifyFormat("const char *c = (const char*)d;", Style); + verifyFormat("const char **e = (const char**)f;", Style); + verifyFormat("char *const *g = (char* const*)h;", Style); + + // Variables should still follow the default alignment + verifyFormat("int *a = nullptr;", Style); + verifyFormat("int *b = (int*)c;", Style); + + // Now test with PAS_Left base and CAS_Right cast + Style.PointerAlignment.Default = FormatStyle::PAS_Left; + Style.PointerAlignment.CStyleCast = FormatStyle::CAS_Right; + Style.ReferenceAlignment.Default = FormatStyle::RAS_Pointer; + Style.ReferenceAlignment.CStyleCast = FormatStyle::CAS_Right; + + // C-style casts should be right-aligned despite PAS_Left + verifyFormat("int* a = (int *)b;", Style); + verifyFormat("int& c = (int &)d;", Style); + verifyFormat("int&& e = (int &&)f;", Style); + + // Multiple pointers with right alignment in casts + verifyFormat("int** a = (int **)b;", Style); + verifyFormat("const int* c = (const int *)d;", Style); + verifyFormat("int*** e = (int ***)f;", Style); + + // Multiple pointers with const qualifiers, right-aligned casts + verifyFormat("const int** a = (const int **)b;", Style); + verifyFormat("int* const* c = (int *const *)d;", Style); + verifyFormat("const int* const* e = (const int *const *)f;", Style); + verifyFormat("int** const g = (int **const)h;", Style); + verifyFormat("const char** i = (const char **)j;", Style); + + // Variables should still follow PointerAlignment (PAS_Left) + verifyFormat("int* a = nullptr;", Style); + verifyFormat("int* b = (int *)c;", Style); + + // Test that default alignment is used when CStyleCast is CAS_Default + Style.PointerAlignment.Default = FormatStyle::PAS_Left; + Style.PointerAlignment.CStyleCast = FormatStyle::CAS_Default; + Style.ReferenceAlignment.Default = FormatStyle::RAS_Pointer; + Style.ReferenceAlignment.CStyleCast = FormatStyle::CAS_Default; + + verifyFormat("int* a = (int*)b;", Style); + verifyFormat("int& c = (int&)d;", Style); + + // Test with ReferenceAlignment override + Style.PointerAlignment.Default = FormatStyle::PAS_Right; + Style.PointerAlignment.CStyleCast = FormatStyle::CAS_Left; + Style.ReferenceAlignment.Default = FormatStyle::RAS_Pointer; + Style.ReferenceAlignment.CStyleCast = FormatStyle::CAS_Right; + + verifyFormat("int *a = (int*)b;", Style); + verifyFormat("int &c = (int &)d;", Style); + verifyFormat("int &&e = (int &&)f;", Style); + + // Chained casts + verifyFormat("int *a = (int*)(void*)b;", Style); + verifyFormat("const char *c = (const char*)(void*)d;", Style); + + // Casts with arithmetic + verifyFormat("int *a = (int*)b + 1;", Style); + verifyFormat("void *c = (void*)(d + sizeof(int));", Style); + + // Test function calls with casts + verifyFormat("foo((int*)bar);", Style); + verifyFormat("foo((int &)bar, (int*)baz);", Style); + + // Test C-style casts in expressions + verifyFormat("if ((int*)a == b)\n return;", Style); + verifyFormat("return (int*)a;", Style); +} + TEST_F(FormatTest, FormatsForLoop) { verifyFormat( "for (int VeryVeryLongLoopVariable = 0; VeryVeryLongLoopVariable < 10;\n" _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
