diff options
author | Daniel Jasper <djasper@google.com> | 2013-08-16 11:20:30 +0000 |
---|---|---|
committer | Daniel Jasper <djasper@google.com> | 2013-08-16 11:20:30 +0000 |
commit | de0328aea8a68b7cfeff6c99ca69ff34af18a5aa (patch) | |
tree | 8e1d225174297bd06e5a09d8ede1b1bf154be183 /clang/lib/Format/Format.cpp | |
parent | f6ea6a5a19609f3482385522d27a2f95a89c4660 (diff) | |
download | bcm5719-llvm-de0328aea8a68b7cfeff6c99ca69ff34af18a5aa.tar.gz bcm5719-llvm-de0328aea8a68b7cfeff6c99ca69ff34af18a5aa.zip |
Split UnwrappedLineFormatter into individual components.
Goals: Structure code better and make components easier to use for
future features (e.g. column layout for long braced initializers).
No functional changes intended.
llvm-svn: 188543
Diffstat (limited to 'clang/lib/Format/Format.cpp')
-rw-r--r-- | clang/lib/Format/Format.cpp | 957 |
1 files changed, 56 insertions, 901 deletions
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 { |