clang-format: Fix various problems in formatting ObjC blocks.

Among other things, this fixes llvm.org/PR15269.

llvm-svn: 197900
diff --git a/clang/lib/Format/ContinuationIndenter.cpp b/clang/lib/Format/ContinuationIndenter.cpp
index c3eeb8f..7b3f5cb 100644
--- a/clang/lib/Format/ContinuationIndenter.cpp
+++ b/clang/lib/Format/ContinuationIndenter.cpp
@@ -177,10 +177,8 @@
       State.Stack.back().FirstLessLess == 0)
     return true;
 
-  // FIXME: Comparing LongestObjCSelectorName to 0 is a hacky way of finding
-  // out whether it is the first parameter. Clean this up.
   if (Current.Type == TT_ObjCSelectorName &&
-      Current.LongestObjCSelectorName == 0 &&
+      State.Stack.back().ObjCSelectorNameFound &&
       State.Stack.back().BreakBeforeParameter)
     return true;
   if (Current.Type == TT_CtorInitializerColon &&
@@ -258,9 +256,12 @@
     Whitespaces.replaceWhitespace(Current, /*Newlines=*/0, /*IndentLevel=*/0,
                                   Spaces, State.Column + Spaces);
 
-  if (Current.Type == TT_ObjCSelectorName && State.Stack.back().ColonPos == 0) {
-    if (State.Stack.back().Indent + Current.LongestObjCSelectorName >
-        State.Column + Spaces + Current.ColumnWidth)
+  if (Current.Type == TT_ObjCSelectorName &&
+      !State.Stack.back().ObjCSelectorNameFound) {
+    if (Current.LongestObjCSelectorName == 0)
+      State.Stack.back().AlignColons = false;
+    else if (State.Stack.back().Indent + Current.LongestObjCSelectorName >
+             State.Column + Spaces + Current.ColumnWidth)
       State.Stack.back().ColonPos =
           State.Stack.back().Indent + Current.LongestObjCSelectorName;
     else
@@ -280,7 +281,9 @@
     // Treat the condition inside an if as if it was a second function
     // parameter, i.e. let nested calls have a continuation indent.
     State.Stack.back().LastSpace = State.Column + 1; // 1 is length of "(".
-  else if (Previous.is(tok::comma) || Previous.Type == TT_ObjCMethodExpr)
+  else if (Current.isNot(tok::comment) &&
+           (Previous.is(tok::comma) ||
+            (Previous.is(tok::colon) && Previous.Type == TT_ObjCMethodExpr)))
     State.Stack.back().LastSpace = State.Column;
   else if ((Previous.Type == TT_BinaryOperator ||
             Previous.Type == TT_ConditionalExpr ||
@@ -381,10 +384,17 @@
     State.Column =
         std::max(State.Stack.back().LastSpace, State.Stack.back().Indent);
   } else if (Current.Type == TT_ObjCSelectorName) {
-    if (State.Stack.back().ColonPos == 0) {
-      State.Stack.back().ColonPos =
-          State.Stack.back().Indent + Current.LongestObjCSelectorName;
-      State.Column = State.Stack.back().ColonPos - Current.ColumnWidth;
+    if (!State.Stack.back().ObjCSelectorNameFound) {
+      if (Current.LongestObjCSelectorName == 0) {
+        State.Column = State.Stack.back().Indent;
+        State.Stack.back().AlignColons = false;
+      } else {
+        State.Stack.back().ColonPos =
+            State.Stack.back().Indent + Current.LongestObjCSelectorName;
+        State.Column = State.Stack.back().ColonPos - Current.ColumnWidth;
+      }
+    } else if (!State.Stack.back().AlignColons) {
+      State.Column = State.Stack.back().Indent;
     } else if (State.Stack.back().ColonPos > Current.ColumnWidth) {
       State.Column = State.Stack.back().ColonPos - Current.ColumnWidth;
     } else {
@@ -397,9 +407,21 @@
     else
       State.Column = ContinuationIndent;
   } else if (Current.Type == TT_StartOfName ||
-             Previous.isOneOf(tok::coloncolon, tok::equal) ||
-             Previous.Type == TT_ObjCMethodExpr) {
+             Previous.isOneOf(tok::coloncolon, tok::equal)) {
     State.Column = ContinuationIndent;
+  } else if (PreviousNonComment &&
+             PreviousNonComment->Type == TT_ObjCMethodExpr) {
+    State.Column = ContinuationIndent;
+    // FIXME: This is hacky, find a better way. The problem is that in an ObjC
+    // method expression, the block should be aligned to the line starting it,
+    // e.g.:
+    //   [aaaaaaaaaaaaaaa aaaaaaaaa: \\ break for some reason
+    //                        ^(int *i) {
+    //                            // ...
+    //                        }];
+    // Thus, we set LastSpace of the next higher ParenLevel, to which we move
+    // when we consume all of the "}"'s FakeRParens at the "{".
+    State.Stack[State.Stack.size() - 2].LastSpace = ContinuationIndent;
   } else if (Current.Type == TT_CtorInitializerColon) {
     State.Column = State.FirstIndent + Style.ConstructorInitializerIndentWidth;
   } else if (Current.Type == TT_CtorInitializerComma) {
@@ -449,7 +471,7 @@
       !PreviousNonComment->isOneOf(tok::comma, tok::semi) &&
       PreviousNonComment->Type != TT_TemplateCloser &&
       PreviousNonComment->Type != TT_BinaryOperator &&
-      Current.Type != TT_BinaryOperator && 
+      Current.Type != TT_BinaryOperator &&
       !PreviousNonComment->opensScope())
     State.Stack.back().BreakBeforeParameter = true;
 
@@ -494,6 +516,8 @@
   if (Current.isMemberAccess())
     State.Stack.back().StartOfFunctionCall =
         Current.LastInChainOfCalls ? 0 : State.Column + Current.ColumnWidth;
+  if (Current.Type == TT_ObjCSelectorName)
+    State.Stack.back().ObjCSelectorNameFound = true;
   if (Current.Type == TT_CtorInitializerColon) {
     // Indent 2 from the column, so:
     // SomeClass::SomeClass()
@@ -588,7 +612,16 @@
         //                   });
         for (unsigned i = 0; i != Current.MatchingParen->FakeRParens; ++i)
           State.Stack.pop_back();
-        NewIndent = State.Stack.back().LastSpace + Style.IndentWidth;
+        bool IsObjCBlock =
+            Previous &&
+            (Previous->is(tok::caret) ||
+             (Previous->is(tok::r_paren) && Previous->MatchingParen &&
+              Previous->MatchingParen->Previous &&
+              Previous->MatchingParen->Previous->is(tok::caret)));
+        // For some reason, ObjC blocks are indented like continuations.
+        NewIndent =
+            State.Stack.back().LastSpace +
+            (IsObjCBlock ? Style.ContinuationIndentWidth : Style.IndentWidth);
         ++NewIndentLevel;
         BreakBeforeParameter = true;
       } else {