diff --git a/clang/docs/ClangFormatStyleOptions.rst b/clang/docs/ClangFormatStyleOptions.rst --- a/clang/docs/ClangFormatStyleOptions.rst +++ b/clang/docs/ClangFormatStyleOptions.rst @@ -2313,6 +2313,38 @@ BasedOnStyle: llvm CanonicalDelimiter: 'cc' +**ReferenceAlignment** (``ReferenceAlignmentStyle``) + Reference alignment style (overrides ``PointerAlignment`` for + references). + + 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; + + + **ReflowComments** (``bool``) If ``true``, clang-format will attempt to re-flow comments. 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 @@ -1888,7 +1888,7 @@ /// line. unsigned PenaltyReturnTypeOnItsOwnLine; - /// The ``&`` and ``*`` alignment style. + /// The ``&``, ``&&`` and ``*`` alignment style. enum PointerAlignmentStyle { /// Align pointer to the left. /// \code @@ -1910,6 +1910,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. @@ -2382,6 +2407,7 @@ PenaltyBreakTemplateDeclaration == R.PenaltyBreakTemplateDeclaration && PointerAlignment == R.PointerAlignment && + ReferenceAlignment == R.ReferenceAlignment && RawStringFormats == R.RawStringFormats && SpaceAfterCStyleCast == R.SpaceAfterCStyleCast && SpaceAfterLogicalNot == R.SpaceAfterLogicalNot && 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 @@ -347,6 +347,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, @@ -559,6 +569,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); @@ -897,6 +908,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.UseCRLF = false; @@ -978,6 +990,7 @@ GoogleStyle.ObjCSpaceAfterProperty = false; GoogleStyle.ObjCSpaceBeforeProtocolList = true; GoogleStyle.PointerAlignment = FormatStyle::PAS_Left; + GoogleStyle.ReferenceAlignment = FormatStyle::RAS_Pointer; GoogleStyle.RawStringFormats = { { FormatStyle::LK_Cpp, @@ -1169,6 +1182,7 @@ MozillaStyle.ObjCSpaceBeforeProtocolList = false; MozillaStyle.PenaltyReturnTypeOnItsOwnLine = 200; MozillaStyle.PointerAlignment = FormatStyle::PAS_Left; + MozillaStyle.ReferenceAlignment = FormatStyle::RAS_Pointer; MozillaStyle.SpaceAfterTemplateKeyword = false; return MozillaStyle; } @@ -1191,6 +1205,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; @@ -1570,10 +1585,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 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 @@ -189,6 +189,9 @@ void calculateUnbreakableTailLengths(AnnotatedLine &Line); + FormatStyle::PointerAlignmentStyle + getTokenPointerAlignment(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 @@ -2822,14 +2822,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)) @@ -2839,7 +2839,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, @@ -2997,7 +2997,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; } @@ -3329,11 +3329,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))) @@ -3803,7 +3803,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)) @@ -4017,5 +4017,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 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 @@ -884,6 +884,43 @@ getLLVMStyleWithColumns(62)); } +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_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); + + // we don't handle this yet, so output may be arbitrary until it's specifically handled + //verifyFormat("int Add2(BTree * &Root, char * szToAdd)", Style); +} + TEST_F(FormatTest, FormatsForLoop) { verifyFormat( "for (int VeryVeryLongLoopVariable = 0; VeryVeryLongLoopVariable < 10;\n" @@ -13744,6 +13781,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);