Index: lib/Format/ContinuationIndenter.cpp =================================================================== --- lib/Format/ContinuationIndenter.cpp +++ lib/Format/ContinuationIndenter.cpp @@ -1073,34 +1073,8 @@ if (Current.isMemberAccess()) State.Stack.back().StartOfFunctionCall = !Current.NextOperator ? 0 : State.Column; - if (Current.is(TT_SelectorName) && - !State.Stack.back().ObjCSelectorNameFound) { + if (Current.is(TT_SelectorName)) State.Stack.back().ObjCSelectorNameFound = true; - - // Reevaluate whether ObjC message arguments fit into one line. - // If a receiver spans multiple lines, e.g.: - // [[object block:^{ - // return 42; - // }] a:42 b:42]; - // BreakBeforeParameter is calculated based on an incorrect assumption - // (it is checked whether the whole expression fits into one line without - // considering a line break inside a message receiver). - if (Current.Previous && Current.Previous->closesScope() && - Current.Previous->MatchingParen && - Current.Previous->MatchingParen->Previous) { - const FormatToken &CurrentScopeOpener = - *Current.Previous->MatchingParen->Previous; - if (CurrentScopeOpener.is(TT_ObjCMethodExpr) && - CurrentScopeOpener.MatchingParen) { - int NecessarySpaceInLine = - getLengthToMatchingParen(CurrentScopeOpener, State.Stack) + - CurrentScopeOpener.TotalLength - Current.TotalLength - 1; - if (State.Column + Current.ColumnWidth + NecessarySpaceInLine <= - Style.ColumnLimit) - State.Stack.back().BreakBeforeParameter = false; - } - } - } if (Current.is(TT_CtorInitializerColon) && Style.BreakConstructorInitializers != FormatStyle::BCIS_AfterColon) { // Indent 2 from the column, so: @@ -1412,6 +1386,29 @@ (Current.is(tok::greater) && Current.is(TT_DictLiteral)))) State.Stack.pop_back(); + // Reevaluate whether ObjC message arguments fit into one line. + // If a receiver spans multiple lines, e.g.: + // [[object block:^{ + // return 42; + // }] a:42 b:42]; + // BreakBeforeParameter is calculated based on an incorrect assumption + // (it is checked whether the whole expression fits into one line without + // considering a line break inside a message receiver). + // We check whether arguements fit after receiver scope closer (into the same + // line). + if (Current.MatchingParen && Current.MatchingParen->Previous) { + const FormatToken &CurrentScopeOpener = *Current.MatchingParen->Previous; + if (CurrentScopeOpener.is(TT_ObjCMethodExpr) && + CurrentScopeOpener.MatchingParen) { + int NecessarySpaceInLine = + getLengthToMatchingParen(CurrentScopeOpener, State.Stack) + + CurrentScopeOpener.TotalLength - Current.TotalLength - 1; + if (State.Column + Current.ColumnWidth + NecessarySpaceInLine <= + Style.ColumnLimit) + State.Stack.back().BreakBeforeParameter = false; + } + } + if (Current.is(tok::r_square)) { // If this ends the array subscript expr, reset the corresponding value. const FormatToken *NextNonComment = Current.getNextNonComment(); Index: unittests/Format/FormatTestObjC.cpp =================================================================== --- unittests/Format/FormatTestObjC.cpp +++ unittests/Format/FormatTestObjC.cpp @@ -811,19 +811,17 @@ " return 42;\n" "}] aaaaaaa:42\n" " bb:42];"); - // Non-corner case. - verifyFormat("[[object aaa:42\n" - " b:42]\n" - " cc:42 d:42];"); - // Arguments just fit into one line. - verifyFormat("[[object aaa:42\n" - " b:42]\n" - " cccccc:42 d:42];"); - // Arguments just over a column limit. - verifyFormat("[[object aaa:42\n" + + // No line break before closing receiver's scope. + verifyFormat("[[obj a:42] a:42\n" + " b:42];\n"); + verifyFormat("[[obj a:42] a:42\n" + " b:42\n" + " c:42];\n"); + verifyFormat("[[obj aaaaaa:42\n" " b:42]\n" - " cccccc:42\n" - " dd:42];"); + " cc:42\n" + " d:42];"); Style.ColumnLimit = 70; verifyFormat(