From: Francois Ferrand Date: Fri, 9 Feb 2018 15:41:56 +0000 (+0000) Subject: clang-format: keep ObjC colon alignment with short object name X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=7a56f8055529e365f3be6233483a60021e84bebe;p=clang clang-format: keep ObjC colon alignment with short object name Summary: When the target object expression is short and the first selector name is long, clang-format used to break the colon alignment: [I performSelectorOnMainThread:@selector(loadAccessories) withObject:nil waitUntilDone:false]; This happens because the colon is placed at `ContinuationIndent + LongestObjCSelectorName`, so that any selector can be wrapped. This is however not needed in case the longest selector is the firstone, and not wrapped. To overcome this, this patch does not include the first selector in `LongestObjCSelectorName` computation (in TokenAnnotator), and lets `ContinuationIndenter` decide how to account for the first selector when wrapping. (Note this was already partly the case, see line 521 of ContinuationIndenter.cpp) This way, the code gets properly aligned whenever possible without breaking the continuation indent. [I performSelectorOnMainThread:@selector(loadAccessories) withObject:nil waitUntilDone:false]; [I // force break performSelectorOnMainThread:@selector(loadAccessories) withObject:nil waitUntilDone:false]; [I perform:@selector(loadAccessories) withSelectorOnMainThread:true waitUntilDone:false]; Reviewers: krasimir, djasper, klimek Subscribers: cfe-commits Differential Revision: https://reviews.llvm.org/D43121 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@324741 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Format/ContinuationIndenter.cpp b/lib/Format/ContinuationIndenter.cpp index 14f8f05645..109dd1749a 100644 --- a/lib/Format/ContinuationIndenter.cpp +++ b/lib/Format/ContinuationIndenter.cpp @@ -701,7 +701,8 @@ unsigned ContinuationIndenter::addTokenOnNewLine(LineState &State, ? std::max(State.Stack.back().Indent, State.FirstIndent + Style.ContinuationIndentWidth) : State.Stack.back().Indent) + - NextNonComment->LongestObjCSelectorName; + std::max(NextNonComment->LongestObjCSelectorName, + NextNonComment->ColumnWidth); } } else if (State.Stack.back().AlignColons && State.Stack.back().ColonPos <= NextNonComment->ColumnWidth) { @@ -900,7 +901,8 @@ unsigned ContinuationIndenter::getNewLineColumn(const LineState &State) { ? std::max(State.Stack.back().Indent, State.FirstIndent + Style.ContinuationIndentWidth) : State.Stack.back().Indent) + - NextNonComment->LongestObjCSelectorName - + std::max(NextNonComment->LongestObjCSelectorName, + NextNonComment->ColumnWidth) - NextNonComment->ColumnWidth; } if (!State.Stack.back().AlignColons) diff --git a/lib/Format/TokenAnnotator.cpp b/lib/Format/TokenAnnotator.cpp index d8c3366941..78c69d1e0f 100644 --- a/lib/Format/TokenAnnotator.cpp +++ b/lib/Format/TokenAnnotator.cpp @@ -591,12 +591,12 @@ private: BeforePrevious->is(tok::r_square) || Contexts.back().LongestObjCSelectorName == 0) { Tok->Previous->Type = TT_SelectorName; - if (Tok->Previous->ColumnWidth > - Contexts.back().LongestObjCSelectorName) - Contexts.back().LongestObjCSelectorName = - Tok->Previous->ColumnWidth; if (!Contexts.back().FirstObjCSelectorName) Contexts.back().FirstObjCSelectorName = Tok->Previous; + else if (Tok->Previous->ColumnWidth > + Contexts.back().LongestObjCSelectorName) + Contexts.back().LongestObjCSelectorName = + Tok->Previous->ColumnWidth; } } else if (Contexts.back().ColonIsForRangeExpr) { Tok->Type = TT_RangeBasedForLoopColon; diff --git a/unittests/Format/FormatTestObjC.cpp b/unittests/Format/FormatTestObjC.cpp index df2e067a30..a2cfb27eaf 100644 --- a/unittests/Format/FormatTestObjC.cpp +++ b/unittests/Format/FormatTestObjC.cpp @@ -693,8 +693,8 @@ TEST_F(FormatTestObjC, FormatObjCMethodExpr) { // Formats pair-parameters. verifyFormat("[I drawRectOn:surface ofSize:aa:bbb atOrigin:cc:dd];"); verifyFormat("[I drawRectOn:surface //\n" - " ofSize:aa:bbb\n" - " atOrigin:cc:dd];"); + " ofSize:aa:bbb\n" + " atOrigin:cc:dd];"); // Inline block as a first argument. verifyFormat("[object justBlock:^{\n" @@ -760,6 +760,26 @@ TEST_F(FormatTestObjC, FormatObjCMethodExpr) { " backing:NSBackingStoreBuffered\n" " defer:NO]);\n" "}"); + + // Respect continuation indent and colon alignment (e.g. when object name is + // short, and first selector is the longest one) + Style = getLLVMStyle(); + Style.Language = FormatStyle::LK_ObjC; + Style.ContinuationIndentWidth = 8; + verifyFormat("[self performSelectorOnMainThread:@selector(loadAccessories)\n" + " withObject:nil\n" + " waitUntilDone:false];"); + verifyFormat("[self performSelector:@selector(loadAccessories)\n" + " withObjectOnMainThread:nil\n" + " waitUntilDone:false];"); + verifyFormat("[aaaaaaaaaaaaaaaaaaaaaaaaa\n" + " performSelectorOnMainThread:@selector(loadAccessories)\n" + " withObject:nil\n" + " waitUntilDone:false];"); + verifyFormat("[self // force wrapping\n" + " performSelectorOnMainThread:@selector(loadAccessories)\n" + " withObject:nil\n" + " waitUntilDone:false];"); } TEST_F(FormatTestObjC, ObjCAt) {