//===--- ContinuationIndenter.cpp - Format C++ code -----------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// /// /// \file /// \brief This file implements the continuation indenter. /// //===----------------------------------------------------------------------===// #define DEBUG_TYPE "format-formatter" #include "BreakableToken.h" #include "ContinuationIndenter.h" #include "WhitespaceManager.h" #include "clang/Basic/OperatorPrecedence.h" #include "clang/Basic/SourceManager.h" #include "clang/Format/Format.h" #include "llvm/Support/Debug.h" #include namespace clang { namespace format { // Returns the length of everything up to the first possible line break after // the ), ], } or > matching \c Tok. static unsigned getLengthToMatchingParen(const FormatToken &Tok) { if (Tok.MatchingParen == NULL) return 0; FormatToken *End = Tok.MatchingParen; while (End->Next && !End->Next->CanBreakBefore) { End = End->Next; } return End->TotalLength - Tok.TotalLength + 1; } // Returns \c true if \c Tok is the "." or "->" of a call and starts the next // segment of a builder type call. static bool startsSegmentOfBuilderTypeCall(const FormatToken &Tok) { return Tok.isMemberAccess() && Tok.Previous && Tok.Previous->closesScope(); } // Returns \c true if \c Current starts a new parameter. static bool startsNextParameter(const FormatToken &Current, const FormatStyle &Style) { const FormatToken &Previous = *Current.Previous; if (Current.Type == TT_CtorInitializerComma && Style.BreakConstructorInitializersBeforeComma) return true; return Previous.is(tok::comma) && !Current.isTrailingComment() && (Previous.Type != TT_CtorInitializerComma || !Style.BreakConstructorInitializersBeforeComma); } ContinuationIndenter::ContinuationIndenter(const FormatStyle &Style, SourceManager &SourceMgr, WhitespaceManager &Whitespaces, encoding::Encoding Encoding, bool BinPackInconclusiveFunctions) : Style(Style), SourceMgr(SourceMgr), Whitespaces(Whitespaces), Encoding(Encoding), BinPackInconclusiveFunctions(BinPackInconclusiveFunctions) {} LineState ContinuationIndenter::getInitialState(unsigned FirstIndent, const AnnotatedLine *Line, bool DryRun) { LineState State; State.FirstIndent = FirstIndent; State.Column = FirstIndent; State.Line = Line; State.NextToken = Line->First; State.Stack.push_back(ParenState(FirstIndent, Line->Level, FirstIndent, /*AvoidBinPacking=*/false, /*NoLineBreak=*/false)); State.LineContainsContinuedForLoopSection = false; State.ParenLevel = 0; State.StartOfStringLiteral = 0; State.StartOfLineLevel = State.ParenLevel; State.LowestLevelOnLine = State.ParenLevel; State.IgnoreStackForComparison = false; // The first token has already been indented and thus consumed. moveStateToNextToken(State, DryRun, /*Newline=*/false); return State; } bool ContinuationIndenter::canBreak(const LineState &State) { const FormatToken &Current = *State.NextToken; const FormatToken &Previous = *Current.Previous; assert(&Previous == Current.Previous); 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. if (!Current.MustBreakBefore && Previous.is(tok::l_brace) && Previous.Type != TT_DictLiteral && Previous.BlockKind == BK_BracedInit && Previous.Previous && Previous.Previous->isOneOf(tok::l_brace, tok::l_paren, tok::comma)) return false; // This prevents breaks like: // ... // SomeParameter, OtherParameter).DoSomething( // ... // As they hide "DoSomething" and are generally bad for readability. if (Previous.opensScope() && State.LowestLevelOnLine < State.StartOfLineLevel) return false; if (Current.isMemberAccess() && State.Stack.back().ContainsUnwrappedBuilder) return false; return !State.Stack.back().NoLineBreak; } bool ContinuationIndenter::mustBreak(const LineState &State) { const FormatToken &Current = *State.NextToken; const FormatToken &Previous = *Current.Previous; if (Current.MustBreakBefore || Current.Type == TT_InlineASMColon) return true; if (State.Stack.back().BreakBeforeClosingBrace && Current.closesBlockTypeList(Style)) return true; if (Previous.is(tok::semi) && State.LineContainsContinuedForLoopSection) return true; if ((startsNextParameter(Current, Style) || Previous.is(tok::semi) || (Style.BreakBeforeTernaryOperators && (Current.is(tok::question) || (Current.Type == TT_ConditionalExpr && Previous.isNot(tok::question)))) || (!Style.BreakBeforeTernaryOperators && (Previous.is(tok::question) || Previous.Type == TT_ConditionalExpr))) && State.Stack.back().BreakBeforeParameter && !Current.isTrailingComment() && !Current.isOneOf(tok::r_paren, tok::r_brace)) return true; if (Style.AlwaysBreakBeforeMultilineStrings && State.Column > State.Stack.back().Indent && // Breaking saves columns. !Previous.isOneOf(tok::kw_return, tok::lessless, tok::at) && Previous.Type != TT_InlineASMColon && NextIsMultilineString(State)) return true; if (((Previous.Type == TT_DictLiteral && Previous.is(tok::l_brace)) || Previous.Type == TT_ArrayInitializerLSquare) && getLengthToMatchingParen(Previous) + State.Column > getColumnLimit(State)) return true; if (!Style.BreakBeforeBinaryOperators) { // If we need to break somewhere inside the LHS of a binary expression, we // should also break after the operator. Otherwise, the formatting would // hide the operator precedence, e.g. in: // if (aaaaaaaaaaaaaa == // bbbbbbbbbbbbbb && c) {.. // For comparisons, we only apply this rule, if the LHS is a binary // expression itself as otherwise, the line breaks seem superfluous. // We need special cases for ">>" which we have split into two ">" while // lexing in order to make template parsing easier. // // FIXME: We'll need something similar for styles that break before binary // operators. bool IsComparison = (Previous.getPrecedence() == prec::Relational || Previous.getPrecedence() == prec::Equality) && Previous.Previous && Previous.Previous->Type != TT_BinaryOperator; // For >>. bool LHSIsBinaryExpr = Previous.Previous && Previous.Previous->EndsBinaryExpression; if (Previous.Type == TT_BinaryOperator && (!IsComparison || LHSIsBinaryExpr) && Current.Type != TT_BinaryOperator && // For >>. !Current.isTrailingComment() && !Previous.isOneOf(tok::lessless, tok::question) && Previous.getPrecedence() != prec::Assignment && State.Stack.back().BreakBeforeParameter) return true; } // Same as above, but for the first "<<" operator. if (Current.is(tok::lessless) && State.Stack.back().BreakBeforeParameter && State.Stack.back().FirstLessLess == 0) return true; // FIXME: Comparing LongestObjCSelectorName to 0 is a hacky way of finding // out whether it is the first parameter. Clean this up. if (Current.Type == TT_ObjCSelectorName && Current.LongestObjCSelectorName == 0 && State.Stack.back().BreakBeforeParameter) return true; if ((Current.Type == TT_CtorInitializerColon || (Previous.ClosesTemplateDeclaration && State.ParenLevel == 0 && !Current.isTrailingComment()))) return true; if ((Current.Type == TT_StartOfName || Current.is(tok::kw_operator)) && State.Line->MightBeFunctionDecl && State.Stack.back().BreakBeforeParameter && State.ParenLevel == 0) return true; if (startsSegmentOfBuilderTypeCall(Current) && (State.Stack.back().CallContinuation != 0 || (State.Stack.back().BreakBeforeParameter && State.Stack.back().ContainsUnwrappedBuilder))) return true; return false; } unsigned ContinuationIndenter::addTokenToState(LineState &State, bool Newline, bool DryRun, unsigned ExtraSpaces) { const FormatToken &Current = *State.NextToken; if (State.Stack.size() == 0 || (Current.Type == TT_ImplicitStringLiteral && (Current.Previous->Tok.getIdentifierInfo() == NULL || Current.Previous->Tok.getIdentifierInfo()->getPPKeywordID() == tok::pp_not_keyword))) { // FIXME: Is this correct? int WhitespaceLength = SourceMgr.getSpellingColumnNumber( State.NextToken->WhitespaceRange.getEnd()) - SourceMgr.getSpellingColumnNumber( State.NextToken->WhitespaceRange.getBegin()); State.Column += WhitespaceLength + State.NextToken->ColumnWidth; State.NextToken = State.NextToken->Next; return 0; } unsigned Penalty = 0; if (Newline) Penalty = addTokenOnNewLine(State, DryRun); else addTokenOnCurrentLine(State, DryRun, ExtraSpaces); return moveStateToNextToken(State, DryRun, Newline) + Penalty; } void ContinuationIndenter::addTokenOnCurrentLine(LineState &State, bool DryRun, unsigned ExtraSpaces) { FormatToken &Current = *State.NextToken; const FormatToken &Previous = *State.NextToken->Previous; if (Current.is(tok::equal) && (State.Line->First->is(tok::kw_for) || State.ParenLevel == 0) && State.Stack.back().VariablePos == 0) { State.Stack.back().VariablePos = State.Column; // Move over * and & if they are bound to the variable name. const FormatToken *Tok = &Previous; while (Tok && State.Stack.back().VariablePos >= Tok->ColumnWidth) { State.Stack.back().VariablePos -= Tok->ColumnWidth; if (Tok->SpacesRequiredBefore != 0) break; Tok = Tok->Previous; } if (Previous.PartOfMultiVariableDeclStmt) State.Stack.back().LastSpace = State.Stack.back().VariablePos; } unsigned Spaces = Current.SpacesRequiredBefore + ExtraSpaces; if (!DryRun) Whitespaces.replaceWhitespace(Current, /*Newlines=*/0, /*IndentLevel=*/0, Spaces, State.Column + Spaces); if (Current.Type == TT_ObjCSelectorName && State.Stack.back().ColonPos == 0) { if (State.Stack.back().Indent + Current.LongestObjCSelectorName > State.Column + Spaces + Current.ColumnWidth) State.Stack.back().ColonPos = State.Stack.back().Indent + Current.LongestObjCSelectorName; else State.Stack.back().ColonPos = State.Column + Spaces + Current.ColumnWidth; } if (Previous.opensScope() && Previous.Type != TT_ObjCMethodExpr && Current.Type != TT_LineComment) State.Stack.back().Indent = State.Column + Spaces; if (State.Stack.back().AvoidBinPacking && startsNextParameter(Current, Style)) State.Stack.back().NoLineBreak = true; if (startsSegmentOfBuilderTypeCall(Current)) State.Stack.back().ContainsUnwrappedBuilder = true; State.Column += Spaces; if (Current.is(tok::l_paren) && Previous.isOneOf(tok::kw_if, tok::kw_for)) // Treat the condition inside an if as if it was a second function // parameter, i.e. let nested calls have a continuation indent. State.Stack.back().LastSpace = State.Column + 1; // 1 is length of "(". else if (Previous.is(tok::comma) || Previous.Type == TT_ObjCMethodExpr) State.Stack.back().LastSpace = State.Column; else if ((Previous.Type == TT_BinaryOperator || Previous.Type == TT_ConditionalExpr || Previous.Type == TT_UnaryOperator || Previous.Type == TT_CtorInitializerColon) && (Previous.getPrecedence() != prec::Assignment || Current.StartsBinaryExpression)) // Always indent relative to the RHS of the expression unless this is a // simple assignment without binary expression on the RHS. Also indent // relative to unary operators and the colons of constructor initializers. State.Stack.back().LastSpace = State.Column; else if (Previous.Type == TT_InheritanceColon) { State.Stack.back().Indent = State.Column; State.Stack.back().LastSpace = State.Column; } else if (Previous.opensScope()) { // If a function has a trailing call, indent all parameters from the // opening parenthesis. This avoids confusing indents like: // OuterFunction(InnerFunctionCall( // break // ParameterToInnerFunction)) // break // .SecondInnerFunctionCall(); bool HasTrailingCall = false; if (Previous.MatchingParen) { const FormatToken *Next = Previous.MatchingParen->getNextNonComment(); HasTrailingCall = Next && Next->isMemberAccess(); } if (HasTrailingCall && State.Stack[State.Stack.size() - 2].CallContinuation == 0) State.Stack.back().LastSpace = State.Column; } } unsigned ContinuationIndenter::addTokenOnNewLine(LineState &State, bool DryRun) { FormatToken &Current = *State.NextToken; const FormatToken &Previous = *State.NextToken->Previous; // If we are continuing an expression, we want to use the continuation indent. unsigned ContinuationIndent = std::max(State.Stack.back().LastSpace, State.Stack.back().Indent) + Style.ContinuationIndentWidth; // Extra penalty that needs to be added because of the way certain line // breaks are chosen. unsigned Penalty = 0; const FormatToken *PreviousNonComment = State.NextToken->getPreviousNonComment(); // The first line break on any ParenLevel causes an extra penalty in order // prefer similar line breaks. if (!State.Stack.back().ContainsLineBreak) Penalty += 15; State.Stack.back().ContainsLineBreak = true; Penalty += State.NextToken->SplitPenalty; // Breaking before the first "<<" is generally not desirable if the LHS is // short. if (Current.is(tok::lessless) && State.Stack.back().FirstLessLess == 0 && State.Column <= Style.ColumnLimit / 2) Penalty += Style.PenaltyBreakFirstLessLess; if (Current.is(tok::l_brace) && Current.BlockKind == BK_Block) { State.Column = State.FirstIndent; } else if (Current.isOneOf(tok::r_brace, tok::r_square)) { if (Current.closesBlockTypeList(Style) || (Current.MatchingParen && Current.MatchingParen->BlockKind == BK_BracedInit)) State.Column = State.Stack[State.Stack.size() - 2].LastSpace; else State.Column = State.FirstIndent; } else if (Current.is(tok::string_literal) && State.StartOfStringLiteral != 0) { State.Column = State.StartOfStringLiteral; State.Stack.back().BreakBeforeParameter = true; } else if (Current.is(tok::lessless) && State.Stack.back().FirstLessLess != 0) { State.Column = State.Stack.back().FirstLessLess; } else if (Current.isMemberAccess()) { if (State.Stack.back().CallContinuation == 0) { State.Column = ContinuationIndent; State.Stack.back().CallContinuation = State.Column; } else { State.Column = State.Stack.back().CallContinuation; } } else if (State.Stack.back().QuestionColumn != 0 && (Current.Type == TT_ConditionalExpr || Previous.Type == TT_ConditionalExpr)) { State.Column = State.Stack.back().QuestionColumn; } else if (Previous.is(tok::comma) && State.Stack.back().VariablePos != 0) { State.Column = State.Stack.back().VariablePos; } else if ((PreviousNonComment && PreviousNonComment->ClosesTemplateDeclaration) || ((Current.Type == TT_StartOfName || Current.is(tok::kw_operator)) && State.ParenLevel == 0 && (!Style.IndentFunctionDeclarationAfterType || State.Line->StartsDefinition))) { State.Column = State.Stack.back().Indent; } else if (Current.Type == TT_ObjCSelectorName) { if (State.Stack.back().ColonPos == 0) { State.Stack.back().ColonPos = State.Stack.back().Indent + Current.LongestObjCSelectorName; State.Column = State.Stack.back().ColonPos - Current.ColumnWidth; } else if (State.Stack.back().ColonPos > Current.ColumnWidth) { State.Column = State.Stack.back().ColonPos - Current.ColumnWidth; } else { State.Column = State.Stack.back().Indent; State.Stack.back().ColonPos = State.Column + Current.ColumnWidth; } } else if (Current.Type == TT_ArraySubscriptLSquare) { if (State.Stack.back().StartOfArraySubscripts != 0) State.Column = State.Stack.back().StartOfArraySubscripts; else State.Column = ContinuationIndent; } else if (Current.Type == TT_StartOfName || Previous.isOneOf(tok::coloncolon, tok::equal) || Previous.Type == TT_ObjCMethodExpr) { State.Column = ContinuationIndent; } else if (Current.Type == TT_CtorInitializerColon) { State.Column = State.FirstIndent + Style.ConstructorInitializerIndentWidth; } else if (Current.Type == TT_CtorInitializerComma) { State.Column = State.Stack.back().Indent; } else { State.Column = State.Stack.back().Indent; // Ensure that we fall back to the continuation indent width instead of just // flushing continuations left. if (State.Column == State.FirstIndent && PreviousNonComment->isNot(tok::r_brace)) State.Column += Style.ContinuationIndentWidth; } if ((Previous.isOneOf(tok::comma, tok::semi) && !State.Stack.back().AvoidBinPacking) || Previous.Type == TT_BinaryOperator) State.Stack.back().BreakBeforeParameter = false; if (Previous.Type == TT_TemplateCloser && State.ParenLevel == 0) State.Stack.back().BreakBeforeParameter = false; if (Current.is(tok::question) || (PreviousNonComment && PreviousNonComment->is(tok::question))) State.Stack.back().BreakBeforeParameter = true; if (!DryRun) { unsigned Newlines = 1; if (Current.is(tok::comment)) Newlines = std::max(Newlines, std::min(Current.NewlinesBefore, Style.MaxEmptyLinesToKeep + 1)); Whitespaces.replaceWhitespace(Current, Newlines, State.Stack.back().IndentLevel, State.Column, State.Column, State.Line->InPPDirective); } if (!Current.isTrailingComment()) State.Stack.back().LastSpace = State.Column; if (Current.isMemberAccess()) State.Stack.back().LastSpace += Current.ColumnWidth; State.StartOfLineLevel = State.ParenLevel; State.LowestLevelOnLine = State.ParenLevel; // Any break on this level means that the parent level has been broken // and we need to avoid bin packing there. for (unsigned i = 0, e = State.Stack.size() - 1; i != e; ++i) { State.Stack[i].BreakBeforeParameter = true; } if (PreviousNonComment && !PreviousNonComment->isOneOf(tok::comma, tok::semi) && PreviousNonComment->Type != TT_TemplateCloser && PreviousNonComment->Type != TT_BinaryOperator && Current.Type != TT_BinaryOperator && !PreviousNonComment->opensScope()) State.Stack.back().BreakBeforeParameter = true; // 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) { // If we are breaking after '(', '{', '<', this is not bin packing // unless AllowAllParametersOfDeclarationOnNextLine is false. if (!(Previous.isOneOf(tok::l_paren, tok::l_brace) || Previous.Type == TT_BinaryOperator) || (!Style.AllowAllParametersOfDeclarationOnNextLine && State.Line->MustBeDeclaration)) State.Stack.back().BreakBeforeParameter = true; } return Penalty; } unsigned ContinuationIndenter::moveStateToNextToken(LineState &State, bool DryRun, bool Newline) { const FormatToken &Current = *State.NextToken; assert(State.Stack.size()); if (Current.Type == TT_InheritanceColon) State.Stack.back().AvoidBinPacking = true; if (Current.is(tok::lessless) && State.Stack.back().FirstLessLess == 0) State.Stack.back().FirstLessLess = State.Column; if (Current.Type == TT_ArraySubscriptLSquare && State.Stack.back().StartOfArraySubscripts == 0) State.Stack.back().StartOfArraySubscripts = State.Column; if ((Current.is(tok::question) && Style.BreakBeforeTernaryOperators) || (Current.getPreviousNonComment() && Current.isNot(tok::colon) && Current.getPreviousNonComment()->is(tok::question) && !Style.BreakBeforeTernaryOperators)) State.Stack.back().QuestionColumn = State.Column; if (!Current.opensScope() && !Current.closesScope()) State.LowestLevelOnLine = std::min(State.LowestLevelOnLine, State.ParenLevel); if (Current.isMemberAccess()) State.Stack.back().StartOfFunctionCall = Current.LastInChainOfCalls ? 0 : State.Column + Current.ColumnWidth; if (Current.Type == TT_CtorInitializerColon) { // Indent 2 from the column, so: // SomeClass::SomeClass() // : First(...), ... // Next(...) // ^ line up here. State.Stack.back().Indent = State.Column + (Style.BreakConstructorInitializersBeforeComma ? 0 : 2); if (Style.ConstructorInitializerAllOnOneLineOrOnePerLine) State.Stack.back().AvoidBinPacking = true; State.Stack.back().BreakBeforeParameter = false; } // In ObjC method declaration we align on the ":" of parameters, but we need // to ensure that we indent parameters on subsequent lines by at least our // continuation indent width. if (Current.Type == TT_ObjCMethodSpecifier) State.Stack.back().Indent += Style.ContinuationIndentWidth; // Insert scopes created by fake parenthesis. const FormatToken *Previous = Current.getPreviousNonComment(); // Don't add extra indentation for the first fake parenthesis after // 'return', assignements or opening <({[. The indentation for these cases // is special cased. bool SkipFirstExtraIndent = (Previous && (Previous->opensScope() || Previous->is(tok::kw_return) || Previous->getPrecedence() == prec::Assignment || Previous->Type == TT_ObjCMethodExpr)); for (SmallVectorImpl::const_reverse_iterator I = Current.FakeLParens.rbegin(), E = Current.FakeLParens.rend(); I != E; ++I) { ParenState NewParenState = State.Stack.back(); NewParenState.ContainsLineBreak = false; // Indent from 'LastSpace' unless this the fake parentheses encapsulating a // builder type call after 'return'. If such a call is line-wrapped, we // commonly just want to indent from the start of the line. if (!Previous || Previous->isNot(tok::kw_return) || *I > 0) NewParenState.Indent = std::max(std::max(State.Column, NewParenState.Indent), State.Stack.back().LastSpace); // Do not indent relative to the fake parentheses inserted for "." or "->". // This is a special case to make the following to statements consistent: // OuterFunction(InnerFunctionCall( // break // ParameterToInnerFunction)); // OuterFunction(SomeObject.InnerFunctionCall( // break // ParameterToInnerFunction)); if (*I > prec::Unknown) NewParenState.LastSpace = std::max(NewParenState.LastSpace, State.Column); // Always indent conditional expressions. Never indent expression where // the 'operator' is ',', ';' or an assignment (i.e. *I <= // prec::Assignment) as those have different indentation rules. Indent // other expression, unless the indentation needs to be skipped. if (*I == prec::Conditional || (!SkipFirstExtraIndent && *I > prec::Assignment && !Style.BreakBeforeBinaryOperators)) NewParenState.Indent += Style.ContinuationIndentWidth; if ((Previous && !Previous->opensScope()) || *I > prec::Comma) NewParenState.BreakBeforeParameter = false; State.Stack.push_back(NewParenState); SkipFirstExtraIndent = false; } // If we encounter an opening (, [, { or <, we add a level to our stacks to // prepare for the following tokens. if (Current.opensScope()) { unsigned NewIndent; unsigned NewIndentLevel = State.Stack.back().IndentLevel; bool AvoidBinPacking; 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. // Thus, we remove all ParenStates caused bake 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 // }); for (unsigned i = 0; i != Current.MatchingParen->FakeRParens; ++i) State.Stack.pop_back(); NewIndent = State.Stack.back().LastSpace + Style.IndentWidth; ++NewIndentLevel; BreakBeforeParameter = true; } else { NewIndent = State.Stack.back().LastSpace; if (Current.opensBlockTypeList(Style)) { NewIndent += Style.IndentWidth; ++NewIndentLevel; } else { NewIndent += Style.ContinuationIndentWidth; } } const FormatToken *NextNoComment = Current.getNextNonComment(); AvoidBinPacking = Current.BlockKind == BK_Block || Current.Type == TT_ArrayInitializerLSquare || Current.Type == TT_DictLiteral || (NextNoComment && NextNoComment->Type == TT_DesignatedInitializerPeriod); } else { NewIndent = Style.ContinuationIndentWidth + std::max(State.Stack.back().LastSpace, State.Stack.back().StartOfFunctionCall); AvoidBinPacking = !Style.BinPackParameters || (Style.ExperimentalAutoDetectBinPacking && (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 || (Current.Type == TT_TemplateOpener && State.Stack.back().ContainsUnwrappedBuilder); State.Stack.push_back(ParenState(NewIndent, NewIndentLevel, State.Stack.back().LastSpace, AvoidBinPacking, NoLineBreak)); State.Stack.back().BreakBeforeParameter = BreakBeforeParameter; ++State.ParenLevel; } // If we encounter a closing ), ], } or >, we can remove a level from our // stacks. 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.Stack.pop_back(); --State.ParenLevel; } if (Current.is(tok::r_square)) { // If this ends the array subscript expr, reset the corresponding value. const FormatToken *NextNonComment = Current.getNextNonComment(); if (NextNonComment && NextNonComment->isNot(tok::l_square)) State.Stack.back().StartOfArraySubscripts = 0; } // 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; State.Stack.pop_back(); State.Stack.back().VariablePos = VariablePos; } } if (Current.is(tok::string_literal) && State.StartOfStringLiteral == 0) { State.StartOfStringLiteral = State.Column; } else if (!Current.isOneOf(tok::comment, tok::identifier, tok::hash, tok::string_literal)) { State.StartOfStringLiteral = 0; } State.Column += Current.ColumnWidth; State.NextToken = State.NextToken->Next; unsigned Penalty = breakProtrudingToken(Current, State, DryRun); if (State.Column > getColumnLimit(State)) { unsigned ExcessCharacters = State.Column - getColumnLimit(State); Penalty += Style.PenaltyExcessCharacter * ExcessCharacters; } // If the previous has a special role, let it consume tokens as appropriate. // It is necessary to start at the previous token for the only implemented // role (comma separated list). That way, the decision whether or not to break // after the "{" is already done and both options are tried and evaluated. // FIXME: This is ugly, find a better way. if (Previous && Previous->Role) Penalty += Previous->Role->format(State, this, DryRun); return Penalty; } unsigned ContinuationIndenter::addMultilineToken(const FormatToken &Current, LineState &State) { // Break before further function parameters on all levels. for (unsigned i = 0, e = State.Stack.size(); i != e; ++i) State.Stack[i].BreakBeforeParameter = true; unsigned ColumnsUsed = State.Column; // We can only affect layout of the first and the last line, so the penalty // for all other lines is constant, and we ignore it. State.Column = Current.LastLineColumnWidth; if (ColumnsUsed > getColumnLimit(State)) return Style.PenaltyExcessCharacter * (ColumnsUsed - getColumnLimit(State)); return 0; } static bool getRawStringLiteralPrefixPostfix(StringRef Text, StringRef &Prefix, StringRef &Postfix) { if (Text.startswith(Prefix = "R\"") || Text.startswith(Prefix = "uR\"") || Text.startswith(Prefix = "UR\"") || Text.startswith(Prefix = "u8R\"") || Text.startswith(Prefix = "LR\"")) { size_t ParenPos = Text.find('('); if (ParenPos != StringRef::npos) { StringRef Delimiter = Text.substr(Prefix.size(), ParenPos - Prefix.size()); Prefix = Text.substr(0, ParenPos + 1); Postfix = Text.substr(Text.size() - 2 - Delimiter.size()); return Postfix.front() == ')' && Postfix.back() == '"' && Postfix.substr(1).startswith(Delimiter); } } return false; } unsigned ContinuationIndenter::breakProtrudingToken(const FormatToken &Current, LineState &State, bool DryRun) { // Don't break multi-line tokens other than block comments. Instead, just // update the state. if (Current.Type != TT_BlockComment && Current.IsMultiline) return addMultilineToken(Current, State); // Don't break implicit string literals. if (Current.Type == TT_ImplicitStringLiteral) return 0; if (!Current.isOneOf(tok::string_literal, tok::wide_string_literal, tok::utf8_string_literal, tok::utf16_string_literal, tok::utf32_string_literal, tok::comment)) return 0; llvm::OwningPtr Token; unsigned StartColumn = State.Column - Current.ColumnWidth; unsigned ColumnLimit = getColumnLimit(State); if (Current.isOneOf(tok::string_literal, tok::wide_string_literal, tok::utf8_string_literal, tok::utf16_string_literal, tok::utf32_string_literal) && Current.Type != TT_ImplicitStringLiteral) { // Don't break string literals inside preprocessor directives (except for // #define directives, as their contents are stored in separate lines and // are not affected by this check). // This way we avoid breaking code with line directives and unknown // preprocessor directives that contain long string literals. if (State.Line->Type == LT_PreprocessorDirective) return 0; // Exempts unterminated string literals from line breaking. The user will // likely want to terminate the string before any line breaking is done. if (Current.IsUnterminatedLiteral) return 0; StringRef Text = Current.TokenText; StringRef Prefix; StringRef Postfix; // FIXME: Handle whitespace between '_T', '(', '"..."', and ')'. // FIXME: Store Prefix and Suffix (or PrefixLength and SuffixLength to // reduce the overhead) for each FormatToken, which is a string, so that we // don't run multiple checks here on the hot path. if ((Text.endswith(Postfix = "\"") && (Text.startswith(Prefix = "\"") || Text.startswith(Prefix = "u\"") || Text.startswith(Prefix = "U\"") || Text.startswith(Prefix = "u8\"") || Text.startswith(Prefix = "L\""))) || (Text.startswith(Prefix = "_T(\"") && Text.endswith(Postfix = "\")")) || getRawStringLiteralPrefixPostfix(Text, Prefix, Postfix)) { Token.reset(new BreakableStringLiteral( Current, State.Line->Level, StartColumn, Prefix, Postfix, State.Line->InPPDirective, Encoding, Style)); } else { return 0; } } else if (Current.Type == TT_BlockComment && Current.isTrailingComment()) { Token.reset(new BreakableBlockComment( Current, State.Line->Level, StartColumn, Current.OriginalColumn, !Current.Previous, State.Line->InPPDirective, Encoding, Style)); } else if (Current.Type == TT_LineComment && (Current.Previous == NULL || Current.Previous->Type != TT_ImplicitStringLiteral)) { Token.reset(new BreakableLineComment(Current, State.Line->Level, StartColumn, /*InPPDirective=*/false, Encoding, Style)); // We don't insert backslashes when breaking line comments. ColumnLimit = Style.ColumnLimit; } else { return 0; } if (Current.UnbreakableTailLength >= ColumnLimit) return 0; unsigned RemainingSpace = ColumnLimit - Current.UnbreakableTailLength; bool BreakInserted = false; unsigned Penalty = 0; unsigned RemainingTokenColumns = 0; for (unsigned LineIndex = 0, EndIndex = Token->getLineCount(); LineIndex != EndIndex; ++LineIndex) { if (!DryRun) Token->replaceWhitespaceBefore(LineIndex, Whitespaces); unsigned TailOffset = 0; RemainingTokenColumns = Token->getLineLengthAfterSplit(LineIndex, TailOffset, StringRef::npos); while (RemainingTokenColumns > RemainingSpace) { BreakableToken::Split Split = Token->getSplit(LineIndex, TailOffset, ColumnLimit); if (Split.first == StringRef::npos) { // The last line's penalty is handled in addNextStateToQueue(). if (LineIndex < EndIndex - 1) Penalty += Style.PenaltyExcessCharacter * (RemainingTokenColumns - RemainingSpace); break; } assert(Split.first != 0); unsigned NewRemainingTokenColumns = Token->getLineLengthAfterSplit( LineIndex, TailOffset + Split.first + Split.second, StringRef::npos); // We can remove extra whitespace instead of breaking the line. if (RemainingTokenColumns + 1 - Split.second <= RemainingSpace) { RemainingTokenColumns = 0; if (!DryRun) Token->replaceWhitespace(LineIndex, TailOffset, Split, Whitespaces); break; } assert(NewRemainingTokenColumns < RemainingTokenColumns); if (!DryRun) Token->insertBreak(LineIndex, TailOffset, Split, Whitespaces); Penalty += Current.SplitPenalty; unsigned ColumnsUsed = Token->getLineLengthAfterSplit(LineIndex, TailOffset, Split.first); if (ColumnsUsed > ColumnLimit) { Penalty += Style.PenaltyExcessCharacter * (ColumnsUsed - ColumnLimit); } TailOffset += Split.first + Split.second; RemainingTokenColumns = NewRemainingTokenColumns; BreakInserted = true; } } State.Column = RemainingTokenColumns; if (BreakInserted) { // If we break the token inside a parameter list, we need to break before // the next parameter on all levels, so that the next parameter is clearly // visible. Line comments already introduce a break. if (Current.Type != TT_LineComment) { for (unsigned i = 0, e = State.Stack.size(); i != e; ++i) State.Stack[i].BreakBeforeParameter = true; } Penalty += Current.is(tok::string_literal) ? Style.PenaltyBreakString : Style.PenaltyBreakComment; State.Stack.back().LastSpace = StartColumn; } return Penalty; } unsigned ContinuationIndenter::getColumnLimit(const LineState &State) const { // In preprocessor directives reserve two chars for trailing " \" return Style.ColumnLimit - (State.Line->InPPDirective ? 2 : 0); } bool ContinuationIndenter::NextIsMultilineString(const LineState &State) { const FormatToken &Current = *State.NextToken; if (!Current.is(tok::string_literal)) return false; // We never consider raw string literals "multiline" for the purpose of // AlwaysBreakBeforeMultilineStrings implementation. if (Current.TokenText.startswith("R\"")) return false; if (Current.IsMultiline) return true; if (Current.getNextNonComment() && Current.getNextNonComment()->is(tok::string_literal)) return true; // Implicit concatenation. if (State.Column + Current.ColumnWidth + Current.UnbreakableTailLength > Style.ColumnLimit) return true; // String will be split. return false; } } // namespace format } // namespace clang