diff --git a/clang/docs/ClangFormatStyleOptions.rst b/clang/docs/ClangFormatStyleOptions.rst --- a/clang/docs/ClangFormatStyleOptions.rst +++ b/clang/docs/ClangFormatStyleOptions.rst @@ -1993,6 +1993,29 @@ [self onOperationDone]; }]; +**ObjCBreakBeforeNestedBlockParam** (``bool``) + Break parameters list into lines when there is nested block + parameters in a fuction call. + + .. code-block:: c++ + + false: + - (void)_aMethod + { + [self.test1 t:self w:self callback:^(typeof(self) self, NSNumber *u, NSNumber *v) { + u = c; + }] + } + true: + - (void)_aMethod + { + [self.test1 t:self + w:self + callback:^(typeof(self) self, NSNumber *u, NSNumber *v) { + u = c; + }] + } + **ObjCSpaceAfterProperty** (``bool``) Add a space after ``@property`` in Objective-C, i.e. use ``@property (readonly)`` instead of ``@property(readonly)``. diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -341,6 +341,9 @@ int a [5]; vs int a[5]; +- Option ``ObjCBreakBeforeNestedBlockParam`` has been added to optionally apply + linebreaks for function arguments declarations before nested blocks. + - Clang-format now supports JavaScript null operators. .. code-block:: c++ diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h --- a/clang/include/clang/Format/Format.h +++ b/clang/include/clang/Format/Format.h @@ -1646,6 +1646,28 @@ /// ``@property (readonly)`` instead of ``@property(readonly)``. bool ObjCSpaceAfterProperty; + /// Break parameters list into lines when there is nested block + /// parameters in a fuction call. + /// \code + /// false: + /// - (void)_aMethod + /// { + /// [self.test1 t:self w:self callback:^(typeof(self) self, NSNumber *u, NSNumber *v) { + /// u = c; + /// }] + /// } + /// true: + /// - (void)_aMethod + /// { + /// [self.test1 t:self + /// w:self + /// callback:^(typeof(self) self, NSNumber *u, NSNumber *v) { + /// u = c; + /// }] + /// } + /// \endcode + bool ObjCBreakBeforeNestedBlockParam; + /// Add a space in front of an Objective-C protocol list, i.e. use /// ``Foo `` instead of ``Foo``. bool ObjCSpaceBeforeProtocolList; @@ -2135,6 +2157,7 @@ NamespaceMacros == R.NamespaceMacros && ObjCBinPackProtocolList == R.ObjCBinPackProtocolList && ObjCBlockIndentWidth == R.ObjCBlockIndentWidth && + ObjCBreakBeforeNestedBlockParam == R.ObjCBreakBeforeNestedBlockParam && ObjCSpaceAfterProperty == R.ObjCSpaceAfterProperty && ObjCSpaceBeforeProtocolList == R.ObjCSpaceBeforeProtocolList && PenaltyBreakAssignment == R.PenaltyBreakAssignment && diff --git a/clang/lib/Format/ContinuationIndenter.cpp b/clang/lib/Format/ContinuationIndenter.cpp --- a/clang/lib/Format/ContinuationIndenter.cpp +++ b/clang/lib/Format/ContinuationIndenter.cpp @@ -861,8 +861,10 @@ // Any break on this level means that the parent level has been broken // and we need to avoid bin packing there. bool NestedBlockSpecialCase = - !Style.isCpp() && Current.is(tok::r_brace) && State.Stack.size() > 1 && - State.Stack[State.Stack.size() - 2].NestedBlockInlined; + (!Style.isCpp() && Current.is(tok::r_brace) && State.Stack.size() > 1 && + State.Stack[State.Stack.size() - 2].NestedBlockInlined) || + (Style.Language == FormatStyle::LK_ObjC && Current.is(tok::r_brace) + && State.Stack.size() > 1 && !Style.ObjCBreakBeforeNestedBlockParam); if (!NestedBlockSpecialCase) for (unsigned i = 0, e = State.Stack.size() - 1; i != e; ++i) State.Stack[i].BreakBeforeParameter = true; @@ -1380,7 +1382,8 @@ (!BinPackInconclusiveFunctions && Current.PackingKind == PPK_Inconclusive))); - if (Current.is(TT_ObjCMethodExpr) && Current.MatchingParen) { + if (Current.is(TT_ObjCMethodExpr) && Current.MatchingParen && + Style.ObjCBreakBeforeNestedBlockParam) { 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. diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp --- a/clang/lib/Format/Format.cpp +++ b/clang/lib/Format/Format.cpp @@ -497,6 +497,8 @@ IO.mapOptional("NamespaceMacros", Style.NamespaceMacros); IO.mapOptional("ObjCBinPackProtocolList", Style.ObjCBinPackProtocolList); IO.mapOptional("ObjCBlockIndentWidth", Style.ObjCBlockIndentWidth); + IO.mapOptional("ObjCBreakBeforeNestedBlockParam", + Style.ObjCBreakBeforeNestedBlockParam); IO.mapOptional("ObjCSpaceAfterProperty", Style.ObjCSpaceAfterProperty); IO.mapOptional("ObjCSpaceBeforeProtocolList", Style.ObjCSpaceBeforeProtocolList); @@ -794,6 +796,7 @@ LLVMStyle.NamespaceIndentation = FormatStyle::NI_None; LLVMStyle.ObjCBinPackProtocolList = FormatStyle::BPS_Auto; LLVMStyle.ObjCBlockIndentWidth = 2; + LLVMStyle.ObjCBreakBeforeNestedBlockParam = true; LLVMStyle.ObjCSpaceAfterProperty = false; LLVMStyle.ObjCSpaceBeforeProtocolList = true; LLVMStyle.PointerAlignment = FormatStyle::PAS_Right; diff --git a/clang/unittests/Format/FormatTestObjC.cpp b/clang/unittests/Format/FormatTestObjC.cpp --- a/clang/unittests/Format/FormatTestObjC.cpp +++ b/clang/unittests/Format/FormatTestObjC.cpp @@ -1398,6 +1398,32 @@ "}"); } +TEST_F(FormatTestObjC, BreakLineBeforeNestedBlockParam) { + Style = getGoogleStyle(FormatStyle::LK_ObjC); + Style.ObjCBreakBeforeNestedBlockParam = false; + Style.ColumnLimit = 0; + + verifyFormat("[self.test1 t:self callback:^(typeof(self) self, NSNumber *u, NSNumber *v) {\n" + " u = v;\n" + "}]"); + + verifyFormat("[self.test1 t:self w:self callback:^(typeof(self) self, NSNumber *u, NSNumber *v) {\n" + " u = v;\n" + "}]"); + + verifyFormat("[self.test1 t:self w:self callback:^(typeof(self) self, NSNumber *u, NSNumber *v) {\n" + " u = c;\n" + "} w:self callback2:^(typeof(self) self, NSNumber *a, NSNumber *b, NSNumber *c) {\n" + " b = c;\n" + "}]"); + + Style.ColumnLimit = 80; + verifyFormat("[self.test_method a:self b:self\n" + " callback:^(typeof(self) self, NSNumber *u, NSNumber *v) {\n" + " u = v;\n" + " }]"); +} + } // end namespace } // end namespace format } // end namespace clang