Here's an update that does two things

1. Splits the behavior changes into 2 bools, since they were controlling 
distinct formatting behaviors
2. Adds support for non-zero column width for 
ObjCAvoidLineBreaksForInlineBlocks. Currently there's potentially broken 
behavior, where the decision to split an objective-c line is determined by the 
length of the opening `[` to the close `]`. In the case of in-line blocks, that 
calculation is deceptive as it includes blocks, which break the line. I added 
getLengthToLineTerminator that matches the closing `]` or the first token with 
children lines. I only changed this behavior when 
ObjCAvoidLineBreaksForInlineBlocks is enabled, but it could be argued that this 
should be default behavior. I opted for compatibility unless you think 
otherwise.


http://reviews.llvm.org/D9237

Files:
  include/clang/Format/Format.h
  lib/Format/ContinuationIndenter.cpp
  lib/Format/Format.cpp
  lib/Format/TokenAnnotator.cpp
  unittests/Format/FormatTest.cpp

EMAIL PREFERENCES
  http://reviews.llvm.org/settings/panel/emailpreferences/
Index: include/clang/Format/Format.h
===================================================================
--- include/clang/Format/Format.h
+++ include/clang/Format/Format.h
@@ -222,6 +222,14 @@
   /// on a single line.
   ShortFunctionStyle AllowShortFunctionsOnASingleLine;
 
+  /// \brief Compress the selector parts to align left when more than two inline
+  /// blocks are specified. Default is true
+  bool ObjCLeftAlignMultipleBlocks;
+
+  /// \brief Avoid inserting line breaks when calculating the length of lines
+  /// with inline Objective-C blocks.
+  bool ObjCAvoidLineBreaksForInlineBlocks;
+
   /// \brief Add a space after \c @property in Objective-C, i.e. use
   /// <tt>\@property (readonly)</tt> instead of <tt>\@property(readonly)</tt>.
   bool ObjCSpaceAfterProperty;
Index: lib/Format/ContinuationIndenter.cpp
===================================================================
--- lib/Format/ContinuationIndenter.cpp
+++ lib/Format/ContinuationIndenter.cpp
@@ -38,6 +38,22 @@
   return End->TotalLength - Tok.TotalLength + 1;
 }
 
+// Returns the length of everything up to the first possible line break after
+// the ), ], } or > matching \c Tok, or the first token with children.
+static unsigned getLengthToLineTerminator(const FormatToken &Tok) {
+  if (!Tok.MatchingParen)
+    return 0;
+  FormatToken *End = Tok.MatchingParen;
+  FormatToken *Cursor = Tok.Next;
+  while (Cursor->Children.size() == 0 && Cursor != End) {
+    Cursor = Cursor->Next;
+  }
+  while (Cursor->Next && !Cursor->Next->CanBreakBefore) {
+    Cursor = Cursor->Next;
+  }
+  return Cursor->TotalLength - Tok.TotalLength + 1;
+}
+
 // Returns \c true if \c Tok is the "." or "->" of a call and starts the next
 // segment of a builder type call.
 static bool startsSegmentOfBuilderTypeCall(const FormatToken &Tok) {
@@ -843,8 +859,10 @@
       if (Style.ColumnLimit) {
         // If this '[' opens an ObjC call, determine whether all parameters fit
         // into one line and put one per line if they don't.
-        if (getLengthToMatchingParen(Current) + State.Column >
-            getColumnLimit(State))
+        unsigned length = (Style.ObjCAvoidLineBreaksForInlineBlocks ?
+                               getLengthToLineTerminator(Current) :
+                               getLengthToMatchingParen(Current));
+        if (length + State.Column > getColumnLimit(State))
           BreakBeforeParameter = true;
       } else {
         // For ColumnLimit = 0, we have to figure out whether there is or has to
@@ -853,7 +871,7 @@
              Tok && Tok != Current.MatchingParen; Tok = Tok->Next) {
           if (Tok->MustBreakBefore || 
               (Tok->CanBreakBefore && Tok->NewlinesBefore > 0)) {
-            BreakBeforeParameter = true;
+            BreakBeforeParameter = !Style.ObjCAvoidLineBreaksForInlineBlocks;
             break;
           }
         }
Index: lib/Format/Format.cpp
===================================================================
--- lib/Format/Format.cpp
+++ lib/Format/Format.cpp
@@ -218,6 +218,8 @@
                    Style.KeepEmptyLinesAtTheStartOfBlocks);
     IO.mapOptional("NamespaceIndentation", Style.NamespaceIndentation);
     IO.mapOptional("ObjCBlockIndentWidth", Style.ObjCBlockIndentWidth);
+    IO.mapOptional("ObjCAvoidLineBreaksForInlineBlocks", Style.ObjCAvoidLineBreaksForInlineBlocks);
+    IO.mapOptional("ObjCLeftAlignMultipleBlocks", Style.ObjCLeftAlignMultipleBlocks);
     IO.mapOptional("ObjCSpaceAfterProperty", Style.ObjCSpaceAfterProperty);
     IO.mapOptional("ObjCSpaceBeforeProtocolList",
                    Style.ObjCSpaceBeforeProtocolList);
@@ -363,6 +365,8 @@
   LLVMStyle.KeepEmptyLinesAtTheStartOfBlocks = true;
   LLVMStyle.NamespaceIndentation = FormatStyle::NI_None;
   LLVMStyle.ObjCBlockIndentWidth = 2;
