Index: clang/include/clang/Format/Format.h =================================================================== --- clang/include/clang/Format/Format.h +++ clang/include/clang/Format/Format.h @@ -1655,7 +1655,7 @@ /// line. unsigned PenaltyReturnTypeOnItsOwnLine; - /// The ``&`` and ``*`` alignment style. + /// The ``&``, ``&&`` and ``*`` alignment style. enum PointerAlignmentStyle { /// Align pointer to the left. /// \code @@ -1677,6 +1677,31 @@ /// Pointer and reference alignment style. PointerAlignmentStyle PointerAlignment; + /// \brief The ``&`` and ``&&`` alignment style. + enum ReferenceAlignmentStyle { + /// Align reference like ``PointerAlignment``. + RAS_Pointer, + /// Align reference to the left. + /// \code + /// int& a; + /// \endcode + RAS_Left, + /// Align reference to the right. + /// \code + /// int &a; + /// \endcode + RAS_Right, + /// Align reference in the middle. + /// \code + /// int & a; + /// \endcode + RAS_Middle + }; + + /// \brief Reference alignment style (overrides ``PointerAlignment`` for + /// references). + ReferenceAlignmentStyle ReferenceAlignment; + /// See documentation of ``RawStringFormats``. struct RawStringFormat { /// The language of this raw string. @@ -2096,6 +2121,7 @@ PenaltyBreakTemplateDeclaration == R.PenaltyBreakTemplateDeclaration && PointerAlignment == R.PointerAlignment && + ReferenceAlignment == R.ReferenceAlignment && RawStringFormats == R.RawStringFormats && SpaceAfterCStyleCast == R.SpaceAfterCStyleCast && SpaceAfterLogicalNot == R.SpaceAfterLogicalNot && Index: clang/lib/Format/Format.cpp =================================================================== --- clang/lib/Format/Format.cpp +++ clang/lib/Format/Format.cpp @@ -312,6 +312,16 @@ } }; +template <> +struct ScalarEnumerationTraits { + static void enumeration(IO &IO, FormatStyle::ReferenceAlignmentStyle &Value) { + IO.enumCase(Value, "Pointer", FormatStyle::RAS_Pointer); + IO.enumCase(Value, "Middle", FormatStyle::RAS_Middle); + IO.enumCase(Value, "Left", FormatStyle::RAS_Left); + IO.enumCase(Value, "Right", FormatStyle::RAS_Right); + } +}; + template <> struct ScalarEnumerationTraits { static void enumeration(IO &IO, @@ -510,6 +520,7 @@ IO.mapOptional("PenaltyReturnTypeOnItsOwnLine", Style.PenaltyReturnTypeOnItsOwnLine); IO.mapOptional("PointerAlignment", Style.PointerAlignment); + IO.mapOptional("ReferenceAlignment", Style.ReferenceAlignment); IO.mapOptional("RawStringFormats", Style.RawStringFormats); IO.mapOptional("ReflowComments", Style.ReflowComments); IO.mapOptional("SortIncludes", Style.SortIncludes); @@ -788,6 +799,7 @@ LLVMStyle.ObjCSpaceAfterProperty = false; LLVMStyle.ObjCSpaceBeforeProtocolList = true; LLVMStyle.PointerAlignment = FormatStyle::PAS_Right; + LLVMStyle.ReferenceAlignment = FormatStyle::RAS_Pointer; LLVMStyle.SpacesBeforeTrailingComments = 1; LLVMStyle.Standard = FormatStyle::LS_Latest; LLVMStyle.UseTab = FormatStyle::UT_Never; @@ -863,6 +875,7 @@ GoogleStyle.ObjCSpaceAfterProperty = false; GoogleStyle.ObjCSpaceBeforeProtocolList = true; GoogleStyle.PointerAlignment = FormatStyle::PAS_Left; + GoogleStyle.ReferenceAlignment = FormatStyle::RAS_Pointer; GoogleStyle.RawStringFormats = { { FormatStyle::LK_Cpp, @@ -1041,6 +1054,7 @@ MozillaStyle.ObjCSpaceBeforeProtocolList = false; MozillaStyle.PenaltyReturnTypeOnItsOwnLine = 200; MozillaStyle.PointerAlignment = FormatStyle::PAS_Left; + MozillaStyle.ReferenceAlignment = FormatStyle::RAS_Pointer; MozillaStyle.SpaceAfterTemplateKeyword = false; return MozillaStyle; } @@ -1063,6 +1077,7 @@ Style.ObjCBlockIndentWidth = 4; Style.ObjCSpaceAfterProperty = true; Style.PointerAlignment = FormatStyle::PAS_Left; + Style.ReferenceAlignment = FormatStyle::RAS_Pointer; Style.SpaceBeforeCpp11BracedList = true; Style.SpaceInEmptyBlock = true; return Style; @@ -1428,10 +1443,12 @@ Tok = Tok->Next; } } - if (Style.DerivePointerAlignment) + if (Style.DerivePointerAlignment) { Style.PointerAlignment = countVariableAlignments(AnnotatedLines) <= 0 ? FormatStyle::PAS_Left : FormatStyle::PAS_Right; + Style.ReferenceAlignment = FormatStyle::RAS_Pointer; + } if (Style.Standard == FormatStyle::LS_Auto) Style.Standard = hasCpp03IncompatibleFormat(AnnotatedLines) ? FormatStyle::LS_Latest Index: clang/lib/Format/TokenAnnotator.h =================================================================== --- clang/lib/Format/TokenAnnotator.h +++ clang/lib/Format/TokenAnnotator.h @@ -189,6 +189,9 @@ void calculateUnbreakableTailLengths(AnnotatedLine &Line); + FormatStyle::PointerAlignmentStyle + getTokenPointerAlignment(const FormatToken &PointerOrReference); + const FormatStyle &Style; const AdditionalKeywords &Keywords; Index: clang/lib/Format/TokenAnnotator.cpp =================================================================== --- clang/lib/Format/TokenAnnotator.cpp +++ clang/lib/Format/TokenAnnotator.cpp @@ -2580,14 +2580,14 @@ } return (Left.Tok.isLiteral() || (!Left.isOneOf(TT_PointerOrReference, tok::l_paren) && - (Style.PointerAlignment != FormatStyle::PAS_Left || + (getTokenPointerAlignment(Right) != FormatStyle::PAS_Left || (Line.IsMultiVariableDeclStmt && (Left.NestingLevel == 0 || (Left.NestingLevel == 1 && Line.First->is(tok::kw_for))))))); } if (Right.is(TT_FunctionTypeLParen) && Left.isNot(tok::l_paren) && (!Left.is(TT_PointerOrReference) || - (Style.PointerAlignment != FormatStyle::PAS_Right && + (getTokenPointerAlignment(Left) != FormatStyle::PAS_Right && !Line.IsMultiVariableDeclStmt))) return true; if (Left.is(TT_PointerOrReference)) @@ -2597,7 +2597,7 @@ (Right.is(tok::l_brace) && Right.BlockKind == BK_Block) || (!Right.isOneOf(TT_PointerOrReference, TT_ArraySubscriptLSquare, tok::l_paren) && - (Style.PointerAlignment != FormatStyle::PAS_Right && + (getTokenPointerAlignment(Left) != FormatStyle::PAS_Right && !Line.IsMultiVariableDeclStmt) && Left.Previous && !Left.Previous->isOneOf(tok::l_paren, tok::coloncolon, @@ -2704,7 +2704,7 @@ // Match const and volatile ref-qualifiers without any additional // qualifiers such as // void Fn() const &; - return Style.PointerAlignment != FormatStyle::PAS_Left; + return getTokenPointerAlignment(Right) != FormatStyle::PAS_Left; return true; } @@ -2958,11 +2958,11 @@ // Space before TT_StructuredBindingLSquare. if (Right.is(TT_StructuredBindingLSquare)) return !Left.isOneOf(tok::amp, tok::ampamp) || - Style.PointerAlignment != FormatStyle::PAS_Right; + getTokenPointerAlignment(Left) != FormatStyle::PAS_Right; // Space before & or && following a TT_StructuredBindingLSquare. if (Right.Next && Right.Next->is(TT_StructuredBindingLSquare) && Right.isOneOf(tok::amp, tok::ampamp)) - return Style.PointerAlignment != FormatStyle::PAS_Left; + return getTokenPointerAlignment(Right) != FormatStyle::PAS_Left; if ((Right.is(TT_BinaryOperator) && !Left.is(tok::l_paren)) || (Left.isOneOf(TT_BinaryOperator, TT_ConditionalExpr) && !Right.is(tok::r_paren))) @@ -3353,7 +3353,7 @@ return !Right.is(tok::l_paren); if (Right.is(TT_PointerOrReference)) return Line.IsMultiVariableDeclStmt || - (Style.PointerAlignment == FormatStyle::PAS_Right && + (getTokenPointerAlignment(Right) == FormatStyle::PAS_Right && (!Right.Next || Right.Next->isNot(TT_FunctionDeclarationName))); if (Right.isOneOf(TT_StartOfName, TT_FunctionDeclarationName) || Right.is(tok::kw_operator)) @@ -3557,5 +3557,23 @@ llvm::errs() << "----\n"; } +FormatStyle::PointerAlignmentStyle TokenAnnotator::getTokenPointerAlignment( + const FormatToken &PointerOrReference) { + if (PointerOrReference.isOneOf(tok::amp, tok::ampamp)) { + switch (Style.ReferenceAlignment) { + case FormatStyle::RAS_Pointer: + return Style.PointerAlignment; + case FormatStyle::RAS_Left: + return FormatStyle::PAS_Left; + case FormatStyle::RAS_Right: + return FormatStyle::PAS_Right; + case FormatStyle::RAS_Middle: + return FormatStyle::PAS_Middle; + } + } + assert(PointerOrReference.is(tok::star)); + return Style.PointerAlignment; +} + } // namespace format } // namespace clang Index: clang/unittests/Format/FormatTest.cpp =================================================================== --- clang/unittests/Format/FormatTest.cpp +++ clang/unittests/Format/FormatTest.cpp @@ -846,6 +846,35 @@ getLLVMStyleWithColumns(62)); } #endif + +TEST_F(FormatTest, SeparatePointerReferenceAlignment) { + FormatStyle Style = getLLVMStyle(); + Style.PointerAlignment = FormatStyle::PAS_Left; + Style.ReferenceAlignment = 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); + verifyFormat("int* a = f1();\nint& b = f2();\nint&& c = f3();", Style); + Style.PointerAlignment = FormatStyle::PAS_Right; + Style.ReferenceAlignment = 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); + verifyFormat("int *a = f1();\nint& b = f2();\nint&& c = f3();", Style); + Style.PointerAlignment = FormatStyle::PAS_Left; + Style.ReferenceAlignment = 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); + verifyFormat("int* a = f1();\nint & b = f2();\nint && c = f3();", Style); + Style.PointerAlignment = FormatStyle::PAS_Middle; + Style.ReferenceAlignment = 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); + verifyFormat("int * a = f1();\nint &b = f2();\nint &&c = f3();", Style); +} + TEST_F(FormatTest, FormatsForLoop) { verifyFormat( "for (int VeryVeryLongLoopVariable = 0; VeryVeryLongLoopVariable < 10;\n" @@ -12562,6 +12591,15 @@ FormatStyle::PAS_Right); CHECK_PARSE("PointerAlignment: Middle", PointerAlignment, FormatStyle::PAS_Middle); + Style.ReferenceAlignment = FormatStyle::RAS_Middle; + CHECK_PARSE("ReferenceAlignment: Pointer", ReferenceAlignment, + FormatStyle::RAS_Pointer); + CHECK_PARSE("ReferenceAlignment: Left", ReferenceAlignment, + FormatStyle::RAS_Left); + CHECK_PARSE("ReferenceAlignment: Right", ReferenceAlignment, + FormatStyle::RAS_Right); + CHECK_PARSE("ReferenceAlignment: Middle", ReferenceAlignment, + FormatStyle::RAS_Middle); // For backward compatibility: CHECK_PARSE("PointerBindsToType: Left", PointerAlignment, FormatStyle::PAS_Left);