From: Daniel Jasper Date: Tue, 22 Oct 2013 15:30:28 +0000 (+0000) Subject: clang-format: Improve formatting of ObjC array literals. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=a07aa665a12ab23bef7aa4aedfe113dd8b13da57;p=clang 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. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@193167 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Format/ContinuationIndenter.cpp b/lib/Format/ContinuationIndenter.cpp index 63a03e0d44..18f0c33452 100644 --- a/lib/Format/ContinuationIndenter.cpp +++ b/lib/Format/ContinuationIndenter.cpp @@ -92,8 +92,8 @@ bool ContinuationIndenter::canBreak(const LineState &State) { 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(const LineState &State) { 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(const LineState &State) { !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::addTokenOnNewLine(LineState &State, 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::addTokenOnNewLine(LineState &State, 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::addTokenOnNewLine(LineState &State, 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::moveStateToNextToken(LineState &State, 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::moveStateToNextToken(LineState &State, (!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::moveStateToNextToken(LineState &State, 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::moveStateToNextToken(LineState &State, 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::moveStateToNextToken(LineState &State, } 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::moveStateToNextToken(LineState &State, (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::moveStateToNextToken(LineState &State, 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 && diff --git a/lib/Format/FormatToken.h b/lib/Format/FormatToken.h index 12621027cc..52cc3ce530 100644 --- a/lib/Format/FormatToken.h +++ b/lib/Format/FormatToken.h @@ -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; diff --git a/lib/Format/TokenAnnotator.cpp b/lib/Format/TokenAnnotator.cpp index 733f70d720..e3984428bd 100644 --- a/lib/Format/TokenAnnotator.cpp +++ b/lib/Format/TokenAnnotator.cpp @@ -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::spaceRequiredBetween(const AnnotatedLine &Line, 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(const AnnotatedLine &Line, 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) { diff --git a/unittests/Format/FormatTest.cpp b/unittests/Format/FormatTest.cpp index 20132f9ccc..6dd9413392 100644 --- a/unittests/Format/FormatTest.cpp +++ b/unittests/Format/FormatTest.cpp @@ -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) {