r209720 - clang-format: Format array and dict literals similar to blocks.

Daniel Jasper djasper at google.com
Wed May 28 02:11:54 PDT 2014


Author: djasper
Date: Wed May 28 04:11:53 2014
New Revision: 209720

URL: http://llvm.org/viewvc/llvm-project?rev=209720&view=rev
Log:
clang-format: Format array and dict literals similar to blocks.

Especially, reduce the amount of indentation if it doesn't increase
readability.

Before:
  NSMutableDictionary* dictionary = [NSMutableDictionary
      dictionaryWithDictionary:@{
                                 aaaaaaaaaaaaaaaaaaaaa : aaaaaaaaaaaaa,
                                 bbbbbbbbbbbbbbbbbb : bbbbb,
                                 cccccccccccccccc : ccccccccccccccc
                               }];

After:
  NSMutableDictionary* dictionary =
      [NSMutableDictionary dictionaryWithDictionary:@{
        aaaaaaaaaaaaaaaaaaaaa : aaaaaaaaaaaaa,
        bbbbbbbbbbbbbbbbbb : bbbbb,
        cccccccccccccccc : ccccccccccccccc
      }];

Modified:
    cfe/trunk/lib/Format/ContinuationIndenter.cpp
    cfe/trunk/unittests/Format/FormatTest.cpp

Modified: cfe/trunk/lib/Format/ContinuationIndenter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/ContinuationIndenter.cpp?rev=209720&r1=209719&r2=209720&view=diff
==============================================================================
--- cfe/trunk/lib/Format/ContinuationIndenter.cpp (original)
+++ cfe/trunk/lib/Format/ContinuationIndenter.cpp Wed May 28 04:11:53 2014
@@ -736,25 +736,58 @@ void ContinuationIndenter::moveStatePast
   }
 }
 
