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
/// \@property (readonly) instead of \@property(readonly).
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) {