From: Nico Weber Date: Fri, 13 Sep 2019 13:18:55 +0000 (+0000) Subject: clang-format: Add support for formatting (some) lambdas with explicit template parame... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=e7ad04375483f262116f29730feaa0e2b4af4e47;p=clang clang-format: Add support for formatting (some) lambdas with explicit template parameters. This patch makes cases work where the lambda's template list doesn't contain any of + - ! ~ / % << | || && ^ == != >= <= ? : true false (see added FIXME). Ports r359967 to clang-format. Differential Revision: https://reviews.llvm.org/D67246 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@371854 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Format/TokenAnnotator.cpp b/lib/Format/TokenAnnotator.cpp index 55ab654f96..9802711834 100644 --- a/lib/Format/TokenAnnotator.cpp +++ b/lib/Format/TokenAnnotator.cpp @@ -40,6 +40,21 @@ static bool canBeObjCSelectorComponent(const FormatToken &Tok) { return Tok.Tok.getIdentifierInfo() != nullptr; } +/// With `Left` being '(', check if we're at either `[...](` or +/// `[...]<...>(`, where the [ opens a lambda capture list. +static bool isLambdaParameterList(const FormatToken *Left) { + // Skip <...> if present. + if (Left->Previous && Left->Previous->is(tok::greater) && + Left->Previous->MatchingParen && + Left->Previous->MatchingParen->is(TT_TemplateOpener)) + Left = Left->Previous->MatchingParen; + + // Check for `[...]`. + return Left->Previous && Left->Previous->is(tok::r_square) && + Left->Previous->MatchingParen && + Left->Previous->MatchingParen->is(TT_LambdaLSquare); +} + /// A parser that gathers additional information about tokens. /// /// The \c TokenAnnotator tries to match parenthesis and square brakets and @@ -191,9 +206,7 @@ private: Left->Previous->is(TT_JsTypeColon)) { // let x: (SomeType); Contexts.back().IsExpression = false; - } else if (Left->Previous && Left->Previous->is(tok::r_square) && - Left->Previous->MatchingParen && - Left->Previous->MatchingParen->is(TT_LambdaLSquare)) { + } else if (isLambdaParameterList(Left)) { // This is a parameter list of a lambda expression. Contexts.back().IsExpression = false; } else if (Line.InPPDirective && diff --git a/lib/Format/UnwrappedLineParser.cpp b/lib/Format/UnwrappedLineParser.cpp index e552a055b0..8fd0e9433b 100644 --- a/lib/Format/UnwrappedLineParser.cpp +++ b/lib/Format/UnwrappedLineParser.cpp @@ -1440,8 +1440,11 @@ bool UnwrappedLineParser::tryToParseLambda() { case tok::identifier: case tok::numeric_constant: case tok::coloncolon: + case tok::kw_class: case tok::kw_mutable: case tok::kw_noexcept: + case tok::kw_template: + case tok::kw_typename: nextToken(); break; // Specialization of a template with an integer parameter can contain @@ -1455,6 +1458,9 @@ bool UnwrappedLineParser::tryToParseLambda() { // followed by an `a->b` expression, such as: // ([obj func:arg] + a->b) // Otherwise the code below would parse as a lambda. + // + // FIXME: This heuristic is incorrect for C++20 generic lambdas with + // explicit template lists: [](U &&u){} case tok::plus: case tok::minus: case tok::exclaim: diff --git a/unittests/Format/FormatTest.cpp b/unittests/Format/FormatTest.cpp index f1a1160fa1..b1fcd39a49 100644 --- a/unittests/Format/FormatTest.cpp +++ b/unittests/Format/FormatTest.cpp @@ -12923,6 +12923,10 @@ TEST_F(FormatTest, FormatsLambdas) { " return 1; //\n" "};"); + // Lambdas with explicit template argument lists. + verifyFormat( + "auto L = []