From 247613548bac55b47eed88e83d5c8640fd4b200a Mon Sep 17 00:00:00 2001 From: Emilia Dreamer Date: Tue, 6 Sep 2022 12:22:34 +0200 Subject: [PATCH] [clang-format] Change heuristic for locating lambda template arguments Previously, the heuristic was simply to look for template argument- specific keywords, such as typename, class, template and auto that are preceded by a left angle bracket <. This changes the heuristic to instead look for a left angle bracket < preceded by a right square bracket ], since according to the C++ grammar, the template arguments must *directly* follow the introducer. (This sort of check might just end up being *too* aggressive) This patch also adds a bunch more token annotator tests for lambdas, specifically for some of the stranger forms of lambdas now allowed as of C++20 or soon-to-be-allowed as part of C++23. Fixes https://github.com/llvm/llvm-project/issues/57093 This does NOT resolve the FIXME regarding explicit template lists, but perhaps it gets closer Differential Revision: https://reviews.llvm.org/D132295 --- clang/lib/Format/UnwrappedLineParser.cpp | 12 ++-- clang/unittests/Format/FormatTest.cpp | 12 ++++ clang/unittests/Format/TokenAnnotatorTest.cpp | 67 +++++++++++++++++++ 3 files changed, 85 insertions(+), 6 deletions(-) diff --git a/clang/lib/Format/UnwrappedLineParser.cpp b/clang/lib/Format/UnwrappedLineParser.cpp index 02b13be0d92e..7ef1e82d754f 100644 --- a/clang/lib/Format/UnwrappedLineParser.cpp +++ b/clang/lib/Format/UnwrappedLineParser.cpp @@ -2210,21 +2210,21 @@ bool UnwrappedLineParser::tryToParseLambda() { case tok::l_square: parseSquare(); break; + case tok::less: + assert(FormatTok->Previous); + if (FormatTok->Previous->is(tok::r_square)) + InTemplateParameterList = true; + nextToken(); + break; case tok::kw_auto: case tok::kw_class: case tok::kw_template: case tok::kw_typename: - assert(FormatTok->Previous); - if (FormatTok->Previous->is(tok::less)) - InTemplateParameterList = true; - nextToken(); - break; case tok::amp: case tok::star: case tok::kw_const: case tok::kw_constexpr: case tok::comma: - case tok::less: case tok::greater: case tok::identifier: case tok::numeric_constant: diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp index 88c16884d0d8..d3e657b018b7 100644 --- a/clang/unittests/Format/FormatTest.cpp +++ b/clang/unittests/Format/FormatTest.cpp @@ -21730,6 +21730,18 @@ TEST_F(FormatTest, FormatsLambdas) { " g();\n" " }\n" "};\n"); + verifyFormat("auto L = [](T...) {\n" + " {\n" + " f();\n" + " g();\n" + " }\n" + "};"); + verifyFormat("auto L = [](T...) {\n" + " {\n" + " f();\n" + " g();\n" + " }\n" + "};"); // Multiple lambdas in the same parentheses change indentation rules. These // lambdas are forced to start on new lines. diff --git a/clang/unittests/Format/TokenAnnotatorTest.cpp b/clang/unittests/Format/TokenAnnotatorTest.cpp index a839fb29115f..a92d44be34f0 100644 --- a/clang/unittests/Format/TokenAnnotatorTest.cpp +++ b/clang/unittests/Format/TokenAnnotatorTest.cpp @@ -809,18 +809,85 @@ TEST_F(TokenAnnotatorTest, UnderstandsLambdas) { Tokens = annotate("[]() -> auto {}"); ASSERT_EQ(Tokens.size(), 9u) << Tokens; + EXPECT_TOKEN(Tokens[0], tok::l_square, TT_LambdaLSquare); EXPECT_TOKEN(Tokens[4], tok::arrow, TT_LambdaArrow); EXPECT_TOKEN(Tokens[6], tok::l_brace, TT_LambdaLBrace); Tokens = annotate("[]() -> auto & {}"); ASSERT_EQ(Tokens.size(), 10u) << Tokens; + EXPECT_TOKEN(Tokens[0], tok::l_square, TT_LambdaLSquare); EXPECT_TOKEN(Tokens[4], tok::arrow, TT_LambdaArrow); EXPECT_TOKEN(Tokens[7], tok::l_brace, TT_LambdaLBrace); Tokens = annotate("[]() -> auto * {}"); ASSERT_EQ(Tokens.size(), 10u) << Tokens; + EXPECT_TOKEN(Tokens[0], tok::l_square, TT_LambdaLSquare); EXPECT_TOKEN(Tokens[4], tok::arrow, TT_LambdaArrow); EXPECT_TOKEN(Tokens[7], tok::l_brace, TT_LambdaLBrace); + + Tokens = annotate("[] {}"); + ASSERT_EQ(Tokens.size(), 5u) << Tokens; + EXPECT_TOKEN(Tokens[0], tok::l_square, TT_LambdaLSquare); + EXPECT_TOKEN(Tokens[2], tok::l_brace, TT_LambdaLBrace); + + Tokens = annotate("[] noexcept {}"); + ASSERT_EQ(Tokens.size(), 6u) << Tokens; + EXPECT_TOKEN(Tokens[0], tok::l_square, TT_LambdaLSquare); + EXPECT_TOKEN(Tokens[3], tok::l_brace, TT_LambdaLBrace); + + Tokens = annotate("[] -> auto {}"); + ASSERT_EQ(Tokens.size(), 7u) << Tokens; + EXPECT_TOKEN(Tokens[0], tok::l_square, TT_LambdaLSquare); + EXPECT_TOKEN(Tokens[2], tok::arrow, TT_LambdaArrow); + EXPECT_TOKEN(Tokens[4], tok::l_brace, TT_LambdaLBrace); + + Tokens = annotate("[] () {}"); + ASSERT_EQ(Tokens.size(), 11u) << Tokens; + EXPECT_TOKEN(Tokens[0], tok::l_square, TT_LambdaLSquare); + EXPECT_TOKEN(Tokens[2], tok::less, TT_TemplateOpener); + EXPECT_TOKEN(Tokens[8], tok::l_brace, TT_LambdaLBrace); + + Tokens = annotate("[] {}"); + ASSERT_EQ(Tokens.size(), 9u) << Tokens; + EXPECT_TOKEN(Tokens[0], tok::l_square, TT_LambdaLSquare); + EXPECT_TOKEN(Tokens[2], tok::less, TT_TemplateOpener); + EXPECT_TOKEN(Tokens[6], tok::l_brace, TT_LambdaLBrace); + + Tokens = annotate("[] () {}"); + ASSERT_EQ(Tokens.size(), 12u) << Tokens; + EXPECT_TOKEN(Tokens[0], tok::l_square, TT_LambdaLSquare); + EXPECT_TOKEN(Tokens[2], tok::less, TT_TemplateOpener); + EXPECT_TOKEN(Tokens[9], tok::l_brace, TT_LambdaLBrace); + + Tokens = annotate("[] {}"); + ASSERT_EQ(Tokens.size(), 10u) << Tokens; + EXPECT_TOKEN(Tokens[0], tok::l_square, TT_LambdaLSquare); + EXPECT_TOKEN(Tokens[2], tok::less, TT_TemplateOpener); + EXPECT_TOKEN(Tokens[7], tok::l_brace, TT_LambdaLBrace); + + Tokens = annotate("[] () {}"); + ASSERT_EQ(Tokens.size(), 12u) << Tokens; + EXPECT_TOKEN(Tokens[0], tok::l_square, TT_LambdaLSquare); + EXPECT_TOKEN(Tokens[2], tok::less, TT_TemplateOpener); + EXPECT_TOKEN(Tokens[9], tok::l_brace, TT_LambdaLBrace); + + Tokens = annotate("[] {}"); + ASSERT_EQ(Tokens.size(), 10u) << Tokens; + EXPECT_TOKEN(Tokens[0], tok::l_square, TT_LambdaLSquare); + EXPECT_TOKEN(Tokens[2], tok::less, TT_TemplateOpener); + EXPECT_TOKEN(Tokens[7], tok::l_brace, TT_LambdaLBrace); + + Tokens = annotate("[] () {}"); + ASSERT_EQ(Tokens.size(), 12u) << Tokens; + EXPECT_TOKEN(Tokens[0], tok::l_square, TT_LambdaLSquare); + EXPECT_TOKEN(Tokens[2], tok::less, TT_TemplateOpener); + EXPECT_TOKEN(Tokens[9], tok::l_brace, TT_LambdaLBrace); + + Tokens = annotate("[] {}"); + ASSERT_EQ(Tokens.size(), 10u) << Tokens; + EXPECT_TOKEN(Tokens[0], tok::l_square, TT_LambdaLSquare); + EXPECT_TOKEN(Tokens[2], tok::less, TT_TemplateOpener); + EXPECT_TOKEN(Tokens[7], tok::l_brace, TT_LambdaLBrace); } TEST_F(TokenAnnotatorTest, UnderstandsFunctionAnnotations) {