r313742 - Fix clang-format's detection of structured bindings.

Manuel Klimek via cfe-commits cfe-commits at lists.llvm.org
Wed Sep 20 02:29:37 PDT 2017


Author: klimek
Date: Wed Sep 20 02:29:37 2017
New Revision: 313742

URL: http://llvm.org/viewvc/llvm-project?rev=313742&view=rev
Log:
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.

Modified:
    cfe/trunk/lib/Format/FormatToken.h
    cfe/trunk/lib/Format/TokenAnnotator.cpp
    cfe/trunk/lib/Format/UnwrappedLineParser.cpp
    cfe/trunk/lib/Format/UnwrappedLineParser.h
    cfe/trunk/unittests/Format/FormatTest.cpp

Modified: cfe/trunk/lib/Format/FormatToken.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/FormatToken.h?rev=313742&r1=313741&r2=313742&view=diff
==============================================================================
--- cfe/trunk/lib/Format/FormatToken.h (original)
+++ cfe/trunk/lib/Format/FormatToken.h Wed Sep 20 02:29:37 2017
@@ -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())

Modified: cfe/trunk/lib/Format/TokenAnnotator.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/TokenAnnotator.cpp?rev=313742&r1=313741&r2=313742&view=diff
==============================================================================
--- cfe/trunk/lib/Format/TokenAnnotator.cpp (original)
+++ cfe/trunk/lib/Format/TokenAnnotator.cpp Wed Sep 20 02:29:37 2017
@@ -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;

Modified: cfe/trunk/lib/Format/UnwrappedLineParser.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/UnwrappedLineParser.cpp?rev=313742&r1=313741&r2=313742&view=diff
==============================================================================
--- cfe/trunk/lib/Format/UnwrappedLineParser.cpp (original)
+++ cfe/trunk/lib/Format/UnwrappedLineParser.cpp Wed Sep 20 02:29:37 2017
@@ -356,7 +356,7 @@ void UnwrappedLineParser::calculateBrace
   // 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::parseStructura
     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::tryToParseLamb
 }
 
 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::addUnwrappedLi
         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
     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(

Modified: cfe/trunk/lib/Format/UnwrappedLineParser.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/UnwrappedLineParser.h?rev=313742&r1=313741&r2=313742&view=diff
==============================================================================
--- cfe/trunk/lib/Format/UnwrappedLineParser.h (original)
+++ cfe/trunk/lib/Format/UnwrappedLineParser.h Wed Sep 20 02:29:37 2017
@@ -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.

Modified: cfe/trunk/unittests/Format/FormatTest.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Format/FormatTest.cpp?rev=313742&r1=313741&r2=313742&view=diff
==============================================================================
--- cfe/trunk/unittests/Format/FormatTest.cpp (original)
+++ cfe/trunk/unittests/Format/FormatTest.cpp Wed Sep 20 02:29:37 2017
@@ -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);




More information about the cfe-commits mailing list