]> granicus.if.org Git - clang/commitdiff
clang-format: keep ObjC colon alignment with short object name
authorFrancois Ferrand <thetypz@gmail.com>
Fri, 9 Feb 2018 15:41:56 +0000 (15:41 +0000)
committerFrancois Ferrand <thetypz@gmail.com>
Fri, 9 Feb 2018 15:41:56 +0000 (15:41 +0000)
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

lib/Format/ContinuationIndenter.cpp
lib/Format/TokenAnnotator.cpp
unittests/Format/FormatTestObjC.cpp

index 14f8f05645de64e1c22e5db59e3c308d2fa92ed1..109dd1749ab36f7c0783c7982b047edc7fb2aa10 100644 (file)
@@ -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)
index d8c3366941c1b5f30765b1bbb72e6b475942a1c0..78c69d1e0fa0b00b7c29fc4692f266ac5a2a6b89 100644 (file)
@@ -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;
index df2e067a302a7ca0b45d21cb9f6ecd5dce436aa0..a2cfb27eafffd97fe3cb84e59dfad5d98db5705e 100644 (file)
@@ -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) {