From 2a42a7b4e87395ae2a4321292f0fd9dce401b4e1 Mon Sep 17 00:00:00 2001 From: Owen Pan Date: Thu, 30 Mar 2023 20:16:52 -0700 Subject: [PATCH] [clang-format] Don't misannotate left squares as lambda introducers A left square can start a lambda only if it's not preceded by an identifier other than return and co-wait/co-yield/co-return. Fixes #54245. Fixes #61786. Differential Revision: https://reviews.llvm.org/D147295 --- clang/lib/Format/UnwrappedLineParser.cpp | 12 ++++----- clang/unittests/Format/TokenAnnotatorTest.cpp | 36 +++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 6 deletions(-) diff --git a/clang/lib/Format/UnwrappedLineParser.cpp b/clang/lib/Format/UnwrappedLineParser.cpp index 3a66129..fdf5d85 100644 --- a/clang/lib/Format/UnwrappedLineParser.cpp +++ b/clang/lib/Format/UnwrappedLineParser.cpp @@ -2231,11 +2231,11 @@ bool UnwrappedLineParser::tryToParseLambdaIntroducer() { const FormatToken *Previous = FormatTok->Previous; const FormatToken *LeftSquare = FormatTok; nextToken(); - if (Previous && - (Previous->isOneOf(tok::identifier, tok::kw_operator, tok::kw_new, - tok::kw_delete, tok::l_square) || - LeftSquare->isCppStructuredBinding(Style) || Previous->closesScope() || - Previous->isSimpleTypeSpecifier())) { + if ((Previous && ((Previous->Tok.getIdentifierInfo() && + !Previous->isOneOf(tok::kw_return, tok::kw_co_await, + tok::kw_co_yield, tok::kw_co_return)) || + Previous->closesScope())) || + LeftSquare->isCppStructuredBinding(Style)) { return false; } if (FormatTok->is(tok::l_square)) @@ -3784,7 +3784,7 @@ void UnwrappedLineParser::parseRecord(bool ParseAsExpr) { // Don't try parsing a lambda if we had a closing parenthesis before, // it was probably a pointer to an array: int (*)[]. if (!tryToParseLambda()) - break; + continue; } else { parseSquare(); continue; diff --git a/clang/unittests/Format/TokenAnnotatorTest.cpp b/clang/unittests/Format/TokenAnnotatorTest.cpp index b058e62..bea85e5 100644 --- a/clang/unittests/Format/TokenAnnotatorTest.cpp +++ b/clang/unittests/Format/TokenAnnotatorTest.cpp @@ -382,6 +382,32 @@ TEST_F(TokenAnnotatorTest, UnderstandsStructs) { Tokens = annotate("struct [[deprecated]] [[nodiscard]] C { int i; };"); EXPECT_EQ(Tokens.size(), 19u) << Tokens; EXPECT_TOKEN(Tokens[12], tok::l_brace, TT_StructLBrace); + + Tokens = annotate("template struct S {};"); + EXPECT_EQ(Tokens.size(), 18u) << Tokens; + EXPECT_TOKEN(Tokens[7], tok::less, TT_TemplateOpener); + EXPECT_TOKEN(Tokens[10], tok::l_square, TT_ArraySubscriptLSquare); + EXPECT_TOKEN(Tokens[13], tok::greater, TT_TemplateCloser); + EXPECT_TOKEN(Tokens[14], tok::l_brace, TT_StructLBrace); + + Tokens = annotate("template struct S {};"); + EXPECT_EQ(Tokens.size(), 18u) << Tokens; + EXPECT_TOKEN(Tokens[7], tok::less, TT_TemplateOpener); + EXPECT_TOKEN(Tokens[10], tok::l_square, TT_ArraySubscriptLSquare); + EXPECT_TOKEN(Tokens[13], tok::greater, TT_TemplateCloser); + EXPECT_TOKEN(Tokens[14], tok::l_brace, TT_StructLBrace); + + Tokens = annotate("template struct S {\n" + " void f(T const (&a)[n]);\n" + "};"); + EXPECT_EQ(Tokens.size(), 35u) << Tokens; + EXPECT_TOKEN(Tokens[10], tok::less, TT_TemplateOpener); + EXPECT_TOKEN(Tokens[13], tok::l_square, TT_ArraySubscriptLSquare); + EXPECT_TOKEN(Tokens[16], tok::greater, TT_TemplateCloser); + EXPECT_TOKEN(Tokens[17], tok::l_brace, TT_StructLBrace); + EXPECT_TOKEN(Tokens[23], tok::l_paren, TT_FunctionTypeLParen); + EXPECT_TOKEN(Tokens[24], tok::amp, TT_UnaryOperator); + EXPECT_TOKEN(Tokens[27], tok::l_square, TT_ArraySubscriptLSquare); } TEST_F(TokenAnnotatorTest, UnderstandsUnions) { @@ -1193,6 +1219,16 @@ TEST_F(TokenAnnotatorTest, UnderstandsObjCBlock) { EXPECT_TOKEN(Tokens[9], tok::l_brace, TT_ObjCBlockLBrace); } +TEST_F(TokenAnnotatorTest, UnderstandsObjCMethodExpr) { + auto Tokens = annotate("void f() {\n" + " //\n" + " BOOL a = [b.c n] > 1;\n" + "}"); + EXPECT_EQ(Tokens.size(), 20u) << Tokens; + EXPECT_TOKEN(Tokens[9], tok::l_square, TT_ObjCMethodExpr); + EXPECT_TOKEN(Tokens[15], tok::greater, TT_BinaryOperator); +} + TEST_F(TokenAnnotatorTest, UnderstandsLambdas) { auto Tokens = annotate("[]() constexpr {}"); ASSERT_EQ(Tokens.size(), 8u) << Tokens; -- 2.7.4