r193167 - clang-format: Improve formatting of ObjC array literals.

Daniel Jasper djasper at google.com
Tue Oct 22 08:30:28 PDT 2013


Author: djasper
Date: Tue Oct 22 10:30:28 2013
New Revision: 193167

URL: http://llvm.org/viewvc/llvm-project?rev=193167&view=rev
Log:
clang-format: Improve formatting of ObjC array literals.

Before:
  NSArray *arguments =
      @[ kind == kUserTicket ? @"--user-store" : @"--system-store",
         @"--print-tickets", @"--productid", @"com.google.Chrome" ];
After:
  NSArray *arguments = @[
      kind == kUserTicket ? @"--user-store" : @"--system-store",
      @"--print-tickets",
      @"--productid",
      @"com.google.Chrome"
  ];

This fixes llvm.org/PR15231.

Modified:
    cfe/trunk/lib/Format/ContinuationIndenter.cpp
    cfe/trunk/lib/Format/FormatToken.h
    cfe/trunk/lib/Format/TokenAnnotator.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=193167&r1=193166&r2=193167&view=diff
==============================================================================
--- cfe/trunk/lib/Format/ContinuationIndenter.cpp (original)
+++ cfe/trunk/lib/Format/ContinuationIndenter.cpp Tue Oct 22 10:30:28 2013
@@ -92,8 +92,8 @@ bool ContinuationIndenter::canBreak(cons
   const FormatToken &Current = *State.NextToken;
   const FormatToken &Previous = *Current.Previous;
   assert(&Previous == Current.Previous);
-  if (!Current.CanBreakBefore &&
-      !(Current.is(tok::r_brace) && State.Stack.back().BreakBeforeClosingBrace))
+  if (!Current.CanBreakBefore && !(State.Stack.back().BreakBeforeClosingBrace &&
+                                   Current.closesBlockTypeList(Style)))
     return false;
   // The opening "{" of a braced list has to be on the same line as the first
   // element if it is nested in another braced init list or function call.
@@ -118,10 +118,8 @@ bool ContinuationIndenter::mustBreak(con
   const FormatToken &Previous = *Current.Previous;
   if (Current.MustBreakBefore || Current.Type == TT_InlineASMColon)
     return true;
-  if ((!Style.Cpp11BracedListStyle ||
-       (Current.MatchingParen &&
-        Current.MatchingParen->BlockKind == BK_Block)) &&
-      Current.is(tok::r_brace) && State.Stack.back().BreakBeforeClosingBrace)
+  if (State.Stack.back().BreakBeforeClosingBrace &&
+      Current.closesBlockTypeList(Style))
     return true;
   if (Previous.is(tok::semi) && State.LineContainsContinuedForLoopSection)
     return true;
@@ -136,7 +134,8 @@ bool ContinuationIndenter::mustBreak(con
       !Previous.isOneOf(tok::kw_return, tok::lessless) &&
       Previous.Type != TT_InlineASMColon && NextIsMultilineString(State))
     return true;
-  if (Previous.Type == TT_ObjCDictLiteral && Previous.is(tok::l_brace) &&
+  if (((Previous.Type == TT_ObjCDictLiteral && Previous.is(tok::l_brace)) ||
+       Previous.Type == TT_ArrayInitializerLSquare) &&
       getLengthToMatchingParen(Previous) + State.Column > getColumnLimit(State))
     return true;
 
@@ -332,10 +331,8 @@ unsigned ContinuationIndenter::addTokenO
 
   if (Current.is(tok::l_brace) && Current.BlockKind == BK_Block) {
     State.Column = State.FirstIndent;
-  } else if (Current.is(tok::r_brace)) {
-    if (Current.MatchingParen &&
-        (Current.MatchingParen->BlockKind == BK_BracedInit ||
-         !Current.MatchingParen->Children.empty()))
+  } else if (Current.isOneOf(tok::r_brace, tok::r_square)) {
+    if (Current.closesBlockTypeList(Style))
       State.Column = State.Stack[State.Stack.size() - 2].LastSpace;
     else
       State.Column = State.FirstIndent;
@@ -372,8 +369,7 @@ unsigned ContinuationIndenter::addTokenO
       State.Column = State.Stack.back().Indent;
       State.Stack.back().ColonPos = State.Column + Current.ColumnWidth;
     }
-  } else if (Current.is(tok::l_square) && Current.Type != TT_ObjCMethodExpr &&
-             Current.Type != TT_LambdaLSquare) {
+  } else if (Current.Type == TT_ArraySubscriptLSquare) {
     if (State.Stack.back().StartOfArraySubscripts != 0)
       State.Column = State.Stack.back().StartOfArraySubscripts;
     else
@@ -431,8 +427,9 @@ unsigned ContinuationIndenter::addTokenO
       TokenBefore->Type != TT_BinaryOperator && !TokenBefore->opensScope())
     State.Stack.back().BreakBeforeParameter = true;
 
-  // If we break after {, we should also break before the corresponding }.
-  if (Previous.is(tok::l_brace))
+  // If we break after { or the [ of an array initializer, we should also break
+  // before the corresponding } or ].
+  if (Previous.is(tok::l_brace) || Previous.Type == TT_ArrayInitializerLSquare)
     State.Stack.back().BreakBeforeClosingBrace = true;
 
   if (State.Stack.back().AvoidBinPacking) {
@@ -457,7 +454,7 @@ unsigned ContinuationIndenter::moveState
     State.Stack.back().AvoidBinPacking = true;
   if (Current.is(tok::lessless) && State.Stack.back().FirstLessLess == 0)
     State.Stack.back().FirstLessLess = State.Column;
-  if (Current.is(tok::l_square) && Current.Type != TT_LambdaLSquare &&
+  if (Current.Type == TT_ArraySubscriptLSquare &&
       State.Stack.back().StartOfArraySubscripts == 0)
     State.Stack.back().StartOfArraySubscripts = State.Column;
   if (Current.is(tok::question))
@@ -527,7 +524,7 @@ unsigned ContinuationIndenter::moveState
         (!SkipFirstExtraIndent && *I > prec::Assignment &&
          !Style.BreakBeforeBinaryOperators))
       NewParenState.Indent += Style.ContinuationIndentWidth;
-    if (Previous && !Previous->opensScope())
+    if ((Previous && !Previous->opensScope()) || *I > prec::Comma)
       NewParenState.BreakBeforeParameter = false;
     State.Stack.push_back(NewParenState);
     SkipFirstExtraIndent = false;
@@ -539,7 +536,9 @@ unsigned ContinuationIndenter::moveState
     unsigned NewIndent;
     unsigned NewIndentLevel = State.Stack.back().IndentLevel;
     bool AvoidBinPacking;
-    if (Current.is(tok::l_brace)) {
+    bool BreakBeforeParameter = false;
+    if (Current.is(tok::l_brace) ||
+        Current.Type == TT_ArrayInitializerLSquare) {
       if (Current.MatchingParen && Current.BlockKind == BK_Block) {
         // If this is an l_brace starting a nested block, we pretend (wrt. to
         // indentation) that we already consumed the corresponding r_brace.
@@ -560,6 +559,7 @@ unsigned ContinuationIndenter::moveState
           State.Stack.pop_back();
         NewIndent = State.Stack.back().LastSpace + Style.IndentWidth;
         ++NewIndentLevel;
+        BreakBeforeParameter = true;
       } else {
         NewIndent = State.Stack.back().LastSpace;
         if (Style.Cpp11BracedListStyle)
@@ -571,6 +571,8 @@ unsigned ContinuationIndenter::moveState
       }
       const FormatToken *NextNoComment = Current.getNextNonComment();
       AvoidBinPacking = Current.BlockKind == BK_Block ||
+                        Current.Type == TT_ArrayInitializerLSquare ||
+                        Current.Type == TT_ObjCDictLiteral ||
                         (NextNoComment &&
                          NextNoComment->Type == TT_DesignatedInitializerPeriod);
     } else {
@@ -582,6 +584,12 @@ unsigned ContinuationIndenter::moveState
                          (Current.PackingKind == PPK_OnePerLine ||
                           (!BinPackInconclusiveFunctions &&
                            Current.PackingKind == PPK_Inconclusive)));
+      // If this '[' opens an ObjC call, determine whether all parameters fit
+      // into one line and put one per line if they don't.
+      if (Current.Type == TT_ObjCMethodExpr &&
+          getLengthToMatchingParen(Current) + State.Column >
+              getColumnLimit(State))
+        BreakBeforeParameter = true;
     }
 
     bool NoLineBreak = State.Stack.back().NoLineBreak ||
@@ -590,23 +598,10 @@ unsigned ContinuationIndenter::moveState
     State.Stack.push_back(ParenState(NewIndent, NewIndentLevel,
                                      State.Stack.back().LastSpace,
                                      AvoidBinPacking, NoLineBreak));
-    State.Stack.back().BreakBeforeParameter = Current.BlockKind == BK_Block;
+    State.Stack.back().BreakBeforeParameter = BreakBeforeParameter;
     ++State.ParenLevel;
   }
 
-  // If this '[' opens an ObjC call, determine whether all parameters fit into
-  // one line and put one per line if they don't.
-  if (Current.isOneOf(tok::l_brace, tok::l_square) &&
-      (Current.Type == TT_ObjCDictLiteral ||
-       Current.Type == TT_ObjCMethodExpr) &&
-      Current.MatchingParen != NULL) {
-    if (getLengthToMatchingParen(Current) + State.Column >
-        getColumnLimit(State)) {
-      State.Stack.back().BreakBeforeParameter = true;
-      State.Stack.back().AvoidBinPacking = true;
-    }
-  }
-
   // If we encounter a closing ), ], } or >, we can remove a level from our
   // stacks.
   if (State.Stack.size() > 1 &&

Modified: cfe/trunk/lib/Format/FormatToken.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/FormatToken.h?rev=193167&r1=193166&r2=193167&view=diff
==============================================================================
--- cfe/trunk/lib/Format/FormatToken.h (original)
+++ cfe/trunk/lib/Format/FormatToken.h Tue Oct 22 10:30:28 2013
@@ -25,6 +25,8 @@ namespace clang {
 namespace format {
 
 enum TokenType {
+  TT_ArrayInitializerLSquare,
+  TT_ArraySubscriptLSquare,
   TT_BinaryOperator,
   TT_BitFieldColon,
   TT_BlockComment,
@@ -39,7 +41,6 @@ enum TokenType {
   TT_FunctionTypeLParen,
   TT_LambdaLSquare,
   TT_LineComment,
-  TT_ObjCArrayLiteral,
   TT_ObjCBlockLParen,
   TT_ObjCDecl,
   TT_ObjCDictLiteral,
@@ -338,6 +339,17 @@ struct FormatToken {
     return Tok;
   }
 
+  bool closesBlockTypeList(const FormatStyle &Style) const {
+    if (is(tok::r_brace) && MatchingParen &&
+        (MatchingParen->BlockKind == BK_Block ||
+         !Style.Cpp11BracedListStyle))
+      return true;
+    if (is(tok::r_square) && MatchingParen &&
+        MatchingParen->Type == TT_ArrayInitializerLSquare)
+      return true;
+    return false;
+  }
+
   FormatToken *MatchingParen;
 
   FormatToken *Previous;

Modified: cfe/trunk/lib/Format/TokenAnnotator.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/TokenAnnotator.cpp?rev=193167&r1=193166&r2=193167&view=diff
==============================================================================
--- cfe/trunk/lib/Format/TokenAnnotator.cpp (original)
+++ cfe/trunk/lib/Format/TokenAnnotator.cpp Tue Oct 22 10:30:28 2013
@@ -197,13 +197,14 @@ private:
          getBinOpPrecedence(Parent->Tok.getKind(), true, true) > prec::Unknown);
     ScopedContextCreator ContextCreator(*this, tok::l_square, 10);
     Contexts.back().IsExpression = true;
-    bool StartsObjCArrayLiteral = Parent && Parent->is(tok::at);
 
     if (StartsObjCMethodExpr) {
       Contexts.back().ColonIsObjCMethodExpr = true;
       Left->Type = TT_ObjCMethodExpr;
-    } else if (StartsObjCArrayLiteral) {
-      Left->Type = TT_ObjCArrayLiteral;
+    } else if (Parent && Parent->is(tok::at)) {
+      Left->Type = TT_ArrayInitializerLSquare;
+    } else if (Left->Type == TT_Unknown) {
+      Left->Type = TT_ArraySubscriptLSquare;
     }
 
     while (CurrentToken != NULL) {
@@ -222,8 +223,6 @@ private:
           // binary operator.
           if (Parent != NULL && Parent->Type == TT_PointerOrReference)
             Parent->Type = TT_BinaryOperator;
-        } else if (StartsObjCArrayLiteral) {
-          CurrentToken->Type = TT_ObjCArrayLiteral;
         }
         Left->MatchingParen = CurrentToken;
         CurrentToken->MatchingParen = Left;
@@ -235,6 +234,9 @@ private:
       }
       if (CurrentToken->isOneOf(tok::r_paren, tok::r_brace))
         return false;
+      if (CurrentToken->is(tok::comma) &&
+          Left->Type == TT_ArraySubscriptLSquare)
+        Left->Type = TT_ArrayInitializerLSquare;
       updateParameterCount(Left, CurrentToken);
       if (!consumeToken())
         return false;
@@ -1263,9 +1265,11 @@ bool TokenAnnotator::spaceRequiredBetwee
   if (Right.is(tok::star) && Left.is(tok::l_paren))
     return false;
   if (Left.is(tok::l_square))
-    return Left.Type == TT_ObjCArrayLiteral && Right.isNot(tok::r_square);
+    return Left.Type == TT_ArrayInitializerLSquare &&
+           Right.isNot(tok::r_square);
   if (Right.is(tok::r_square))
-    return Right.Type == TT_ObjCArrayLiteral;
+    return Right.MatchingParen &&
+           Right.MatchingParen->Type == TT_ArrayInitializerLSquare;
   if (Right.is(tok::l_square) && Right.Type != TT_ObjCMethodExpr &&
       Right.Type != TT_LambdaLSquare && Left.isNot(tok::numeric_constant))
     return false;
@@ -1481,15 +1485,17 @@ bool TokenAnnotator::canBreakBefore(cons
   if (Left.is(tok::greater) && Right.is(tok::greater) &&
       Left.Type != TT_TemplateCloser)
     return false;
+  if (Left.Type == TT_ArrayInitializerLSquare)
+    return true;
   return (Left.isBinaryOperator() && Left.isNot(tok::lessless) &&
           !Style.BreakBeforeBinaryOperators) ||
          Left.isOneOf(tok::comma, tok::coloncolon, tok::semi, tok::l_brace,
                       tok::kw_class, tok::kw_struct) ||
-         Right.isOneOf(tok::lessless, tok::arrow, tok::period, tok::colon) ||
+         Right.isOneOf(tok::lessless, tok::arrow, tok::period, tok::colon,
+                       tok::l_square, tok::at) ||
          (Left.is(tok::r_paren) &&
           Right.isOneOf(tok::identifier, tok::kw_const, tok::kw___attribute)) ||
-         (Left.is(tok::l_paren) && !Right.is(tok::r_paren)) ||
-         Right.is(tok::l_square);
+         (Left.is(tok::l_paren) && !Right.is(tok::r_paren));
 }
 
 void TokenAnnotator::printDebugInfo(const AnnotatedLine &Line) {

Modified: cfe/trunk/unittests/Format/FormatTest.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Format/FormatTest.cpp?rev=193167&r1=193166&r2=193167&view=diff
==============================================================================
--- cfe/trunk/unittests/Format/FormatTest.cpp (original)
+++ cfe/trunk/unittests/Format/FormatTest.cpp Tue Oct 22 10:30:28 2013
@@ -5378,6 +5378,7 @@ TEST_F(FormatTest, ObjCLiterals) {
   verifyFormat(
       "NSArray *array = @[ @\" Hey \", NSApp, [NSNumber numberWithInt:42] ];");
   verifyFormat("return @[ @3, @[], @[ @4, @5 ] ];");
+  verifyFormat("NSArray *array = @[ [foo description] ];");
 
   verifyFormat("@{");
   verifyFormat("@{}");
@@ -5408,6 +5409,13 @@ TEST_F(FormatTest, ObjCLiterals) {
       "  NSFontAttributeNameeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee : "
       "regularFont,\n"
       "};");
+  verifyFormat(
+      "NSArray *arguments = @[\n"
+      "  kind == kUserTicket ? @\"--user-store\" : @\"--system-store\",\n"
+      "  @\"--print-tickets\",\n"
+      "  @\"--productid\",\n"
+      "  @\"com.google.Chrome\"\n"
+      "];");
 }
 
 TEST_F(FormatTest, ReformatRegionAdjustsIndent) {





More information about the cfe-commits mailing list