Index: include/clang/Format/Format.h
===================================================================
--- include/clang/Format/Format.h
+++ include/clang/Format/Format.h
@@ -222,6 +222,9 @@
/// on a single line.
ShortFunctionStyle AllowShortFunctionsOnASingleLine;
+ /// \brief Compress the selector parts when more than two inline blocks are specified
+ bool ObjCXcodeBlockFormat;
+
/// \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
@@ -416,6 +416,7 @@
} else if (NextNonComment->is(TT_SelectorName)) {
if (!State.Stack.back().ObjCSelectorNameFound) {
if (NextNonComment->LongestObjCSelectorName == 0) {
+ // This catches keys in Literal NSDictionaries
State.Stack.back().AlignColons = false;
} else {
State.Stack.back().ColonPos =
@@ -853,7 +854,7 @@
Tok && Tok != Current.MatchingParen; Tok = Tok->Next) {
if (Tok->MustBreakBefore ||
(Tok->CanBreakBefore && Tok->NewlinesBefore > 0)) {
- BreakBeforeParameter = true;
+ BreakBeforeParameter = Style.ObjCXcodeBlockFormat == false;
break;
}
}
Index: lib/Format/Format.cpp
===================================================================
--- lib/Format/Format.cpp
+++ lib/Format/Format.cpp
@@ -218,6 +218,7 @@
Style.KeepEmptyLinesAtTheStartOfBlocks);
IO.mapOptional("NamespaceIndentation", Style.NamespaceIndentation);
IO.mapOptional("ObjCBlockIndentWidth", Style.ObjCBlockIndentWidth);
+ IO.mapOptional("ObjCXcodeBlockFormat", Style.ObjCXcodeBlockFormat);
IO.mapOptional("ObjCSpaceAfterProperty", Style.ObjCSpaceAfterProperty);
IO.mapOptional("ObjCSpaceBeforeProtocolList",
Style.ObjCSpaceBeforeProtocolList);
@@ -363,6 +364,7 @@
LLVMStyle.KeepEmptyLinesAtTheStartOfBlocks = true;
LLVMStyle.NamespaceIndentation = FormatStyle::NI_None;
LLVMStyle.ObjCBlockIndentWidth = 2;
+ LLVMStyle.ObjCXcodeBlockFormat = 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,8 @@
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.ObjCXcodeBlockFormat == false)
Contexts.back().FirstObjCSelectorName->LongestObjCSelectorName = 0;
}
next();
Index: unittests/Format/FormatTest.cpp
===================================================================
--- unittests/Format/FormatTest.cpp
+++ unittests/Format/FormatTest.cpp
@@ -9799,6 +9799,86 @@
FourIndent);
}
+TEST_F(FormatTest, FormatsXcodeStyleBlocks) {
+ FormatStyle AppleStyle = getLLVMStyle();
+ AppleStyle.ColumnLimit = 0;
+ AppleStyle.IndentWidth = 4;
+ AppleStyle.ObjCBlockIndentWidth = 4;
+ AppleStyle.ObjCXcodeBlockFormat = true;
+ verifyFormat("[operation setCompletionBlock:^(BOOL complete) {\n"
+ " [self onOperationDone];\n"
+ "}];",
+ AppleStyle);
+
+ verifyFormat("[myObject doSomethingWith:arg1 // Comment to force colon alignment\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"
+ " }];",
+ AppleStyle);
+ verifyFormat("[myObject doSomethingWith:arg1 firstBlock:^(Foo *a) {\n"
+ " // ...\n"
+ " int i;\n"
+ "} secondBlock:^(Bar *b) {\n"
+ " // ...\n"
+ " int i;\n"
+ "} thirdBlock:^Foo(Bar *b) {\n"
+ " // ...\n"
+ " int i;\n"
+ "}];",
+ AppleStyle);
+
+ verifyFormat("[[SessionService sharedService]"
+ " loadWindowWithCompletionBlock:^(SessionWindow *window) {\n"
+ " if (window) {\n"
+ " [self windowDidLoad:window];\n"
+ " } else {\n"
+ " [self errorLoadingWindow];\n"
+ " }\n"
+ "}];",
+ AppleStyle);
+
+ verifyFormat("[UIView animateWithDuration:0 animations:^{ // This does not change behavior\n"
+ " view.center = CGPointZero;\n"
+ "} completion:^(BOOL finished) {\n"
+ " NSLog(complete);\n"
+ "}];",
+ AppleStyle);
+ verifyFormat("[UIView animateWithDuration:0 animations:^{\n"
+ " view.center = CGPointZero;\n"
+ "} completion:^(BOOL finished) {\n"
+ " NSLog(complete);\n"
+ "}];",
+ AppleStyle);
+ verifyFormat("[UIView animateWithDuration:0 // This will force colon alignment\n"
+ " animations:^{\n"
+ " view.center = CGPointZero;\n"
+ " }\n"
+ " completion:^(BOOL finished) {\n"
+ " NSLog(complete);\n"
+ " }];",
+ AppleStyle);
+
+ verifyFormat("- (void)aMethod {\n"
+ " [self.magicalRecordStack saveWithBlock:^(NSManagedObjectContext *localContext) {\n"
+ " NSLog(format, localContext);\n"
+ " } completion:^(BOOL success, NSError *error) {\n"
+ " NSLog(format, localContext);\n"
+ " }];\n"
+ "}",
+ AppleStyle);
+
+}
+
+
TEST_F(FormatTest, FormatsBlocksWithZeroColumnWidth) {
FormatStyle ZeroColumn = getLLVMStyle();
ZeroColumn.ColumnLimit = 0;