Skip to content

Commit

Permalink
[clang-format] Fix a bug in mis-annotating arrows (#67780)
Browse files Browse the repository at this point in the history
Fixed #66923.
  • Loading branch information
owenca committed Oct 2, 2023
1 parent 75441a6 commit c83d64f
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 31 deletions.
72 changes: 41 additions & 31 deletions clang/lib/Format/TokenAnnotator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2016,8 +2016,7 @@ class AnnotatingParser {
Style.Language == FormatStyle::LK_Java) {
Current.setType(TT_LambdaArrow);
} else if (Current.is(tok::arrow) && AutoFound &&
(Line.MightBeFunctionDecl || Line.InPPDirective) &&
Current.NestingLevel == 0 &&
Line.MightBeFunctionDecl && Current.NestingLevel == 0 &&
!Current.Previous->isOneOf(tok::kw_operator, tok::identifier)) {
// not auto operator->() -> xxx;
Current.setType(TT_TrailingReturnArrow);
Expand Down Expand Up @@ -3252,7 +3251,8 @@ void TokenAnnotator::annotate(AnnotatedLine &Line) {
// This function heuristically determines whether 'Current' starts the name of a
// function declaration.
static bool isFunctionDeclarationName(bool IsCpp, const FormatToken &Current,
const AnnotatedLine &Line) {
const AnnotatedLine &Line,
FormatToken *&ClosingParen) {
assert(Current.Previous);

if (Current.is(TT_FunctionDeclarationName))
Expand Down Expand Up @@ -3344,16 +3344,16 @@ static bool isFunctionDeclarationName(bool IsCpp, const FormatToken &Current,
// Check whether parameter list can belong to a function declaration.
if (!Next || Next->isNot(tok::l_paren) || !Next->MatchingParen)
return false;
ClosingParen = Next->MatchingParen;
assert(ClosingParen->is(tok::r_paren));
// If the lines ends with "{", this is likely a function definition.
if (Line.Last->is(tok::l_brace))
return true;
if (Next->Next == Next->MatchingParen)
if (Next->Next == ClosingParen)
return true; // Empty parentheses.
// If there is an &/&& after the r_paren, this is likely a function.
if (Next->MatchingParen->Next &&
Next->MatchingParen->Next->is(TT_PointerOrReference)) {
if (ClosingParen->Next && ClosingParen->Next->is(TT_PointerOrReference))
return true;
}

// Check for K&R C function definitions (and C++ function definitions with
// unnamed parameters), e.g.:
Expand All @@ -3370,7 +3370,7 @@ static bool isFunctionDeclarationName(bool IsCpp, const FormatToken &Current,
return true;
}

for (const FormatToken *Tok = Next->Next; Tok && Tok != Next->MatchingParen;
for (const FormatToken *Tok = Next->Next; Tok && Tok != ClosingParen;
Tok = Tok->Next) {
if (Tok->is(TT_TypeDeclarationParen))
return true;
Expand Down Expand Up @@ -3442,11 +3442,12 @@ void TokenAnnotator::calculateFormattingInformation(AnnotatedLine &Line) const {
calculateArrayInitializerColumnList(Line);

bool LineIsFunctionDeclaration = false;
FormatToken *ClosingParen = nullptr;
for (FormatToken *Tok = Current, *AfterLastAttribute = nullptr; Tok;
Tok = Tok->Next) {
if (Tok->Previous->EndsCppAttributeGroup)
AfterLastAttribute = Tok;
if (isFunctionDeclarationName(Style.isCpp(), *Tok, Line)) {
if (isFunctionDeclarationName(Style.isCpp(), *Tok, Line, ClosingParen)) {
LineIsFunctionDeclaration = true;
Tok->setFinalizedType(TT_FunctionDeclarationName);
if (AfterLastAttribute &&
Expand All @@ -3458,29 +3459,38 @@ void TokenAnnotator::calculateFormattingInformation(AnnotatedLine &Line) const {
}
}

if (Style.isCpp() && !LineIsFunctionDeclaration) {
// Annotate */&/&& in `operator` function calls as binary operators.
for (const auto *Tok = Line.First; Tok; Tok = Tok->Next) {
if (Tok->isNot(tok::kw_operator))
continue;
do {
Tok = Tok->Next;
} while (Tok && Tok->isNot(TT_OverloadedOperatorLParen));
if (!Tok)
break;
const auto *LeftParen = Tok;
for (Tok = Tok->Next; Tok && Tok != LeftParen->MatchingParen;
Tok = Tok->Next) {
if (Tok->isNot(tok::identifier))
continue;
auto *Next = Tok->Next;
const bool NextIsBinaryOperator =
Next && Next->isOneOf(tok::star, tok::amp, tok::ampamp) &&
Next->Next && Next->Next->is(tok::identifier);
if (!NextIsBinaryOperator)
if (Style.isCpp()) {
if (!LineIsFunctionDeclaration) {
// Annotate */&/&& in `operator` function calls as binary operators.
for (const auto *Tok = Line.First; Tok; Tok = Tok->Next) {
if (Tok->isNot(tok::kw_operator))
continue;
Next->setType(TT_BinaryOperator);
Tok = Next;
do {
Tok = Tok->Next;
} while (Tok && Tok->isNot(TT_OverloadedOperatorLParen));
if (!Tok)
break;
const auto *LeftParen = Tok;
for (Tok = Tok->Next; Tok && Tok != LeftParen->MatchingParen;
Tok = Tok->Next) {
if (Tok->isNot(tok::identifier))
continue;
auto *Next = Tok->Next;
const bool NextIsBinaryOperator =
Next && Next->isOneOf(tok::star, tok::amp, tok::ampamp) &&
Next->Next && Next->Next->is(tok::identifier);
if (!NextIsBinaryOperator)
continue;
Next->setType(TT_BinaryOperator);
Tok = Next;
}
}
} else if (ClosingParen) {
for (auto *Tok = ClosingParen->Next; Tok; Tok = Tok->Next) {
if (Tok->is(tok::arrow)) {
Tok->setType(TT_TrailingReturnArrow);
break;
}
}
}
}
Expand Down
4 changes: 4 additions & 0 deletions clang/unittests/Format/TokenAnnotatorTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1759,6 +1759,10 @@ TEST_F(TokenAnnotatorTest, UnderstandsTrailingReturnArrow) {
ASSERT_EQ(Tokens.size(), 16u) << Tokens;
EXPECT_TOKEN(Tokens[11], tok::arrow, TT_Unknown);

Tokens = annotate("#define P(ptr) auto p = (ptr)->p");
ASSERT_EQ(Tokens.size(), 15u) << Tokens;
EXPECT_TOKEN(Tokens[12], tok::arrow, TT_Unknown);

// Mixed
Tokens = annotate("auto f() -> int { auto a = b()->c; }");
ASSERT_EQ(Tokens.size(), 18u) << Tokens;
Expand Down

0 comments on commit c83d64f

Please sign in to comment.