+  LLVMStyle.ObjCLeftAlignMultipleBlocks = true;
+  LLVMStyle.ObjCAvoidLineBreaksForInlineBlocks = false;
   LLVMStyle.ObjCSpaceAfterProperty = false;
   LLVMStyle.ObjCSpaceBeforeProtocolList = true;
   LLVMStyle.PointerAlignment = FormatStyle::PAS_Right;
Index: lib/Format/TokenAnnotator.cpp
===================================================================
--- lib/Format/TokenAnnotator.cpp
+++ lib/Format/TokenAnnotator.cpp
@@ -290,7 +290,9 @@
         if (Contexts.back().FirstObjCSelectorName) {
           Contexts.back().FirstObjCSelectorName->LongestObjCSelectorName =
               Contexts.back().LongestObjCSelectorName;
-          if (Left->BlockParameterCount > 1)
+          // Compress blocks if there are multiple block arguments
+          if (Left->BlockParameterCount > 1 &&
+              Style.ObjCLeftAlignMultipleBlocks)
             Contexts.back().FirstObjCSelectorName->LongestObjCSelectorName = 0;
         }
         next();
Index: unittests/Format/FormatTest.cpp
===================================================================
--- unittests/Format/FormatTest.cpp
+++ unittests/Format/FormatTest.cpp
@@ -9797,6 +9797,61 @@
                "    [self onOperationDone];\n"
                "}];",
                FourIndent);
+
+  FormatStyle AvoidBreaks = getLLVMStyle();
+  AvoidBreaks.ObjCAvoidLineBreaksForInlineBlocks = true;
+  verifyFormat("[UIView animateWithDuration:0 animations:^{ // This does not change behavior\n"
+               "  view.center = CGPointZero;\n"
+               "} completion:^(BOOL finished) {\n"
+               "  NSLog(complete);\n"
+               "}];",
+               AvoidBreaks);
+  verifyFormat("[UIView animateWithDuration:0 animations:^{\n"
+               "  view.center = CGPointZero;\n"
+               "} completion:^(BOOL finished) {\n"
+               "  NSLog(complete);\n"
+               "}];",
+               AvoidBreaks);
+  verifyFormat("[UIView animateWithDuration:0 // Break\n"
+               "    animations:^{\n"
+               "      view.center = CGPointZero;\n"
+               "    }\n"
+               "    completion:^(BOOL finished) {\n"
+               "      NSLog(complete);\n"
+               "    }];",
+               AvoidBreaks);
+}
+
+TEST_F(FormatTest, FormatsBlocksLeftAligned) {
+  FormatStyle DisableLeftAlignedStyle = getLLVMStyle();
+  DisableLeftAlignedStyle.ColumnLimit = 0;
+  DisableLeftAlignedStyle.IndentWidth = 4;
+  DisableLeftAlignedStyle.ObjCBlockIndentWidth = 4;
+  DisableLeftAlignedStyle.ObjCLeftAlignMultipleBlocks = false;
+
+  verifyFormat("[myObject doSomethingWith:arg1 // Comment\n"
+               "               firstBlock:^(Foo *a) {\n"
+               "                   // ...\n"
+               "                   int i;\n"
+               "               }\n"
+               "              secondBlock:^(Bar *b) {\n"
+               "                  // ...\n"
+               "                  int i;\n"
+               "              }\n"
+               "               thirdBlock:^Foo(Bar *b) {\n"
+               "                   // ...\n"
+               "                   int i;\n"
+               "               }];",
+               DisableLeftAlignedStyle);
+  verifyFormat("[UIView animateWithDuration:0\n"
+               "                 animations:^{\n"
+               "                     view.center = CGPointZero;\n"
+               "                 }\n"
+               "                 completion:^(BOOL finished) {\n"
+               "                     NSLog(complete);\n"
+               "                 }];",
+               DisableLeftAlignedStyle);
+
 }
 
 TEST_F(FormatTest, FormatsBlocksWithZeroColumnWidth) {
@@ -9865,6 +9920,29 @@
             "  int i;\n"
             "};",
             format("void   (^largeBlock)(void) = ^{ int   i; };", ZeroColumn));
+
+  ZeroColumn.ObjCAvoidLineBreaksForInlineBlocks = true;
+  verifyFormat("[UIView animateWithDuration:0 animations:^{ // This does not change behavior\n"
+               "  view.center = CGPointZero;\n"
+               "} completion:^(BOOL finished) {\n"
+               "  NSLog(complete);\n"
+               "}];",
+               ZeroColumn);
+  verifyFormat("[UIView animateWithDuration:0 animations:^{\n"
+               "  view.center = CGPointZero;\n"
+               "} completion:^(BOOL finished) {\n"
+               "  NSLog(complete);\n"
+               "}];",
+               ZeroColumn);
+
+  verifyFormat("[UIView animateWithDuration:0 // Break\n"
+               "    animations:^{\n"
+               "      view.center = CGPointZero;\n"
+               "    }\n"
+               "    completion:^(BOOL finished) {\n"
+               "      NSLog(complete);\n"
+               "    }];",
+               ZeroColumn);
 }
 
 TEST_F(FormatTest, SupportsCRLF) {
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to