From: Manuel Klimek Date: Wed, 20 Sep 2017 09:29:37 +0000 (+0000) Subject: Fix clang-format's detection of structured bindings. X-Git-Tag: llvmorg-6.0.0-rc1~7628 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=e411aa85acffbd8da2ea332e6acf86b7f6804192;p=platform%2Fupstream%2Fllvm.git Fix clang-format's detection of structured bindings. Correctly determine when [ is part of a structured binding instead of a lambda. To be able to reuse the implementation already available, this patch also: - sets the Previous link of FormatTokens in the UnwrappedLineParser - moves the isCppStructuredBinding function into FormatToken Before: auto const const &&[x, y] { A *i }; After: auto const const && [x, y]{A * i}; Fixing formatting of the type of the structured binding is still missing. llvm-svn: 313742 --- diff --git a/clang/lib/Format/FormatToken.h b/clang/lib/Format/FormatToken.h index 9fa0e44..92444f6 100644 --- a/clang/lib/Format/FormatToken.h +++ b/clang/lib/Format/FormatToken.h @@ -472,6 +472,19 @@ struct FormatToken { Style.Language == FormatStyle::LK_TextProto)); } + /// \brief Returns whether the token is the left square bracket of a C++ + /// structured binding declaration. + bool isCppStructuredBinding(const FormatStyle &Style) const { + if (!Style.isCpp() || isNot(tok::l_square)) + return false; + const FormatToken* T = this; + do { + T = T->getPreviousNonComment(); + } while (T && T->isOneOf(tok::kw_const, tok::kw_volatile, tok::amp, + tok::ampamp)); + return T && T->is(tok::kw_auto); + } + /// \brief Same as opensBlockOrBlockTypeList, but for the closing token. bool closesBlockOrBlockTypeList(const FormatStyle &Style) const { if (is(TT_TemplateString) && closesScope()) diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp index 79fa5a7..1ef0cf8 100644 --- a/clang/lib/Format/TokenAnnotator.cpp +++ b/clang/lib/Format/TokenAnnotator.cpp @@ -310,16 +310,6 @@ private: return false; } - bool isCppStructuredBinding(const FormatToken *Tok) { - if (!Style.isCpp() || !Tok->is(tok::l_square)) - return false; - do { - Tok = Tok->getPreviousNonComment(); - } while (Tok && Tok->isOneOf(tok::kw_const, tok::kw_volatile, tok::amp, - tok::ampamp)); - return Tok && Tok->is(tok::kw_auto); - } - bool parseSquare() { if (!CurrentToken) return false; @@ -354,7 +344,7 @@ private: unsigned BindingIncrease = 1; if (Left->is(TT_Unknown)) { - if (isCppStructuredBinding(Left)) { + if (Left->isCppStructuredBinding(Style)) { Left->Type = TT_StructuredBindingLSquare; } else if (StartsObjCMethodExpr) { Left->Type = TT_ObjCMethodExpr; diff --git a/clang/lib/Format/UnwrappedLineParser.cpp b/clang/lib/Format/UnwrappedLineParser.cpp index 8722d80..1e6a6aa 100644 --- a/clang/lib/Format/UnwrappedLineParser.cpp +++ b/clang/lib/Format/UnwrappedLineParser.cpp @@ -356,7 +356,7 @@ void UnwrappedLineParser::calculateBraceTypes(bool ExpectClassBody) { // definitions, too. unsigned StoredPosition = Tokens->getPosition(); FormatToken *Tok = FormatTok; - const FormatToken *PrevTok = getPreviousToken(); + const FormatToken *PrevTok = Tok->Previous; // Keep a stack of positions of lbrace tokens. We will // update information about whether an lbrace starts a // braced init list or a different block during the loop. @@ -1100,7 +1100,7 @@ void UnwrappedLineParser::parseStructuralElement() { break; } do { - const FormatToken *Previous = getPreviousToken(); + const FormatToken *Previous = FormatTok->Previous; switch (FormatTok->Tok.getKind()) { case tok::at: nextToken(); @@ -1356,10 +1356,11 @@ bool UnwrappedLineParser::tryToParseLambda() { } bool UnwrappedLineParser::tryToParseLambdaIntroducer() { - const FormatToken* Previous = getPreviousToken(); + const FormatToken* Previous = FormatTok->Previous; if (Previous && (Previous->isOneOf(tok::identifier, tok::kw_operator, tok::kw_new, tok::kw_delete) || + FormatTok->isCppStructuredBinding(Style) || Previous->closesScope() || Previous->isSimpleTypeSpecifier())) { nextToken(); return false; @@ -2232,6 +2233,8 @@ void UnwrappedLineParser::addUnwrappedLine() { std::make_move_iterator(PreprocessorDirectives.end())); PreprocessorDirectives.clear(); } + // Disconnect the current token from the last token on the previous line. + FormatTok->Previous = nullptr; } bool UnwrappedLineParser::eof() const { return FormatTok->Tok.is(tok::eof); } @@ -2378,18 +2381,12 @@ void UnwrappedLineParser::nextToken(int LevelDifference) { return; flushComments(isOnNewLine(*FormatTok)); pushToken(FormatTok); + FormatToken* Previous = FormatTok; if (Style.Language != FormatStyle::LK_JavaScript) readToken(LevelDifference); else readTokenWithJavaScriptASI(); -} - -const FormatToken *UnwrappedLineParser::getPreviousToken() { - // FIXME: This is a dirty way to access the previous token. Find a better - // solution. - if (!Line || Line->Tokens.empty()) - return nullptr; - return Line->Tokens.back().Tok; + FormatTok->Previous = Previous; } void UnwrappedLineParser::distributeComments( diff --git a/clang/lib/Format/UnwrappedLineParser.h b/clang/lib/Format/UnwrappedLineParser.h index 93b3bfa..a4b5576 100644 --- a/clang/lib/Format/UnwrappedLineParser.h +++ b/clang/lib/Format/UnwrappedLineParser.h @@ -129,7 +129,6 @@ private: // - if the token is '}' and closes a block, LevelDifference is -1. void nextToken(int LevelDifference = 0); void readToken(int LevelDifference = 0); - const FormatToken *getPreviousToken(); // Decides which comment tokens should be added to the current line and which // should be added as comments before the next token. diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp index 34206e9..a1b0e5f 100644 --- a/clang/unittests/Format/FormatTest.cpp +++ b/clang/unittests/Format/FormatTest.cpp @@ -11588,6 +11588,11 @@ TEST_F(FormatTest, StructuredBindings) { format("auto const volatile &&[a, b] = f();")); EXPECT_EQ("auto && [a, b] = f();", format("auto &&[a, b] = f();")); + // Make sure we don't mistake structured bindings for lambdas. + verifyFormat("auto [a, b]{A * i};"); + verifyFormat("auto const [a, b]{A * i};"); + verifyFormat("auto const && [a, b]{A * i};"); + format::FormatStyle Spaces = format::getLLVMStyle(); Spaces.SpacesInSquareBrackets = true; verifyFormat("auto [ a, b ] = f();", Spaces);