diff options
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Format/ContinuationIndenter.cpp')
-rw-r--r-- | contrib/llvm/tools/clang/lib/Format/ContinuationIndenter.cpp | 759 |
1 files changed, 495 insertions, 264 deletions
diff --git a/contrib/llvm/tools/clang/lib/Format/ContinuationIndenter.cpp b/contrib/llvm/tools/clang/lib/Format/ContinuationIndenter.cpp index 971acc2..014c30e 100644 --- a/contrib/llvm/tools/clang/lib/Format/ContinuationIndenter.cpp +++ b/contrib/llvm/tools/clang/lib/Format/ContinuationIndenter.cpp @@ -12,8 +12,6 @@ /// //===----------------------------------------------------------------------===// -#define DEBUG_TYPE "format-formatter" - #include "BreakableToken.h" #include "ContinuationIndenter.h" #include "WhitespaceManager.h" @@ -23,13 +21,15 @@ #include "llvm/Support/Debug.h" #include <string> +#define DEBUG_TYPE "format-formatter" + 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) + if (!Tok.MatchingParen) return 0; FormatToken *End = Tok.MatchingParen; while (End->Next && !End->Next->CanBreakBefore) { @@ -63,7 +63,8 @@ ContinuationIndenter::ContinuationIndenter(const FormatStyle &Style, bool BinPackInconclusiveFunctions) : Style(Style), SourceMgr(SourceMgr), Whitespaces(Whitespaces), Encoding(Encoding), - BinPackInconclusiveFunctions(BinPackInconclusiveFunctions) {} + BinPackInconclusiveFunctions(BinPackInconclusiveFunctions), + CommentPragmasRegex(Style.CommentPragmas) {} LineState ContinuationIndenter::getInitialState(unsigned FirstIndent, const AnnotatedLine *Line, @@ -77,10 +78,9 @@ LineState ContinuationIndenter::getInitialState(unsigned FirstIndent, /*AvoidBinPacking=*/false, /*NoLineBreak=*/false)); State.LineContainsContinuedForLoopSection = false; - State.ParenLevel = 0; State.StartOfStringLiteral = 0; - State.StartOfLineLevel = State.ParenLevel; - State.LowestLevelOnLine = State.ParenLevel; + State.StartOfLineLevel = 0; + State.LowestLevelOnLine = 0; State.IgnoreStackForComparison = false; // The first token has already been indented and thus consumed. @@ -98,8 +98,8 @@ bool ContinuationIndenter::canBreak(const LineState &State) { // 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.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: @@ -107,10 +107,21 @@ bool ContinuationIndenter::canBreak(const LineState &State) { // SomeParameter, OtherParameter).DoSomething( // ... // As they hide "DoSomething" and are generally bad for readability. - if (Previous.opensScope() && State.LowestLevelOnLine < State.StartOfLineLevel) + if (Previous.opensScope() && Previous.isNot(tok::l_brace) && + State.LowestLevelOnLine < State.StartOfLineLevel && + State.LowestLevelOnLine < Current.NestingLevel) return false; if (Current.isMemberAccess() && State.Stack.back().ContainsUnwrappedBuilder) return false; + + // Don't create a 'hanging' indent if there are multiple blocks in a single + // statement. + if (Style.Language == FormatStyle::LK_JavaScript && + Previous.is(tok::l_brace) && State.Stack.size() > 1 && + State.Stack[State.Stack.size() - 2].JSFunctionInlined && + State.Stack[State.Stack.size() - 2].HasMultipleNestedBlocks) + return false; + return !State.Stack.back().NoLineBreak; } @@ -136,13 +147,21 @@ bool ContinuationIndenter::mustBreak(const LineState &State) { 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)) + Previous.Type != TT_InlineASMColon && + Previous.Type != TT_ConditionalExpr && nextIsMultilineString(State)) return true; if (((Previous.Type == TT_DictLiteral && Previous.is(tok::l_brace)) || Previous.Type == TT_ArrayInitializerLSquare) && + Style.ColumnLimit > 0 && getLengthToMatchingParen(Previous) + State.Column > getColumnLimit(State)) return true; + if (Current.Type == TT_CtorInitializerColon && + ((Style.AllowShortFunctionsOnASingleLine != FormatStyle::SFS_All) || + Style.BreakConstructorInitializersBeforeComma || Style.ColumnLimit != 0)) + return true; + if (State.Column < getNewLineColumn(State)) + return false; 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 @@ -165,38 +184,45 @@ bool ContinuationIndenter::mustBreak(const LineState &State) { if (Previous.Type == TT_BinaryOperator && (!IsComparison || LHSIsBinaryExpr) && Current.Type != TT_BinaryOperator && // For >>. - !Current.isTrailingComment() && - !Previous.isOneOf(tok::lessless, tok::question) && + !Current.isTrailingComment() && !Previous.is(tok::lessless) && 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 && + if (Current.is(tok::lessless) && Current.Type != TT_OverloadedOperator && + 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 && + if (Current.Type == TT_SelectorName && + State.Stack.back().ObjCSelectorNameFound && State.Stack.back().BreakBeforeParameter) return true; - if ((Current.Type == TT_CtorInitializerColon || - (Previous.ClosesTemplateDeclaration && State.ParenLevel == 0 && - !Current.isTrailingComment()))) + if (Previous.ClosesTemplateDeclaration && Current.NestingLevel == 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) + // If the return type spans multiple lines, wrap before the function name. + if ((Current.Type == TT_FunctionDeclarationName || + Current.is(tok::kw_operator)) && + State.Stack.back().BreakBeforeParameter) return true; + if (startsSegmentOfBuilderTypeCall(Current) && (State.Stack.back().CallContinuation != 0 || (State.Stack.back().BreakBeforeParameter && State.Stack.back().ContainsUnwrappedBuilder))) return true; + + // The following could be precomputed as they do not depend on the state. + // However, as they should take effect only if the UnwrappedLine does not fit + // into the ColumnLimit, they are checked here in the ContinuationIndenter. + if (Style.ColumnLimit != 0 && Previous.BlockKind == BK_Block && + Previous.is(tok::l_brace) && !Current.isOneOf(tok::r_brace, tok::comment)) + return true; + return false; } @@ -205,9 +231,9 @@ unsigned ContinuationIndenter::addTokenToState(LineState &State, bool Newline, unsigned ExtraSpaces) { const FormatToken &Current = *State.NextToken; - if (State.Stack.size() == 0 || - (Current.Type == TT_ImplicitStringLiteral && - (Current.Previous->Tok.getIdentifierInfo() == NULL || + assert(!State.Stack.empty()); + if ((Current.Type == TT_ImplicitStringLiteral && + (Current.Previous->Tok.getIdentifierInfo() == nullptr || Current.Previous->Tok.getIdentifierInfo()->getPPKeywordID() == tok::pp_not_keyword))) { // FIXME: Is this correct? @@ -215,8 +241,8 @@ unsigned ContinuationIndenter::addTokenToState(LineState &State, bool Newline, State.NextToken->WhitespaceRange.getEnd()) - SourceMgr.getSpellingColumnNumber( State.NextToken->WhitespaceRange.getBegin()); - State.Column += WhitespaceLength + State.NextToken->ColumnWidth; - State.NextToken = State.NextToken->Next; + State.Column += WhitespaceLength; + moveStateToNextToken(State, DryRun, /*Newline=*/false); return 0; } @@ -234,7 +260,7 @@ void ContinuationIndenter::addTokenOnCurrentLine(LineState &State, bool DryRun, 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.Line->First->is(tok::kw_for) || Current.NestingLevel == 0) && State.Stack.back().VariablePos == 0) { State.Stack.back().VariablePos = State.Column; // Move over * and & if they are bound to the variable name. @@ -255,9 +281,12 @@ void ContinuationIndenter::addTokenOnCurrentLine(LineState &State, bool 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) + if (Current.Type == TT_SelectorName && + !State.Stack.back().ObjCSelectorNameFound) { + if (Current.LongestObjCSelectorName == 0) + State.Stack.back().AlignColons = false; + else if (State.Stack.back().Indent + Current.LongestObjCSelectorName > + State.Column + Spaces + Current.ColumnWidth) State.Stack.back().ColonPos = State.Stack.back().Indent + Current.LongestObjCSelectorName; else @@ -265,7 +294,7 @@ void ContinuationIndenter::addTokenOnCurrentLine(LineState &State, bool DryRun, } if (Previous.opensScope() && Previous.Type != TT_ObjCMethodExpr && - Current.Type != TT_LineComment) + (Current.Type != TT_LineComment || Previous.BlockKind == BK_BracedInit)) State.Stack.back().Indent = State.Column + Spaces; if (State.Stack.back().AvoidBinPacking && startsNextParameter(Current, Style)) State.Stack.back().NoLineBreak = true; @@ -273,17 +302,21 @@ void ContinuationIndenter::addTokenOnCurrentLine(LineState &State, bool DryRun, State.Stack.back().ContainsUnwrappedBuilder = true; State.Column += Spaces; - if (Current.is(tok::l_paren) && Previous.isOneOf(tok::kw_if, tok::kw_for)) + if (Current.isNot(tok::comment) && Previous.is(tok::l_paren) && + Previous.Previous && Previous.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 (!Current.isOneOf(tok::comment, tok::caret) && + (Previous.is(tok::comma) || + (Previous.is(tok::colon) && 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 || + ((Previous.getPrecedence() != prec::Assignment && + (Previous.isNot(tok::lessless) || Previous.OperatorIndex != 0 || + !Previous.LastOperator)) || 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 @@ -313,17 +346,16 @@ 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 + const FormatToken *PreviousNonComment = Current.getPreviousNonComment(); + const FormatToken *NextNonComment = Previous.getNextNonComment(); + if (!NextNonComment) + NextNonComment = &Current; + // The first line break on any NestingLevel causes an extra penalty in order // prefer similar line breaks. if (!State.Stack.back().ContainsLineBreak) Penalty += 15; @@ -332,96 +364,61 @@ unsigned ContinuationIndenter::addTokenOnNewLine(LineState &State, 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) + // short. Also always add the penalty if the LHS is split over mutliple lines + // to avoid unnecessary line breaks that just work around this penalty. + if (NextNonComment->is(tok::lessless) && + State.Stack.back().FirstLessLess == 0 && + (State.Column <= Style.ColumnLimit / 3 || + State.Stack.back().BreakBeforeParameter)) 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.Column = getNewLineColumn(State); + if (NextNonComment->isMemberAccess()) { + if (State.Stack.back().CallContinuation == 0) 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 (NextNonComment->Type == TT_SelectorName) { + if (!State.Stack.back().ObjCSelectorNameFound) { + if (NextNonComment->LongestObjCSelectorName == 0) { + State.Stack.back().AlignColons = false; + } else { + State.Stack.back().ColonPos = + State.Stack.back().Indent + NextNonComment->LongestObjCSelectorName; + } + } else if (State.Stack.back().AlignColons && + State.Stack.back().ColonPos <= NextNonComment->ColumnWidth) { + State.Stack.back().ColonPos = State.Column + NextNonComment->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; + } else if (PreviousNonComment && PreviousNonComment->is(tok::colon) && + (PreviousNonComment->Type == TT_ObjCMethodExpr || + PreviousNonComment->Type == TT_DictLiteral)) { + // FIXME: This is hacky, find a better way. The problem is that in an ObjC + // method expression, the block should be aligned to the line starting it, + // e.g.: + // [aaaaaaaaaaaaaaa aaaaaaaaa: \\ break for some reason + // ^(int *i) { + // // ... + // }]; + // Thus, we set LastSpace of the next higher NestingLevel, to which we move + // when we consume all of the "}"'s FakeRParens at the "{". + if (State.Stack.size() > 1) + State.Stack[State.Stack.size() - 2].LastSpace = + std::max(State.Stack.back().LastSpace, State.Stack.back().Indent) + + 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) + if (Previous.Type == TT_TemplateCloser && Current.NestingLevel == 0) State.Stack.back().BreakBeforeParameter = false; - if (Current.is(tok::question) || + if (NextNonComment->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)); + unsigned Newlines = std::max( + 1u, std::min(Current.NewlinesBefore, Style.MaxEmptyLinesToKeep + 1)); Whitespaces.replaceWhitespace(Current, Newlines, State.Stack.back().IndentLevel, State.Column, State.Column, State.Line->InPPDirective); @@ -429,51 +426,164 @@ unsigned ContinuationIndenter::addTokenOnNewLine(LineState &State, 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; + State.StartOfLineLevel = Current.NestingLevel; + State.LowestLevelOnLine = Current.NestingLevel; // 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; + bool JavaScriptFormat = Style.Language == FormatStyle::LK_JavaScript && + Current.is(tok::r_brace) && + State.Stack.size() > 1 && + State.Stack[State.Stack.size() - 2].JSFunctionInlined; + if (!JavaScriptFormat) { + 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()) + 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) + if (PreviousNonComment && + (PreviousNonComment->is(tok::l_brace) || + PreviousNonComment->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. + // unless AllowAllParametersOfDeclarationOnNextLine is false or this is a + // dict/object literal. if (!(Previous.isOneOf(tok::l_paren, tok::l_brace) || Previous.Type == TT_BinaryOperator) || (!Style.AllowAllParametersOfDeclarationOnNextLine && - State.Line->MustBeDeclaration)) + State.Line->MustBeDeclaration) || + Previous.Type == TT_DictLiteral) State.Stack.back().BreakBeforeParameter = true; } return Penalty; } +unsigned ContinuationIndenter::getNewLineColumn(const LineState &State) { + if (!State.NextToken || !State.NextToken->Previous) + return 0; + 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; + const FormatToken *PreviousNonComment = Current.getPreviousNonComment(); + const FormatToken *NextNonComment = Previous.getNextNonComment(); + if (!NextNonComment) + NextNonComment = &Current; + if (NextNonComment->is(tok::l_brace) && NextNonComment->BlockKind == BK_Block) + return Current.NestingLevel == 0 ? State.FirstIndent + : State.Stack.back().Indent; + if (Current.isOneOf(tok::r_brace, tok::r_square)) { + if (State.Stack.size() > 1 && + State.Stack[State.Stack.size() - 2].JSFunctionInlined) + return State.FirstIndent; + if (Current.closesBlockTypeList(Style) || + (Current.MatchingParen && + Current.MatchingParen->BlockKind == BK_BracedInit)) + return State.Stack[State.Stack.size() - 2].LastSpace; + else + return State.FirstIndent; + } + if (Current.is(tok::identifier) && Current.Next && + Current.Next->Type == TT_DictLiteral) + return State.Stack.back().Indent; + if (NextNonComment->isStringLiteral() && State.StartOfStringLiteral != 0) + return State.StartOfStringLiteral; + if (NextNonComment->is(tok::lessless) && + State.Stack.back().FirstLessLess != 0) + return State.Stack.back().FirstLessLess; + if (NextNonComment->isMemberAccess()) { + if (State.Stack.back().CallContinuation == 0) { + return ContinuationIndent; + } else { + return State.Stack.back().CallContinuation; + } + } + if (State.Stack.back().QuestionColumn != 0 && + ((NextNonComment->is(tok::colon) && + NextNonComment->Type == TT_ConditionalExpr) || + Previous.Type == TT_ConditionalExpr)) + return State.Stack.back().QuestionColumn; + if (Previous.is(tok::comma) && State.Stack.back().VariablePos != 0) + return State.Stack.back().VariablePos; + if ((PreviousNonComment && (PreviousNonComment->ClosesTemplateDeclaration || + PreviousNonComment->Type == TT_AttributeParen)) || + (!Style.IndentWrappedFunctionNames && + (NextNonComment->is(tok::kw_operator) || + NextNonComment->Type == TT_FunctionDeclarationName))) + return std::max(State.Stack.back().LastSpace, State.Stack.back().Indent); + if (NextNonComment->Type == TT_SelectorName) { + if (!State.Stack.back().ObjCSelectorNameFound) { + if (NextNonComment->LongestObjCSelectorName == 0) { + return State.Stack.back().Indent; + } else { + return State.Stack.back().Indent + + NextNonComment->LongestObjCSelectorName - + NextNonComment->ColumnWidth; + } + } else if (!State.Stack.back().AlignColons) { + return State.Stack.back().Indent; + } else if (State.Stack.back().ColonPos > NextNonComment->ColumnWidth) { + return State.Stack.back().ColonPos - NextNonComment->ColumnWidth; + } else { + return State.Stack.back().Indent; + } + } + if (NextNonComment->Type == TT_ArraySubscriptLSquare) { + if (State.Stack.back().StartOfArraySubscripts != 0) + return State.Stack.back().StartOfArraySubscripts; + else + return ContinuationIndent; + } + if (NextNonComment->Type == TT_StartOfName || + Previous.isOneOf(tok::coloncolon, tok::equal)) { + return ContinuationIndent; + } + if (PreviousNonComment && PreviousNonComment->is(tok::colon) && + (PreviousNonComment->Type == TT_ObjCMethodExpr || + PreviousNonComment->Type == TT_DictLiteral)) + return ContinuationIndent; + if (NextNonComment->Type == TT_CtorInitializerColon) + return State.FirstIndent + Style.ConstructorInitializerIndentWidth; + if (NextNonComment->Type == TT_CtorInitializerComma) + return State.Stack.back().Indent; + if (State.Stack.back().Indent == State.FirstIndent && PreviousNonComment && + PreviousNonComment->isNot(tok::r_brace)) + // Ensure that we fall back to the continuation indent width instead of + // just flushing continuations left. + return State.Stack.back().Indent + Style.ContinuationIndentWidth; + return State.Stack.back().Indent; +} + unsigned ContinuationIndenter::moveStateToNextToken(LineState &State, bool DryRun, bool Newline) { - const FormatToken &Current = *State.NextToken; assert(State.Stack.size()); + const FormatToken &Current = *State.NextToken; 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.is(tok::lessless) && Current.Type != TT_OverloadedOperator) { + if (State.Stack.back().FirstLessLess == 0) + State.Stack.back().FirstLessLess = State.Column; + else + State.Stack.back().LastOperatorWrapped = Newline; + } + if ((Current.Type == TT_BinaryOperator && Current.isNot(tok::lessless)) || + Current.Type == TT_ConditionalExpr) + State.Stack.back().LastOperatorWrapped = Newline; if (Current.Type == TT_ArraySubscriptLSquare && State.Stack.back().StartOfArraySubscripts == 0) State.Stack.back().StartOfArraySubscripts = State.Column; @@ -484,10 +594,12 @@ unsigned ContinuationIndenter::moveStateToNextToken(LineState &State, State.Stack.back().QuestionColumn = State.Column; if (!Current.opensScope() && !Current.closesScope()) State.LowestLevelOnLine = - std::min(State.LowestLevelOnLine, State.ParenLevel); + std::min(State.LowestLevelOnLine, Current.NestingLevel); if (Current.isMemberAccess()) State.Stack.back().StartOfFunctionCall = - Current.LastInChainOfCalls ? 0 : State.Column + Current.ColumnWidth; + Current.LastOperator ? 0 : State.Column + Current.ColumnWidth; + if (Current.Type == TT_SelectorName) + State.Stack.back().ObjCSelectorNameFound = true; if (Current.Type == TT_CtorInitializerColon) { // Indent 2 from the column, so: // SomeClass::SomeClass() @@ -509,8 +621,67 @@ unsigned ContinuationIndenter::moveStateToNextToken(LineState &State, // Insert scopes created by fake parenthesis. const FormatToken *Previous = Current.getPreviousNonComment(); + + // Add special behavior to support a format commonly used for JavaScript + // closures: + // SomeFunction(function() { + // foo(); + // bar(); + // }, a, b, c); + if (Style.Language == FormatStyle::LK_JavaScript) { + if (Current.isNot(tok::comment) && Previous && Previous->is(tok::l_brace) && + State.Stack.size() > 1) { + if (State.Stack[State.Stack.size() - 2].JSFunctionInlined && Newline) { + for (unsigned i = 0, e = State.Stack.size() - 1; i != e; ++i) { + State.Stack[i].NoLineBreak = true; + } + } + State.Stack[State.Stack.size() - 2].JSFunctionInlined = false; + } + if (Current.TokenText == "function") + State.Stack.back().JSFunctionInlined = !Newline; + } + + moveStatePastFakeLParens(State, Newline); + moveStatePastScopeOpener(State, Newline); + moveStatePastScopeCloser(State); + moveStatePastFakeRParens(State); + + if (Current.isStringLiteral() && State.StartOfStringLiteral == 0) { + State.StartOfStringLiteral = State.Column; + } else if (!Current.isOneOf(tok::comment, tok::identifier, tok::hash) && + !Current.isStringLiteral()) { + 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 (Current.Role) + Current.Role->formatFromToken(State, this, DryRun); + // 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->formatAfterToken(State, this, DryRun); + + return Penalty; +} + +void ContinuationIndenter::moveStatePastFakeLParens(LineState &State, + bool Newline) { + const FormatToken &Current = *State.NextToken; + 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 + // 'return', assignments or opening <({[. The indentation for these cases // is special cased. bool SkipFirstExtraIndent = (Previous && (Previous->opensScope() || Previous->is(tok::kw_return) || @@ -531,6 +702,24 @@ unsigned ContinuationIndenter::moveStateToNextToken(LineState &State, std::max(std::max(State.Column, NewParenState.Indent), State.Stack.back().LastSpace); + // Don't allow the RHS of an operator to be split over multiple lines unless + // there is a line-break right after the operator. + // Exclude relational operators, as there, it is always more desirable to + // have the LHS 'left' of the RHS. + if (Previous && Previous->getPrecedence() > prec::Assignment && + (Previous->Type == TT_BinaryOperator || + Previous->Type == TT_ConditionalExpr) && + Previous->getPrecedence() != prec::Relational) { + bool BreakBeforeOperator = Previous->is(tok::lessless) || + (Previous->Type == TT_BinaryOperator && + Style.BreakBeforeBinaryOperators) || + (Previous->Type == TT_ConditionalExpr && + Style.BreakBeforeTernaryOperators); + if ((!Newline && !BreakBeforeOperator) || + (!State.Stack.back().LastOperatorWrapped && BreakBeforeOperator)) + NewParenState.NoLineBreak = true; + } + // 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 @@ -539,6 +728,7 @@ unsigned ContinuationIndenter::moveStateToNextToken(LineState &State, // ParameterToInnerFunction)); if (*I > prec::Unknown) NewParenState.LastSpace = std::max(NewParenState.LastSpace, State.Column); + NewParenState.StartOfFunctionCall = State.Column; // Always indent conditional expressions. Never indent expression where // the 'operator' is ',', ';' or an assignment (i.e. *I <= @@ -553,131 +743,160 @@ unsigned ContinuationIndenter::moveStateToNextToken(LineState &State, 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; +// 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 LineState &State) { + const FormatToken &Tok = *State.NextToken; + if (!Tok.MatchingParen) + return false; + const FormatToken *Left = &Tok; + if (Tok.isOneOf(tok::r_brace, tok::r_square)) + Left = Tok.MatchingParen; + return !State.Stack.back().HasMultipleNestedBlocks && + 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) { + // Don't remove FakeRParens attached to r_braces that surround nested blocks + // as they will have been removed early (see above). + if (fakeRParenSpecialCase(State)) + return; + + consumeRParens(State, *State.NextToken); +} - 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; +void ContinuationIndenter::moveStatePastScopeOpener(LineState &State, + bool Newline) { + const FormatToken &Current = *State.NextToken; + if (!Current.opensScope()) + return; + + if (Current.MatchingParen && Current.BlockKind == BK_Block) { + moveStateToNewBlock(State); + return; } + unsigned NewIndent; + unsigned NewIndentLevel = State.Stack.back().IndentLevel; + bool AvoidBinPacking; + bool BreakBeforeParameter = false; + if (Current.is(tok::l_brace) || Current.Type == TT_ArrayInitializerLSquare) { + if (fakeRParenSpecialCase(State)) + consumeRParens(State, *Current.MatchingParen); + + NewIndent = State.Stack.back().LastSpace; + if (Current.opensBlockTypeList(Style)) { + NewIndent += Style.IndentWidth; + NewIndent = std::min(State.Column + 2, NewIndent); + ++NewIndentLevel; + } else { + NewIndent += Style.ContinuationIndentWidth; + NewIndent = std::min(State.Column + 1, NewIndent); + } + const FormatToken *NextNoComment = Current.getNextNonComment(); + AvoidBinPacking = Current.Type == TT_ArrayInitializerLSquare || + Current.Type == TT_DictLiteral || + Style.Language == FormatStyle::LK_Proto || + !Style.BinPackParameters || + (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 && Style.ColumnLimit != 0 && + 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.Stack.back().HasMultipleNestedBlocks = Current.BlockParameterCount > 1; +} + +void ContinuationIndenter::moveStatePastScopeCloser(LineState &State) { + const FormatToken &Current = *State.NextToken; + if (!Current.closesScope()) + return; + // 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.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; +void ContinuationIndenter::moveStateToNewBlock(LineState &State) { + // 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 (fakeRParenSpecialCase(State)) + consumeRParens(State, *State.NextToken->MatchingParen); + + // For some reason, ObjC blocks are indented like continuations. + unsigned NewIndent = State.Stack.back().LastSpace + + (State.NextToken->Type == TT_ObjCBlockLBrace + ? Style.ContinuationIndentWidth + : Style.IndentWidth); + State.Stack.push_back(ParenState( + NewIndent, /*NewIndentLevel=*/State.Stack.back().IndentLevel + 1, + State.Stack.back().LastSpace, /*AvoidBinPacking=*/true, + State.Stack.back().NoLineBreak)); + State.Stack.back().BreakBeforeParameter = true; } unsigned ContinuationIndenter::addMultilineToken(const FormatToken &Current, @@ -696,8 +915,7 @@ unsigned ContinuationIndenter::addMultilineToken(const FormatToken &Current, return 0; } -static bool getRawStringLiteralPrefixPostfix(StringRef Text, - StringRef &Prefix, +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\"") || @@ -727,19 +945,14 @@ unsigned ContinuationIndenter::breakProtrudingToken(const FormatToken &Current, 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)) + if (!Current.isStringLiteral() && !Current.is(tok::comment)) return 0; - llvm::OwningPtr<BreakableToken> Token; + std::unique_ptr<BreakableToken> 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) { + if (Current.isStringLiteral()) { // 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). @@ -755,13 +968,20 @@ unsigned ContinuationIndenter::breakProtrudingToken(const FormatToken &Current, StringRef Text = Current.TokenText; StringRef Prefix; StringRef Postfix; + bool IsNSStringLiteral = false; // 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.startswith("\"") && Current.Previous && + Current.Previous->is(tok::at)) { + IsNSStringLiteral = true; + Prefix = "@\""; + } if ((Text.endswith(Postfix = "\"") && - (Text.startswith(Prefix = "\"") || Text.startswith(Prefix = "u\"") || - Text.startswith(Prefix = "U\"") || Text.startswith(Prefix = "u8\"") || + (IsNSStringLiteral || 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)) { @@ -772,12 +992,16 @@ unsigned ContinuationIndenter::breakProtrudingToken(const FormatToken &Current, return 0; } } else if (Current.Type == TT_BlockComment && Current.isTrailingComment()) { + if (CommentPragmasRegex.match(Current.TokenText.substr(2))) + return 0; 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 == nullptr || Current.Previous->Type != TT_ImplicitStringLiteral)) { + if (CommentPragmasRegex.match(Current.TokenText.substr(2))) + return 0; Token.reset(new BreakableLineComment(Current, State.Line->Level, StartColumn, /*InPPDirective=*/false, Encoding, Style)); @@ -822,6 +1046,12 @@ unsigned ContinuationIndenter::breakProtrudingToken(const FormatToken &Current, break; } + // When breaking before a tab character, it may be moved by a few columns, + // but will still be expanded to the next tab stop, so we don't save any + // columns. + if (NewRemainingTokenColumns == RemainingTokenColumns) + break; + assert(NewRemainingTokenColumns < RemainingTokenColumns); if (!DryRun) Token->insertBreak(LineIndex, TailOffset, Split, Whitespaces); @@ -848,8 +1078,8 @@ unsigned ContinuationIndenter::breakProtrudingToken(const FormatToken &Current, State.Stack[i].BreakBeforeParameter = true; } - Penalty += Current.is(tok::string_literal) ? Style.PenaltyBreakString - : Style.PenaltyBreakComment; + Penalty += Current.isStringLiteral() ? Style.PenaltyBreakString + : Style.PenaltyBreakComment; State.Stack.back().LastSpace = StartColumn; } @@ -861,18 +1091,19 @@ unsigned ContinuationIndenter::getColumnLimit(const LineState &State) const { return Style.ColumnLimit - (State.Line->InPPDirective ? 2 : 0); } -bool ContinuationIndenter::NextIsMultilineString(const LineState &State) { +bool ContinuationIndenter::nextIsMultilineString(const LineState &State) { const FormatToken &Current = *State.NextToken; - if (!Current.is(tok::string_literal)) + if (!Current.isStringLiteral() || Current.Type == TT_ImplicitStringLiteral) return false; // We never consider raw string literals "multiline" for the purpose of - // AlwaysBreakBeforeMultilineStrings implementation. + // AlwaysBreakBeforeMultilineStrings implementation as they are special-cased + // (see TokenAnnotator::mustBreakBefore(). if (Current.TokenText.startswith("R\"")) return false; if (Current.IsMultiline) return true; if (Current.getNextNonComment() && - Current.getNextNonComment()->is(tok::string_literal)) + Current.getNextNonComment()->isStringLiteral()) return true; // Implicit concatenation. if (State.Column + Current.ColumnWidth + Current.UnbreakableTailLength > Style.ColumnLimit) |