+// Remove the fake r_parens after 'Tok'.
+static void consumeRParens(LineState& State, const FormatToken &Tok) {
+  for (unsigned i = 0, e = Tok.FakeRParens; i != e; ++i) {
+    unsigned VariablePos = State.Stack.back().VariablePos;
+    assert(State.Stack.size() > 1);
+    if (State.Stack.size() == 1) {
+      // Do not pop the last element.
+      break;
+    }
+    State.Stack.pop_back();
+    State.Stack.back().VariablePos = VariablePos;
+  }
+}
+
+// Returns whether 'Tok' opens or closes a scope requiring special handling
+// of the subsequent fake r_parens.
+//
+// For example, if this is an l_brace starting a nested block, we pretend (wrt.
+// to indentation) that we already consumed the corresponding r_brace. Thus, we
+// remove all ParenStates caused by fake parentheses that end at the r_brace.
+// The net effect of this is that we don't indent relative to the l_brace, if
+// the nested block is the last parameter of a function. This formats:
+//
+//   SomeFunction(a, [] {
+//     f();  // break
+//   });
+//
+// instead of:
+//   SomeFunction(a, [] {
+//                     f();  // break
+//                   });
+static bool fakeRParenSpecialCase(const FormatToken& Tok) {
+  if (!Tok.MatchingParen)
+    return false;
+  const FormatToken *Left = &Tok;
+  if (Tok.isOneOf(tok::r_brace, tok::r_square))
+    Left = Tok.MatchingParen;
+  return Left->isOneOf(tok::l_brace, tok::l_square) &&
+         (Left->BlockKind == BK_Block ||
+          Left->Type == TT_ArrayInitializerLSquare ||
+          Left->Type == TT_DictLiteral);
+}
+
 void ContinuationIndenter::moveStatePastFakeRParens(LineState &State) {
   const FormatToken &Current = *State.NextToken;
 
-  // Remove scopes created by fake parenthesis.
-  if (Current.isNot(tok::r_brace) ||
-      (Current.MatchingParen && Current.MatchingParen->BlockKind != BK_Block)) {
-    // Don't remove FakeRParens attached to r_braces that surround nested blocks
-    // as they will have been removed early (see above).
-    for (unsigned i = 0, e = Current.FakeRParens; i != e; ++i) {
-      unsigned VariablePos = State.Stack.back().VariablePos;
-      assert(State.Stack.size() > 1);
-      if (State.Stack.size() == 1) {
-        // Do not pop the last element.
-        break;
-      }
-      State.Stack.pop_back();
-      State.Stack.back().VariablePos = VariablePos;
-    }
-  }
+  // Don't remove FakeRParens attached to r_braces that surround nested blocks
+  // as they will have been removed early (see above).
+  if (fakeRParenSpecialCase(Current))
+    return;
+
+  consumeRParens(State, *State.NextToken);
 }
 
 void ContinuationIndenter::moveStatePastScopeOpener(LineState &State,
@@ -773,6 +806,9 @@ void ContinuationIndenter::moveStatePast
   bool AvoidBinPacking;
   bool BreakBeforeParameter = false;
   if (Current.is(tok::l_brace) || Current.Type == TT_ArrayInitializerLSquare) {
+    if (fakeRParenSpecialCase(Current))
+      consumeRParens(State, *Current.MatchingParen);
+
     NewIndent = State.Stack.back().LastSpace;
     if (Current.opensBlockTypeList(Style)) {
       NewIndent += Style.IndentWidth;
@@ -824,9 +860,9 @@ void ContinuationIndenter::moveStatePast
   if (State.Stack.size() > 1 &&
       (Current.isOneOf(tok::r_paren, tok::r_square) ||
        (Current.is(tok::r_brace) && State.NextToken != State.Line->First) ||
-       State.NextToken->Type == TT_TemplateCloser)) {
+       State.NextToken->Type == TT_TemplateCloser))
     State.Stack.pop_back();
-  }
+
   if (Current.is(tok::r_square)) {
     // If this ends the array subscript expr, reset the corresponding value.
     const FormatToken *NextNonComment = Current.getNextNonComment();
@@ -836,35 +872,13 @@ void ContinuationIndenter::moveStatePast
 }
 
 void ContinuationIndenter::moveStateToNewBlock(LineState &State) {
-  // If this is an l_brace starting a nested block, we pretend (wrt. to
-  // indentation) that we already consumed the corresponding r_brace. Thus, we
-  // remove all ParenStates caused by fake parentheses that end at the r_brace.
-  // The net effect of this is that we don't indent relative to the l_brace, if
-  // the nested block is the last parameter of a function. For example, this
-  // formats:
-  //
-  //   SomeFunction(a, [] {
-  //     f();  // break
-  //   });
-  //
-  // instead of:
-  //   SomeFunction(a, [] {
-  //                     f();  // break
-  //                   });
-  //
   // If we have already found more than one lambda introducers on this level, we
   // opt out of this because similarity between the lambdas is more important.
-  if (State.Stack.back().LambdasFound <= 1) {
-    for (unsigned i = 0; i != State.NextToken->MatchingParen->FakeRParens;
-         ++i) {
-      assert(State.Stack.size() > 1);
-      if (State.Stack.size() == 1) {
-        // Do not pop the last element.
-        break;
-      }
-      State.Stack.pop_back();
-    }
-  }
+  // FIXME: This should use fakeRParenSpecialCase() and fakeRParenSpecialCase()
+  // Needs to include the LambdasFound check. Otherwise the corresponding
+  // fake r_parens will never be consumed.
+  if (State.Stack.back().LambdasFound <= 1)
+    consumeRParens(State, *State.NextToken->MatchingParen);
 
   // For some reason, ObjC blocks are indented like continuations.
   unsigned NewIndent = State.Stack.back().LastSpace +

Modified: cfe/trunk/unittests/Format/FormatTest.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Format/FormatTest.cpp?rev=209720&r1=209719&r2=209720&view=diff
==============================================================================
--- cfe/trunk/unittests/Format/FormatTest.cpp (original)
+++ cfe/trunk/unittests/Format/FormatTest.cpp Wed May 28 04:11:53 2014
@@ -6491,6 +6491,12 @@ TEST_F(FormatTest, ObjCDictLiterals) {
       "  @\"dte\" : [NSDate date],\n"
       "  @\"processInfo\" : [NSProcessInfo processInfo]\n"
       "};");
+  verifyFormat("NSMutableDictionary *dictionary =\n"
+               "    [NSMutableDictionary dictionaryWithDictionary:@{\n"
+               "      aaaaaaaaaaaaaaaaaaaaa : aaaaaaaaaaaaa,\n"
+               "      bbbbbbbbbbbbbbbbbb : bbbbb,\n"
+               "      cccccccccccccccc : ccccccccccccccc\n"
+               "    }];");
 }
 
 TEST_F(FormatTest, ObjCArrayLiterals) {
@@ -8590,10 +8596,12 @@ TEST_F(FormatTest, FormatsWithWebKitStyl
             format("NSArray*a=[[NSArray alloc]initWithArray:@[ @\"a\" ]\n"
                    "             copyItems:YES];",
                    Style));
+  // FIXME: This does not seem right, there should be more indentation before
+  // the array literal's entries. Nested blocks have the same problem.
   EXPECT_EQ("NSArray* a = [[NSArray alloc] initWithArray:@[\n"
-            "                                               @\"a\",\n"
-            "                                               @\"a\"\n"
-            "                                            ]\n"
+            "    @\"a\",\n"
+            "    @\"a\"\n"
+            "]\n"
             "                                  copyItems:YES];",
             format("NSArray* a = [[NSArray alloc] initWithArray:@[\n"
                    "     @\"a\",\n"





More information about the cfe-commits mailing list