]> granicus.if.org Git - clang/commitdiff
[clang-format] Refine structured binding detection
authorKrasimir Georgiev <krasimir@google.com>
Mon, 25 Mar 2019 17:29:16 +0000 (17:29 +0000)
committerKrasimir Georgiev <krasimir@google.com>
Mon, 25 Mar 2019 17:29:16 +0000 (17:29 +0000)
Summary:
Revision r356575 had the unfortunate consequence that now clang-format never
detects an ObjC call expression after `&&`.

This patch tries harder to distinguish between C++17 structured bindings and
ObjC call expressions and adds a few regression tests.

Reviewers: klimek

Reviewed By: klimek

Subscribers: cfe-commits

Tags: #clang

Differential Revision: https://reviews.llvm.org/D59774

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@356928 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Format/TokenAnnotator.cpp
unittests/Format/FormatTestObjC.cpp

index ccf5e51576d33f153ab5b111e34163648b59d65e..04fc3a64f55b82dacfbc55deffcf4218b6a44175 100644 (file)
@@ -13,6 +13,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "TokenAnnotator.h"
+#include "FormatToken.h"
 #include "clang/Basic/SourceManager.h"
 #include "llvm/ADT/SmallPtrSet.h"
 #include "llvm/Support/Debug.h"
@@ -440,10 +441,11 @@ private:
         Contexts.back().InCSharpAttributeSpecifier;
 
     bool InsideInlineASM = Line.startsWith(tok::kw_asm);
+    bool IsCppStructuredBinding = Left->isCppStructuredBinding(Style);
     bool StartsObjCMethodExpr =
-        !InsideInlineASM && !CppArrayTemplates && Style.isCpp() &&
-        !IsCpp11AttributeSpecifier && Contexts.back().CanBeExpression &&
-        Left->isNot(TT_LambdaLSquare) &&
+        !IsCppStructuredBinding && !InsideInlineASM && !CppArrayTemplates &&
+        Style.isCpp() && !IsCpp11AttributeSpecifier &&
+        Contexts.back().CanBeExpression && Left->isNot(TT_LambdaLSquare) &&
         !CurrentToken->isOneOf(tok::l_brace, tok::r_square) &&
         (!Parent ||
          Parent->isOneOf(tok::colon, tok::l_square, tok::l_paren,
@@ -451,14 +453,12 @@ private:
          Parent->isUnaryOperator() ||
          // FIXME(bug 36976): ObjC return types shouldn't use TT_CastRParen.
          Parent->isOneOf(TT_ObjCForIn, TT_CastRParen) ||
-         // for (auto && [A,B] : C)  && structure binding seen as ObjCMethodExpr
-         (Parent->isNot(tok::ampamp) &&
-          getBinOpPrecedence(Parent->Tok.getKind(), true, true) >
-              prec::Unknown));
+         (getBinOpPrecedence(Parent->Tok.getKind(), true, true) >
+          prec::Unknown));
     bool ColonFound = false;
 
     unsigned BindingIncrease = 1;
-    if (Left->isCppStructuredBinding(Style)) {
+    if (IsCppStructuredBinding) {
       Left->Type = TT_StructuredBindingLSquare;
     } else if (Left->is(TT_Unknown)) {
       if (StartsObjCMethodExpr) {
index e1a95dbb39541d33d7309dc97e83349dcf3a5ea4..b859d92a89ce1bfb485f663a235e35f70cbe324a 100644 (file)
@@ -1357,6 +1357,30 @@ TEST_F(FormatTestObjC, DisambiguatesCallsFromCppLambdas) {
   // verifyFormat("x = ([a foo:bar] >> b->c == 'd');");
 }
 
+TEST_F(FormatTestObjC,  DisambiguatesCallsFromStructuredBindings) {
+  verifyFormat("int f() {\n"
+               "  if (a && [f arg])\n"
+               "    return 0;\n"
+               "}");
+  verifyFormat("int f() {\n"
+               "  if (a & [f arg])\n"
+               "    return 0;\n"
+               "}");
+  verifyFormat("int f() {\n"
+               "  for (auto &[elem] : list)\n"
+               "    return 0;\n"
+               "}");
+  verifyFormat("int f() {\n"
+               "  for (auto &&[elem] : list)\n"
+               "    return 0;\n"
+               "}");
+  verifyFormat(
+      "int f() {\n"
+      "  for (auto /**/ const /**/ volatile /**/ && /**/ [elem] : list)\n"
+      "    return 0;\n"
+      "}");
+}
+
 } // end namespace
 } // end namespace format
 } // end namespace clang