llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang-format Author: Daan De Meyer (DaanDeMeyer) <details> <summary>Changes</summary> 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. Fixes https://github.com/llvm/llvm-project/issues/136597 --- Patch is 54.70 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/169160.diff 7 Files Affected: - (modified) clang/docs/ClangFormatStyleOptions.rst (+137-30) - (modified) clang/include/clang/Format/Format.h (+82-2) - (modified) clang/lib/Format/Format.cpp (+86-12) - (modified) clang/lib/Format/TokenAnnotator.cpp (+55-8) - (modified) clang/lib/Format/WhitespaceManager.cpp (+5-5) - (modified) clang/unittests/Format/ConfigParseTest.cpp (+50-12) - (modified) clang/unittests/Format/FormatTest.cpp (+188-59) ``````````diff diff --git a/clang/docs/ClangFormatStyleOptions.rst b/clang/docs/ClangFormatStyleOptions.rst index 94d6f0d27619f..e08e22964691d 100644 --- a/clang/docs/ClangFormatStyleOptions.rst +++ b/clang/docs/ClangFormatStyleOptions.rst @@ -5668,31 +5668,84 @@ 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 - int *a; + Nested configuration flags: - * ``PAS_Middle`` (in configuration: ``Middle``) - Align pointer in the middle. + Pointer and reference alignment options. - .. code-block:: c++ + * ``PointerAlignmentStyle Default`` + The default alignment for pointers and references. + + 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; + + + * ``ReturnTypeAlignmentStyle ReturnType`` + The alignment for pointers in 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; + int *a(void); @@ -5824,34 +5877,88 @@ 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; + + + * ``ReturnTypeAlignmentStyle ReturnType`` + The alignment for references in 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; + int *a(void); diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h index b6f124f948b59..21369d21796f4 100644 --- a/clang/include/clang/Format/Format.h +++ b/clang/include/clang/Format/Format.h @@ -4017,6 +4017,27 @@ struct FormatStyle { /// \version 3.7 unsigned PenaltyReturnTypeOnItsOwnLine; + /// \brief The pointer/reference alignment style for 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 + }; + /// The ``&``, ``&&`` and ``*`` alignment style. enum PointerAlignmentStyle : int8_t { /// Align pointer to the left. @@ -4036,9 +4057,38 @@ struct FormatStyle { PAS_Middle }; + /// Pointer and reference alignment options. + struct PointerAlignmentOptions { + /// The default alignment for pointers and references. + PointerAlignmentStyle Default; + /// The alignment for pointers in return types. + ReturnTypeAlignmentStyle ReturnType; + bool operator==(const PointerAlignmentOptions &R) const { + return Default == R.Default && ReturnType == R.ReturnType; + } + 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 +4258,39 @@ struct FormatStyle { RAS_Middle }; + /// Reference alignment options. + struct ReferenceAlignmentOptions { + /// The default alignment for references. + ReferenceAlignmentStyle Default; + /// The alignment for references in return types. + ReturnTypeAlignmentStyle ReturnType; + bool operator==(const ReferenceAlignmentOptions &R) const { + return Default == R.Default && ReturnType == R.ReturnType; + } + 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..cb7a1a6f07623 100644 --- a/clang/lib/Format/Format.cpp +++ b/clang/lib/Format/Format.cpp @@ -541,10 +541,49 @@ 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, + /*ReturnType=*/FormatStyle::RTAS_Default})); + IO.enumCase(Value, "Left", + FormatStyle::PointerAlignmentOptions( + {/*Default=*/FormatStyle::PAS_Left, + /*ReturnType=*/FormatStyle::RTAS_Default})); + IO.enumCase(Value, "Right", + FormatStyle::PointerAlignmentOptions( + {/*Default=*/FormatStyle::PAS_Right, + /*ReturnType=*/FormatStyle::RTAS_Default})); // 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, + /*ReturnType=*/FormatStyle::RTAS_Default})); + IO.enumCase(Value, "false", + FormatStyle::PointerAlignmentOptions( + {/*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); + } +}; + +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); } }; @@ -589,6 +628,32 @@ 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, + /*ReturnType=*/FormatStyle::RTAS_Default})); + IO.enumCase(Value, "Middle", + FormatStyle::ReferenceAlignmentOptions( + {/*Default=*/FormatStyle::RAS_Middle, + /*ReturnType=*/FormatStyle::RTAS_Default})); + IO.enumCase(Value, "Left", + FormatStyle::ReferenceAlignmentOptions( + {/*Default=*/FormatStyle::RAS_Left, + /*ReturnType=*/FormatStyle::RTAS_Default})); + IO.enumCase(Value, "Right", + FormatStyle::ReferenceAlignmentOptions( + {/*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); + } +}; + template <> struct ScalarEnumerationTraits<FormatStyle::ReferenceAlignmentStyle> { static void enumeration(IO &IO, FormatStyle::ReferenceAlignmentStyle &Value) { @@ -1785,10 +1850,12 @@ 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, + /*ReturnType=*/FormatStyle::RTAS_Default}; LLVMStyle.PPIndentWidth = -1; LLVMStyle.QualifierAlignment = FormatStyle::QAS_Leave; - LLVMStyle.ReferenceAlignment = FormatStyle::RAS_Pointer; + LLVMStyle.ReferenceAlignment = {/*Default=*/FormatStyle::RAS_Pointer, + /*ReturnType=*/FormatStyle::RTAS_Default}; LLVMStyle.ReflowComments = FormatStyle::RCS_Always; LLVMStyle.RemoveBracesLLVM = false; LLVMStyle.RemoveEmptyLinesInUnwrappedLines = false; @@ -1910,7 +1977,8 @@ 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, + /*ReturnType=*/FormatStyle::RTAS_Default}; GoogleStyle.RawStringFormats = { { FormatStyle::LK_Cpp, @@ -2105,7 +2173,8 @@ FormatStyle getMozillaStyle() { MozillaStyle.ObjCSpaceAfterProperty = true; MozillaStyle.ObjCSpaceBeforeProtocolList = false; MozillaStyle.PenaltyReturnTypeOnItsOwnLine = 200; - MozillaStyle.PointerAlignment = FormatStyle::PAS_Left; + MozillaStyle.PointerAlignment = {/*Default=*/FormatStyle::PAS_Left, + /*ReturnType=*/FormatStyle::RTAS_Default}; MozillaStyle.SpaceAfterTemplateKeyword = false; return MozillaStyle; } @@ -2128,7 +2197,8 @@ FormatStyle getWebKitStyle() { Style.NamespaceIndentation = FormatStyle::NI_Inner; Style.ObjCBlockIndentWidth = 4; Style.ObjCSpaceAfterProperty = true; - Style.PointerAlignment = FormatStyle::PAS_Left; + Style.PointerAlignment = {/*Default=*/FormatStyle::PAS_Left, + /*ReturnType=*/FormatStyle::RTAS_Default}; Style.SpaceBeforeCpp11BracedList = true; Style.SpaceInEmptyBraces = FormatStyle::SIEB_Always; return Style; @@ -2861,11 +2931,15 @@ class Formatter : public TokenAnalyzer { } if (Style.DerivePointerAlignment) { const auto NetRightCount = countVariableAlignments(AnnotatedLines); - if (NetRightCount > 0) - Style.PointerAlignment = FormatStyle::PAS_Right; - else if (NetRightCount < 0) - Style.PointerAlignment = FormatStyle::PAS_Left; - Style.ReferenceAlignment = FormatStyle::RAS_Pointer; + if (NetRightCount > 0) { + Style.PointerAlignment = {/*Default=*/FormatStyle::PAS_Right, + /*ReturnType=*/FormatStyle::RTAS_Default}; + } else if (NetRightCount < 0) { + Style.PointerAlignment = {/*Default=*/FormatStyle::PAS_Left, + /*ReturnType=*/FormatStyle::RTAS_Default}; + } + Style.ReferenceAlignment = {/*Default=*/FormatStyle::RAS_Pointer, + /*ReturnType=*/FormatStyle::RTAS_Default}; } 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..a9e7bac343ab4 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); @@ -6540,12 +6540,44 @@ void TokenAnnotator::printDebugInfo(const AnnotatedLine &Line) const { llvm::errs() << "----\n"; } +static bool isReturnType(const FormatToken &Tok) { + // Look forward to see if there's a function declaration paren + const FormatToken *Next = Tok.Next; + while (Next) { + if (Next->isOneOf(TT_FunctionDeclarationLParen, TT_FunctionTypeLParen)) + return true; + // Stop at certain tokens that indicate we're not in a return type + if (Next->isOneOf(tok::semi, tok::l_brace, tok::comma, tok::equal, + TT_LambdaLSquare)) { + break; + } + + Next = Next->Next; + } + return false; +} + FormatStyle::PointerAlignmentStyle TokenAnnotator::getTokenReferenceAlignment(const FormatToken &Reference) const { assert(Reference.isOneOf(tok::amp, tok::ampamp)); - switch (Style.ReferenceAlignment) { + + if (Style.ReferenceAlignment.ReturnType != FormatStyle::RTAS_Default && + isReturnType(Reference)) { + switch (Style.ReferenceAlignment.ReturnType) { + 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(0); + } + } + + 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 +6586,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 +6595,22 @@ TokenAnnotator::getTokenPointerOrReferenceAlignment( if (PointerOrReference.isOneOf(tok::amp, tok::ampamp)) return getTokenReferenceAlignment(PointerOrReference); assert(PointerOrReference.is(tok::star)); - return Style.PointerAlignment; + + if (Style.PointerAlignment.ReturnType != FormatStyle::RTAS_Default && + isReturnType(PointerOrReference)) { + switch (Style.PointerAlignment.ReturnType) { + case FormatStyle::RTAS_Left: + return FormatStyle::PAS_Left; + case FormatStyle::RTAS_Right: + return FormatStyle::PAS_Right; + case FormatStyle::RTAS_Middle: + return FormatStyle::PAS_... [truncated] `````````` </details> https://github.com/llvm/llvm-project/pull/169160 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
