diff options
-rw-r--r-- | clang/lib/Format/CMakeLists.txt | 1 | ||||
-rw-r--r-- | clang/lib/Format/ContinuationIndenter.cpp | 670 | ||||
-rw-r--r-- | clang/lib/Format/ContinuationIndenter.h | 277 | ||||
-rw-r--r-- | clang/lib/Format/Format.cpp | 957 |
4 files changed, 1004 insertions, 901 deletions
diff --git a/clang/lib/Format/CMakeLists.txt b/clang/lib/Format/CMakeLists.txt index 560e38b4bfa..c4f9c6fbb64 100644 --- a/clang/lib/Format/CMakeLists.txt +++ b/clang/lib/Format/CMakeLists.txt @@ -2,6 +2,7 @@ set(LLVM_LINK_COMPONENTS support) add_clang_library(clangFormat BreakableToken.cpp + ContinuationIndenter.cpp Format.cpp TokenAnnotator.cpp UnwrappedLineParser.cpp diff --git a/clang/lib/Format/ContinuationIndenter.cpp b/clang/lib/Format/ContinuationIndenter.cpp new file mode 100644 index 00000000000..b26d453059f --- /dev/null +++ b/clang/lib/Format/ContinuationIndenter.cpp @@ -0,0 +1,670 @@ +//===--- 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 <string> + +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; +} + +ContinuationIndenter::ContinuationIndenter(const FormatStyle &Style, + SourceManager &SourceMgr, + const AnnotatedLine &Line, + unsigned FirstIndent, + WhitespaceManager &Whitespaces, + encoding::Encoding Encoding, + bool BinPackInconclusiveFunctions) + : Style(Style), SourceMgr(SourceMgr), Line(Line), FirstIndent(FirstIndent), + Whitespaces(Whitespaces), Encoding(Encoding), + BinPackInconclusiveFunctions(BinPackInconclusiveFunctions) {} + +LineState ContinuationIndenter::getInitialState() { + // Initialize state dependent on indent. + LineState State; + State.Column = FirstIndent; + State.NextToken = Line.First; + State.Stack.push_back(ParenState(FirstIndent, 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=*/false, + /*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 && + !(Current.is(tok::r_brace) && State.Stack.back().BreakBeforeClosingBrace)) + 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.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; + 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 (!Style.Cpp11BracedListStyle && Current.is(tok::r_brace) && + State.Stack.back().BreakBeforeClosingBrace) + return true; + if (Previous.is(tok::semi) && State.LineContainsContinuedForLoopSection) + return true; + if (Style.BreakConstructorInitializersBeforeComma) { + if (Previous.Type == TT_CtorInitializerComma) + return false; + if (Current.Type == TT_CtorInitializerComma) + return true; + } + if ((Previous.isOneOf(tok::comma, tok::semi) || Current.is(tok::question) || + (Current.Type == TT_ConditionalExpr && + !(Current.is(tok::colon) && Previous.is(tok::question)))) && + 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 && + Current.is(tok::string_literal) && Previous.isNot(tok::lessless) && + Previous.Type != TT_InlineASMColon && + ((Current.getNextNonComment() && + Current.getNextNonComment()->is(tok::string_literal)) || + (Current.TokenText.find("\\\n") != StringRef::npos))) + 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->FakeRParens > 0; + 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))) + return true; + + if ((Current.Type == TT_StartOfName || Current.is(tok::kw_operator)) && + Line.MightBeFunctionDecl && State.Stack.back().BreakBeforeParameter && + State.ParenLevel == 0) + return true; + return false; +} + +unsigned ContinuationIndenter::addTokenToState(LineState &State, bool Newline, + bool DryRun) { + const FormatToken &Current = *State.NextToken; + const FormatToken &Previous = *State.NextToken->Previous; + + // Extra penalty that needs to be added because of the way certain line + // breaks are chosen. + unsigned ExtraPenalty = 0; + + if (State.Stack.size() == 0 || Current.Type == TT_ImplicitStringLiteral) { + // FIXME: Is this correct? + int WhitespaceLength = SourceMgr.getSpellingColumnNumber( + State.NextToken->WhitespaceRange.getEnd()) - + SourceMgr.getSpellingColumnNumber( + State.NextToken->WhitespaceRange.getBegin()); + State.Column += WhitespaceLength + State.NextToken->CodePointCount; + State.NextToken = State.NextToken->Next; + return 0; + } + + // If we are continuing an expression, we want to indent an extra 4 spaces. + unsigned ContinuationIndent = + std::max(State.Stack.back().LastSpace, State.Stack.back().Indent) + 4; + if (Newline) { + // 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) + ExtraPenalty += Style.PenaltyBreakFirstLessLess; + + State.Stack.back().ContainsLineBreak = true; + if (Current.is(tok::r_brace)) { + if (Current.BlockKind == BK_BracedInit) + State.Column = State.Stack[State.Stack.size() - 2].LastSpace; + else + State.Column = 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.isOneOf(tok::period, tok::arrow) && + Current.Type != TT_DesignatedInitializerPeriod) { + if (State.Stack.back().CallContinuation == 0) { + State.Column = ContinuationIndent; + State.Stack.back().CallContinuation = State.Column; + } else { + State.Column = State.Stack.back().CallContinuation; + } + } else if (Current.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 (Previous.ClosesTemplateDeclaration || + ((Current.Type == TT_StartOfName || + Current.is(tok::kw_operator)) && + State.ParenLevel == 0 && + (!Style.IndentFunctionDeclarationAfterType || + Line.StartsDefinition))) { + State.Column = State.Stack.back().Indent; + } else if (Current.Type == TT_ObjCSelectorName) { + if (State.Stack.back().ColonPos > Current.CodePointCount) { + State.Column = State.Stack.back().ColonPos - Current.CodePointCount; + } else { + State.Column = State.Stack.back().Indent; + State.Stack.back().ColonPos = State.Column + Current.CodePointCount; + } + } else if (Current.is(tok::l_square) && Current.Type != TT_ObjCMethodExpr) { + 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 = 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 indenting 4 spaces instead of just + // flushing continuations left. + if (State.Column == FirstIndent) + State.Column += 4; + } + + if (Current.is(tok::question)) + State.Stack.back().BreakBeforeParameter = true; + 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 (!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.Column, + State.Column, Line.InPPDirective); + } + + if (!Current.isTrailingComment()) + State.Stack.back().LastSpace = State.Column; + if (Current.isOneOf(tok::arrow, tok::period) && + Current.Type != TT_DesignatedInitializerPeriod) + State.Stack.back().LastSpace += Current.CodePointCount; + 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; + } + const FormatToken *TokenBefore = Current.getPreviousNonComment(); + if (TokenBefore && !TokenBefore->isOneOf(tok::comma, tok::semi) && + TokenBefore->Type != TT_TemplateCloser && + 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)) + 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 && + Line.MustBeDeclaration)) + State.Stack.back().BreakBeforeParameter = true; + } + + } else { + if (Current.is(tok::equal) && + (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->CodePointCount) { + State.Stack.back().VariablePos -= Tok->CodePointCount; + if (Tok->SpacesRequiredBefore != 0) + break; + Tok = Tok->Previous; + } + if (Previous.PartOfMultiVariableDeclStmt) + State.Stack.back().LastSpace = State.Stack.back().VariablePos; + } + + unsigned Spaces = State.NextToken->SpacesRequiredBefore; + + if (!DryRun) + Whitespaces.replaceWhitespace(Current, 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.CodePointCount) + State.Stack.back().ColonPos = + State.Stack.back().Indent + Current.LongestObjCSelectorName; + else + State.Stack.back().ColonPos = + State.Column + Spaces + Current.CodePointCount; + } + + if (Previous.opensScope() && Previous.Type != TT_ObjCMethodExpr && + Current.Type != TT_LineComment) + State.Stack.back().Indent = State.Column + Spaces; + if (Previous.is(tok::comma) && !Current.isTrailingComment() && + State.Stack.back().AvoidBinPacking) + State.Stack.back().NoLineBreak = 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 an indent of 4. + State.Stack.back().LastSpace = State.Column + 1; // 1 is length of "(". + else if (Previous.is(tok::comma)) + State.Stack.back().LastSpace = State.Column; + else if ((Previous.Type == TT_BinaryOperator || + Previous.Type == TT_ConditionalExpr || + Previous.Type == TT_CtorInitializerColon) && + !(Previous.getPrecedence() == prec::Assignment && + Current.FakeLParens.empty())) + // Always indent relative to the RHS of the expression unless this is a + // simple assignment without binary expression on the RHS. + State.Stack.back().LastSpace = State.Column; + else if (Previous.Type == TT_InheritanceColon) + State.Stack.back().Indent = State.Column; + else if (Previous.opensScope()) { + // If a function has multiple parameters (including a single parameter + // that is a binary expression) or a trailing call, indent all + // parameters from the opening parenthesis. This avoids confusing + // indents like: + // OuterFunction(InnerFunctionCall( + // ParameterToInnerFunction), + // SecondParameterToOuterFunction); + bool HasMultipleParameters = !Current.FakeLParens.empty(); + bool HasTrailingCall = false; + if (Previous.MatchingParen) { + const FormatToken *Next = Previous.MatchingParen->getNextNonComment(); + if (Next && Next->isOneOf(tok::period, tok::arrow)) + HasTrailingCall = true; + } + if (HasMultipleParameters || HasTrailingCall) + State.Stack.back().LastSpace = State.Column; + } + } + + return moveStateToNextToken(State, DryRun, Newline) + ExtraPenalty; +} + +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.is(tok::l_square) && + State.Stack.back().StartOfArraySubscripts == 0) + State.Stack.back().StartOfArraySubscripts = State.Column; + if (Current.is(tok::question)) + State.Stack.back().QuestionColumn = State.Column; + if (!Current.opensScope() && !Current.closesScope()) + State.LowestLevelOnLine = + std::min(State.LowestLevelOnLine, State.ParenLevel); + if (Current.isOneOf(tok::period, tok::arrow) && + Line.Type == LT_BuilderTypeCall && State.ParenLevel == 0) + State.Stack.back().StartOfFunctionCall = + Current.LastInChainOfCalls ? 0 : State.Column + Current.CodePointCount; + 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; + } + + // If return returns a binary expression, align after it. + if (Current.is(tok::kw_return) && !Current.FakeLParens.empty()) + State.Stack.back().LastSpace = State.Column + 7; + + // 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 4. + if (Current.Type == TT_ObjCMethodSpecifier) + State.Stack.back().Indent += 4; + + // 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 = + Current.is(tok::kw_return) || + (Previous && (Previous->opensScope() || + Previous->getPrecedence() == prec::Assignment)); + for (SmallVectorImpl<prec::Level>::const_reverse_iterator + I = Current.FakeLParens.rbegin(), + E = Current.FakeLParens.rend(); + I != E; ++I) { + ParenState NewParenState = State.Stack.back(); + NewParenState.ContainsLineBreak = false; + NewParenState.Indent = + std::max(std::max(State.Column, NewParenState.Indent), + State.Stack.back().LastSpace); + + // 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 += 4; + if (Previous && !Previous->opensScope()) + 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 LastSpace = State.Stack.back().LastSpace; + bool AvoidBinPacking; + if (Current.is(tok::l_brace)) { + NewIndent = + LastSpace + (Style.Cpp11BracedListStyle ? 4 : Style.IndentWidth); + const FormatToken *NextNoComment = Current.getNextNonComment(); + AvoidBinPacking = NextNoComment && + NextNoComment->Type == TT_DesignatedInitializerPeriod; + } else { + NewIndent = + 4 + std::max(LastSpace, State.Stack.back().StartOfFunctionCall); + AvoidBinPacking = !Style.BinPackParameters || + (Style.ExperimentalAutoDetectBinPacking && + (Current.PackingKind == PPK_OnePerLine || + (!BinPackInconclusiveFunctions && + Current.PackingKind == PPK_Inconclusive))); + } + + State.Stack.push_back(ParenState(NewIndent, LastSpace, AvoidBinPacking, + State.Stack.back().NoLineBreak)); + ++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.is(tok::l_square) && Current.Type == TT_ObjCMethodExpr && + Current.MatchingParen != NULL) { + if (getLengthToMatchingParen(Current) + State.Column > getColumnLimit()) + State.Stack.back().BreakBeforeParameter = true; + } + + // If we encounter a closing ), ], } or >, we can remove a level from our + // stacks. + if (Current.isOneOf(tok::r_paren, tok::r_square) || + (Current.is(tok::r_brace) && State.NextToken != 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. + 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.CodePointCount; + + State.NextToken = State.NextToken->Next; + + if (!Newline && Style.AlwaysBreakBeforeMultilineStrings && + Current.is(tok::string_literal) && Current.CanBreakBefore) + return 0; + + return breakProtrudingToken(Current, State, DryRun); +} + +unsigned ContinuationIndenter::breakProtrudingToken(const FormatToken &Current, + LineState &State, + bool DryRun) { + llvm::OwningPtr<BreakableToken> Token; + unsigned StartColumn = State.Column - Current.CodePointCount; + unsigned OriginalStartColumn = + SourceMgr.getSpellingColumnNumber(Current.getStartOfNonWhitespace()) - 1; + + if (Current.is(tok::string_literal) && + Current.Type != TT_ImplicitStringLiteral) { + // Only break up default narrow strings. + if (!Current.TokenText.startswith("\"")) + return 0; + // Don't break string literals with escaped newlines. As clang-format must + // not change the string's content, it is unlikely that we'll end up with + // a better format. + if (Current.TokenText.find("\\\n") != StringRef::npos) + 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; + + Token.reset(new BreakableStringLiteral(Current, StartColumn, + Line.InPPDirective, Encoding)); + } else if (Current.Type == TT_BlockComment && Current.isTrailingComment()) { + Token.reset(new BreakableBlockComment( + Style, Current, StartColumn, OriginalStartColumn, !Current.Previous, + Line.InPPDirective, Encoding)); + } else if (Current.Type == TT_LineComment && + (Current.Previous == NULL || + Current.Previous->Type != TT_ImplicitStringLiteral)) { + // Don't break line comments with escaped newlines. These look like + // separate line comments, but in fact contain a single line comment with + // multiple lines including leading whitespace and the '//' markers. + // + // FIXME: If we want to handle them correctly, we'll need to adjust + // leading whitespace in consecutive lines when changing indentation of + // the first line similar to what we do with block comments. + StringRef::size_type EscapedNewlinePos = Current.TokenText.find("\\\n"); + if (EscapedNewlinePos != StringRef::npos) { + State.Column = + StartColumn + + encoding::getCodePointCount( + Current.TokenText.substr(0, EscapedNewlinePos), Encoding) + + 1; + return 0; + } + + Token.reset(new BreakableLineComment(Current, StartColumn, + Line.InPPDirective, Encoding)); + } else { + return 0; + } + if (Current.UnbreakableTailLength >= getColumnLimit()) + return 0; + + unsigned RemainingSpace = getColumnLimit() - 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, getColumnLimit()); + 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); + assert(NewRemainingTokenColumns < RemainingTokenColumns); + if (!DryRun) + Token->insertBreak(LineIndex, TailOffset, Split, Whitespaces); + Penalty += Current.is(tok::string_literal) ? Style.PenaltyBreakString + : Style.PenaltyBreakComment; + unsigned ColumnsUsed = + Token->getLineLengthAfterSplit(LineIndex, TailOffset, Split.first); + if (ColumnsUsed > getColumnLimit()) { + Penalty += + Style.PenaltyExcessCharacter * (ColumnsUsed - getColumnLimit()); + } + 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; + } + + State.Stack.back().LastSpace = StartColumn; + } + return Penalty; +} + +unsigned ContinuationIndenter::getColumnLimit() const { + // In preprocessor directives reserve two chars for trailing " \" + return Style.ColumnLimit - (Line.InPPDirective ? 2 : 0); +} + +} // namespace format +} // namespace clang diff --git a/clang/lib/Format/ContinuationIndenter.h b/clang/lib/Format/ContinuationIndenter.h new file mode 100644 index 00000000000..14e0da0e697 --- /dev/null +++ b/clang/lib/Format/ContinuationIndenter.h @@ -0,0 +1,277 @@ +//===--- ContinuationIndenter.h - Format C++ code ---------------*- C++ -*-===// +// +// 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 an indenter that manages the indentation of +/// continuations. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_FORMAT_CONTINUATION_INDENTER_H +#define LLVM_CLANG_FORMAT_CONTINUATION_INDENTER_H + +#include "Encoding.h" +#include "clang/Format/Format.h" + +namespace clang { +class SourceManager; + +namespace format { + +class AnnotatedLine; +struct FormatToken; +struct LineState; +struct ParenState; +class WhitespaceManager; + +class ContinuationIndenter { +public: + /// \brief Constructs a \c ContinuationIndenter to format \p Line starting in + /// column \p FirstIndent. + ContinuationIndenter(const FormatStyle &Style, SourceManager &SourceMgr, + const AnnotatedLine &Line, unsigned FirstIndent, + WhitespaceManager &Whitespaces, + encoding::Encoding Encoding, + bool BinPackInconclusiveFunctions); + + /// \brief Get the initial state, i.e. the state after placing the line's + /// first token. + LineState getInitialState(); + + // FIXME: canBreak and mustBreak aren't strictly indentation-related. Find a + // better home. + /// \brief Returns \c true, if a line break after \p State is allowed. + bool canBreak(const LineState &State); + + /// \brief Returns \c true, if a line break after \p State is mandatory. + bool mustBreak(const LineState &State); + + /// \brief Appends the next token to \p State and updates information + /// necessary for indentation. + /// + /// Puts the token on the current line if \p Newline is \c false and adds a + /// line break and necessary indentation otherwise. + /// + /// If \p DryRun is \c false, also creates and stores the required + /// \c Replacement. + unsigned addTokenToState(LineState &State, bool Newline, bool DryRun); + + /// \brief Get the column limit for this line. This is the style's column + /// limit, potentially reduced for preprocessor definitions. + unsigned getColumnLimit() const; + +private: + /// \brief Mark the next token as consumed in \p State and modify its stacks + /// accordingly. + unsigned moveStateToNextToken(LineState &State, bool DryRun, bool Newline); + + /// \brief If the current token sticks out over the end of the line, break + /// it if possible. + /// + /// \returns An extra penalty if a token was broken, otherwise 0. + /// + /// The returned penalty will cover the cost of the additional line breaks and + /// column limit violation in all lines except for the last one. The penalty + /// for the column limit violation in the last line (and in single line + /// tokens) is handled in \c addNextStateToQueue. + unsigned breakProtrudingToken(const FormatToken &Current, LineState &State, + bool DryRun); + + FormatStyle Style; + SourceManager &SourceMgr; + const AnnotatedLine &Line; + const unsigned FirstIndent; + WhitespaceManager &Whitespaces; + encoding::Encoding Encoding; + bool BinPackInconclusiveFunctions; +}; + +struct ParenState { + ParenState(unsigned Indent, unsigned LastSpace, bool AvoidBinPacking, + bool NoLineBreak) + : Indent(Indent), LastSpace(LastSpace), FirstLessLess(0), + BreakBeforeClosingBrace(false), QuestionColumn(0), + AvoidBinPacking(AvoidBinPacking), BreakBeforeParameter(false), + NoLineBreak(NoLineBreak), ColonPos(0), StartOfFunctionCall(0), + StartOfArraySubscripts(0), NestedNameSpecifierContinuation(0), + CallContinuation(0), VariablePos(0), ContainsLineBreak(false) {} + + /// \brief The position to which a specific parenthesis level needs to be + /// indented. + unsigned Indent; + + /// \brief The position of the last space on each level. + /// + /// Used e.g. to break like: + /// functionCall(Parameter, otherCall( + /// OtherParameter)); + unsigned LastSpace; + + /// \brief The position the first "<<" operator encountered on each level. + /// + /// Used to align "<<" operators. 0 if no such operator has been encountered + /// on a level. + unsigned FirstLessLess; + + /// \brief Whether a newline needs to be inserted before the block's closing + /// brace. + /// + /// We only want to insert a newline before the closing brace if there also + /// was a newline after the beginning left brace. + bool BreakBeforeClosingBrace; + + /// \brief The column of a \c ? in a conditional expression; + unsigned QuestionColumn; + + /// \brief Avoid bin packing, i.e. multiple parameters/elements on multiple + /// lines, in this context. + bool AvoidBinPacking; + + /// \brief Break after the next comma (or all the commas in this context if + /// \c AvoidBinPacking is \c true). + bool BreakBeforeParameter; + + /// \brief Line breaking in this context would break a formatting rule. + bool NoLineBreak; + + /// \brief The position of the colon in an ObjC method declaration/call. + unsigned ColonPos; + + /// \brief The start of the most recent function in a builder-type call. + unsigned StartOfFunctionCall; + + /// \brief Contains the start of array subscript expressions, so that they + /// can be aligned. + unsigned StartOfArraySubscripts; + + /// \brief If a nested name specifier was broken over multiple lines, this + /// contains the start column of the second line. Otherwise 0. + unsigned NestedNameSpecifierContinuation; + + /// \brief If a call expression was broken over multiple lines, this + /// contains the start column of the second line. Otherwise 0. + unsigned CallContinuation; + + /// \brief The column of the first variable name in a variable declaration. + /// + /// Used to align further variables if necessary. + unsigned VariablePos; + + /// \brief \c true if this \c ParenState already contains a line-break. + /// + /// The first line break in a certain \c ParenState causes extra penalty so + /// that clang-format prefers similar breaks, i.e. breaks in the same + /// parenthesis. + bool ContainsLineBreak; + + bool operator<(const ParenState &Other) const { + if (Indent != Other.Indent) + return Indent < Other.Indent; + if (LastSpace != Other.LastSpace) + return LastSpace < Other.LastSpace; + if (FirstLessLess != Other.FirstLessLess) + return FirstLessLess < Other.FirstLessLess; + if (BreakBeforeClosingBrace != Other.BreakBeforeClosingBrace) + return BreakBeforeClosingBrace; + if (QuestionColumn != Other.QuestionColumn) + return QuestionColumn < Other.QuestionColumn; + if (AvoidBinPacking != Other.AvoidBinPacking) + return AvoidBinPacking; + if (BreakBeforeParameter != Other.BreakBeforeParameter) + return BreakBeforeParameter; + if (NoLineBreak != Other.NoLineBreak) + return NoLineBreak; + if (ColonPos != Other.ColonPos) + return ColonPos < Other.ColonPos; + if (StartOfFunctionCall != Other.StartOfFunctionCall) + return StartOfFunctionCall < Other.StartOfFunctionCall; + if (StartOfArraySubscripts != Other.StartOfArraySubscripts) + return StartOfArraySubscripts < Other.StartOfArraySubscripts; + if (CallContinuation != Other.CallContinuation) + return CallContinuation < Other.CallContinuation; + if (VariablePos != Other.VariablePos) + return VariablePos < Other.VariablePos; + if (ContainsLineBreak != Other.ContainsLineBreak) + return ContainsLineBreak < Other.ContainsLineBreak; + return false; + } +}; + +/// \brief The current state when indenting a unwrapped line. +/// +/// As the indenting tries different combinations this is copied by value. +struct LineState { + /// \brief The number of used columns in the current line. + unsigned Column; + + /// \brief The token that needs to be next formatted. + const FormatToken *NextToken; + + /// \brief \c true if this line contains a continued for-loop section. + bool LineContainsContinuedForLoopSection; + + /// \brief The level of nesting inside (), [], <> and {}. + unsigned ParenLevel; + + /// \brief The \c ParenLevel at the start of this line. + unsigned StartOfLineLevel; + + /// \brief The lowest \c ParenLevel on the current line. + unsigned LowestLevelOnLine; + + /// \brief The start column of the string literal, if we're in a string + /// literal sequence, 0 otherwise. + unsigned StartOfStringLiteral; + + /// \brief A stack keeping track of properties applying to parenthesis + /// levels. + std::vector<ParenState> Stack; + + /// \brief Ignore the stack of \c ParenStates for state comparison. + /// + /// In long and deeply nested unwrapped lines, the current algorithm can + /// be insufficient for finding the best formatting with a reasonable amount + /// of time and memory. Setting this flag will effectively lead to the + /// algorithm not analyzing some combinations. However, these combinations + /// rarely contain the optimal solution: In short, accepting a higher + /// penalty early would need to lead to different values in the \c + /// ParenState stack (in an otherwise identical state) and these different + /// values would need to lead to a significant amount of avoided penalty + /// later. + /// + /// FIXME: Come up with a better algorithm instead. + bool IgnoreStackForComparison; + + /// \brief Comparison operator to be able to used \c LineState in \c map. + bool operator<(const LineState &Other) const { + if (NextToken != Other.NextToken) + return NextToken < Other.NextToken; + if (Column != Other.Column) + return Column < Other.Column; + if (LineContainsContinuedForLoopSection != + Other.LineContainsContinuedForLoopSection) + return LineContainsContinuedForLoopSection; + if (ParenLevel != Other.ParenLevel) + return ParenLevel < Other.ParenLevel; + if (StartOfLineLevel != Other.StartOfLineLevel) + return StartOfLineLevel < Other.StartOfLineLevel; + if (LowestLevelOnLine != Other.LowestLevelOnLine) + return LowestLevelOnLine < Other.LowestLevelOnLine; + if (StartOfStringLiteral != Other.StartOfStringLiteral) + return StartOfStringLiteral < Other.StartOfStringLiteral; + if (IgnoreStackForComparison || Other.IgnoreStackForComparison) + return false; + return Stack < Other.Stack; + } +}; + +} // end namespace format +} // end namespace clang + +#endif // LLVM_CLANG_FORMAT_CONTINUATION_INDENTER_H diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp index ec1497c87f4..20a2af50121 100644 --- a/clang/lib/Format/Format.cpp +++ b/clang/lib/Format/Format.cpp @@ -15,12 +15,11 @@ #define DEBUG_TYPE "format-formatter" -#include "BreakableToken.h" +#include "ContinuationIndenter.h" #include "TokenAnnotator.h" #include "UnwrappedLineParser.h" #include "WhitespaceManager.h" #include "clang/Basic/Diagnostic.h" -#include "clang/Basic/OperatorPrecedence.h" #include "clang/Basic/SourceManager.h" #include "clang/Format/Format.h" #include "clang/Lex/Lexer.h" @@ -300,67 +299,37 @@ std::string configurationAsText(const FormatStyle &Style) { return Stream.str(); } -// 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; -} - namespace { -class UnwrappedLineFormatter { +class NoColumnLimitFormatter { public: - UnwrappedLineFormatter(const FormatStyle &Style, SourceManager &SourceMgr, - const AnnotatedLine &Line, unsigned FirstIndent, - const FormatToken *RootToken, - WhitespaceManager &Whitespaces, - encoding::Encoding Encoding, - bool BinPackInconclusiveFunctions) - : Style(Style), SourceMgr(SourceMgr), Line(Line), - FirstIndent(FirstIndent), RootToken(RootToken), - Whitespaces(Whitespaces), Count(0), Encoding(Encoding), - BinPackInconclusiveFunctions(BinPackInconclusiveFunctions) {} + NoColumnLimitFormatter(ContinuationIndenter *Indenter) + : Indenter(Indenter) {} - /// \brief Formats an \c UnwrappedLine. - void format(const AnnotatedLine *NextLine) { - // Initialize state dependent on indent. - LineState State; - State.Column = FirstIndent; - State.NextToken = RootToken; - State.Stack.push_back(ParenState(FirstIndent, 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=*/false, /*Newline=*/false); - - if (Style.ColumnLimit == 0) { - formatWithoutColumnLimit(State); - return; + /// \brief Formats the line starting at \p State, simply keeping all of the + /// input's line breaking decisions. + void format() { + LineState State = Indenter->getInitialState(); + while (State.NextToken != NULL) { + bool Newline = + Indenter->mustBreak(State) || + (Indenter->canBreak(State) && State.NextToken->NewlinesBefore > 0); + Indenter->addTokenToState(State, Newline, /*DryRun=*/false); } + } +private: + ContinuationIndenter *Indenter; +}; - // If everything fits on a single line, just put it there. - unsigned ColumnLimit = Style.ColumnLimit; - if (NextLine && NextLine->InPPDirective && - !NextLine->First->HasUnescapedNewline) - ColumnLimit = getColumnLimit(); - if (Line.Last->TotalLength <= ColumnLimit - FirstIndent) { - while (State.NextToken != NULL) { - addTokenToState(false, false, State); - } - } +class UnwrappedLineFormatter { +public: + UnwrappedLineFormatter(ContinuationIndenter *Indenter, + const FormatStyle &Style, const AnnotatedLine &Line) + : Indenter(Indenter), Style(Style), Line(Line), Count(0) {} + + /// \brief Formats an \c UnwrappedLine. + void format() { + LineState State = Indenter->getInitialState(); // If the ObjC method declaration does not fit on a line, we should format // it with one arg per line. @@ -372,717 +341,6 @@ public: } private: - void DebugTokenState(const FormatToken &FormatTok) { - const Token &Tok = FormatTok.Tok; - llvm::dbgs() << StringRef(SourceMgr.getCharacterData(Tok.getLocation()), - Tok.getLength()); - llvm::dbgs(); - } - - struct ParenState { - ParenState(unsigned Indent, unsigned LastSpace, bool AvoidBinPacking, - bool NoLineBreak) - : Indent(Indent), LastSpace(LastSpace), FirstLessLess(0), - BreakBeforeClosingBrace(false), QuestionColumn(0), - AvoidBinPacking(AvoidBinPacking), BreakBeforeParameter(false), - NoLineBreak(NoLineBreak), ColonPos(0), StartOfFunctionCall(0), - StartOfArraySubscripts(0), NestedNameSpecifierContinuation(0), - CallContinuation(0), VariablePos(0), ContainsLineBreak(false) {} - - /// \brief The position to which a specific parenthesis level needs to be - /// indented. - unsigned Indent; - - /// \brief The position of the last space on each level. - /// - /// Used e.g. to break like: - /// functionCall(Parameter, otherCall( - /// OtherParameter)); - unsigned LastSpace; - - /// \brief The position the first "<<" operator encountered on each level. - /// - /// Used to align "<<" operators. 0 if no such operator has been encountered - /// on a level. - unsigned FirstLessLess; - - /// \brief Whether a newline needs to be inserted before the block's closing - /// brace. - /// - /// We only want to insert a newline before the closing brace if there also - /// was a newline after the beginning left brace. - bool BreakBeforeClosingBrace; - - /// \brief The column of a \c ? in a conditional expression; - unsigned QuestionColumn; - - /// \brief Avoid bin packing, i.e. multiple parameters/elements on multiple - /// lines, in this context. - bool AvoidBinPacking; - - /// \brief Break after the next comma (or all the commas in this context if - /// \c AvoidBinPacking is \c true). - bool BreakBeforeParameter; - - /// \brief Line breaking in this context would break a formatting rule. - bool NoLineBreak; - - /// \brief The position of the colon in an ObjC method declaration/call. - unsigned ColonPos; - - /// \brief The start of the most recent function in a builder-type call. - unsigned StartOfFunctionCall; - - /// \brief Contains the start of array subscript expressions, so that they - /// can be aligned. - unsigned StartOfArraySubscripts; - - /// \brief If a nested name specifier was broken over multiple lines, this - /// contains the start column of the second line. Otherwise 0. - unsigned NestedNameSpecifierContinuation; - - /// \brief If a call expression was broken over multiple lines, this - /// contains the start column of the second line. Otherwise 0. - unsigned CallContinuation; - - /// \brief The column of the first variable name in a variable declaration. - /// - /// Used to align further variables if necessary. - unsigned VariablePos; - - /// \brief \c true if this \c ParenState already contains a line-break. - /// - /// The first line break in a certain \c ParenState causes extra penalty so - /// that clang-format prefers similar breaks, i.e. breaks in the same - /// parenthesis. - bool ContainsLineBreak; - - bool operator<(const ParenState &Other) const { - if (Indent != Other.Indent) - return Indent < Other.Indent; - if (LastSpace != Other.LastSpace) - return LastSpace < Other.LastSpace; - if (FirstLessLess != Other.FirstLessLess) - return FirstLessLess < Other.FirstLessLess; - if (BreakBeforeClosingBrace != Other.BreakBeforeClosingBrace) - return BreakBeforeClosingBrace; - if (QuestionColumn != Other.QuestionColumn) - return QuestionColumn < Other.QuestionColumn; - if (AvoidBinPacking != Other.AvoidBinPacking) - return AvoidBinPacking; - if (BreakBeforeParameter != Other.BreakBeforeParameter) - return BreakBeforeParameter; - if (NoLineBreak != Other.NoLineBreak) - return NoLineBreak; - if (ColonPos != Other.ColonPos) - return ColonPos < Other.ColonPos; - if (StartOfFunctionCall != Other.StartOfFunctionCall) - return StartOfFunctionCall < Other.StartOfFunctionCall; - if (StartOfArraySubscripts != Other.StartOfArraySubscripts) - return StartOfArraySubscripts < Other.StartOfArraySubscripts; - if (CallContinuation != Other.CallContinuation) - return CallContinuation < Other.CallContinuation; - if (VariablePos != Other.VariablePos) - return VariablePos < Other.VariablePos; - if (ContainsLineBreak != Other.ContainsLineBreak) - return ContainsLineBreak < Other.ContainsLineBreak; - return false; - } - }; - - /// \brief The current state when indenting a unwrapped line. - /// - /// As the indenting tries different combinations this is copied by value. - struct LineState { - /// \brief The number of used columns in the current line. - unsigned Column; - - /// \brief The token that needs to be next formatted. - const FormatToken *NextToken; - - /// \brief \c true if this line contains a continued for-loop section. - bool LineContainsContinuedForLoopSection; - - /// \brief The level of nesting inside (), [], <> and {}. - unsigned ParenLevel; - - /// \brief The \c ParenLevel at the start of this line. - unsigned StartOfLineLevel; - - /// \brief The lowest \c ParenLevel on the current line. - unsigned LowestLevelOnLine; - - /// \brief The start column of the string literal, if we're in a string - /// literal sequence, 0 otherwise. - unsigned StartOfStringLiteral; - - /// \brief A stack keeping track of properties applying to parenthesis - /// levels. - std::vector<ParenState> Stack; - - /// \brief Ignore the stack of \c ParenStates for state comparison. - /// - /// In long and deeply nested unwrapped lines, the current algorithm can - /// be insufficient for finding the best formatting with a reasonable amount - /// of time and memory. Setting this flag will effectively lead to the - /// algorithm not analyzing some combinations. However, these combinations - /// rarely contain the optimal solution: In short, accepting a higher - /// penalty early would need to lead to different values in the \c - /// ParenState stack (in an otherwise identical state) and these different - /// values would need to lead to a significant amount of avoided penalty - /// later. - /// - /// FIXME: Come up with a better algorithm instead. - bool IgnoreStackForComparison; - - /// \brief Comparison operator to be able to used \c LineState in \c map. - bool operator<(const LineState &Other) const { - if (NextToken != Other.NextToken) - return NextToken < Other.NextToken; - if (Column != Other.Column) - return Column < Other.Column; - if (LineContainsContinuedForLoopSection != - Other.LineContainsContinuedForLoopSection) - return LineContainsContinuedForLoopSection; - if (ParenLevel != Other.ParenLevel) - return ParenLevel < Other.ParenLevel; - if (StartOfLineLevel != Other.StartOfLineLevel) - return StartOfLineLevel < Other.StartOfLineLevel; - if (LowestLevelOnLine != Other.LowestLevelOnLine) - return LowestLevelOnLine < Other.LowestLevelOnLine; - if (StartOfStringLiteral != Other.StartOfStringLiteral) - return StartOfStringLiteral < Other.StartOfStringLiteral; - if (IgnoreStackForComparison || Other.IgnoreStackForComparison) - return false; - return Stack < Other.Stack; - } - }; - - /// \brief Formats the line starting at \p State, simply keeping all of the - /// input's line breaking decisions. - void formatWithoutColumnLimit(LineState &State) { - while (State.NextToken != NULL) { - bool Newline = mustBreak(State) || - (canBreak(State) && State.NextToken->NewlinesBefore > 0); - addTokenToState(Newline, /*DryRun=*/false, State); - } - } - - /// \brief Appends the next token to \p State and updates information - /// necessary for indentation. - /// - /// Puts the token on the current line if \p Newline is \c false and adds a - /// line break and necessary indentation otherwise. - /// - /// If \p DryRun is \c false, also creates and stores the required - /// \c Replacement. - unsigned addTokenToState(bool Newline, bool DryRun, LineState &State) { - const FormatToken &Current = *State.NextToken; - const FormatToken &Previous = *State.NextToken->Previous; - - // Extra penalty that needs to be added because of the way certain line - // breaks are chosen. - unsigned ExtraPenalty = 0; - - if (State.Stack.size() == 0 || Current.Type == TT_ImplicitStringLiteral) { - // FIXME: Is this correct? - int WhitespaceLength = SourceMgr.getSpellingColumnNumber( - State.NextToken->WhitespaceRange.getEnd()) - - SourceMgr.getSpellingColumnNumber( - State.NextToken->WhitespaceRange.getBegin()); - State.Column += WhitespaceLength + State.NextToken->CodePointCount; - State.NextToken = State.NextToken->Next; - return 0; - } - - // If we are continuing an expression, we want to indent an extra 4 spaces. - unsigned ContinuationIndent = - std::max(State.Stack.back().LastSpace, State.Stack.back().Indent) + 4; - if (Newline) { - // 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) - ExtraPenalty += Style.PenaltyBreakFirstLessLess; - - State.Stack.back().ContainsLineBreak = true; - if (Current.is(tok::r_brace)) { - if (Current.BlockKind == BK_BracedInit) - State.Column = State.Stack[State.Stack.size() - 2].LastSpace; - else - State.Column = 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.isOneOf(tok::period, tok::arrow) && - Current.Type != TT_DesignatedInitializerPeriod) { - if (State.Stack.back().CallContinuation == 0) { - State.Column = ContinuationIndent; - State.Stack.back().CallContinuation = State.Column; - } else { - State.Column = State.Stack.back().CallContinuation; - } - } else if (Current.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 (Previous.ClosesTemplateDeclaration || - ((Current.Type == TT_StartOfName || - Current.is(tok::kw_operator)) && - State.ParenLevel == 0 && - (!Style.IndentFunctionDeclarationAfterType || - Line.StartsDefinition))) { - State.Column = State.Stack.back().Indent; - } else if (Current.Type == TT_ObjCSelectorName) { - if (State.Stack.back().ColonPos > Current.CodePointCount) { - State.Column = State.Stack.back().ColonPos - Current.CodePointCount; - } else { - State.Column = State.Stack.back().Indent; - State.Stack.back().ColonPos = State.Column + Current.CodePointCount; - } - } else if (Current.is(tok::l_square) && - Current.Type != TT_ObjCMethodExpr) { - 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 = 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 indenting 4 spaces instead of just - // flushing continuations left. - if (State.Column == FirstIndent) - State.Column += 4; - } - - if (Current.is(tok::question)) - State.Stack.back().BreakBeforeParameter = true; - 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 (!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.Column, - State.Column, Line.InPPDirective); - } - - if (!Current.isTrailingComment()) - State.Stack.back().LastSpace = State.Column; - if (Current.isOneOf(tok::arrow, tok::period) && - Current.Type != TT_DesignatedInitializerPeriod) - State.Stack.back().LastSpace += Current.CodePointCount; - 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; - } - const FormatToken *TokenBefore = Current.getPreviousNonComment(); - if (TokenBefore && !TokenBefore->isOneOf(tok::comma, tok::semi) && - TokenBefore->Type != TT_TemplateCloser && - 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)) - 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 && - Line.MustBeDeclaration)) - State.Stack.back().BreakBeforeParameter = true; - } - - } else { - if (Current.is(tok::equal) && - (RootToken->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->CodePointCount) { - State.Stack.back().VariablePos -= Tok->CodePointCount; - if (Tok->SpacesRequiredBefore != 0) - break; - Tok = Tok->Previous; - } - if (Previous.PartOfMultiVariableDeclStmt) - State.Stack.back().LastSpace = State.Stack.back().VariablePos; - } - - unsigned Spaces = State.NextToken->SpacesRequiredBefore; - - if (!DryRun) - Whitespaces.replaceWhitespace(Current, 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.CodePointCount) - State.Stack.back().ColonPos = - State.Stack.back().Indent + Current.LongestObjCSelectorName; - else - State.Stack.back().ColonPos = - State.Column + Spaces + Current.CodePointCount; - } - - if (Previous.opensScope() && Previous.Type != TT_ObjCMethodExpr && - Current.Type != TT_LineComment) - State.Stack.back().Indent = State.Column + Spaces; - if (Previous.is(tok::comma) && !Current.isTrailingComment() && - State.Stack.back().AvoidBinPacking) - State.Stack.back().NoLineBreak = 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 an indent of 4. - State.Stack.back().LastSpace = State.Column + 1; // 1 is length of "(". - else if (Previous.is(tok::comma)) - State.Stack.back().LastSpace = State.Column; - else if ((Previous.Type == TT_BinaryOperator || - Previous.Type == TT_ConditionalExpr || - Previous.Type == TT_CtorInitializerColon) && - !(Previous.getPrecedence() == prec::Assignment && - Current.FakeLParens.empty())) - // Always indent relative to the RHS of the expression unless this is a - // simple assignment without binary expression on the RHS. - State.Stack.back().LastSpace = State.Column; - else if (Previous.Type == TT_InheritanceColon) - State.Stack.back().Indent = State.Column; - else if (Previous.opensScope()) { - // If a function has multiple parameters (including a single parameter - // that is a binary expression) or a trailing call, indent all - // parameters from the opening parenthesis. This avoids confusing - // indents like: - // OuterFunction(InnerFunctionCall( - // ParameterToInnerFunction), - // SecondParameterToOuterFunction); - bool HasMultipleParameters = !Current.FakeLParens.empty(); - bool HasTrailingCall = false; - if (Previous.MatchingParen) { - const FormatToken *Next = Previous.MatchingParen->getNextNonComment(); - if (Next && Next->isOneOf(tok::period, tok::arrow)) - HasTrailingCall = true; - } - if (HasMultipleParameters || HasTrailingCall) - State.Stack.back().LastSpace = State.Column; - } - } - - return moveStateToNextToken(State, DryRun, Newline) + ExtraPenalty; - } - - /// \brief Mark the next token as consumed in \p State and modify its stacks - /// accordingly. - unsigned 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.is(tok::l_square) && - State.Stack.back().StartOfArraySubscripts == 0) - State.Stack.back().StartOfArraySubscripts = State.Column; - if (Current.is(tok::question)) - State.Stack.back().QuestionColumn = State.Column; - if (!Current.opensScope() && !Current.closesScope()) - State.LowestLevelOnLine = - std::min(State.LowestLevelOnLine, State.ParenLevel); - if (Current.isOneOf(tok::period, tok::arrow) && - Line.Type == LT_BuilderTypeCall && State.ParenLevel == 0) - State.Stack.back().StartOfFunctionCall = - Current.LastInChainOfCalls ? 0 - : State.Column + Current.CodePointCount; - 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; - } - - // If return returns a binary expression, align after it. - if (Current.is(tok::kw_return) && !Current.FakeLParens.empty()) - State.Stack.back().LastSpace = State.Column + 7; - - // 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 4. - if (Current.Type == TT_ObjCMethodSpecifier) - State.Stack.back().Indent += 4; - - // 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 = - Current.is(tok::kw_return) || - (Previous && (Previous->opensScope() || - Previous->getPrecedence() == prec::Assignment)); - for (SmallVectorImpl<prec::Level>::const_reverse_iterator - I = Current.FakeLParens.rbegin(), - E = Current.FakeLParens.rend(); - I != E; ++I) { - ParenState NewParenState = State.Stack.back(); - NewParenState.ContainsLineBreak = false; - NewParenState.Indent = - std::max(std::max(State.Column, NewParenState.Indent), - State.Stack.back().LastSpace); - - // 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 += 4; - if (Previous && !Previous->opensScope()) - 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 LastSpace = State.Stack.back().LastSpace; - bool AvoidBinPacking; - if (Current.is(tok::l_brace)) { - NewIndent = - LastSpace + (Style.Cpp11BracedListStyle ? 4 : Style.IndentWidth); - const FormatToken *NextNoComment = Current.getNextNonComment(); - AvoidBinPacking = NextNoComment && - NextNoComment->Type == TT_DesignatedInitializerPeriod; - } else { - NewIndent = - 4 + std::max(LastSpace, State.Stack.back().StartOfFunctionCall); - AvoidBinPacking = !Style.BinPackParameters || - (Style.ExperimentalAutoDetectBinPacking && - (Current.PackingKind == PPK_OnePerLine || - (!BinPackInconclusiveFunctions && - Current.PackingKind == PPK_Inconclusive))); - } - - State.Stack.push_back(ParenState(NewIndent, LastSpace, AvoidBinPacking, - State.Stack.back().NoLineBreak)); - ++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.is(tok::l_square) && Current.Type == TT_ObjCMethodExpr && - Current.MatchingParen != NULL) { - if (getLengthToMatchingParen(Current) + State.Column > getColumnLimit()) - State.Stack.back().BreakBeforeParameter = true; - } - - // If we encounter a closing ), ], } or >, we can remove a level from our - // stacks. - if (Current.isOneOf(tok::r_paren, tok::r_square) || - (Current.is(tok::r_brace) && State.NextToken != RootToken) || - 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. - 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.CodePointCount; - - State.NextToken = State.NextToken->Next; - - if (!Newline && Style.AlwaysBreakBeforeMultilineStrings && - Current.is(tok::string_literal) && Current.CanBreakBefore) - return 0; - - return breakProtrudingToken(Current, State, DryRun); - } - - /// \brief If the current token sticks out over the end of the line, break - /// it if possible. - /// - /// \returns An extra penalty if a token was broken, otherwise 0. - /// - /// The returned penalty will cover the cost of the additional line breaks and - /// column limit violation in all lines except for the last one. The penalty - /// for the column limit violation in the last line (and in single line - /// tokens) is handled in \c addNextStateToQueue. - unsigned breakProtrudingToken(const FormatToken &Current, LineState &State, - bool DryRun) { - llvm::OwningPtr<BreakableToken> Token; - unsigned StartColumn = State.Column - Current.CodePointCount; - unsigned OriginalStartColumn = - SourceMgr.getSpellingColumnNumber(Current.getStartOfNonWhitespace()) - - 1; - - if (Current.is(tok::string_literal) && - Current.Type != TT_ImplicitStringLiteral) { - // Only break up default narrow strings. - if (!Current.TokenText.startswith("\"")) - return 0; - // Don't break string literals with escaped newlines. As clang-format must - // not change the string's content, it is unlikely that we'll end up with - // a better format. - if (Current.TokenText.find("\\\n") != StringRef::npos) - 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; - - Token.reset(new BreakableStringLiteral(Current, StartColumn, - Line.InPPDirective, Encoding)); - } else if (Current.Type == TT_BlockComment && Current.isTrailingComment()) { - Token.reset(new BreakableBlockComment( - Style, Current, StartColumn, OriginalStartColumn, !Current.Previous, - Line.InPPDirective, Encoding)); - } else if (Current.Type == TT_LineComment && - (Current.Previous == NULL || - Current.Previous->Type != TT_ImplicitStringLiteral)) { - // Don't break line comments with escaped newlines. These look like - // separate line comments, but in fact contain a single line comment with - // multiple lines including leading whitespace and the '//' markers. - // - // FIXME: If we want to handle them correctly, we'll need to adjust - // leading whitespace in consecutive lines when changing indentation of - // the first line similar to what we do with block comments. - StringRef::size_type EscapedNewlinePos = Current.TokenText.find("\\\n"); - if (EscapedNewlinePos != StringRef::npos) { - State.Column = - StartColumn + - encoding::getCodePointCount( - Current.TokenText.substr(0, EscapedNewlinePos), Encoding) + - 1; - return 0; - } - - Token.reset(new BreakableLineComment(Current, StartColumn, - Line.InPPDirective, Encoding)); - } else { - return 0; - } - if (Current.UnbreakableTailLength >= getColumnLimit()) - return 0; - - unsigned RemainingSpace = getColumnLimit() - 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, getColumnLimit()); - 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); - assert(NewRemainingTokenColumns < RemainingTokenColumns); - if (!DryRun) - Token->insertBreak(LineIndex, TailOffset, Split, Whitespaces); - Penalty += Current.is(tok::string_literal) ? Style.PenaltyBreakString - : Style.PenaltyBreakComment; - unsigned ColumnsUsed = - Token->getLineLengthAfterSplit(LineIndex, TailOffset, Split.first); - if (ColumnsUsed > getColumnLimit()) { - Penalty += - Style.PenaltyExcessCharacter * (ColumnsUsed - getColumnLimit()); - } - 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; - } - - State.Stack.back().LastSpace = StartColumn; - } - return Penalty; - } - - unsigned getColumnLimit() { - // In preprocessor directives reserve two chars for trailing " \" - return Style.ColumnLimit - (Line.InPPDirective ? 2 : 0); - } - /// \brief An edge in the solution space from \c Previous->State to \c State, /// inserting a newline dependent on the \c NewLine. struct StateNode { @@ -1173,7 +431,7 @@ private: << (*I)->Previous->State.NextToken->SplitPenalty << "\n"; } }); - addTokenToState((*I)->NewLine, false, State); + Indenter->addTokenToState(State, (*I)->NewLine, false); } } @@ -1183,9 +441,9 @@ private: /// penalty of \p Penalty. Insert a line break if \p NewLine is \c true. void addNextStateToQueue(unsigned Penalty, StateNode *PreviousNode, bool NewLine) { - if (NewLine && !canBreak(PreviousNode->State)) + if (NewLine && !Indenter->canBreak(PreviousNode->State)) return; - if (!NewLine && mustBreak(PreviousNode->State)) + if (!NewLine && Indenter->mustBreak(PreviousNode->State)) return; if (NewLine) { if (!PreviousNode->State.Stack.back().ContainsLineBreak) @@ -1195,9 +453,10 @@ private: StateNode *Node = new (Allocator.Allocate()) StateNode(PreviousNode->State, NewLine, PreviousNode); - Penalty += addTokenToState(NewLine, true, Node->State); - if (Node->State.Column > getColumnLimit()) { - unsigned ExcessCharacters = Node->State.Column - getColumnLimit(); + Penalty += Indenter->addTokenToState(Node->State, NewLine, true); + if (Node->State.Column > Indenter->getColumnLimit()) { + unsigned ExcessCharacters = + Node->State.Column - Indenter->getColumnLimit(); Penalty += Style.PenaltyExcessCharacter * ExcessCharacters; } @@ -1205,137 +464,15 @@ private: ++Count; } - /// \brief Returns \c true, if a line break after \p State is allowed. - bool 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)) - 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.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; - return !State.Stack.back().NoLineBreak; - } - - /// \brief Returns \c true, if a line break after \p State is mandatory. - bool mustBreak(const LineState &State) { - const FormatToken &Current = *State.NextToken; - const FormatToken &Previous = *Current.Previous; - if (Current.MustBreakBefore || Current.Type == TT_InlineASMColon) - return true; - if (!Style.Cpp11BracedListStyle && Current.is(tok::r_brace) && - State.Stack.back().BreakBeforeClosingBrace) - return true; - if (Previous.is(tok::semi) && State.LineContainsContinuedForLoopSection) - return true; - if (Style.BreakConstructorInitializersBeforeComma) { - if (Previous.Type == TT_CtorInitializerComma) - return false; - if (Current.Type == TT_CtorInitializerComma) - return true; - } - if ((Previous.isOneOf(tok::comma, tok::semi) || Current.is(tok::question) || - (Current.Type == TT_ConditionalExpr && - !(Current.is(tok::colon) && Previous.is(tok::question)))) && - 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 && - Current.is(tok::string_literal) && Previous.isNot(tok::lessless) && - Previous.Type != TT_InlineASMColon && - ((Current.getNextNonComment() && - Current.getNextNonComment()->is(tok::string_literal)) || - (Current.TokenText.find("\\\n") != StringRef::npos))) - 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->FakeRParens > 0; - 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))) - return true; - - if ((Current.Type == TT_StartOfName || Current.is(tok::kw_operator)) && - Line.MightBeFunctionDecl && State.Stack.back().BreakBeforeParameter && - State.ParenLevel == 0) - return true; - return false; - } - - // Returns the total number of columns required for the remaining tokens. - unsigned getRemainingLength(const LineState &State) { - if (State.NextToken && State.NextToken->Previous) - return Line.Last->TotalLength - State.NextToken->Previous->TotalLength; - return 0; - } - + ContinuationIndenter *Indenter; FormatStyle Style; - SourceManager &SourceMgr; const AnnotatedLine &Line; - const unsigned FirstIndent; - const FormatToken *RootToken; - WhitespaceManager &Whitespaces; llvm::SpecificBumpPtrAllocator<StateNode> Allocator; QueueType Queue; // Increasing count of \c StateNode items we have created. This is used // to create a deterministic order independent of the container. unsigned Count; - encoding::Encoding Encoding; - bool BinPackInconclusiveFunctions; }; class FormatTokenLexer { @@ -1549,10 +686,28 @@ public: SourceMgr.getSpellingColumnNumber(FirstTok->Tok.getLocation()) - 1; } - UnwrappedLineFormatter Formatter(Style, SourceMgr, TheLine, Indent, - TheLine.First, Whitespaces, Encoding, - BinPackInconclusiveFunctions); - Formatter.format(I + 1 != E ? &*(I + 1) : NULL); + ContinuationIndenter Indenter(Style, SourceMgr, TheLine, Indent, + Whitespaces, Encoding, + BinPackInconclusiveFunctions); + + // If everything fits on a single line, just put it there. + unsigned ColumnLimit = Style.ColumnLimit; + if ((I + 1) != E && (I + 1)->InPPDirective && + !(I + 1)->First->HasUnescapedNewline) + ColumnLimit = Indenter.getColumnLimit(); + + if (I->Last->TotalLength + Indent <= ColumnLimit) { + LineState State = Indenter.getInitialState(); + while (State.NextToken != NULL) + Indenter.addTokenToState(State, false, false); + } else if (Style.ColumnLimit == 0) { + NoColumnLimitFormatter Formatter(&Indenter); + Formatter.format(); + } else { + UnwrappedLineFormatter Formatter(&Indenter, Style, TheLine); + Formatter.format(); + } + IndentForLevel[TheLine.Level] = LevelIndent; PreviousLineWasTouched = true; } else { |