[Format] Don't derive pointers right based on space before method ref-qualifiers

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.

Differential Revision: https://reviews.llvm.org/D118921
This commit is contained in:
Sam McCall
2022-02-03 18:15:49 +01:00
parent 42afaf7f47
commit acc3ce945c
2 changed files with 28 additions and 0 deletions

View File

@@ -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"
@@ -1940,6 +1941,14 @@ private:
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)

View File

@@ -9710,6 +9710,25 @@ TEST_F(FormatTest, UnderstandsFunctionRefQualification) {
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) {