From e8ccc81a9f66361450148338b8457dd2c6ad11de Mon Sep 17 00:00:00 2001
From: Nico Weber <nicolasweber@gmx.de>
Date: Sat, 12 Jan 2013 22:48:47 +0000
Subject: [PATCH] Formatter: Prefer breaking before ObjC selector names over
 breaking at their ':'

Before:
  if ((self = [super initWithContentRect:contentRect styleMask:
                  styleMask backing:NSBackingStoreBuffered defer:YES])) {

Now:
  if ((self = [super initWithContentRect:contentRect styleMask:styleMask
                  backing:NSBackingStoreBuffered defer:YES])) {




git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@172333 91177308-0d34-0410-b5e6-96231b3b80d8
---
 lib/Format/Format.cpp           | 21 ++++++++++++++++++++-
 unittests/Format/FormatTest.cpp | 15 +++++++++++----
 2 files changed, 31 insertions(+), 5 deletions(-)

diff --git a/lib/Format/Format.cpp b/lib/Format/Format.cpp
index 8ca0a823fe4..de870900b41 100644
--- a/lib/Format/Format.cpp
+++ b/lib/Format/Format.cpp
@@ -170,7 +170,7 @@ static void replacePPWhitespace(
 
 /// \brief Checks whether the (remaining) \c UnwrappedLine starting with
 /// \p RootToken fits into \p Limit columns.
-bool fitsIntoLimit(const AnnotatedToken &RootToken, unsigned Limit) {
+static bool fitsIntoLimit(const AnnotatedToken &RootToken, unsigned Limit) {
   unsigned Columns = RootToken.FormatTok.TokenLength;
   bool FitsOnALine = true;
   const AnnotatedToken *Tok = &RootToken;
@@ -188,6 +188,15 @@ bool fitsIntoLimit(const AnnotatedToken &RootToken, unsigned Limit) {
   return FitsOnALine;
 }
 
+/// \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;
+}
+
 class UnwrappedLineFormatter {
 public:
   UnwrappedLineFormatter(const FormatStyle &Style, SourceManager &SourceMgr,
@@ -479,6 +488,14 @@ private:
     if (Left.is(tok::semi) || Left.is(tok::comma) ||
         Left.ClosesTemplateDeclaration)
       return 0;
+
+    // In Objective-C method expressions, prefer breaking before "param:" over
+    // breaking after it.
+    if (isObjCSelectorName(Right))
+      return 0;
+    if (Right.is(tok::colon) && Right.Type == TT_ObjCMethodExpr)
+      return 20;
+
     if (Left.is(tok::l_paren))
       return 20;
 
@@ -1188,6 +1205,8 @@ private:
       return false;
     if (Left.is(tok::colon) && Left.Type == TT_ObjCMethodExpr)
       return true;
+    if (isObjCSelectorName(Right))
+      return true;
     if (Left.ClosesTemplateDeclaration)
       return true;
     if (Left.Type == TT_PointerOrReference || Left.Type == TT_TemplateCloser ||
diff --git a/unittests/Format/FormatTest.cpp b/unittests/Format/FormatTest.cpp
index 668e8af76bc..cba25fcf8f4 100644
--- a/unittests/Format/FormatTest.cpp
+++ b/unittests/Format/FormatTest.cpp
@@ -1537,12 +1537,18 @@ TEST_F(FormatTest, FormatObjCMethodExpr) {
   verifyFormat("throw [self errorFor:a];");
   verifyFormat("@throw [self errorFor:a];");
 
-  // The formatting of this isn't ideal yet. It tests that the formatter doesn't
-  // break after "backing" but before ":", which would be at 80 columns.
+  // This tests that the formatter doesn't break after "backing" but before ":",
+  // which would be at 80 columns.
   verifyFormat(
       "void f() {\n"
-      "  if ((self = [super initWithContentRect:contentRect styleMask:\n"
-      "                  styleMask backing:NSBackingStoreBuffered defer:YES]))");
+      "  if ((self = [super initWithContentRect:contentRect styleMask:styleMask\n"
+      "                  backing:NSBackingStoreBuffered defer:YES]))");
+  
+  verifyFormat("[foo setasdfasdffffffffffffadfasdfasdf:\n"
+               "    [bar dowith:asdfdsfasdfasdfasfasfasfsafasdfsfad]];");
+
+  verifyFormat("[foo checkThatBreakingAfterColonWorksOk:\n"
+               "    [bar ifItDoes:reduceOverallLineLengthLikeInThisCase]];");
   
 }
 
@@ -1582,6 +1588,7 @@ TEST_F(FormatTest, ObjCAt) {
   verifyFormat("@'c'");
   verifyFormat("@true");
   verifyFormat("NSNumber *smallestInt = @(-INT_MAX - 1);");
+  // FIXME: Array and dictionary literals need more work.
   verifyFormat("@[");
   verifyFormat("@{");
 
-- 
GitLab