diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -253,6 +253,9 @@ - ``git-clang-format`` no longer formats changes to symbolic links. (Fixes https://llvm.org/PR46992.) +- Makes ``PointerAligment: Right`` working with ``AlignConsecutiveDeclarations``. + (Fixes https://llvm.org/PR27353) + libclang -------- diff --git a/clang/lib/Format/WhitespaceManager.cpp b/clang/lib/Format/WhitespaceManager.cpp --- a/clang/lib/Format/WhitespaceManager.cpp +++ b/clang/lib/Format/WhitespaceManager.cpp @@ -262,7 +262,8 @@ // Align a single sequence of tokens, see AlignTokens below. template static void -AlignTokenSequence(unsigned Start, unsigned End, unsigned Column, F &&Matches, +AlignTokenSequence(const FormatStyle &Style, unsigned Start, unsigned End, + unsigned Column, F &&Matches, SmallVector &Changes) { bool FoundMatchOnLine = false; int Shift = 0; @@ -365,9 +366,22 @@ Changes[i].Spaces += Shift; assert(Shift >= 0); + Changes[i].StartOfTokenColumn += Shift; if (i + 1 != Changes.size()) Changes[i + 1].PreviousEndOfTokenColumn += Shift; + + // If PointerAlignment is PAS_Right, keep *s or &s next to the token + if (Style.PointerAlignment == FormatStyle::PAS_Right && + Changes[i].Spaces != 0) { + for (int Previous = i - 1; + Previous >= 0 && + Changes[Previous].Tok->getType() == TT_PointerOrReference; + --Previous) { + Changes[Previous + 1].Spaces -= Shift; + Changes[Previous].Spaces += Shift; + } + } } } @@ -437,8 +451,8 @@ // containing any matching token to be aligned and located after such token. auto AlignCurrentSequence = [&] { if (StartOfSequence > 0 && StartOfSequence < EndOfSequence) - AlignTokenSequence(StartOfSequence, EndOfSequence, MinColumn, Matches, - Changes); + AlignTokenSequence(Style, StartOfSequence, EndOfSequence, MinColumn, + Matches, Changes); MinColumn = 0; MaxColumn = UINT_MAX; StartOfSequence = 0; @@ -728,12 +742,6 @@ if (Style.AlignConsecutiveDeclarations == FormatStyle::ACS_None) return; - // FIXME: Currently we don't handle properly the PointerAlignment: Right - // The * and & are not aligned and are left dangling. Something has to be done - // about it, but it raises the question of alignment of code like: - // const char* const* v1; - // float const* v2; - // SomeVeryLongType const& v3; AlignTokens( Style, [](Change const &C) { 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 @@ -14881,6 +14881,7 @@ FormatStyle Alignment = getLLVMStyle(); Alignment.AlignConsecutiveMacros = FormatStyle::ACS_Consecutive; Alignment.AlignConsecutiveDeclarations = FormatStyle::ACS_None; + Alignment.PointerAlignment = FormatStyle::PAS_Right; verifyFormat("float const a = 5;\n" "int oneTwoThree = 123;", Alignment); @@ -14916,8 +14917,8 @@ verifyFormat("int oneTwoThree{0}; // comment\n" "unsigned oneTwo; // comment", Alignment); - verifyFormat("unsigned int * a;\n" - "int * b;\n" + verifyFormat("unsigned int *a;\n" + "int *b;\n" "unsigned int Const *c;\n" "unsigned int const *d;\n" "unsigned int Const &e;\n" @@ -15039,9 +15040,11 @@ " double bar();\n" "};\n", Alignment); + + // PAS_Right EXPECT_EQ("void SomeFunction(int parameter = 0) {\n" " int const i = 1;\n" - " int * j = 2;\n" + " int *j = 2;\n" " int big = 10000;\n" "\n" " unsigned oneTwoThree = 123;\n" @@ -15062,6 +15065,161 @@ "int ll=10000;\n" "}", Alignment)); + EXPECT_EQ("void SomeFunction(int parameter = 0) {\n" + " int const i = 1;\n" + " int **j = 2, ***k;\n" + " int &k = i;\n" + " int &&l = i + j;\n" + " int big = 10000;\n" + "\n" + " unsigned oneTwoThree = 123;\n" + " int oneTwo = 12;\n" + " method();\n" + " float k = 2;\n" + " int ll = 10000;\n" + "}", + format("void SomeFunction(int parameter= 0) {\n" + " int const i= 1;\n" + " int **j=2,***k;\n" + "int &k=i;\n" + "int &&l=i+j;\n" + " int big = 10000;\n" + "\n" + "unsigned oneTwoThree =123;\n" + "int oneTwo = 12;\n" + " method();\n" + "float k= 2;\n" + "int ll=10000;\n" + "}", + Alignment)); + // variables are aligned at their name, pointers are at the right most + // position + verifyFormat("int *a;\n" + "int **b;\n" + "int ***c;\n" + "int foobar;\n", + Alignment); + + // PAS_Left + FormatStyle AlignmentLeft = Alignment; + AlignmentLeft.PointerAlignment = FormatStyle::PAS_Left; + EXPECT_EQ("void SomeFunction(int parameter = 0) {\n" + " int const i = 1;\n" + " int* j = 2;\n" + " int big = 10000;\n" + "\n" + " unsigned oneTwoThree = 123;\n" + " int oneTwo = 12;\n" + " method();\n" + " float k = 2;\n" + " int ll = 10000;\n" + "}", + format("void SomeFunction(int parameter= 0) {\n" + " int const i= 1;\n" + " int *j=2;\n" + " int big = 10000;\n" + "\n" + "unsigned oneTwoThree =123;\n" + "int oneTwo = 12;\n" + " method();\n" + "float k= 2;\n" + "int ll=10000;\n" + "}", + AlignmentLeft)); + EXPECT_EQ("void SomeFunction(int parameter = 0) {\n" + " int const i = 1;\n" + " int** j = 2;\n" + " int& k = i;\n" + " int&& l = i + j;\n" + " int big = 10000;\n" + "\n" + " unsigned oneTwoThree = 123;\n" + " int oneTwo = 12;\n" + " method();\n" + " float k = 2;\n" + " int ll = 10000;\n" + "}", + format("void SomeFunction(int parameter= 0) {\n" + " int const i= 1;\n" + " int **j=2;\n" + "int &k=i;\n" + "int &&l=i+j;\n" + " int big = 10000;\n" + "\n" + "unsigned oneTwoThree =123;\n" + "int oneTwo = 12;\n" + " method();\n" + "float k= 2;\n" + "int ll=10000;\n" + "}", + AlignmentLeft)); + // variables are aligned at their name, pointers are at the left most position + verifyFormat("int* a;\n" + "int** b;\n" + "int*** c;\n" + "int foobar;\n", + AlignmentLeft); + + // PAS_Middle + FormatStyle AlignmentMiddle = Alignment; + AlignmentMiddle.PointerAlignment = FormatStyle::PAS_Middle; + EXPECT_EQ("void SomeFunction(int parameter = 0) {\n" + " int const i = 1;\n" + " int * j = 2;\n" + " int big = 10000;\n" + "\n" + " unsigned oneTwoThree = 123;\n" + " int oneTwo = 12;\n" + " method();\n" + " float k = 2;\n" + " int ll = 10000;\n" + "}", + format("void SomeFunction(int parameter= 0) {\n" + " int const i= 1;\n" + " int *j=2;\n" + " int big = 10000;\n" + "\n" + "unsigned oneTwoThree =123;\n" + "int oneTwo = 12;\n" + " method();\n" + "float k= 2;\n" + "int ll=10000;\n" + "}", + AlignmentMiddle)); + EXPECT_EQ("void SomeFunction(int parameter = 0) {\n" + " int const i = 1;\n" + " int ** j = 2, ***k;\n" + " int & k = i;\n" + " int && l = i + j;\n" + " int big = 10000;\n" + "\n" + " unsigned oneTwoThree = 123;\n" + " int oneTwo = 12;\n" + " method();\n" + " float k = 2;\n" + " int ll = 10000;\n" + "}", + format("void SomeFunction(int parameter= 0) {\n" + " int const i= 1;\n" + " int **j=2,***k;\n" + "int &k=i;\n" + "int &&l=i+j;\n" + " int big = 10000;\n" + "\n" + "unsigned oneTwoThree =123;\n" + "int oneTwo = 12;\n" + " method();\n" + "float k= 2;\n" + "int ll=10000;\n" + "}", + AlignmentMiddle)); + // variables are aligned at their name, pointers are in the middle + verifyFormat("int * a;\n" + "int * b;\n" + "int *** c;\n" + "int foobar;\n", + AlignmentMiddle); + Alignment.AlignConsecutiveAssignments = FormatStyle::ACS_None; Alignment.AlignEscapedNewlines = FormatStyle::ENAS_DontAlign; verifyFormat("#define A \\\n" @@ -15095,7 +15253,7 @@ Alignment); verifyFormat("void SomeFunction(int parameter = 0) {\n" " int const i = 1;\n" - " int * j = 2;\n" + " int *j = 2;\n" " int big = 10000;\n" "}", Alignment); @@ -15198,7 +15356,7 @@ " float b,\n" " int c,\n" " uint32_t *d) {\n" - " int * e = 0;\n" + " int *e = 0;\n" " float f = 0;\n" " double g = 0;\n" "}\n"