sammccall created this revision. sammccall added a reviewer: benhamilton. sammccall requested review of this revision. Herald added a project: clang. Herald added a subscriber: cfe-commits.
The second space in `void foo() &` is always produced by clang-format, and isn't evidence of any particular style. Before this patch, it was considered evidence of PAS_Right, because there is a space before a pointerlike ampersand. This caused the following code to have "unstable" pointer alignment: void a() &; void b() &; int *x; PAS_Left, Derive=false would produce 'int* x' with other lines unchanged. But subsequent formatting with Derive=true would produce 'int *x' again. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D118921 Files: clang/lib/Format/Format.cpp clang/unittests/Format/FormatTest.cpp Index: clang/unittests/Format/FormatTest.cpp =================================================================== --- clang/unittests/Format/FormatTest.cpp +++ clang/unittests/Format/FormatTest.cpp @@ -9683,6 +9683,25 @@ AlignLeftBreakTemplate); verifyFormat("void (*foopt)(int) = &func;"); + + FormatStyle DerivePointerAlignment = getLLVMStyle(); + DerivePointerAlignment.DerivePointerAlignment = true; + // There's always a space between the function and its trailing qualifiers. + // This isn't evidence for PAS_Right (or for PAS_Left). + std::string Prefix = "void a() &;\n" + "void b() &;\n"; + verifyFormat(Prefix + "int* x;", DerivePointerAlignment); + verifyFormat(Prefix + "int *x;", DerivePointerAlignment); + // Same if the function is an overloaded operator instead. + Prefix = "void operator()() &;\n" + "void operator()() &;\n"; + verifyFormat(Prefix + "int* x;", DerivePointerAlignment); + verifyFormat(Prefix + "int *x;", DerivePointerAlignment); + // However a space between cv-qualifiers and ref-qualifiers *is* evidence. + Prefix = "void a() const &;\n" + "void b() const &;\n"; + EXPECT_EQ(Prefix + "int *x;", + format(Prefix + "int* x;", DerivePointerAlignment)); } TEST_F(FormatTest, UnderstandsNewAndDelete) { Index: clang/lib/Format/Format.cpp =================================================================== --- clang/lib/Format/Format.cpp +++ clang/lib/Format/Format.cpp @@ -18,6 +18,7 @@ #include "ContinuationIndenter.h" #include "DefinitionBlockSeparator.h" #include "FormatInternal.h" +#include "FormatToken.h" #include "FormatTokenLexer.h" #include "NamespaceEndCommentsFixer.h" #include "QualifierAlignmentFixer.h" @@ -1945,6 +1946,17 @@ for (FormatToken *Tok = Line->First; Tok && Tok->Next; Tok = Tok->Next) { if (!Tok->is(TT_PointerOrReference)) continue; + // Don't treat space in `void foo() &&` as evidence. + if (const auto *Prev = Tok->getPreviousNonComment()) { + if (Prev->is(tok::r_paren) && Prev->MatchingParen) { + if (const auto *Func = + Prev->MatchingParen->getPreviousNonComment()) { + if (Func->isOneOf(TT_FunctionDeclarationName, TT_StartOfName, + TT_OverloadedOperator)) + continue; + } + } + } bool SpaceBefore = Tok->hasWhitespaceBefore(); bool SpaceAfter = Tok->Next->hasWhitespaceBefore(); if (SpaceBefore && !SpaceAfter)
Index: clang/unittests/Format/FormatTest.cpp =================================================================== --- clang/unittests/Format/FormatTest.cpp +++ clang/unittests/Format/FormatTest.cpp @@ -9683,6 +9683,25 @@ AlignLeftBreakTemplate); verifyFormat("void (*foopt)(int) = &func;"); + + FormatStyle DerivePointerAlignment = getLLVMStyle(); + DerivePointerAlignment.DerivePointerAlignment = true; + // There's always a space between the function and its trailing qualifiers. + // This isn't evidence for PAS_Right (or for PAS_Left). + std::string Prefix = "void a() &;\n" + "void b() &;\n"; + verifyFormat(Prefix + "int* x;", DerivePointerAlignment); + verifyFormat(Prefix + "int *x;", DerivePointerAlignment); + // Same if the function is an overloaded operator instead. + Prefix = "void operator()() &;\n" + "void operator()() &;\n"; + verifyFormat(Prefix + "int* x;", DerivePointerAlignment); + verifyFormat(Prefix + "int *x;", DerivePointerAlignment); + // However a space between cv-qualifiers and ref-qualifiers *is* evidence. + Prefix = "void a() const &;\n" + "void b() const &;\n"; + EXPECT_EQ(Prefix + "int *x;", + format(Prefix + "int* x;", DerivePointerAlignment)); } TEST_F(FormatTest, UnderstandsNewAndDelete) { Index: clang/lib/Format/Format.cpp =================================================================== --- clang/lib/Format/Format.cpp +++ clang/lib/Format/Format.cpp @@ -18,6 +18,7 @@ #include "ContinuationIndenter.h" #include "DefinitionBlockSeparator.h" #include "FormatInternal.h" +#include "FormatToken.h" #include "FormatTokenLexer.h" #include "NamespaceEndCommentsFixer.h" #include "QualifierAlignmentFixer.h" @@ -1945,6 +1946,17 @@ for (FormatToken *Tok = Line->First; Tok && Tok->Next; Tok = Tok->Next) { if (!Tok->is(TT_PointerOrReference)) continue; + // Don't treat space in `void foo() &&` as evidence. + if (const auto *Prev = Tok->getPreviousNonComment()) { + if (Prev->is(tok::r_paren) && Prev->MatchingParen) { + if (const auto *Func = + Prev->MatchingParen->getPreviousNonComment()) { + if (Func->isOneOf(TT_FunctionDeclarationName, TT_StartOfName, + TT_OverloadedOperator)) + continue; + } + } + } bool SpaceBefore = Tok->hasWhitespaceBefore(); bool SpaceAfter = Tok->Next->hasWhitespaceBefore(); if (SpaceBefore && !SpaceAfter)
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits