Initial support for formatting ObjC method declarations/calls.

We can now format stuff like:
- (void)doSomethingWith:(GTMFoo *)theFoo
                   rect:(NSRect)theRect
               interval:(float)theInterval {
  [myObject doFooWith:arg1 //
                 name:arg2
                error:arg3];

}

This seems to fix everything mentioned in llvm.org/PR14939.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@174364 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Format/Format.cpp b/lib/Format/Format.cpp
index 06ebc78..bbebec3 100644
--- a/lib/Format/Format.cpp
+++ b/lib/Format/Format.cpp
@@ -268,7 +268,7 @@
         : Indent(Indent), LastSpace(LastSpace), AssignmentColumn(0),
           FirstLessLess(0), BreakBeforeClosingBrace(false), QuestionColumn(0),
           AvoidBinPacking(AvoidBinPacking), BreakAfterComma(false),
-          HasMultiParameterLine(HasMultiParameterLine) {
+          HasMultiParameterLine(HasMultiParameterLine), ColonPos(0) {
     }
 
     /// \brief The position to which a specific parenthesis level needs to be
@@ -312,6 +312,9 @@
     /// \brief This context already has a line with more than one parameter.
     bool HasMultiParameterLine;
 
+    /// \brief The position of the colon in an ObjC method declaration/call.
+    unsigned ColonPos;
+
     bool operator<(const ParenState &Other) const {
       if (Indent != Other.Indent)
         return Indent < Other.Indent;
@@ -331,6 +334,8 @@
         return BreakAfterComma;
       if (HasMultiParameterLine != Other.HasMultiParameterLine)
         return HasMultiParameterLine;
+      if (ColonPos != Other.ColonPos)
+        return ColonPos < Other.ColonPos;
       return false;
     }
   };
@@ -427,6 +432,17 @@
       } else if (Previous.Type == TT_BinaryOperator &&
                  State.Stack.back().AssignmentColumn != 0) {
         State.Column = State.Stack.back().AssignmentColumn;
+      } else if (Current.Type == TT_ObjCSelectorName) {
+        if (State.Stack.back().ColonPos > Current.FormatTok.TokenLength) {
+          State.Column =
+              State.Stack.back().ColonPos - Current.FormatTok.TokenLength;
+        } else {
+          State.Column = State.Stack.back().Indent;
+          State.Stack.back().ColonPos =
+              State.Column + Current.FormatTok.TokenLength;
+        }
+      } else if (Previous.Type == TT_ObjCMethodExpr) {
+        State.Column = State.Stack.back().Indent + 4;
       } else {
         State.Column = State.Stack[ParenLevel].Indent;
       }
@@ -461,6 +477,17 @@
       if (!DryRun)
         Whitespaces.replaceWhitespace(Current, 0, Spaces, State.Column, Style);
 
+      if (Current.Type == TT_ObjCSelectorName &&
+          State.Stack.back().ColonPos == 0) {
+        if (State.Stack.back().Indent + Current.LongestObjCSelectorName >
+            State.Column + Spaces + Current.FormatTok.TokenLength)
+          State.Stack.back().ColonPos =
+              State.Stack.back().Indent + Current.LongestObjCSelectorName;
+        else
+          State.Stack.back().ColonPos =
+              State.Column + Spaces + Current.LongestObjCSelectorName;
+      }
+
       // FIXME: Do we need to do this for assignments nested in other
       // expressions?
       if (RootToken.isNot(tok::kw_for) && ParenLevel == 0 &&
@@ -699,6 +726,9 @@
         State.Stack.back().BreakAfterComma &&
         !isTrailingComment(*State.NextToken))
       return true;
+    if (State.NextToken->Type == TT_ObjCSelectorName &&
+        State.Stack.back().ColonPos != 0)
+      return true;
     if ((State.NextToken->Type == TT_CtorInitializerColon ||
          (State.NextToken->Parent->ClosesTemplateDeclaration &&
           State.Stack.size() == 1)))
diff --git a/lib/Format/TokenAnnotator.cpp b/lib/Format/TokenAnnotator.cpp
index f34bc89..03717e9 100644
--- a/lib/Format/TokenAnnotator.cpp
+++ b/lib/Format/TokenAnnotator.cpp
@@ -20,15 +20,6 @@
 namespace clang {
 namespace format {
 
-/// \brief Returns if a token is an Objective-C selector name.
-///
-/// For example, "bar" is a selector name in [foo bar:(4 + 5)].
-static bool isObjCSelectorName(const AnnotatedToken &Tok) {
-  return Tok.is(tok::identifier) && !Tok.Children.empty() &&
-         Tok.Children[0].is(tok::colon) &&
-         Tok.Children[0].Type == TT_ObjCMethodExpr;
-}
-
 static bool isBinaryOperator(const AnnotatedToken &Tok) {
   // Comma is a binary operator, but does not behave as such wrt. formatting.
   return getPrecedence(Tok) > prec::Comma;
@@ -65,6 +56,7 @@
   AnnotatingParser(SourceManager &SourceMgr, Lexer &Lex, AnnotatedLine &Line)
       : SourceMgr(SourceMgr), Lex(Lex), Line(Line), CurrentToken(&Line.First),
         KeywordVirtualFound(false), ColonIsObjCMethodExpr(false),
+        LongestObjCSelectorName(0), FirstObjCSelectorName(NULL),
         ColonIsForRangeExpr(false), IsExpression(false),
         LookForFunctionName(Line.MustBeDeclaration), BindingStrength(1) {
   }
@@ -82,6 +74,8 @@
 
     void markStart(AnnotatedToken &Left) {
       P.ColonIsObjCMethodExpr = true;
+      P.LongestObjCSelectorName = 0;
+      P.FirstObjCSelectorName = NULL;
       Left.Type = TT_ObjCMethodExpr;
     }
 
@@ -168,8 +162,13 @@
         Left->MatchingParen = CurrentToken;
         CurrentToken->MatchingParen = Left;
 
-        if (StartsObjCMethodExpr)
+        if (StartsObjCMethodExpr) {
           objCSelector.markEnd(*CurrentToken);
+          if (FirstObjCSelectorName != NULL) {
+            FirstObjCSelectorName->LongestObjCSelectorName =
+                LongestObjCSelectorName;
+          }
+        }
 
         next();
         return true;
@@ -221,6 +220,9 @@
         }
         Left->MatchingParen = CurrentToken;
         CurrentToken->MatchingParen = Left;
+        if (FirstObjCSelectorName != NULL)
+          FirstObjCSelectorName->LongestObjCSelectorName =
+              LongestObjCSelectorName;
         next();
         return true;
       }
@@ -295,12 +297,19 @@
       break;
     case tok::colon:
       // Colons from ?: are handled in parseConditional().
-      if (Tok->Parent->is(tok::r_paren))
+      if (Tok->Parent->is(tok::r_paren)) {
         Tok->Type = TT_CtorInitializerColon;
-      else if (ColonIsObjCMethodExpr)
+      } else if (ColonIsObjCMethodExpr ||
+                 Line.First.Type == TT_ObjCMethodSpecifier) {
         Tok->Type = TT_ObjCMethodExpr;
-      else if (ColonIsForRangeExpr)
+        Tok->Parent->Type = TT_ObjCSelectorName;
+        if (Tok->Parent->FormatTok.TokenLength > LongestObjCSelectorName)
+          LongestObjCSelectorName = Tok->Parent->FormatTok.TokenLength;
+        if (FirstObjCSelectorName == NULL)
+          FirstObjCSelectorName = Tok->Parent;
+      } else if (ColonIsForRangeExpr) {
         Tok->Type = TT_RangeBasedForLoopColon;
+      }
       break;
     case tok::kw_if:
     case tok::kw_while:
@@ -452,6 +461,13 @@
     if (PeriodsAndArrows >= 2 && CanBeBuilderTypeStmt)
       return LT_BuilderTypeCall;
 
+    if (Line.First.Type == TT_ObjCMethodSpecifier) {
+      if (FirstObjCSelectorName != NULL)
+        FirstObjCSelectorName->LongestObjCSelectorName =
+            LongestObjCSelectorName;
+      return LT_ObjCMethodDecl;
+    }
+
     return LT_Other;
   }
 
@@ -474,6 +490,8 @@
   AnnotatedToken *CurrentToken;
   bool KeywordVirtualFound;
   bool ColonIsObjCMethodExpr;
+  unsigned LongestObjCSelectorName;
+  AnnotatedToken *FirstObjCSelectorName;
   bool ColonIsForRangeExpr;
   bool IsExpression;
   bool LookForFunctionName;
@@ -725,9 +743,9 @@
 
   // In Objective-C method expressions, prefer breaking before "param:" over
   // breaking after it.
-  if (isObjCSelectorName(Right))
+  if (Right.Type == TT_ObjCSelectorName)
     return 0;
-  if (Right.is(tok::colon) && Right.Type == TT_ObjCMethodExpr)
+  if (Left.is(tok::colon) && Left.Type == TT_ObjCMethodExpr)
     return 20;
 
   if (Left.is(tok::l_paren) || Left.is(tok::l_square) ||
@@ -885,7 +903,7 @@
     return false;
   if (Left.is(tok::colon) && Left.Type == TT_ObjCMethodExpr)
     return true;
-  if (isObjCSelectorName(Right))
+  if (Right.Type == TT_ObjCSelectorName)
     return true;
   if (Left.ClosesTemplateDeclaration)
     return true;
diff --git a/lib/Format/TokenAnnotator.h b/lib/Format/TokenAnnotator.h
index 0386b88..64c597e 100644
--- a/lib/Format/TokenAnnotator.h
+++ b/lib/Format/TokenAnnotator.h
@@ -40,6 +40,7 @@
   TT_ObjCMethodSpecifier,
   TT_ObjCMethodExpr,
   TT_ObjCProperty,
+  TT_ObjCSelectorName,
   TT_OverloadedOperator,
   TT_PointerOrReference,
   TT_PureVirtualSpecifier,
@@ -69,7 +70,8 @@
       : FormatTok(FormatTok), Type(TT_Unknown), SpaceRequiredBefore(false),
         CanBreakBefore(false), MustBreakBefore(false),
         ClosesTemplateDeclaration(false), MatchingParen(NULL),
-        ParameterCount(1), BindingStrength(0), SplitPenalty(0), Parent(NULL) {
+        ParameterCount(1), BindingStrength(0), SplitPenalty(0),
+        LongestObjCSelectorName(0), Parent(NULL) {
   }
 
   bool is(tok::TokenKind Kind) const { return FormatTok.Tok.is(Kind); }
@@ -109,6 +111,10 @@
   /// \brief Penalty for inserting a line break before this token.
   unsigned SplitPenalty;
 
+  /// \brief If this is the first ObjC selector name in an ObjC method
+  /// definition or call, this contains the length of the longest name.
+  unsigned LongestObjCSelectorName;
+
   std::vector<AnnotatedToken> Children;
   AnnotatedToken *Parent;