diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h --- a/clang/include/clang/Format/Format.h +++ b/clang/include/clang/Format/Format.h @@ -2932,6 +2932,27 @@ /// \version 3.7 PointerAlignmentStyle PointerAlignment; + /// The ``&``, ``&&`` and ``*`` alignment style when in C style casts. + enum PointerAlignmentInCastStyle { + /// Align pointers and references like ``PointerAlignment`` for pointers and + // like `'ReferenceAlignment`' for references. + PACS_Pointer, + /// Align pointer to the left. + /// \code + /// (int*) a; + /// \endcode + PACS_Left, + /// Align pointer to the right. + /// \code + /// (int *) a; + /// \endcode + PACS_Right, + }; + + /// Pointer alignment style in C style casts. + /// \version 14 + PointerAlignmentInCastStyle PointerAlignmentInCast; + /// The number of columns to use for indentation of preprocessor statements. /// When set to -1 (default) ``IndentWidth`` is used also for preprocessor /// statements. diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp --- a/clang/lib/Format/Format.cpp +++ b/clang/lib/Format/Format.cpp @@ -429,6 +429,16 @@ } }; +template <> +struct ScalarEnumerationTraits { + static void enumeration(IO &IO, + FormatStyle::PointerAlignmentInCastStyle &Value) { + IO.enumCase(Value, "Pointer", FormatStyle::PACS_Pointer); + IO.enumCase(Value, "Left", FormatStyle::PACS_Left); + IO.enumCase(Value, "Right", FormatStyle::PACS_Right); + } +}; + template <> struct ScalarEnumerationTraits { static void @@ -765,6 +775,7 @@ IO.mapOptional("PenaltyIndentedWhitespace", Style.PenaltyIndentedWhitespace); IO.mapOptional("PointerAlignment", Style.PointerAlignment); + IO.mapOptional("PointerAlignmentInCast", Style.PointerAlignmentInCast); IO.mapOptional("PPIndentWidth", Style.PPIndentWidth); IO.mapOptional("RawStringFormats", Style.RawStringFormats); IO.mapOptional("ReferenceAlignment", Style.ReferenceAlignment); @@ -1192,6 +1203,7 @@ LLVMStyle.ObjCSpaceAfterProperty = false; LLVMStyle.ObjCSpaceBeforeProtocolList = true; LLVMStyle.PointerAlignment = FormatStyle::PAS_Right; + LLVMStyle.PointerAlignmentInCast = FormatStyle::PACS_Pointer; LLVMStyle.ReferenceAlignment = FormatStyle::RAS_Pointer; LLVMStyle.ShortNamespaceLines = 1; LLVMStyle.SpacesBeforeTrailingComments = 1; diff --git a/clang/lib/Format/TokenAnnotator.h b/clang/lib/Format/TokenAnnotator.h --- a/clang/lib/Format/TokenAnnotator.h +++ b/clang/lib/Format/TokenAnnotator.h @@ -199,6 +199,9 @@ FormatStyle::PointerAlignmentStyle getTokenPointerOrReferenceAlignment(const FormatToken &PointerOrReference); + FormatStyle::PointerAlignmentStyle getTokenPointerOrReferenceAlignmentInCase( + const FormatToken &PointerOrReference); + const FormatStyle &Style; const AdditionalKeywords &Keywords; diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp --- a/clang/lib/Format/TokenAnnotator.cpp +++ b/clang/lib/Format/TokenAnnotator.cpp @@ -3037,6 +3037,19 @@ Right.Next->Next->is(TT_RangeBasedForLoopColon)) return getTokenPointerOrReferenceAlignment(Right) != FormatStyle::PAS_Left; + // To find if we are currently in a C style cast we just have to follow the + // linked list until one of three conditions. If we have either reached the + // end of the list or find the opening parenthesis of a cast we can assume + // we are not currently in a cast. If we instead find the right-most + // parenthesis of a cast we know we are in a cast. + if (!Left.isOneOf(TT_PointerOrReference, tok::l_paren)) + for (const FormatToken *Tok = &Right; + Tok && + (!Tok->MatchingParen || !Tok->MatchingParen->is(TT_CastRParen)); + Tok = Tok->Next) + if (Tok->Next && Tok->Next->is(TT_CastRParen)) + return getTokenPointerOrReferenceAlignmentInCase(Right) != + FormatStyle::PAS_Left; return ( (!Left.isOneOf(TT_PointerOrReference, tok::l_paren) && (getTokenPointerOrReferenceAlignment(Right) != FormatStyle::PAS_Left || @@ -4444,5 +4457,20 @@ return Style.PointerAlignment; } +FormatStyle::PointerAlignmentStyle +TokenAnnotator::getTokenPointerOrReferenceAlignmentInCase( + const FormatToken &PointerOrReference) { + switch (Style.PointerAlignmentInCast) { + case FormatStyle::PACS_Pointer: + return getTokenPointerOrReferenceAlignment(PointerOrReference); + case FormatStyle::PACS_Left: + return FormatStyle::PAS_Left; + case FormatStyle::PACS_Right: + return FormatStyle::PAS_Right; + } + assert(0); //"Unhandled value of PointerAlignmentInCast" + return Style.PointerAlignment; +} + } // namespace format } // namespace clang diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp --- a/clang/unittests/Format/FormatTest.cpp +++ b/clang/unittests/Format/FormatTest.cpp @@ -15343,6 +15343,30 @@ Style)); } +TEST_F(FormatTest, AlignPointersInCasts) { + FormatStyle Style = getLLVMStyle(); + Style.PointerAlignment = FormatStyle::PAS_Right; + verifyFormat("(const int (*(*foo)(const void *))[3]) a", Style); + Style.PointerAlignment = FormatStyle::PAS_Left; + verifyFormat("(const int (*(*foo)(const void*))[3]) a", Style); + Style.PointerAlignmentInCast = FormatStyle::PACS_Right; + verifyFormat("(const int (*(*foo)(const void *))[3]) a", Style); + Style.PointerAlignment = FormatStyle::PAS_Right; + Style.PointerAlignmentInCast = FormatStyle::PACS_Left; + verifyFormat("(const int (*(*foo)(const void*))[3]) a", Style); + + Style.PointerAlignmentInCast = FormatStyle::PACS_Pointer; + Style.ReferenceAlignment = FormatStyle::RAS_Pointer; + verifyFormat("(const int (*(*foo)(const void &))[3]) a", Style); + Style.ReferenceAlignment = FormatStyle::RAS_Left; + verifyFormat("(const int (*(*foo)(const void&))[3]) a", Style); + Style.PointerAlignmentInCast = FormatStyle::PACS_Right; + verifyFormat("(const int (*(*foo)(const void &))[3]) a", Style); + Style.ReferenceAlignment = FormatStyle::RAS_Right; + Style.PointerAlignmentInCast = FormatStyle::PACS_Left; + verifyFormat("(const int (*(*foo)(const void&))[3]) a", Style); +} + TEST_F(FormatTest, AlignConsecutiveAssignmentsAcrossEmptyLines) { FormatStyle Alignment = getLLVMStyle(); Alignment.AlignConsecutiveMacros = FormatStyle::ACS_Consecutive; @@ -18817,6 +18841,13 @@ FormatStyle::PAS_Right); CHECK_PARSE("PointerAlignment: Middle", PointerAlignment, FormatStyle::PAS_Middle); + Style.PointerAlignmentInCast = FormatStyle::PACS_Left; + CHECK_PARSE("PointerAlignmentInCast: Pointer", PointerAlignmentInCast, + FormatStyle::PACS_Pointer); + CHECK_PARSE("PointerAlignmentInCast: Left", PointerAlignmentInCast, + FormatStyle::PACS_Left); + CHECK_PARSE("PointerAlignmentInCast: Right", PointerAlignmentInCast, + FormatStyle::PACS_Right); Style.ReferenceAlignment = FormatStyle::RAS_Middle; CHECK_PARSE("ReferenceAlignment: Pointer", ReferenceAlignment, FormatStyle::RAS_Pointer);