Skip to content

Commit

Permalink
[clang-format] Don't misannotate left squares as lambda introducers
Browse files Browse the repository at this point in the history
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
  • Loading branch information
owenca committed Mar 31, 2023
1 parent ba6e747 commit 2a42a7b
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 6 deletions.
12 changes: 6 additions & 6 deletions clang/lib/Format/UnwrappedLineParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down Expand Up @@ -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;
Expand Down
36 changes: 36 additions & 0 deletions clang/unittests/Format/TokenAnnotatorTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 <typename T> struct S<const T[N]> {};");
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 <typename T> struct S<T const[N]> {};");
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 <typename T, unsigned n> struct S<T const[n]> {\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) {
Expand Down Expand Up @@ -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;
Expand Down

0 comments on commit 2a42a7b

Please sign in to comment.