[clang] 3f3620e - [clang-format] Correctly annotate */&/&& in operator function calls
Owen Pan via cfe-commits
cfe-commits at lists.llvm.org
Mon Jul 3 17:49:18 PDT 2023
Author: Owen Pan
Date: 2023-07-03T17:49:10-07:00
New Revision: 3f3620e5c9ee0f7b64afc39e5a26c6f4cc5e7b37
URL: https://github.com/llvm/llvm-project/commit/3f3620e5c9ee0f7b64afc39e5a26c6f4cc5e7b37
DIFF: https://github.com/llvm/llvm-project/commit/3f3620e5c9ee0f7b64afc39e5a26c6f4cc5e7b37.diff
LOG: [clang-format] Correctly annotate */&/&& in operator function calls
Reverts 4986f3f2f220 (but keeps its unit tests) and fixes #49973
differently.
Also fixes bugs that incorrectly annotate the operator keyword as
TT_FunctionDeclarationName in function calls and as TT_Unknown in function
declarations and definitions.
Differential Revision: https://reviews.llvm.org/D154184
Added:
Modified:
clang/lib/Format/TokenAnnotator.cpp
clang/unittests/Format/FormatTest.cpp
clang/unittests/Format/TokenAnnotatorTest.cpp
Removed:
################################################################################
diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp
index 735089f1ad9d7a..5536c89ae1067d 100644
--- a/clang/lib/Format/TokenAnnotator.cpp
+++ b/clang/lib/Format/TokenAnnotator.cpp
@@ -310,14 +310,9 @@ class AnnotatingParser {
// If faced with "a.operator*(argument)" or "a->operator*(argument)",
// i.e. the operator is called as a member function,
// then the argument must be an expression.
- // If faced with "operator+(argument)", i.e. the operator is called as
- // a free function, then the argument is an expression only if the current
- // line can't be a declaration.
- bool IsOperatorCallSite =
- (Prev->Previous &&
- Prev->Previous->isOneOf(tok::period, tok::arrow)) ||
- (!Line.MustBeDeclaration && !Line.InMacroBody);
- Contexts.back().IsExpression = IsOperatorCallSite;
+ bool OperatorCalledAsMemberFunction =
+ Prev->Previous && Prev->Previous->isOneOf(tok::period, tok::arrow);
+ Contexts.back().IsExpression = OperatorCalledAsMemberFunction;
} else if (OpeningParen.is(TT_VerilogInstancePortLParen)) {
Contexts.back().IsExpression = true;
Contexts.back().ContextType = Context::VerilogInstancePortList;
@@ -3133,6 +3128,7 @@ void TokenAnnotator::annotate(AnnotatedLine &Line) {
// function declaration.
static bool isFunctionDeclarationName(bool IsCpp, const FormatToken &Current,
const AnnotatedLine &Line) {
+ assert(Current.Previous);
auto skipOperatorName = [](const FormatToken *Next) -> const FormatToken * {
for (; Next; Next = Next->Next) {
if (Next->is(TT_OverloadedOperatorLParen))
@@ -3171,7 +3167,12 @@ static bool isFunctionDeclarationName(bool IsCpp, const FormatToken &Current,
// Find parentheses of parameter list.
const FormatToken *Next = Current.Next;
if (Current.is(tok::kw_operator)) {
- if (Current.Previous && Current.Previous->is(tok::coloncolon))
+ const auto *Previous = Current.Previous;
+ if (Previous->Tok.getIdentifierInfo() &&
+ !Previous->isOneOf(tok::kw_return, tok::kw_co_return)) {
+ return true;
+ }
+ if (!Previous->isOneOf(tok::star, tok::amp, tok::ampamp))
return false;
Next = skipOperatorName(Next);
} else {
@@ -3302,9 +3303,11 @@ void TokenAnnotator::calculateFormattingInformation(AnnotatedLine &Line) const {
if (AlignArrayOfStructures)
calculateArrayInitializerColumnList(Line);
+ bool LineIsFunctionDeclaration = false;
for (FormatToken *Tok = Current, *AfterLastAttribute = nullptr; Tok;
Tok = Tok->Next) {
if (isFunctionDeclarationName(Style.isCpp(), *Tok, Line)) {
+ LineIsFunctionDeclaration = true;
Tok->setType(TT_FunctionDeclarationName);
if (AfterLastAttribute &&
mustBreakAfterAttributes(*AfterLastAttribute, Style)) {
@@ -3317,6 +3320,33 @@ void TokenAnnotator::calculateFormattingInformation(AnnotatedLine &Line) const {
AfterLastAttribute = Tok;
}
+ 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)
+ continue;
+ Next->setType(TT_BinaryOperator);
+ Tok = Next;
+ }
+ }
+ }
+
while (Current) {
const FormatToken *Prev = Current->Previous;
if (Current->is(TT_LineComment)) {
diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp
index e1e97197617237..a4f2b8300a2735 100644
--- a/clang/unittests/Format/FormatTest.cpp
+++ b/clang/unittests/Format/FormatTest.cpp
@@ -11580,13 +11580,11 @@ TEST_F(FormatTest, UnderstandsUsesOfStarAndAmp) {
" }",
getLLVMStyleWithColumns(50)));
-// FIXME: We should be able to figure out this is an operator call
-#if 0
verifyFormat("#define FOO \\\n"
" void foo() { \\\n"
" operator+(a * b); \\\n"
- " }", getLLVMStyleWithColumns(25));
-#endif
+ " }",
+ getLLVMStyleWithColumns(25));
// FIXME: We cannot handle this case yet; we might be able to figure out that
// foo<x> d > v; doesn't make sense.
diff --git a/clang/unittests/Format/TokenAnnotatorTest.cpp b/clang/unittests/Format/TokenAnnotatorTest.cpp
index b6fbe7380d5d2e..8767b97c94de27 100644
--- a/clang/unittests/Format/TokenAnnotatorTest.cpp
+++ b/clang/unittests/Format/TokenAnnotatorTest.cpp
@@ -594,61 +594,59 @@ TEST_F(TokenAnnotatorTest, UnderstandsFunctionRefQualifiers) {
TEST_F(TokenAnnotatorTest, UnderstandsOverloadedOperators) {
auto Tokens = annotate("x.operator+()");
ASSERT_EQ(Tokens.size(), 7u) << Tokens;
- EXPECT_TOKEN(Tokens[2], tok::kw_operator, TT_FunctionDeclarationName);
+ EXPECT_TOKEN(Tokens[2], tok::kw_operator, TT_Unknown);
EXPECT_TOKEN(Tokens[3], tok::plus, TT_OverloadedOperator);
EXPECT_TOKEN(Tokens[4], tok::l_paren, TT_OverloadedOperatorLParen);
Tokens = annotate("x.operator=()");
ASSERT_EQ(Tokens.size(), 7u) << Tokens;
- EXPECT_TOKEN(Tokens[2], tok::kw_operator, TT_FunctionDeclarationName);
+ EXPECT_TOKEN(Tokens[2], tok::kw_operator, TT_Unknown);
EXPECT_TOKEN(Tokens[3], tok::equal, TT_OverloadedOperator);
EXPECT_TOKEN(Tokens[4], tok::l_paren, TT_OverloadedOperatorLParen);
Tokens = annotate("x.operator+=()");
ASSERT_EQ(Tokens.size(), 7u) << Tokens;
- EXPECT_TOKEN(Tokens[2], tok::kw_operator, TT_FunctionDeclarationName);
+ EXPECT_TOKEN(Tokens[2], tok::kw_operator, TT_Unknown);
EXPECT_TOKEN(Tokens[3], tok::plusequal, TT_OverloadedOperator);
EXPECT_TOKEN(Tokens[4], tok::l_paren, TT_OverloadedOperatorLParen);
Tokens = annotate("x.operator,()");
ASSERT_EQ(Tokens.size(), 7u) << Tokens;
- EXPECT_TOKEN(Tokens[2], tok::kw_operator, TT_FunctionDeclarationName);
+ EXPECT_TOKEN(Tokens[2], tok::kw_operator, TT_Unknown);
EXPECT_TOKEN(Tokens[3], tok::comma, TT_OverloadedOperator);
EXPECT_TOKEN(Tokens[4], tok::l_paren, TT_OverloadedOperatorLParen);
Tokens = annotate("x.operator()()");
ASSERT_EQ(Tokens.size(), 8u) << Tokens;
- EXPECT_TOKEN(Tokens[2], tok::kw_operator, TT_FunctionDeclarationName);
+ EXPECT_TOKEN(Tokens[2], tok::kw_operator, TT_Unknown);
EXPECT_TOKEN(Tokens[3], tok::l_paren, TT_OverloadedOperator);
EXPECT_TOKEN(Tokens[4], tok::r_paren, TT_OverloadedOperator);
EXPECT_TOKEN(Tokens[5], tok::l_paren, TT_OverloadedOperatorLParen);
Tokens = annotate("x.operator[]()");
ASSERT_EQ(Tokens.size(), 8u) << Tokens;
- EXPECT_TOKEN(Tokens[2], tok::kw_operator, TT_FunctionDeclarationName);
+ EXPECT_TOKEN(Tokens[2], tok::kw_operator, TT_Unknown);
// EXPECT_TOKEN(Tokens[3], tok::l_square, TT_OverloadedOperator);
// EXPECT_TOKEN(Tokens[4], tok::r_square, TT_OverloadedOperator);
EXPECT_TOKEN(Tokens[5], tok::l_paren, TT_OverloadedOperatorLParen);
Tokens = annotate("x.operator\"\"_a()");
ASSERT_EQ(Tokens.size(), 7u) << Tokens;
- EXPECT_TOKEN(Tokens[2], tok::kw_operator, TT_FunctionDeclarationName);
+ EXPECT_TOKEN(Tokens[2], tok::kw_operator, TT_Unknown);
EXPECT_TOKEN(Tokens[3], tok::string_literal, TT_OverloadedOperator);
EXPECT_TOKEN(Tokens[4], tok::l_paren, TT_OverloadedOperatorLParen);
Tokens = annotate("x.operator\"\" _a()");
ASSERT_EQ(Tokens.size(), 8u) << Tokens;
- // FIXME
- // EXPECT_TOKEN(Tokens[2], tok::kw_operator, TT_FunctionDeclarationName);
+ EXPECT_TOKEN(Tokens[2], tok::kw_operator, TT_Unknown);
EXPECT_TOKEN(Tokens[3], tok::string_literal, TT_OverloadedOperator);
EXPECT_TOKEN(Tokens[5], tok::l_paren, TT_OverloadedOperatorLParen);
Tokens = annotate("x.operator\"\"if()");
ASSERT_EQ(Tokens.size(), 7u) << Tokens;
- EXPECT_TOKEN(Tokens[2], tok::kw_operator, TT_FunctionDeclarationName);
+ EXPECT_TOKEN(Tokens[2], tok::kw_operator, TT_Unknown);
EXPECT_TOKEN(Tokens[3], tok::string_literal, TT_OverloadedOperator);
EXPECT_TOKEN(Tokens[4], tok::l_paren, TT_OverloadedOperatorLParen);
Tokens = annotate("x.operator\"\"s()");
ASSERT_EQ(Tokens.size(), 7u) << Tokens;
- EXPECT_TOKEN(Tokens[2], tok::kw_operator, TT_FunctionDeclarationName);
+ EXPECT_TOKEN(Tokens[2], tok::kw_operator, TT_Unknown);
EXPECT_TOKEN(Tokens[3], tok::string_literal, TT_OverloadedOperator);
EXPECT_TOKEN(Tokens[4], tok::l_paren, TT_OverloadedOperatorLParen);
Tokens = annotate("x.operator\"\" s()");
ASSERT_EQ(Tokens.size(), 8u) << Tokens;
- // FIXME
- // EXPECT_TOKEN(Tokens[2], tok::kw_operator, TT_FunctionDeclarationName);
+ EXPECT_TOKEN(Tokens[2], tok::kw_operator, TT_Unknown);
EXPECT_TOKEN(Tokens[3], tok::string_literal, TT_OverloadedOperator);
EXPECT_TOKEN(Tokens[5], tok::l_paren, TT_OverloadedOperatorLParen);
@@ -678,20 +676,44 @@ TEST_F(TokenAnnotatorTest, UnderstandsOverloadedOperators) {
EXPECT_TOKEN(Tokens[6], tok::l_paren, TT_OverloadedOperatorLParen);
EXPECT_TOKEN(Tokens[8], tok::star, TT_PointerOrReference);
+ Tokens = annotate("class Foo {\n"
+ " int c = operator+(a * b);\n"
+ "}");
+ ASSERT_EQ(Tokens.size(), 16u) << Tokens;
+ EXPECT_TOKEN(Tokens[6], tok::kw_operator, TT_Unknown);
+ EXPECT_TOKEN(Tokens[7], tok::plus, TT_OverloadedOperator);
+ EXPECT_TOKEN(Tokens[8], tok::l_paren, TT_OverloadedOperatorLParen);
+ EXPECT_TOKEN(Tokens[10], tok::star, TT_BinaryOperator);
+
Tokens = annotate("void foo() {\n"
" operator+(a * b);\n"
"}");
ASSERT_EQ(Tokens.size(), 15u) << Tokens;
+ EXPECT_TOKEN(Tokens[5], tok::kw_operator, TT_Unknown);
EXPECT_TOKEN(Tokens[6], tok::plus, TT_OverloadedOperator);
EXPECT_TOKEN(Tokens[7], tok::l_paren, TT_OverloadedOperatorLParen);
EXPECT_TOKEN(Tokens[9], tok::star, TT_BinaryOperator);
+ Tokens = annotate("return operator+(a * b, c & d) + operator+(a && b && c);");
+ ASSERT_EQ(Tokens.size(), 24u) << Tokens;
+ EXPECT_TOKEN(Tokens[1], tok::kw_operator, TT_Unknown);
+ EXPECT_TOKEN(Tokens[2], tok::plus, TT_OverloadedOperator);
+ EXPECT_TOKEN(Tokens[3], tok::l_paren, TT_OverloadedOperatorLParen);
+ EXPECT_TOKEN(Tokens[5], tok::star, TT_BinaryOperator);
+ EXPECT_TOKEN(Tokens[9], tok::amp, TT_BinaryOperator);
+ EXPECT_TOKEN(Tokens[13], tok::kw_operator, TT_Unknown);
+ EXPECT_TOKEN(Tokens[14], tok::plus, TT_OverloadedOperator);
+ EXPECT_TOKEN(Tokens[15], tok::l_paren, TT_OverloadedOperatorLParen);
+ EXPECT_TOKEN(Tokens[17], tok::ampamp, TT_BinaryOperator);
+ EXPECT_TOKEN(Tokens[19], tok::ampamp, TT_BinaryOperator);
+
Tokens = annotate("class Foo {\n"
" void foo() {\n"
" operator+(a * b);\n"
" }\n"
"}");
ASSERT_EQ(Tokens.size(), 19u) << Tokens;
+ EXPECT_TOKEN(Tokens[8], tok::kw_operator, TT_Unknown);
EXPECT_TOKEN(Tokens[9], tok::plus, TT_OverloadedOperator);
EXPECT_TOKEN(Tokens[10], tok::l_paren, TT_OverloadedOperatorLParen);
EXPECT_TOKEN(Tokens[12], tok::star, TT_BinaryOperator);
More information about the cfe-commits
mailing list