]> granicus.if.org Git - clang/commitdiff
[clang-format] Fix putting ObjC message arguments in one line for multiline receiver
authorJacek Olesiak <jolesiak@google.com>
Thu, 24 May 2018 10:50:36 +0000 (10:50 +0000)
committerJacek Olesiak <jolesiak@google.com>
Thu, 24 May 2018 10:50:36 +0000 (10:50 +0000)
Summary:
Reapply reverted changes from D46879.

Currently BreakBeforeParameter is set to true everytime message receiver spans multiple lines, e.g.:
```
[[object block:^{
  return 42;
}] aa:42 bb:42];
```
will be formatted:
```
[[object block:^{
  return 42;
}] aa:42
   bb:42];
```
even though arguments could fit into one line. This change fixes this behavior.

Test Plan:
make -j12 FormatTests && tools/clang/unittests/Format/FormatTests

Reviewers: benhamilton, krasimir

Reviewed By: benhamilton, krasimir

Subscribers: djasper, klimek, cfe-commits

Differential Revision: https://reviews.llvm.org/D47195

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@333171 91177308-0d34-0410-b5e6-96231b3b80d8

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

index eacdfdc6e0532aab44f1f19a993f9c802dce1875..ac871471d9d7eb29de862a0fe00a7ac249439aaf 100644 (file)
@@ -1387,6 +1387,29 @@ void ContinuationIndenter::moveStatePastScopeCloser(LineState &State) {
        (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 c29c9d702bc9691ad020b60f49c4b977aa805638..43510c42790abcc981e9819dd234eaeab1a2ed39 100644 (file)
@@ -796,6 +796,41 @@ TEST_F(FormatTestObjC, FormatObjCMethodExpr) {
   verifyFormat("[((Foo *)foo) bar];");
   verifyFormat("[((Foo *)foo) bar:1 blech:2];");
 
+  // Message receiver taking multiple lines.
+  Style.ColumnLimit = 20;
+  // Non-corner case.
+  verifyFormat("[[object block:^{\n"
+               "  return 42;\n"
+               "}] a:42 b:42];");
+  // Arguments just fit into one line.
+  verifyFormat("[[object block:^{\n"
+               "  return 42;\n"
+               "}] aaaaaaa:42 b:42];");
+  // Arguments just over a column limit.
+  verifyFormat("[[object block:^{\n"
+               "  return 42;\n"
+               "}] aaaaaaa:42\n"
+               "        bb:42];");
+  // Arguments just fit into one line.
+  Style.ColumnLimit = 23;
+  verifyFormat("[[obj a:42\n"
+               "      b:42\n"
+               "      c:42\n"
+               "      d:42] e:42 f:42];");
+
+  // Arguments do not fit into one line with a receiver.
+  Style.ColumnLimit = 20;
+  verifyFormat("[[obj a:42] a:42\n"
+               "            b:42];");
+  verifyFormat("[[obj a:42] a:42\n"
+               "            b:42\n"
+               "            c:42];");
+  verifyFormat("[[obj aaaaaa:42\n"
+               "           b:42]\n"
+               "    cc:42\n"
+               "     d:42];");
+
+
   Style.ColumnLimit = 70;
   verifyFormat(
       "void f() {\n"