rymiel created this revision. rymiel added a project: clang-format. rymiel added reviewers: HazardyKnusperkeks, owenpan, MyDeveloperDay. Herald added projects: All, clang. Herald added a subscriber: cfe-commits. rymiel requested review of this revision.
The heuristic for determining if an arrow is a trailing return arrow looks for the auto keyword, along with parentheses. This isn't sufficient, since it also triggers on variable declarations with an auto type, and with an arrow operator. This patch unsets the `auto` state when the annotator encounters the equals sign of a variable declaration. Fixes https://github.com/llvm/llvm-project/issues/61469 Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D147377 Files: clang/lib/Format/TokenAnnotator.cpp clang/unittests/Format/TokenAnnotatorTest.cpp Index: clang/unittests/Format/TokenAnnotatorTest.cpp =================================================================== --- clang/unittests/Format/TokenAnnotatorTest.cpp +++ clang/unittests/Format/TokenAnnotatorTest.cpp @@ -1468,6 +1468,72 @@ EXPECT_TOKEN(Tokens[9], tok::colon, TT_GenericSelectionColon); } +TEST_F(TokenAnnotatorTest, UnderstandsTrailingReturnArrow) { + auto Tokens = annotate("auto f() -> int;"); + ASSERT_EQ(Tokens.size(), 8u) << Tokens; + EXPECT_TOKEN(Tokens[4], tok::arrow, TT_TrailingReturnArrow); + + Tokens = annotate("auto operator->() -> int;"); + ASSERT_EQ(Tokens.size(), 9u) << Tokens; + EXPECT_TOKEN(Tokens[2], tok::arrow, TT_OverloadedOperator); + EXPECT_TOKEN(Tokens[5], tok::arrow, TT_TrailingReturnArrow); + + Tokens = annotate("auto operator++(int) -> int;"); + ASSERT_EQ(Tokens.size(), 10u) << Tokens; + EXPECT_TOKEN(Tokens[6], tok::arrow, TT_TrailingReturnArrow); + + Tokens = annotate("auto operator=() -> int;"); + ASSERT_EQ(Tokens.size(), 9u) << Tokens; + EXPECT_TOKEN(Tokens[5], tok::arrow, TT_TrailingReturnArrow); + + Tokens = annotate("auto operator=(int) -> int;"); + ASSERT_EQ(Tokens.size(), 10u) << Tokens; + EXPECT_TOKEN(Tokens[6], tok::arrow, TT_TrailingReturnArrow); + + Tokens = annotate("auto foo() -> auto { return Val; }"); + ASSERT_EQ(Tokens.size(), 12u) << Tokens; + EXPECT_TOKEN(Tokens[4], tok::arrow, TT_TrailingReturnArrow); + + Tokens = annotate("struct S { auto bar() const -> int; };"); + ASSERT_EQ(Tokens.size(), 14u) << Tokens; + EXPECT_TOKEN(Tokens[8], tok::arrow, TT_TrailingReturnArrow); + + // Not trailing return arrows + Tokens = annotate("auto a = b->c;"); + ASSERT_EQ(Tokens.size(), 8u) << Tokens; + EXPECT_TOKEN(Tokens[4], tok::arrow, TT_Unknown); + + Tokens = annotate("auto a = (b)->c;"); + ASSERT_EQ(Tokens.size(), 10u) << Tokens; + EXPECT_TOKEN(Tokens[6], tok::arrow, TT_Unknown); + + Tokens = annotate("auto a = b()->c;"); + ASSERT_EQ(Tokens.size(), 10u) << Tokens; + EXPECT_TOKEN(Tokens[6], tok::arrow, TT_Unknown); + + Tokens = annotate("auto a = b->c();"); + ASSERT_EQ(Tokens.size(), 10u) << Tokens; + EXPECT_TOKEN(Tokens[4], tok::arrow, TT_Unknown); + + Tokens = annotate("decltype(auto) a = b()->c;"); + ASSERT_EQ(Tokens.size(), 13u) << Tokens; + EXPECT_TOKEN(Tokens[9], tok::arrow, TT_Unknown); + + Tokens = annotate("void f() { auto a = b->c(); }"); + ASSERT_EQ(Tokens.size(), 16u) << Tokens; + EXPECT_TOKEN(Tokens[9], tok::arrow, TT_Unknown); + + Tokens = annotate("void f() { auto a = b()->c; }"); + ASSERT_EQ(Tokens.size(), 16u) << Tokens; + EXPECT_TOKEN(Tokens[11], tok::arrow, TT_Unknown); + + // Mixed + Tokens = annotate("auto f() -> int { auto a = b()->c; }"); + ASSERT_EQ(Tokens.size(), 18u) << Tokens; + EXPECT_TOKEN(Tokens[4], tok::arrow, TT_TrailingReturnArrow); + EXPECT_TOKEN(Tokens[13], tok::arrow, TT_Unknown); +} + TEST_F(TokenAnnotatorTest, UnderstandsVerilogOperators) { auto Annotate = [this](llvm::StringRef Code) { return annotate(Code, getLLVMStyle(FormatStyle::LK_Verilog)); Index: clang/lib/Format/TokenAnnotator.cpp =================================================================== --- clang/lib/Format/TokenAnnotator.cpp +++ clang/lib/Format/TokenAnnotator.cpp @@ -1970,6 +1970,12 @@ if (Current.getPrecedence() == prec::Assignment) Contexts.back().VerilogAssignmentFound = true; } + if (AutoFound && Current.is(tok::equal) && Current.Previous && + Current.Previous->isNot(tok::kw_operator)) { + // AutoFound is only used for function declarations with `auto`. This + // looks like a variable declaration, so unset it. + AutoFound = false; + } Current.setType(TT_BinaryOperator); } else if (Current.is(tok::comment)) { if (Current.TokenText.startswith("/*")) {
Index: clang/unittests/Format/TokenAnnotatorTest.cpp =================================================================== --- clang/unittests/Format/TokenAnnotatorTest.cpp +++ clang/unittests/Format/TokenAnnotatorTest.cpp @@ -1468,6 +1468,72 @@ EXPECT_TOKEN(Tokens[9], tok::colon, TT_GenericSelectionColon); } +TEST_F(TokenAnnotatorTest, UnderstandsTrailingReturnArrow) { + auto Tokens = annotate("auto f() -> int;"); + ASSERT_EQ(Tokens.size(), 8u) << Tokens; + EXPECT_TOKEN(Tokens[4], tok::arrow, TT_TrailingReturnArrow); + + Tokens = annotate("auto operator->() -> int;"); + ASSERT_EQ(Tokens.size(), 9u) << Tokens; + EXPECT_TOKEN(Tokens[2], tok::arrow, TT_OverloadedOperator); + EXPECT_TOKEN(Tokens[5], tok::arrow, TT_TrailingReturnArrow); + + Tokens = annotate("auto operator++(int) -> int;"); + ASSERT_EQ(Tokens.size(), 10u) << Tokens; + EXPECT_TOKEN(Tokens[6], tok::arrow, TT_TrailingReturnArrow); + + Tokens = annotate("auto operator=() -> int;"); + ASSERT_EQ(Tokens.size(), 9u) << Tokens; + EXPECT_TOKEN(Tokens[5], tok::arrow, TT_TrailingReturnArrow); + + Tokens = annotate("auto operator=(int) -> int;"); + ASSERT_EQ(Tokens.size(), 10u) << Tokens; + EXPECT_TOKEN(Tokens[6], tok::arrow, TT_TrailingReturnArrow); + + Tokens = annotate("auto foo() -> auto { return Val; }"); + ASSERT_EQ(Tokens.size(), 12u) << Tokens; + EXPECT_TOKEN(Tokens[4], tok::arrow, TT_TrailingReturnArrow); + + Tokens = annotate("struct S { auto bar() const -> int; };"); + ASSERT_EQ(Tokens.size(), 14u) << Tokens; + EXPECT_TOKEN(Tokens[8], tok::arrow, TT_TrailingReturnArrow); + + // Not trailing return arrows + Tokens = annotate("auto a = b->c;"); + ASSERT_EQ(Tokens.size(), 8u) << Tokens; + EXPECT_TOKEN(Tokens[4], tok::arrow, TT_Unknown); + + Tokens = annotate("auto a = (b)->c;"); + ASSERT_EQ(Tokens.size(), 10u) << Tokens; + EXPECT_TOKEN(Tokens[6], tok::arrow, TT_Unknown); + + Tokens = annotate("auto a = b()->c;"); + ASSERT_EQ(Tokens.size(), 10u) << Tokens; + EXPECT_TOKEN(Tokens[6], tok::arrow, TT_Unknown); + + Tokens = annotate("auto a = b->c();"); + ASSERT_EQ(Tokens.size(), 10u) << Tokens; + EXPECT_TOKEN(Tokens[4], tok::arrow, TT_Unknown); + + Tokens = annotate("decltype(auto) a = b()->c;"); + ASSERT_EQ(Tokens.size(), 13u) << Tokens; + EXPECT_TOKEN(Tokens[9], tok::arrow, TT_Unknown); + + Tokens = annotate("void f() { auto a = b->c(); }"); + ASSERT_EQ(Tokens.size(), 16u) << Tokens; + EXPECT_TOKEN(Tokens[9], tok::arrow, TT_Unknown); + + Tokens = annotate("void f() { auto a = b()->c; }"); + ASSERT_EQ(Tokens.size(), 16u) << Tokens; + EXPECT_TOKEN(Tokens[11], tok::arrow, TT_Unknown); + + // Mixed + Tokens = annotate("auto f() -> int { auto a = b()->c; }"); + ASSERT_EQ(Tokens.size(), 18u) << Tokens; + EXPECT_TOKEN(Tokens[4], tok::arrow, TT_TrailingReturnArrow); + EXPECT_TOKEN(Tokens[13], tok::arrow, TT_Unknown); +} + TEST_F(TokenAnnotatorTest, UnderstandsVerilogOperators) { auto Annotate = [this](llvm::StringRef Code) { return annotate(Code, getLLVMStyle(FormatStyle::LK_Verilog)); Index: clang/lib/Format/TokenAnnotator.cpp =================================================================== --- clang/lib/Format/TokenAnnotator.cpp +++ clang/lib/Format/TokenAnnotator.cpp @@ -1970,6 +1970,12 @@ if (Current.getPrecedence() == prec::Assignment) Contexts.back().VerilogAssignmentFound = true; } + if (AutoFound && Current.is(tok::equal) && Current.Previous && + Current.Previous->isNot(tok::kw_operator)) { + // AutoFound is only used for function declarations with `auto`. This + // looks like a variable declaration, so unset it. + AutoFound = false; + } Current.setType(TT_BinaryOperator); } else if (Current.is(tok::comment)) { if (Current.TokenText.startswith("/*")) {
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits