From 753a5114f9076c545c33cf3ced0d76e27bc0a2d5 Mon Sep 17 00:00:00 2001
From: Manuel Klimek <klimek@google.com>
Date: Wed, 4 Sep 2013 13:25:30 +0000
Subject: [PATCH] Implement parsing of blocks (^{ ... }) in the unwrapped line
 parser.

This patch makes sure we produce the right number of unwrapped lines,
a follow-up patch will make the whitespace formatting consistent.

Before:
 void f() {
   int i = {[operation setCompletionBlock : ^{ [self onOperationDone];
 }]
 }
 ;
 }

After:
 void f() {
   int i = {[operation setCompletionBlock : ^{
     [self onOperationDone];
   }] };
 }

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@189932 91177308-0d34-0410-b5e6-96231b3b80d8
---
 lib/Format/UnwrappedLineParser.cpp | 44 ++++++++++++++++++++----------
 lib/Format/UnwrappedLineParser.h   |  1 +
 unittests/Format/FormatTest.cpp    | 11 ++++++++
 3 files changed, 42 insertions(+), 14 deletions(-)

diff --git a/lib/Format/UnwrappedLineParser.cpp b/lib/Format/UnwrappedLineParser.cpp
index f58ee82303..c780fdb566 100644
--- a/lib/Format/UnwrappedLineParser.cpp
+++ b/lib/Format/UnwrappedLineParser.cpp
@@ -346,6 +346,20 @@ void UnwrappedLineParser::parseBlock(bool MustBeDeclaration, bool AddLevel) {
   Line->Level = InitialLevel;
 }
 
+void UnwrappedLineParser::parseChildBlock() {
+  FormatTok->BlockKind = BK_Block;
+  nextToken();
+  {
+    ScopedLineState LineState(*this);
+    ScopedDeclarationState DeclarationState(*Line, DeclarationScopeStack,
+                                            /*MustBeDeclaration=*/false);
+    Line->Level += 1;
+    parseLevel(/*HasOpeningBrace=*/true);
+    Line->Level -= 1;
+  }
+  nextToken();
+}
+
 void UnwrappedLineParser::parsePPDirective() {
   assert(FormatTok->Tok.is(tok::hash) && "'#' expected");
   ScopedMacroState MacroState(*Line, Tokens, FormatTok, StructuralError);
@@ -591,6 +605,12 @@ void UnwrappedLineParser::parseStructuralElement() {
     case tok::l_paren:
       parseParens();
       break;
+    case tok::caret:
+      nextToken();
+      if (FormatTok->is(tok::l_brace)) {
+        parseChildBlock();
+      }
+      break;
     case tok::l_brace:
       if (!tryToParseBracedList()) {
         // A block outside of parentheses must be the last part of a
@@ -674,17 +694,7 @@ void UnwrappedLineParser::tryToParseLambda() {
         break;
     }
   }
-  FormatTok->BlockKind = BK_Block;
-  nextToken();
-  {
-    ScopedLineState LineState(*this);
-    ScopedDeclarationState DeclarationState(*Line, DeclarationScopeStack,
-                                            /*MustBeDeclaration=*/false);
-    Line->Level += 1;
-    parseLevel(/*HasOpeningBrace=*/true);
-    Line->Level -= 1;
-  }
-  nextToken();
+  parseChildBlock();
 }
 
 bool UnwrappedLineParser::tryToParseLambdaIntroducer() {
@@ -741,9 +751,15 @@ 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::caret:
+      nextToken();
+      if (FormatTok->is(tok::l_brace)) {
+        parseChildBlock();
+      }
+      break;
+    case tok::l_square:
+      tryToParseLambda();
+      break;
     case tok::l_brace:
       // Assume there are no blocks inside a braced init list apart
       // from the ones we explicitly parse out (like lambdas).
diff --git a/lib/Format/UnwrappedLineParser.h b/lib/Format/UnwrappedLineParser.h
index 4660b1dbac..5c59da3beb 100644
--- a/lib/Format/UnwrappedLineParser.h
+++ b/lib/Format/UnwrappedLineParser.h
@@ -66,6 +66,7 @@ private:
   void parseFile();
   void parseLevel(bool HasOpeningBrace);
   void parseBlock(bool MustBeDeclaration, bool AddLevel = true);
+  void parseChildBlock();
   void parsePPDirective();
   void parsePPDefine();
   void parsePPIf();
diff --git a/unittests/Format/FormatTest.cpp b/unittests/Format/FormatTest.cpp
index d2b2dfd99b..32226fc501 100644
--- a/unittests/Format/FormatTest.cpp
+++ b/unittests/Format/FormatTest.cpp
@@ -6311,5 +6311,16 @@ TEST_F(FormatTest, FormatsLambdas) {
       "}\n");
 }
 
+TEST_F(FormatTest, FormatsBlocks) {
+  // FIXME: Make whitespace formatting consistent. Ask a ObjC dev how
+  // it would ideally look.
+  verifyFormat("[operation setCompletionBlock:^{\n"
+               "  [self onOperationDone];\n"
+               "}];\n");
+  verifyFormat("int i = {[operation setCompletionBlock : ^{\n"
+               "  [self onOperationDone];\n"
+               "}] };\n");
+}
+
 } // end namespace tooling
 } // end namespace clang
-- 
2.40.0