From: Manuel Klimek Date: Tue, 3 Sep 2013 15:10:01 +0000 (+0000) Subject: First step towards correctly formatting lambdas. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=b61a8afba4120f5f1f1af4c7d2a6646a65bd8020;p=clang First step towards correctly formatting lambdas. Implements parsing of lambdas in the UnwrappedLineParser. This introduces the correct line breaks; the formatting of lambda captures are still incorrect, and the braces are also still formatted as if they were braced init lists instead of blocks. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@189818 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Format/UnwrappedLineParser.cpp b/lib/Format/UnwrappedLineParser.cpp index a149c185aa..253dbf97fd 100644 --- a/lib/Format/UnwrappedLineParser.cpp +++ b/lib/Format/UnwrappedLineParser.cpp @@ -640,6 +640,9 @@ void UnwrappedLineParser::parseStructuralElement() { parseBracedList(); } break; + case tok::l_square: + tryToParseLambda(); + break; default: nextToken(); break; @@ -647,6 +650,77 @@ void UnwrappedLineParser::parseStructuralElement() { } while (!eof()); } +void UnwrappedLineParser::tryToParseLambda() { + if (!tryToParseLambdaIntroducer()) { + return; + } + if (FormatTok->is(tok::l_paren)) { + parseParens(); + } + + while (FormatTok->isNot(tok::l_brace)) { + switch (FormatTok->Tok.getKind()) { + case tok::l_brace: + break; + return; + case tok::l_paren: + parseParens(); + break; + case tok::semi: + case tok::equal: + case tok::eof: + return; + default: + nextToken(); + break; + } + } + nextToken(); + { + ScopedLineState LineState(*this); + ScopedDeclarationState DeclarationState(*Line, DeclarationScopeStack, + /*MustBeDeclaration=*/false); + Line->Level += 1; + parseLevel(/*HasOpeningBrace=*/true); + Line->Level -= 1; + } + nextToken(); +} + +bool UnwrappedLineParser::tryToParseLambdaIntroducer() { + nextToken(); + if (FormatTok->is(tok::equal)) { + nextToken(); + if (FormatTok->is(tok::r_square)) return true; + if (FormatTok->isNot(tok::comma)) return false; + nextToken(); + } else if (FormatTok->is(tok::amp)) { + nextToken(); + if (FormatTok->is(tok::r_square)) return true; + if (!FormatTok->isOneOf(tok::comma, tok::identifier)) { + return false; + } + if (FormatTok->is(tok::comma)) nextToken(); + } else if (FormatTok->is(tok::r_square)) { + nextToken(); + return true; + } + do { + if (FormatTok->is(tok::amp)) nextToken(); + if (!FormatTok->isOneOf(tok::identifier, tok::kw_this)) return false; + nextToken(); + if (FormatTok->is(tok::comma)) { + nextToken(); + } else if (FormatTok->is(tok::r_square)) { + nextToken(); + return true; + } else { + return false; + } + } while (!eof()); + return false; +} + bool UnwrappedLineParser::tryToParseBracedList() { if (FormatTok->BlockKind == BK_Unknown) calculateBraceTypes(); @@ -667,6 +741,9 @@ void UnwrappedLineParser::parseBracedList() { // here, otherwise our bail-out scenarios below break. The better solution // might be to just implement a more or less complete expression parser. switch (FormatTok->Tok.getKind()) { + case tok::l_square: + tryToParseLambda(); + break; case tok::l_brace: parseBracedList(); break; @@ -710,6 +787,9 @@ void UnwrappedLineParser::parseReturn() { nextToken(); addUnwrappedLine(); return; + case tok::l_square: + tryToParseLambda(); + break; default: nextToken(); break; diff --git a/lib/Format/UnwrappedLineParser.h b/lib/Format/UnwrappedLineParser.h index d23d157ccc..4660b1dbac 100644 --- a/lib/Format/UnwrappedLineParser.h +++ b/lib/Format/UnwrappedLineParser.h @@ -93,6 +93,8 @@ private: void parseObjCUntilAtEnd(); void parseObjCInterfaceOrImplementation(); void parseObjCProtocol(); + void tryToParseLambda(); + bool tryToParseLambdaIntroducer(); void addUnwrappedLine(); bool eof() const; void nextToken(); diff --git a/unittests/Format/FormatTest.cpp b/unittests/Format/FormatTest.cpp index bdbc1555e4..e9bf2c54fd 100644 --- a/unittests/Format/FormatTest.cpp +++ b/unittests/Format/FormatTest.cpp @@ -3681,7 +3681,7 @@ TEST_F(FormatTest, UnderstandsUsesOfStarAndAmp) { verifyGoogleFormat("return sizeof(int**);"); verifyIndependentOfContext("Type **A = static_cast(P);"); verifyGoogleFormat("Type** A = static_cast(P);"); - verifyFormat("auto a = [](int **&, int ***) {};"); + verifyFormat("auto a = [](int **&, int ***) {\n};"); verifyIndependentOfContext("InvalidRegions[*R] = 0;"); @@ -3865,7 +3865,7 @@ TEST_F(FormatTest, FormatsCasts) { verifyFormat("f(foo).b;"); verifyFormat("f(foo)(b);"); verifyFormat("f(foo)[b];"); - verifyFormat("[](foo) { return 4; }(bar)];"); + verifyFormat("[](foo) {\n return 4;\n}(bar);"); verifyFormat("(*funptr)(foo)[4];"); verifyFormat("funptrs[4](foo)[4];"); verifyFormat("void f(int *);"); @@ -6257,5 +6257,45 @@ TEST_F(FormatTest, FormatsProtocolBufferDefinitions) { "}"); } +TEST_F(FormatTest, FormatsLambdas) { + // FIXME: The formatting is incorrect; this test currently checks that + // parsing of the unwrapped lines doesn't regress. + verifyFormat( + "int c = [b]() mutable {\n" + " return [&b]{\n" + " return b++;\n" + " }();\n" + "}();\n"); + verifyFormat( + "int c = [&]{\n" + " [ = ]{\n" + " return b++;\n" + " }();\n" + "}();\n"); + verifyFormat( + "int c = [ &, &a, a]{\n" + " [ =, c, &d]{\n" + " return b++;\n" + " }();\n" + "}();\n"); + verifyFormat( + "int c = [&a, &a, a]{\n" + " [ =, a, b, &c]{\n" + " return b++;\n" + " }();\n" + "}();\n"); + verifyFormat( + "auto c = {[&a, &a, a]{\n" + " [ =, a, b, &c]{\n" + " return b++;\n" + " }();\n" + "} }\n"); + verifyFormat( + "auto c = {[&a, &a, a]{\n" + " [ =, a, b, &c]{\n" + " }();\n" + "} }\n"); +} + } // end namespace tooling } // end namespace clang