r223936 - clang-format: Factor out UnwrappedLineFormatter into a separate file.
Nico Weber
thakis at chromium.org
Wed Dec 10 11:35:42 PST 2014
For what it's worth, I would find it super helpful if there were
class-level comments on the classes in lib/Format that briefly describe the
main responsibility of each class and explain terminology ("An unwrapped
line is a $concise explanation"). There are now enough classes in
lib/Format that I'm always a bit confused about this when reading this code.
On Wed, Dec 10, 2014 at 11:00 AM, Daniel Jasper <djasper at google.com> wrote:
> Author: djasper
> Date: Wed Dec 10 13:00:42 2014
> New Revision: 223936
>
> URL: http://llvm.org/viewvc/llvm-project?rev=223936&view=rev
> Log:
> clang-format: Factor out UnwrappedLineFormatter into a separate file.
>
> No functional changes intended.
>
> Added:
> cfe/trunk/lib/Format/UnwrappedLineFormatter.cpp
> cfe/trunk/lib/Format/UnwrappedLineFormatter.h
> Modified:
> cfe/trunk/lib/Format/CMakeLists.txt
> cfe/trunk/lib/Format/Format.cpp
>
> Modified: cfe/trunk/lib/Format/CMakeLists.txt
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/CMakeLists.txt?rev=223936&r1=223935&r2=223936&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/Format/CMakeLists.txt (original)
> +++ cfe/trunk/lib/Format/CMakeLists.txt Wed Dec 10 13:00:42 2014
> @@ -6,6 +6,7 @@ add_clang_library(clangFormat
> Format.cpp
> FormatToken.cpp
> TokenAnnotator.cpp
> + UnwrappedLineFormatter.cpp
> UnwrappedLineParser.cpp
> WhitespaceManager.cpp
>
>
> Modified: cfe/trunk/lib/Format/Format.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/Format.cpp?rev=223936&r1=223935&r2=223936&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/Format/Format.cpp (original)
> +++ cfe/trunk/lib/Format/Format.cpp Wed Dec 10 13:00:42 2014
> @@ -15,6 +15,7 @@
>
> #include "ContinuationIndenter.h"
> #include "TokenAnnotator.h"
> +#include "UnwrappedLineFormatter.h"
> #include "UnwrappedLineParser.h"
> #include "WhitespaceManager.h"
> #include "clang/Basic/Diagnostic.h"
> @@ -589,779 +590,6 @@ std::string configurationAsText(const Fo
>
> namespace {
>
> -bool startsExternCBlock(const AnnotatedLine &Line) {
> - const FormatToken *Next = Line.First->getNextNonComment();
> - const FormatToken *NextNext = Next ? Next->getNextNonComment() :
> nullptr;
> - return Line.First->is(tok::kw_extern) && Next &&
> Next->isStringLiteral() &&
> - NextNext && NextNext->is(tok::l_brace);
> -}
> -
> -class NoColumnLimitFormatter {
> -public:
> - NoColumnLimitFormatter(ContinuationIndenter *Indenter) :
> Indenter(Indenter) {}
> -
> - /// \brief Formats the line starting at \p State, simply keeping all of
> the
> - /// input's line breaking decisions.
> - void format(unsigned FirstIndent, const AnnotatedLine *Line) {
> - LineState State =
> - Indenter->getInitialState(FirstIndent, Line, /*DryRun=*/false);
> - while (State.NextToken) {
> - bool Newline =
> - Indenter->mustBreak(State) ||
> - (Indenter->canBreak(State) && State.NextToken->NewlinesBefore >
> 0);
> - Indenter->addTokenToState(State, Newline, /*DryRun=*/false);
> - }
> - }
> -
> -private:
> - ContinuationIndenter *Indenter;
> -};
> -
> -class LineJoiner {
> -public:
> - LineJoiner(const FormatStyle &Style) : Style(Style) {}
> -
> - /// \brief Calculates how many lines can be merged into 1 starting at
> \p I.
> - unsigned
> - tryFitMultipleLinesInOne(unsigned Indent,
> - SmallVectorImpl<AnnotatedLine
> *>::const_iterator I,
> - SmallVectorImpl<AnnotatedLine
> *>::const_iterator E) {
> - // We can never merge stuff if there are trailing line comments.
> - const AnnotatedLine *TheLine = *I;
> - if (TheLine->Last->is(TT_LineComment))
> - return 0;
> -
> - if (Style.ColumnLimit > 0 && Indent > Style.ColumnLimit)
> - return 0;
> -
> - unsigned Limit =
> - Style.ColumnLimit == 0 ? UINT_MAX : Style.ColumnLimit - Indent;
> - // If we already exceed the column limit, we set 'Limit' to 0. The
> different
> - // tryMerge..() functions can then decide whether to still do merging.
> - Limit = TheLine->Last->TotalLength > Limit
> - ? 0
> - : Limit - TheLine->Last->TotalLength;
> -
> - if (I + 1 == E || I[1]->Type == LT_Invalid ||
> I[1]->First->MustBreakBefore)
> - return 0;
> -
> - // FIXME: TheLine->Level != 0 might or might not be the right check
> to do.
> - // If necessary, change to something smarter.
> - bool MergeShortFunctions =
> - Style.AllowShortFunctionsOnASingleLine == FormatStyle::SFS_All ||
> - (Style.AllowShortFunctionsOnASingleLine == FormatStyle::SFS_Empty
> &&
> - I[1]->First->is(tok::r_brace)) ||
> - (Style.AllowShortFunctionsOnASingleLine ==
> FormatStyle::SFS_Inline &&
> - TheLine->Level != 0);
> -
> - if (TheLine->Last->is(TT_FunctionLBrace) &&
> - TheLine->First != TheLine->Last) {
> - return MergeShortFunctions ? tryMergeSimpleBlock(I, E, Limit) : 0;
> - }
> - if (TheLine->Last->is(tok::l_brace)) {
> - return Style.BreakBeforeBraces == FormatStyle::BS_Attach
> - ? tryMergeSimpleBlock(I, E, Limit)
> - : 0;
> - }
> - if (I[1]->First->is(TT_FunctionLBrace) &&
> - Style.BreakBeforeBraces != FormatStyle::BS_Attach) {
> - if (I[1]->Last->is(TT_LineComment))
> - return 0;
> -
> - // Check for Limit <= 2 to account for the " {".
> - if (Limit <= 2 || (Style.ColumnLimit == 0 &&
> containsMustBreak(TheLine)))
> - return 0;
> - Limit -= 2;
> -
> - unsigned MergedLines = 0;
> - if (MergeShortFunctions) {
> - MergedLines = tryMergeSimpleBlock(I + 1, E, Limit);
> - // If we managed to merge the block, count the function header,
> which is
> - // on a separate line.
> - if (MergedLines > 0)
> - ++MergedLines;
> - }
> - return MergedLines;
> - }
> - if (TheLine->First->is(tok::kw_if)) {
> - return Style.AllowShortIfStatementsOnASingleLine
> - ? tryMergeSimpleControlStatement(I, E, Limit)
> - : 0;
> - }
> - if (TheLine->First->isOneOf(tok::kw_for, tok::kw_while)) {
> - return Style.AllowShortLoopsOnASingleLine
> - ? tryMergeSimpleControlStatement(I, E, Limit)
> - : 0;
> - }
> - if (TheLine->First->isOneOf(tok::kw_case, tok::kw_default)) {
> - return Style.AllowShortCaseLabelsOnASingleLine
> - ? tryMergeShortCaseLabels(I, E, Limit)
> - : 0;
> - }
> - if (TheLine->InPPDirective &&
> - (TheLine->First->HasUnescapedNewline || TheLine->First->IsFirst))
> {
> - return tryMergeSimplePPDirective(I, E, Limit);
> - }
> - return 0;
> - }
> -
> -private:
> - unsigned
> - tryMergeSimplePPDirective(SmallVectorImpl<AnnotatedLine
> *>::const_iterator I,
> - SmallVectorImpl<AnnotatedLine
> *>::const_iterator E,
> - unsigned Limit) {
> - if (Limit == 0)
> - return 0;
> - if (!I[1]->InPPDirective || I[1]->First->HasUnescapedNewline)
> - return 0;
> - if (I + 2 != E && I[2]->InPPDirective &&
> !I[2]->First->HasUnescapedNewline)
> - return 0;
> - if (1 + I[1]->Last->TotalLength > Limit)
> - return 0;
> - return 1;
> - }
> -
> - unsigned tryMergeSimpleControlStatement(
> - SmallVectorImpl<AnnotatedLine *>::const_iterator I,
> - SmallVectorImpl<AnnotatedLine *>::const_iterator E, unsigned Limit)
> {
> - if (Limit == 0)
> - return 0;
> - if ((Style.BreakBeforeBraces == FormatStyle::BS_Allman ||
> - Style.BreakBeforeBraces == FormatStyle::BS_GNU) &&
> - (I[1]->First->is(tok::l_brace) &&
> !Style.AllowShortBlocksOnASingleLine))
> - return 0;
> - if (I[1]->InPPDirective != (*I)->InPPDirective ||
> - (I[1]->InPPDirective && I[1]->First->HasUnescapedNewline))
> - return 0;
> - Limit = limitConsideringMacros(I + 1, E, Limit);
> - AnnotatedLine &Line = **I;
> - if (Line.Last->isNot(tok::r_paren))
> - return 0;
> - if (1 + I[1]->Last->TotalLength > Limit)
> - return 0;
> - if (I[1]->First->isOneOf(tok::semi, tok::kw_if, tok::kw_for,
> - tok::kw_while, TT_LineComment))
> - return 0;
> - // Only inline simple if's (no nested if or else).
> - if (I + 2 != E && Line.First->is(tok::kw_if) &&
> - I[2]->First->is(tok::kw_else))
> - return 0;
> - return 1;
> - }
> -
> - unsigned tryMergeShortCaseLabels(
> - SmallVectorImpl<AnnotatedLine *>::const_iterator I,
> - SmallVectorImpl<AnnotatedLine *>::const_iterator E, unsigned Limit)
> {
> - if (Limit == 0 || I + 1 == E ||
> - I[1]->First->isOneOf(tok::kw_case, tok::kw_default))
> - return 0;
> - unsigned NumStmts = 0;
> - unsigned Length = 0;
> - bool InPPDirective = I[0]->InPPDirective;
> - for (; NumStmts < 3; ++NumStmts) {
> - if (I + 1 + NumStmts == E)
> - break;
> - const AnnotatedLine *Line = I[1 + NumStmts];
> - if (Line->InPPDirective != InPPDirective)
> - break;
> - if (Line->First->isOneOf(tok::kw_case, tok::kw_default,
> tok::r_brace))
> - break;
> - if (Line->First->isOneOf(tok::kw_if, tok::kw_for, tok::kw_switch,
> - tok::kw_while, tok::comment))
> - return 0;
> - Length += I[1 + NumStmts]->Last->TotalLength + 1; // 1 for the
> space.
> - }
> - if (NumStmts == 0 || NumStmts == 3 || Length > Limit)
> - return 0;
> - return NumStmts;
> - }
> -
> - unsigned
> - tryMergeSimpleBlock(SmallVectorImpl<AnnotatedLine *>::const_iterator I,
> - SmallVectorImpl<AnnotatedLine *>::const_iterator E,
> - unsigned Limit) {
> - AnnotatedLine &Line = **I;
> -
> - // Don't merge ObjC @ keywords and methods.
> - if (Style.Language != FormatStyle::LK_Java &&
> - Line.First->isOneOf(tok::at, tok::minus, tok::plus))
> - return 0;
> -
> - // Check that the current line allows merging. This depends on
> whether we
> - // are in a control flow statements as well as several style flags.
> - if (Line.First->isOneOf(tok::kw_else, tok::kw_case))
> - return 0;
> - if (Line.First->isOneOf(tok::kw_if, tok::kw_while, tok::kw_do,
> tok::kw_try,
> - tok::kw_catch, tok::kw_for, tok::r_brace)) {
> - if (!Style.AllowShortBlocksOnASingleLine)
> - return 0;
> - if (!Style.AllowShortIfStatementsOnASingleLine &&
> - Line.First->is(tok::kw_if))
> - return 0;
> - if (!Style.AllowShortLoopsOnASingleLine &&
> - Line.First->isOneOf(tok::kw_while, tok::kw_do, tok::kw_for))
> - return 0;
> - // FIXME: Consider an option to allow short exception handling
> clauses on
> - // a single line.
> - if (Line.First->isOneOf(tok::kw_try, tok::kw_catch))
> - return 0;
> - }
> -
> - FormatToken *Tok = I[1]->First;
> - if (Tok->is(tok::r_brace) && !Tok->MustBreakBefore &&
> - (Tok->getNextNonComment() == nullptr ||
> - Tok->getNextNonComment()->is(tok::semi))) {
> - // We merge empty blocks even if the line exceeds the column limit.
> - Tok->SpacesRequiredBefore = 0;
> - Tok->CanBreakBefore = true;
> - return 1;
> - } else if (Limit != 0 && Line.First->isNot(tok::kw_namespace) &&
> - !startsExternCBlock(Line)) {
> - // We don't merge short records.
> - if (Line.First->isOneOf(tok::kw_class, tok::kw_union,
> tok::kw_struct))
> - return 0;
> -
> - // Check that we still have three lines and they fit into the limit.
> - if (I + 2 == E || I[2]->Type == LT_Invalid)
> - return 0;
> - Limit = limitConsideringMacros(I + 2, E, Limit);
> -
> - if (!nextTwoLinesFitInto(I, Limit))
> - return 0;
> -
> - // Second, check that the next line does not contain any braces -
> if it
> - // does, readability declines when putting it into a single line.
> - if (I[1]->Last->is(TT_LineComment))
> - return 0;
> - do {
> - if (Tok->is(tok::l_brace) && Tok->BlockKind != BK_BracedInit)
> - return 0;
> - Tok = Tok->Next;
> - } while (Tok);
> -
> - // Last, check that the third line starts with a closing brace.
> - Tok = I[2]->First;
> - if (Tok->isNot(tok::r_brace))
> - return 0;
> -
> - return 2;
> - }
> - return 0;
> - }
> -
> - /// Returns the modified column limit for \p I if it is inside a macro
> and
> - /// needs a trailing '\'.
> - unsigned
> - limitConsideringMacros(SmallVectorImpl<AnnotatedLine *>::const_iterator
> I,
> - SmallVectorImpl<AnnotatedLine *>::const_iterator
> E,
> - unsigned Limit) {
> - if (I[0]->InPPDirective && I + 1 != E &&
> - !I[1]->First->HasUnescapedNewline && !I[1]->First->is(tok::eof)) {
> - return Limit < 2 ? 0 : Limit - 2;
> - }
> - return Limit;
> - }
> -
> - bool nextTwoLinesFitInto(SmallVectorImpl<AnnotatedLine
> *>::const_iterator I,
> - unsigned Limit) {
> - if (I[1]->First->MustBreakBefore || I[2]->First->MustBreakBefore)
> - return false;
> - return 1 + I[1]->Last->TotalLength + 1 + I[2]->Last->TotalLength <=
> Limit;
> - }
> -
> - bool containsMustBreak(const AnnotatedLine *Line) {
> - for (const FormatToken *Tok = Line->First; Tok; Tok = Tok->Next) {
> - if (Tok->MustBreakBefore)
> - return true;
> - }
> - return false;
> - }
> -
> - const FormatStyle &Style;
> -};
> -
> -class UnwrappedLineFormatter {
> -public:
> - UnwrappedLineFormatter(ContinuationIndenter *Indenter,
> - WhitespaceManager *Whitespaces,
> - const FormatStyle &Style)
> - : Indenter(Indenter), Whitespaces(Whitespaces), Style(Style),
> - Joiner(Style) {}
> -
> - unsigned format(const SmallVectorImpl<AnnotatedLine *> &Lines, bool
> DryRun,
> - int AdditionalIndent = 0, bool FixBadIndentation =
> false) {
> - // Try to look up already computed penalty in DryRun-mode.
> - std::pair<const SmallVectorImpl<AnnotatedLine *> *, unsigned>
> CacheKey(
> - &Lines, AdditionalIndent);
> - auto CacheIt = PenaltyCache.find(CacheKey);
> - if (DryRun && CacheIt != PenaltyCache.end())
> - return CacheIt->second;
> -
> - assert(!Lines.empty());
> - unsigned Penalty = 0;
> - std::vector<int> IndentForLevel;
> - for (unsigned i = 0, e = Lines[0]->Level; i != e; ++i)
> - IndentForLevel.push_back(Style.IndentWidth * i + AdditionalIndent);
> - const AnnotatedLine *PreviousLine = nullptr;
> - for (SmallVectorImpl<AnnotatedLine *>::const_iterator I =
> Lines.begin(),
> - E = Lines.end();
> - I != E; ++I) {
> - const AnnotatedLine &TheLine = **I;
> - const FormatToken *FirstTok = TheLine.First;
> - int Offset = getIndentOffset(*FirstTok);
> -
> - // Determine indent and try to merge multiple unwrapped lines.
> - unsigned Indent;
> - if (TheLine.InPPDirective) {
> - Indent = TheLine.Level * Style.IndentWidth;
> - } else {
> - while (IndentForLevel.size() <= TheLine.Level)
> - IndentForLevel.push_back(-1);
> - IndentForLevel.resize(TheLine.Level + 1);
> - Indent = getIndent(IndentForLevel, TheLine.Level);
> - }
> - unsigned LevelIndent = Indent;
> - if (static_cast<int>(Indent) + Offset >= 0)
> - Indent += Offset;
> -
> - // Merge multiple lines if possible.
> - unsigned MergedLines = Joiner.tryFitMultipleLinesInOne(Indent, I,
> E);
> - if (MergedLines > 0 && Style.ColumnLimit == 0) {
> - // Disallow line merging if there is a break at the start of one
> of the
> - // input lines.
> - for (unsigned i = 0; i < MergedLines; ++i) {
> - if (I[i + 1]->First->NewlinesBefore > 0)
> - MergedLines = 0;
> - }
> - }
> - if (!DryRun) {
> - for (unsigned i = 0; i < MergedLines; ++i) {
> - join(*I[i], *I[i + 1]);
> - }
> - }
> - I += MergedLines;
> -
> - bool FixIndentation =
> - FixBadIndentation && (LevelIndent != FirstTok->OriginalColumn);
> - if (TheLine.First->is(tok::eof)) {
> - if (PreviousLine && PreviousLine->Affected && !DryRun) {
> - // Remove the file's trailing whitespace.
> - unsigned Newlines = std::min(FirstTok->NewlinesBefore, 1u);
> - Whitespaces->replaceWhitespace(*TheLine.First, Newlines,
> - /*IndentLevel=*/0, /*Spaces=*/0,
> - /*TargetColumn=*/0);
> - }
> - } else if (TheLine.Type != LT_Invalid &&
> - (TheLine.Affected || FixIndentation)) {
> - if (FirstTok->WhitespaceRange.isValid()) {
> - if (!DryRun)
> - formatFirstToken(*TheLine.First, PreviousLine, TheLine.Level,
> - Indent, TheLine.InPPDirective);
> - } else {
> - Indent = LevelIndent = FirstTok->OriginalColumn;
> - }
> -
> - // If everything fits on a single line, just put it there.
> - unsigned ColumnLimit = Style.ColumnLimit;
> - if (I + 1 != E) {
> - AnnotatedLine *NextLine = I[1];
> - if (NextLine->InPPDirective &&
> !NextLine->First->HasUnescapedNewline)
> - ColumnLimit = getColumnLimit(TheLine.InPPDirective);
> - }
> -
> - if (TheLine.Last->TotalLength + Indent <= ColumnLimit ||
> - TheLine.Type == LT_ImportStatement) {
> - LineState State = Indenter->getInitialState(Indent, &TheLine,
> DryRun);
> - while (State.NextToken) {
> - formatChildren(State, /*Newline=*/false, /*DryRun=*/false,
> Penalty);
> - Indenter->addTokenToState(State, /*Newline=*/false, DryRun);
> - }
> - } else if (Style.ColumnLimit == 0) {
> - // FIXME: Implement nested blocks for ColumnLimit = 0.
> - NoColumnLimitFormatter Formatter(Indenter);
> - if (!DryRun)
> - Formatter.format(Indent, &TheLine);
> - } else {
> - Penalty += format(TheLine, Indent, DryRun);
> - }
> -
> - if (!TheLine.InPPDirective)
> - IndentForLevel[TheLine.Level] = LevelIndent;
> - } else if (TheLine.ChildrenAffected) {
> - format(TheLine.Children, DryRun);
> - } else {
> - // Format the first token if necessary, and notify the
> WhitespaceManager
> - // about the unchanged whitespace.
> - for (FormatToken *Tok = TheLine.First; Tok; Tok = Tok->Next) {
> - if (Tok == TheLine.First &&
> - (Tok->NewlinesBefore > 0 || Tok->IsFirst)) {
> - unsigned LevelIndent = Tok->OriginalColumn;
> - if (!DryRun) {
> - // Remove trailing whitespace of the previous line.
> - if ((PreviousLine && PreviousLine->Affected) ||
> - TheLine.LeadingEmptyLinesAffected) {
> - formatFirstToken(*Tok, PreviousLine, TheLine.Level,
> LevelIndent,
> - TheLine.InPPDirective);
> - } else {
> - Whitespaces->addUntouchableToken(*Tok,
> TheLine.InPPDirective);
> - }
> - }
> -
> - if (static_cast<int>(LevelIndent) - Offset >= 0)
> - LevelIndent -= Offset;
> - if (Tok->isNot(tok::comment) && !TheLine.InPPDirective)
> - IndentForLevel[TheLine.Level] = LevelIndent;
> - } else if (!DryRun) {
> - Whitespaces->addUntouchableToken(*Tok, TheLine.InPPDirective);
> - }
> - }
> - }
> - if (!DryRun) {
> - for (FormatToken *Tok = TheLine.First; Tok; Tok = Tok->Next) {
> - Tok->Finalized = true;
> - }
> - }
> - PreviousLine = *I;
> - }
> - PenaltyCache[CacheKey] = Penalty;
> - return Penalty;
> - }
> -
> -private:
> - /// \brief Formats an \c AnnotatedLine and returns the penalty.
> - ///
> - /// If \p DryRun is \c false, directly applies the changes.
> - unsigned format(const AnnotatedLine &Line, unsigned FirstIndent,
> - bool DryRun) {
> - LineState State = Indenter->getInitialState(FirstIndent, &Line,
> DryRun);
> -
> - // If the ObjC method declaration does not fit on a line, we should
> format
> - // it with one arg per line.
> - if (State.Line->Type == LT_ObjCMethodDecl)
> - State.Stack.back().BreakBeforeParameter = true;
> -
> - // Find best solution in solution space.
> - return analyzeSolutionSpace(State, DryRun);
> - }
> -
> - /// \brief An edge in the solution space from \c Previous->State to \c
> State,
> - /// inserting a newline dependent on the \c NewLine.
> - struct StateNode {
> - StateNode(const LineState &State, bool NewLine, StateNode *Previous)
> - : State(State), NewLine(NewLine), Previous(Previous) {}
> - LineState State;
> - bool NewLine;
> - StateNode *Previous;
> - };
> -
> - /// \brief A pair of <penalty, count> that is used to prioritize the
> BFS on.
> - ///
> - /// In case of equal penalties, we want to prefer states that were
> inserted
> - /// first. During state generation we make sure that we insert states
> first
> - /// that break the line as late as possible.
> - typedef std::pair<unsigned, unsigned> OrderedPenalty;
> -
> - /// \brief An item in the prioritized BFS search queue. The \c
> StateNode's
> - /// \c State has the given \c OrderedPenalty.
> - typedef std::pair<OrderedPenalty, StateNode *> QueueItem;
> -
> - /// \brief The BFS queue type.
> - typedef std::priority_queue<QueueItem, std::vector<QueueItem>,
> - std::greater<QueueItem> > QueueType;
> -
> - /// \brief Get the offset of the line relatively to the level.
> - ///
> - /// For example, 'public:' labels in classes are offset by 1 or 2
> - /// characters to the left from their level.
> - int getIndentOffset(const FormatToken &RootToken) {
> - if (Style.Language == FormatStyle::LK_Java)
> - return 0;
> - if (RootToken.isAccessSpecifier(false) ||
> RootToken.isObjCAccessSpecifier())
> - return Style.AccessModifierOffset;
> - return 0;
> - }
> -
> - /// \brief Add a new line and the required indent before the first Token
> - /// of the \c UnwrappedLine if there was no structural parsing error.
> - void formatFirstToken(FormatToken &RootToken,
> - const AnnotatedLine *PreviousLine, unsigned
> IndentLevel,
> - unsigned Indent, bool InPPDirective) {
> - unsigned Newlines =
> - std::min(RootToken.NewlinesBefore, Style.MaxEmptyLinesToKeep + 1);
> - // Remove empty lines before "}" where applicable.
> - if (RootToken.is(tok::r_brace) &&
> - (!RootToken.Next ||
> - (RootToken.Next->is(tok::semi) && !RootToken.Next->Next)))
> - Newlines = std::min(Newlines, 1u);
> - if (Newlines == 0 && !RootToken.IsFirst)
> - Newlines = 1;
> - if (RootToken.IsFirst && !RootToken.HasUnescapedNewline)
> - Newlines = 0;
> -
> - // Remove empty lines after "{".
> - if (!Style.KeepEmptyLinesAtTheStartOfBlocks && PreviousLine &&
> - PreviousLine->Last->is(tok::l_brace) &&
> - PreviousLine->First->isNot(tok::kw_namespace) &&
> - !startsExternCBlock(*PreviousLine))
> - Newlines = 1;
> -
> - // Insert extra new line before access specifiers.
> - if (PreviousLine && PreviousLine->Last->isOneOf(tok::semi,
> tok::r_brace) &&
> - RootToken.isAccessSpecifier() && RootToken.NewlinesBefore == 1)
> - ++Newlines;
> -
> - // Remove empty lines after access specifiers.
> - if (PreviousLine && PreviousLine->First->isAccessSpecifier())
> - Newlines = std::min(1u, Newlines);
> -
> - Whitespaces->replaceWhitespace(RootToken, Newlines, IndentLevel,
> Indent,
> - Indent, InPPDirective &&
> -
> !RootToken.HasUnescapedNewline);
> - }
> -
> - /// \brief Get the indent of \p Level from \p IndentForLevel.
> - ///
> - /// \p IndentForLevel must contain the indent for the level \c l
> - /// at \p IndentForLevel[l], or a value < 0 if the indent for
> - /// that level is unknown.
> - unsigned getIndent(ArrayRef<int> IndentForLevel, unsigned Level) {
> - if (IndentForLevel[Level] != -1)
> - return IndentForLevel[Level];
> - if (Level == 0)
> - return 0;
> - return getIndent(IndentForLevel, Level - 1) + Style.IndentWidth;
> - }
> -
> - void join(AnnotatedLine &A, const AnnotatedLine &B) {
> - assert(!A.Last->Next);
> - assert(!B.First->Previous);
> - if (B.Affected)
> - A.Affected = true;
> - A.Last->Next = B.First;
> - B.First->Previous = A.Last;
> - B.First->CanBreakBefore = true;
> - unsigned LengthA = A.Last->TotalLength +
> B.First->SpacesRequiredBefore;
> - for (FormatToken *Tok = B.First; Tok; Tok = Tok->Next) {
> - Tok->TotalLength += LengthA;
> - A.Last = Tok;
> - }
> - }
> -
> - unsigned getColumnLimit(bool InPPDirective) const {
> - // In preprocessor directives reserve two chars for trailing " \"
> - return Style.ColumnLimit - (InPPDirective ? 2 : 0);
> - }
> -
> - struct CompareLineStatePointers {
> - bool operator()(LineState *obj1, LineState *obj2) const {
> - return *obj1 < *obj2;
> - }
> - };
> -
> - /// \brief Analyze the entire solution space starting from \p
> InitialState.
> - ///
> - /// This implements a variant of Dijkstra's algorithm on the graph that
> spans
> - /// the solution space (\c LineStates are the nodes). The algorithm
> tries to
> - /// find the shortest path (the one with lowest penalty) from \p
> InitialState
> - /// to a state where all tokens are placed. Returns the penalty.
> - ///
> - /// If \p DryRun is \c false, directly applies the changes.
> - unsigned analyzeSolutionSpace(LineState &InitialState, bool DryRun =
> false) {
> - std::set<LineState *, CompareLineStatePointers> Seen;
> -
> - // Increasing count of \c StateNode items we have created. This is
> used to
> - // create a deterministic order independent of the container.
> - unsigned Count = 0;
> - QueueType Queue;
> -
> - // Insert start element into queue.
> - StateNode *Node =
> - new (Allocator.Allocate()) StateNode(InitialState, false,
> nullptr);
> - Queue.push(QueueItem(OrderedPenalty(0, Count), Node));
> - ++Count;
> -
> - unsigned Penalty = 0;
> -
> - // While not empty, take first element and follow edges.
> - while (!Queue.empty()) {
> - Penalty = Queue.top().first.first;
> - StateNode *Node = Queue.top().second;
> - if (!Node->State.NextToken) {
> - DEBUG(llvm::dbgs() << "\n---\nPenalty for line: " << Penalty <<
> "\n");
> - break;
> - }
> - Queue.pop();
> -
> - // Cut off the analysis of certain solutions if the analysis gets
> too
> - // complex. See description of IgnoreStackForComparison.
> - if (Count > 10000)
> - Node->State.IgnoreStackForComparison = true;
> -
> - if (!Seen.insert(&Node->State).second)
> - // State already examined with lower penalty.
> - continue;
> -
> - FormatDecision LastFormat = Node->State.NextToken->Decision;
> - if (LastFormat == FD_Unformatted || LastFormat == FD_Continue)
> - addNextStateToQueue(Penalty, Node, /*NewLine=*/false, &Count,
> &Queue);
> - if (LastFormat == FD_Unformatted || LastFormat == FD_Break)
> - addNextStateToQueue(Penalty, Node, /*NewLine=*/true, &Count,
> &Queue);
> - }
> -
> - if (Queue.empty()) {
> - // We were unable to find a solution, do nothing.
> - // FIXME: Add diagnostic?
> - DEBUG(llvm::dbgs() << "Could not find a solution.\n");
> - return 0;
> - }
> -
> - // Reconstruct the solution.
> - if (!DryRun)
> - reconstructPath(InitialState, Queue.top().second);
> -
> - DEBUG(llvm::dbgs() << "Total number of analyzed states: " << Count <<
> "\n");
> - DEBUG(llvm::dbgs() << "---\n");
> -
> - return Penalty;
> - }
> -
> - void reconstructPath(LineState &State, StateNode *Current) {
> - std::deque<StateNode *> Path;
> - // We do not need a break before the initial token.
> - while (Current->Previous) {
> - Path.push_front(Current);
> - Current = Current->Previous;
> - }
> - for (std::deque<StateNode *>::iterator I = Path.begin(), E =
> Path.end();
> - I != E; ++I) {
> - unsigned Penalty = 0;
> - formatChildren(State, (*I)->NewLine, /*DryRun=*/false, Penalty);
> - Penalty += Indenter->addTokenToState(State, (*I)->NewLine, false);
> -
> - DEBUG({
> - if ((*I)->NewLine) {
> - llvm::dbgs() << "Penalty for placing "
> - << (*I)->Previous->State.NextToken->Tok.getName()
> << ": "
> - << Penalty << "\n";
> - }
> - });
> - }
> - }
> -
> - /// \brief Add the following state to the analysis queue \c Queue.
> - ///
> - /// Assume the current state is \p PreviousNode and has been reached
> with a
> - /// penalty of \p Penalty. Insert a line break if \p NewLine is \c true.
> - void addNextStateToQueue(unsigned Penalty, StateNode *PreviousNode,
> - bool NewLine, unsigned *Count, QueueType
> *Queue) {
> - if (NewLine && !Indenter->canBreak(PreviousNode->State))
> - return;
> - if (!NewLine && Indenter->mustBreak(PreviousNode->State))
> - return;
> -
> - StateNode *Node = new (Allocator.Allocate())
> - StateNode(PreviousNode->State, NewLine, PreviousNode);
> - if (!formatChildren(Node->State, NewLine, /*DryRun=*/true, Penalty))
> - return;
> -
> - Penalty += Indenter->addTokenToState(Node->State, NewLine, true);
> -
> - Queue->push(QueueItem(OrderedPenalty(Penalty, *Count), Node));
> - ++(*Count);
> - }
> -
> - /// \brief If the \p State's next token is an r_brace closing a nested
> block,
> - /// format the nested block before it.
> - ///
> - /// Returns \c true if all children could be placed successfully and
> adapts
> - /// \p Penalty as well as \p State. If \p DryRun is false, also directly
> - /// creates changes using \c Whitespaces.
> - ///
> - /// The crucial idea here is that children always get formatted upon
> - /// encountering the closing brace right after the nested block. Now,
> if we
> - /// are currently trying to keep the "}" on the same line (i.e. \p
> NewLine is
> - /// \c false), the entire block has to be kept on the same line (which
> is only
> - /// possible if it fits on the line, only contains a single statement,
> etc.
> - ///
> - /// If \p NewLine is true, we format the nested block on separate
> lines, i.e.
> - /// break after the "{", format all lines with correct indentation and
> the put
> - /// the closing "}" on yet another new line.
> - ///
> - /// This enables us to keep the simple structure of the
> - /// \c UnwrappedLineFormatter, where we only have two options for each
> token:
> - /// break or don't break.
> - bool formatChildren(LineState &State, bool NewLine, bool DryRun,
> - unsigned &Penalty) {
> - FormatToken &Previous = *State.NextToken->Previous;
> - const FormatToken *LBrace = State.NextToken->getPreviousNonComment();
> - if (!LBrace || LBrace->isNot(tok::l_brace) ||
> - LBrace->BlockKind != BK_Block || Previous.Children.size() == 0)
> - // The previous token does not open a block. Nothing to do. We don't
> - // assert so that we can simply call this function for all tokens.
> - return true;
> -
> - if (NewLine) {
> - int AdditionalIndent =
> - State.FirstIndent - State.Line->Level * Style.IndentWidth;
> - if (State.Stack.size() < 2 ||
> - !State.Stack[State.Stack.size() - 2].NestedBlockInlined) {
> - AdditionalIndent = State.Stack.back().Indent -
> - Previous.Children[0]->Level *
> Style.IndentWidth;
> - }
> -
> - Penalty += format(Previous.Children, DryRun, AdditionalIndent,
> - /*FixBadIndentation=*/true);
> - return true;
> - }
> -
> - if (Previous.Children[0]->First->MustBreakBefore)
> - return false;
> -
> - // Cannot merge multiple statements into a single line.
> - if (Previous.Children.size() > 1)
> - return false;
> -
> - // Cannot merge into one line if this line ends on a comment.
> - if (Previous.is(tok::comment))
> - return false;
> -
> - // We can't put the closing "}" on a line with a trailing comment.
> - if (Previous.Children[0]->Last->isTrailingComment())
> - return false;
> -
> - // If the child line exceeds the column limit, we wouldn't want to
> merge it.
> - // We add +2 for the trailing " }".
> - if (Style.ColumnLimit > 0 &&
> - Previous.Children[0]->Last->TotalLength + State.Column + 2 >
> - Style.ColumnLimit)
> - return false;
> -
> - if (!DryRun) {
> - Whitespaces->replaceWhitespace(
> - *Previous.Children[0]->First,
> - /*Newlines=*/0, /*IndentLevel=*/0, /*Spaces=*/1,
> - /*StartOfTokenColumn=*/State.Column, State.Line->InPPDirective);
> - }
> - Penalty += format(*Previous.Children[0], State.Column + 1, DryRun);
> -
> - State.Column += 1 + Previous.Children[0]->Last->TotalLength;
> - return true;
> - }
> -
> - ContinuationIndenter *Indenter;
> - WhitespaceManager *Whitespaces;
> - FormatStyle Style;
> - LineJoiner Joiner;
> -
> - llvm::SpecificBumpPtrAllocator<StateNode> Allocator;
> -
> - // Cache to store the penalty of formatting a vector of AnnotatedLines
> - // starting from a specific additional offset. Improves performance if
> there
> - // are many nested blocks.
> - std::map<std::pair<const SmallVectorImpl<AnnotatedLine *> *, unsigned>,
> - unsigned> PenaltyCache;
> -};
> -
> class FormatTokenLexer {
> public:
> FormatTokenLexer(SourceManager &SourceMgr, FileID ID, FormatStyle
> &Style,
>
> Added: cfe/trunk/lib/Format/UnwrappedLineFormatter.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/UnwrappedLineFormatter.cpp?rev=223936&view=auto
>
> ==============================================================================
> --- cfe/trunk/lib/Format/UnwrappedLineFormatter.cpp (added)
> +++ cfe/trunk/lib/Format/UnwrappedLineFormatter.cpp Wed Dec 10 13:00:42
> 2014
> @@ -0,0 +1,699 @@
> +//===--- UnwrappedLineFormatter.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.
> +//
>
> +//===----------------------------------------------------------------------===//
> +
> +#include "UnwrappedLineFormatter.h"
> +#include "WhitespaceManager.h"
> +#include "llvm/Support/Debug.h"
> +
> +#define DEBUG_TYPE "format-formatter"
> +
> +namespace clang {
> +namespace format {
> +
> +namespace {
> +
> +bool startsExternCBlock(const AnnotatedLine &Line) {
> + const FormatToken *Next = Line.First->getNextNonComment();
> + const FormatToken *NextNext = Next ? Next->getNextNonComment() :
> nullptr;
> + return Line.First->is(tok::kw_extern) && Next &&
> Next->isStringLiteral() &&
> + NextNext && NextNext->is(tok::l_brace);
> +}
> +
> +class LineJoiner {
> +public:
> + LineJoiner(const FormatStyle &Style) : Style(Style) {}
> +
> + /// \brief Calculates how many lines can be merged into 1 starting at
> \p I.
> + unsigned
> + tryFitMultipleLinesInOne(unsigned Indent,
> + SmallVectorImpl<AnnotatedLine
> *>::const_iterator I,
> + SmallVectorImpl<AnnotatedLine
> *>::const_iterator E) {
> + // We can never merge stuff if there are trailing line comments.
> + const AnnotatedLine *TheLine = *I;
> + if (TheLine->Last->is(TT_LineComment))
> + return 0;
> +
> + if (Style.ColumnLimit > 0 && Indent > Style.ColumnLimit)
> + return 0;
> +
> + unsigned Limit =
> + Style.ColumnLimit == 0 ? UINT_MAX : Style.ColumnLimit - Indent;
> + // If we already exceed the column limit, we set 'Limit' to 0. The
> different
> + // tryMerge..() functions can then decide whether to still do merging.
> + Limit = TheLine->Last->TotalLength > Limit
> + ? 0
> + : Limit - TheLine->Last->TotalLength;
> +
> + if (I + 1 == E || I[1]->Type == LT_Invalid ||
> I[1]->First->MustBreakBefore)
> + return 0;
> +
> + // FIXME: TheLine->Level != 0 might or might not be the right check
> to do.
> + // If necessary, change to something smarter.
> + bool MergeShortFunctions =
> + Style.AllowShortFunctionsOnASingleLine == FormatStyle::SFS_All ||
> + (Style.AllowShortFunctionsOnASingleLine == FormatStyle::SFS_Empty
> &&
> + I[1]->First->is(tok::r_brace)) ||
> + (Style.AllowShortFunctionsOnASingleLine ==
> FormatStyle::SFS_Inline &&
> + TheLine->Level != 0);
> +
> + if (TheLine->Last->is(TT_FunctionLBrace) &&
> + TheLine->First != TheLine->Last) {
> + return MergeShortFunctions ? tryMergeSimpleBlock(I, E, Limit) : 0;
> + }
> + if (TheLine->Last->is(tok::l_brace)) {
> + return Style.BreakBeforeBraces == FormatStyle::BS_Attach
> + ? tryMergeSimpleBlock(I, E, Limit)
> + : 0;
> + }
> + if (I[1]->First->is(TT_FunctionLBrace) &&
> + Style.BreakBeforeBraces != FormatStyle::BS_Attach) {
> + if (I[1]->Last->is(TT_LineComment))
> + return 0;
> +
> + // Check for Limit <= 2 to account for the " {".
> + if (Limit <= 2 || (Style.ColumnLimit == 0 &&
> containsMustBreak(TheLine)))
> + return 0;
> + Limit -= 2;
> +
> + unsigned MergedLines = 0;
> + if (MergeShortFunctions) {
> + MergedLines = tryMergeSimpleBlock(I + 1, E, Limit);
> + // If we managed to merge the block, count the function header,
> which is
> + // on a separate line.
> + if (MergedLines > 0)
> + ++MergedLines;
> + }
> + return MergedLines;
> + }
> + if (TheLine->First->is(tok::kw_if)) {
> + return Style.AllowShortIfStatementsOnASingleLine
> + ? tryMergeSimpleControlStatement(I, E, Limit)
> + : 0;
> + }
> + if (TheLine->First->isOneOf(tok::kw_for, tok::kw_while)) {
> + return Style.AllowShortLoopsOnASingleLine
> + ? tryMergeSimpleControlStatement(I, E, Limit)
> + : 0;
> + }
> + if (TheLine->First->isOneOf(tok::kw_case, tok::kw_default)) {
> + return Style.AllowShortCaseLabelsOnASingleLine
> + ? tryMergeShortCaseLabels(I, E, Limit)
> + : 0;
> + }
> + if (TheLine->InPPDirective &&
> + (TheLine->First->HasUnescapedNewline || TheLine->First->IsFirst))
> {
> + return tryMergeSimplePPDirective(I, E, Limit);
> + }
> + return 0;
> + }
> +
> +private:
> + unsigned
> + tryMergeSimplePPDirective(SmallVectorImpl<AnnotatedLine
> *>::const_iterator I,
> + SmallVectorImpl<AnnotatedLine
> *>::const_iterator E,
> + unsigned Limit) {
> + if (Limit == 0)
> + return 0;
> + if (!I[1]->InPPDirective || I[1]->First->HasUnescapedNewline)
> + return 0;
> + if (I + 2 != E && I[2]->InPPDirective &&
> !I[2]->First->HasUnescapedNewline)
> + return 0;
> + if (1 + I[1]->Last->TotalLength > Limit)
> + return 0;
> + return 1;
> + }
> +
> + unsigned tryMergeSimpleControlStatement(
> + SmallVectorImpl<AnnotatedLine *>::const_iterator I,
> + SmallVectorImpl<AnnotatedLine *>::const_iterator E, unsigned Limit)
> {
> + if (Limit == 0)
> + return 0;
> + if ((Style.BreakBeforeBraces == FormatStyle::BS_Allman ||
> + Style.BreakBeforeBraces == FormatStyle::BS_GNU) &&
> + (I[1]->First->is(tok::l_brace) &&
> !Style.AllowShortBlocksOnASingleLine))
> + return 0;
> + if (I[1]->InPPDirective != (*I)->InPPDirective ||
> + (I[1]->InPPDirective && I[1]->First->HasUnescapedNewline))
> + return 0;
> + Limit = limitConsideringMacros(I + 1, E, Limit);
> + AnnotatedLine &Line = **I;
> + if (Line.Last->isNot(tok::r_paren))
> + return 0;
> + if (1 + I[1]->Last->TotalLength > Limit)
> + return 0;
> + if (I[1]->First->isOneOf(tok::semi, tok::kw_if, tok::kw_for,
> + tok::kw_while, TT_LineComment))
> + return 0;
> + // Only inline simple if's (no nested if or else).
> + if (I + 2 != E && Line.First->is(tok::kw_if) &&
> + I[2]->First->is(tok::kw_else))
> + return 0;
> + return 1;
> + }
> +
> + unsigned tryMergeShortCaseLabels(
> + SmallVectorImpl<AnnotatedLine *>::const_iterator I,
> + SmallVectorImpl<AnnotatedLine *>::const_iterator E, unsigned Limit)
> {
> + if (Limit == 0 || I + 1 == E ||
> + I[1]->First->isOneOf(tok::kw_case, tok::kw_default))
> + return 0;
> + unsigned NumStmts = 0;
> + unsigned Length = 0;
> + bool InPPDirective = I[0]->InPPDirective;
> + for (; NumStmts < 3; ++NumStmts) {
> + if (I + 1 + NumStmts == E)
> + break;
> + const AnnotatedLine *Line = I[1 + NumStmts];
> + if (Line->InPPDirective != InPPDirective)
> + break;
> + if (Line->First->isOneOf(tok::kw_case, tok::kw_default,
> tok::r_brace))
> + break;
> + if (Line->First->isOneOf(tok::kw_if, tok::kw_for, tok::kw_switch,
> + tok::kw_while, tok::comment))
> + return 0;
> + Length += I[1 + NumStmts]->Last->TotalLength + 1; // 1 for the
> space.
> + }
> + if (NumStmts == 0 || NumStmts == 3 || Length > Limit)
> + return 0;
> + return NumStmts;
> + }
> +
> + unsigned
> + tryMergeSimpleBlock(SmallVectorImpl<AnnotatedLine *>::const_iterator I,
> + SmallVectorImpl<AnnotatedLine *>::const_iterator E,
> + unsigned Limit) {
> + AnnotatedLine &Line = **I;
> +
> + // Don't merge ObjC @ keywords and methods.
> + if (Style.Language != FormatStyle::LK_Java &&
> + Line.First->isOneOf(tok::at, tok::minus, tok::plus))
> + return 0;
> +
> + // Check that the current line allows merging. This depends on
> whether we
> + // are in a control flow statements as well as several style flags.
> + if (Line.First->isOneOf(tok::kw_else, tok::kw_case))
> + return 0;
> + if (Line.First->isOneOf(tok::kw_if, tok::kw_while, tok::kw_do,
> tok::kw_try,
> + tok::kw_catch, tok::kw_for, tok::r_brace)) {
> + if (!Style.AllowShortBlocksOnASingleLine)
> + return 0;
> + if (!Style.AllowShortIfStatementsOnASingleLine &&
> + Line.First->is(tok::kw_if))
> + return 0;
> + if (!Style.AllowShortLoopsOnASingleLine &&
> + Line.First->isOneOf(tok::kw_while, tok::kw_do, tok::kw_for))
> + return 0;
> + // FIXME: Consider an option to allow short exception handling
> clauses on
> + // a single line.
> + if (Line.First->isOneOf(tok::kw_try, tok::kw_catch))
> + return 0;
> + }
> +
> + FormatToken *Tok = I[1]->First;
> + if (Tok->is(tok::r_brace) && !Tok->MustBreakBefore &&
> + (Tok->getNextNonComment() == nullptr ||
> + Tok->getNextNonComment()->is(tok::semi))) {
> + // We merge empty blocks even if the line exceeds the column limit.
> + Tok->SpacesRequiredBefore = 0;
> + Tok->CanBreakBefore = true;
> + return 1;
> + } else if (Limit != 0 && Line.First->isNot(tok::kw_namespace) &&
> + !startsExternCBlock(Line)) {
> + // We don't merge short records.
> + if (Line.First->isOneOf(tok::kw_class, tok::kw_union,
> tok::kw_struct))
> + return 0;
> +
> + // Check that we still have three lines and they fit into the limit.
> + if (I + 2 == E || I[2]->Type == LT_Invalid)
> + return 0;
> + Limit = limitConsideringMacros(I + 2, E, Limit);
> +
> + if (!nextTwoLinesFitInto(I, Limit))
> + return 0;
> +
> + // Second, check that the next line does not contain any braces -
> if it
> + // does, readability declines when putting it into a single line.
> + if (I[1]->Last->is(TT_LineComment))
> + return 0;
> + do {
> + if (Tok->is(tok::l_brace) && Tok->BlockKind != BK_BracedInit)
> + return 0;
> + Tok = Tok->Next;
> + } while (Tok);
> +
> + // Last, check that the third line starts with a closing brace.
> + Tok = I[2]->First;
> + if (Tok->isNot(tok::r_brace))
> + return 0;
> +
> + return 2;
> + }
> + return 0;
> + }
> +
> + /// Returns the modified column limit for \p I if it is inside a macro
> and
> + /// needs a trailing '\'.
> + unsigned
> + limitConsideringMacros(SmallVectorImpl<AnnotatedLine *>::const_iterator
> I,
> + SmallVectorImpl<AnnotatedLine *>::const_iterator
> E,
> + unsigned Limit) {
> + if (I[0]->InPPDirective && I + 1 != E &&
> + !I[1]->First->HasUnescapedNewline && !I[1]->First->is(tok::eof)) {
> + return Limit < 2 ? 0 : Limit - 2;
> + }
> + return Limit;
> + }
> +
> + bool nextTwoLinesFitInto(SmallVectorImpl<AnnotatedLine
> *>::const_iterator I,
> + unsigned Limit) {
> + if (I[1]->First->MustBreakBefore || I[2]->First->MustBreakBefore)
> + return false;
> + return 1 + I[1]->Last->TotalLength + 1 + I[2]->Last->TotalLength <=
> Limit;
> + }
> +
> + bool containsMustBreak(const AnnotatedLine *Line) {
> + for (const FormatToken *Tok = Line->First; Tok; Tok = Tok->Next) {
> + if (Tok->MustBreakBefore)
> + return true;
> + }
> + return false;
> + }
> +
> + const FormatStyle &Style;
> +};
> +
> +class NoColumnLimitFormatter {
> +public:
> + NoColumnLimitFormatter(ContinuationIndenter *Indenter) :
> Indenter(Indenter) {}
> +
> + /// \brief Formats the line starting at \p State, simply keeping all of
> the
> + /// input's line breaking decisions.
> + void format(unsigned FirstIndent, const AnnotatedLine *Line) {
> + LineState State =
> + Indenter->getInitialState(FirstIndent, Line, /*DryRun=*/false);
> + while (State.NextToken) {
> + bool Newline =
> + Indenter->mustBreak(State) ||
> + (Indenter->canBreak(State) && State.NextToken->NewlinesBefore >
> 0);
> + Indenter->addTokenToState(State, Newline, /*DryRun=*/false);
> + }
> + }
> +
> +private:
> + ContinuationIndenter *Indenter;
> +};
> +
> +} // namespace
> +
> +unsigned
> +UnwrappedLineFormatter::format(const SmallVectorImpl<AnnotatedLine *>
> &Lines,
> + bool DryRun, int AdditionalIndent,
> + bool FixBadIndentation) {
> + LineJoiner Joiner(Style);
> +
> + // Try to look up already computed penalty in DryRun-mode.
> + std::pair<const SmallVectorImpl<AnnotatedLine *> *, unsigned> CacheKey(
> + &Lines, AdditionalIndent);
> + auto CacheIt = PenaltyCache.find(CacheKey);
> + if (DryRun && CacheIt != PenaltyCache.end())
> + return CacheIt->second;
> +
> + assert(!Lines.empty());
> + unsigned Penalty = 0;
> + std::vector<int> IndentForLevel;
> + for (unsigned i = 0, e = Lines[0]->Level; i != e; ++i)
> + IndentForLevel.push_back(Style.IndentWidth * i + AdditionalIndent);
> + const AnnotatedLine *PreviousLine = nullptr;
> + for (SmallVectorImpl<AnnotatedLine *>::const_iterator I = Lines.begin(),
> + E = Lines.end();
> + I != E; ++I) {
> + const AnnotatedLine &TheLine = **I;
> + const FormatToken *FirstTok = TheLine.First;
> + int Offset = getIndentOffset(*FirstTok);
> +
> + // Determine indent and try to merge multiple unwrapped lines.
> + unsigned Indent;
> + if (TheLine.InPPDirective) {
> + Indent = TheLine.Level * Style.IndentWidth;
> + } else {
> + while (IndentForLevel.size() <= TheLine.Level)
> + IndentForLevel.push_back(-1);
> + IndentForLevel.resize(TheLine.Level + 1);
> + Indent = getIndent(IndentForLevel, TheLine.Level);
> + }
> + unsigned LevelIndent = Indent;
> + if (static_cast<int>(Indent) + Offset >= 0)
> + Indent += Offset;
> +
> + // Merge multiple lines if possible.
> + unsigned MergedLines = Joiner.tryFitMultipleLinesInOne(Indent, I, E);
> + if (MergedLines > 0 && Style.ColumnLimit == 0) {
> + // Disallow line merging if there is a break at the start of one of
> the
> + // input lines.
> + for (unsigned i = 0; i < MergedLines; ++i) {
> + if (I[i + 1]->First->NewlinesBefore > 0)
> + MergedLines = 0;
> + }
> + }
> + if (!DryRun) {
> + for (unsigned i = 0; i < MergedLines; ++i) {
> + join(*I[i], *I[i + 1]);
> + }
> + }
> + I += MergedLines;
> +
> + bool FixIndentation =
> + FixBadIndentation && (LevelIndent != FirstTok->OriginalColumn);
> + if (TheLine.First->is(tok::eof)) {
> + if (PreviousLine && PreviousLine->Affected && !DryRun) {
> + // Remove the file's trailing whitespace.
> + unsigned Newlines = std::min(FirstTok->NewlinesBefore, 1u);
> + Whitespaces->replaceWhitespace(*TheLine.First, Newlines,
> + /*IndentLevel=*/0, /*Spaces=*/0,
> + /*TargetColumn=*/0);
> + }
> + } else if (TheLine.Type != LT_Invalid &&
> + (TheLine.Affected || FixIndentation)) {
> + if (FirstTok->WhitespaceRange.isValid()) {
> + if (!DryRun)
> + formatFirstToken(*TheLine.First, PreviousLine, TheLine.Level,
> Indent,
> + TheLine.InPPDirective);
> + } else {
> + Indent = LevelIndent = FirstTok->OriginalColumn;
> + }
> +
> + // If everything fits on a single line, just put it there.
> + unsigned ColumnLimit = Style.ColumnLimit;
> + if (I + 1 != E) {
> + AnnotatedLine *NextLine = I[1];
> + if (NextLine->InPPDirective &&
> !NextLine->First->HasUnescapedNewline)
> + ColumnLimit = getColumnLimit(TheLine.InPPDirective);
> + }
> +
> + if (TheLine.Last->TotalLength + Indent <= ColumnLimit ||
> + TheLine.Type == LT_ImportStatement) {
> + LineState State = Indenter->getInitialState(Indent, &TheLine,
> DryRun);
> + while (State.NextToken) {
> + formatChildren(State, /*Newline=*/false, /*DryRun=*/false,
> Penalty);
> + Indenter->addTokenToState(State, /*Newline=*/false, DryRun);
> + }
> + } else if (Style.ColumnLimit == 0) {
> + // FIXME: Implement nested blocks for ColumnLimit = 0.
> + NoColumnLimitFormatter Formatter(Indenter);
> + if (!DryRun)
> + Formatter.format(Indent, &TheLine);
> + } else {
> + Penalty += format(TheLine, Indent, DryRun);
> + }
> +
> + if (!TheLine.InPPDirective)
> + IndentForLevel[TheLine.Level] = LevelIndent;
> + } else if (TheLine.ChildrenAffected) {
> + format(TheLine.Children, DryRun);
> + } else {
> + // Format the first token if necessary, and notify the
> WhitespaceManager
> + // about the unchanged whitespace.
> + for (FormatToken *Tok = TheLine.First; Tok; Tok = Tok->Next) {
> + if (Tok == TheLine.First && (Tok->NewlinesBefore > 0 ||
> Tok->IsFirst)) {
> + unsigned LevelIndent = Tok->OriginalColumn;
> + if (!DryRun) {
> + // Remove trailing whitespace of the previous line.
> + if ((PreviousLine && PreviousLine->Affected) ||
> + TheLine.LeadingEmptyLinesAffected) {
> + formatFirstToken(*Tok, PreviousLine, TheLine.Level,
> LevelIndent,
> + TheLine.InPPDirective);
> + } else {
> + Whitespaces->addUntouchableToken(*Tok,
> TheLine.InPPDirective);
> + }
> + }
> +
> + if (static_cast<int>(LevelIndent) - Offset >= 0)
> + LevelIndent -= Offset;
> + if (Tok->isNot(tok::comment) && !TheLine.InPPDirective)
> + IndentForLevel[TheLine.Level] = LevelIndent;
> + } else if (!DryRun) {
> + Whitespaces->addUntouchableToken(*Tok, TheLine.InPPDirective);
> + }
> + }
> + }
> + if (!DryRun) {
> + for (FormatToken *Tok = TheLine.First; Tok; Tok = Tok->Next) {
> + Tok->Finalized = true;
> + }
> + }
> + PreviousLine = *I;
> + }
> + PenaltyCache[CacheKey] = Penalty;
> + return Penalty;
> +}
> +
> +unsigned UnwrappedLineFormatter::format(const AnnotatedLine &Line,
> + unsigned FirstIndent, bool
> DryRun) {
> + LineState State = Indenter->getInitialState(FirstIndent, &Line, DryRun);
> +
> + // If the ObjC method declaration does not fit on a line, we should
> format
> + // it with one arg per line.
> + if (State.Line->Type == LT_ObjCMethodDecl)
> + State.Stack.back().BreakBeforeParameter = true;
> +
> + // Find best solution in solution space.
> + return analyzeSolutionSpace(State, DryRun);
> +}
> +
> +void UnwrappedLineFormatter::formatFirstToken(FormatToken &RootToken,
> + const AnnotatedLine
> *PreviousLine,
> + unsigned IndentLevel,
> + unsigned Indent,
> + bool InPPDirective) {
> + unsigned Newlines =
> + std::min(RootToken.NewlinesBefore, Style.MaxEmptyLinesToKeep + 1);
> + // Remove empty lines before "}" where applicable.
> + if (RootToken.is(tok::r_brace) &&
> + (!RootToken.Next ||
> + (RootToken.Next->is(tok::semi) && !RootToken.Next->Next)))
> + Newlines = std::min(Newlines, 1u);
> + if (Newlines == 0 && !RootToken.IsFirst)
> + Newlines = 1;
> + if (RootToken.IsFirst && !RootToken.HasUnescapedNewline)
> + Newlines = 0;
> +
> + // Remove empty lines after "{".
> + if (!Style.KeepEmptyLinesAtTheStartOfBlocks && PreviousLine &&
> + PreviousLine->Last->is(tok::l_brace) &&
> + PreviousLine->First->isNot(tok::kw_namespace) &&
> + !startsExternCBlock(*PreviousLine))
> + Newlines = 1;
> +
> + // Insert extra new line before access specifiers.
> + if (PreviousLine && PreviousLine->Last->isOneOf(tok::semi,
> tok::r_brace) &&
> + RootToken.isAccessSpecifier() && RootToken.NewlinesBefore == 1)
> + ++Newlines;
> +
> + // Remove empty lines after access specifiers.
> + if (PreviousLine && PreviousLine->First->isAccessSpecifier())
> + Newlines = std::min(1u, Newlines);
> +
> + Whitespaces->replaceWhitespace(RootToken, Newlines, IndentLevel, Indent,
> + Indent, InPPDirective &&
> +
> !RootToken.HasUnescapedNewline);
> +}
> +
> +/// \brief Get the indent of \p Level from \p IndentForLevel.
> +///
> +/// \p IndentForLevel must contain the indent for the level \c l
> +/// at \p IndentForLevel[l], or a value < 0 if the indent for
> +/// that level is unknown.
> +unsigned UnwrappedLineFormatter::getIndent(ArrayRef<int> IndentForLevel,
> + unsigned Level) {
> + if (IndentForLevel[Level] != -1)
> + return IndentForLevel[Level];
> + if (Level == 0)
> + return 0;
> + return getIndent(IndentForLevel, Level - 1) + Style.IndentWidth;
> +}
> +
> +void UnwrappedLineFormatter::join(AnnotatedLine &A, const AnnotatedLine
> &B) {
> + assert(!A.Last->Next);
> + assert(!B.First->Previous);
> + if (B.Affected)
> + A.Affected = true;
> + A.Last->Next = B.First;
> + B.First->Previous = A.Last;
> + B.First->CanBreakBefore = true;
> + unsigned LengthA = A.Last->TotalLength + B.First->SpacesRequiredBefore;
> + for (FormatToken *Tok = B.First; Tok; Tok = Tok->Next) {
> + Tok->TotalLength += LengthA;
> + A.Last = Tok;
> + }
> +}
> +
> +unsigned UnwrappedLineFormatter::analyzeSolutionSpace(LineState
> &InitialState,
> + bool DryRun) {
> + std::set<LineState *, CompareLineStatePointers> Seen;
> +
> + // Increasing count of \c StateNode items we have created. This is used
> to
> + // create a deterministic order independent of the container.
> + unsigned Count = 0;
> + QueueType Queue;
> +
> + // Insert start element into queue.
> + StateNode *Node =
> + new (Allocator.Allocate()) StateNode(InitialState, false, nullptr);
> + Queue.push(QueueItem(OrderedPenalty(0, Count), Node));
> + ++Count;
> +
> + unsigned Penalty = 0;
> +
> + // While not empty, take first element and follow edges.
> + while (!Queue.empty()) {
> + Penalty = Queue.top().first.first;
> + StateNode *Node = Queue.top().second;
> + if (!Node->State.NextToken) {
> + DEBUG(llvm::dbgs() << "\n---\nPenalty for line: " << Penalty <<
> "\n");
> + break;
> + }
> + Queue.pop();
> +
> + // Cut off the analysis of certain solutions if the analysis gets too
> + // complex. See description of IgnoreStackForComparison.
> + if (Count > 10000)
> + Node->State.IgnoreStackForComparison = true;
> +
> + if (!Seen.insert(&Node->State).second)
> + // State already examined with lower penalty.
> + continue;
> +
> + FormatDecision LastFormat = Node->State.NextToken->Decision;
> + if (LastFormat == FD_Unformatted || LastFormat == FD_Continue)
> + addNextStateToQueue(Penalty, Node, /*NewLine=*/false, &Count,
> &Queue);
> + if (LastFormat == FD_Unformatted || LastFormat == FD_Break)
> + addNextStateToQueue(Penalty, Node, /*NewLine=*/true, &Count,
> &Queue);
> + }
> +
> + if (Queue.empty()) {
> + // We were unable to find a solution, do nothing.
> + // FIXME: Add diagnostic?
> + DEBUG(llvm::dbgs() << "Could not find a solution.\n");
> + return 0;
> + }
> +
> + // Reconstruct the solution.
> + if (!DryRun)
> + reconstructPath(InitialState, Queue.top().second);
> +
> + DEBUG(llvm::dbgs() << "Total number of analyzed states: " << Count <<
> "\n");
> + DEBUG(llvm::dbgs() << "---\n");
> +
> + return Penalty;
> +}
> +
> +void UnwrappedLineFormatter::reconstructPath(LineState &State,
> + StateNode *Current) {
> + std::deque<StateNode *> Path;
> + // We do not need a break before the initial token.
> + while (Current->Previous) {
> + Path.push_front(Current);
> + Current = Current->Previous;
> + }
> + for (std::deque<StateNode *>::iterator I = Path.begin(), E = Path.end();
> + I != E; ++I) {
> + unsigned Penalty = 0;
> + formatChildren(State, (*I)->NewLine, /*DryRun=*/false, Penalty);
> + Penalty += Indenter->addTokenToState(State, (*I)->NewLine, false);
> +
> + DEBUG({
> + if ((*I)->NewLine) {
> + llvm::dbgs() << "Penalty for placing "
> + << (*I)->Previous->State.NextToken->Tok.getName() <<
> ": "
> + << Penalty << "\n";
> + }
> + });
> + }
> +}
> +
> +void UnwrappedLineFormatter::addNextStateToQueue(unsigned Penalty,
> + StateNode *PreviousNode,
> + bool NewLine, unsigned
> *Count,
> + QueueType *Queue) {
> + if (NewLine && !Indenter->canBreak(PreviousNode->State))
> + return;
> + if (!NewLine && Indenter->mustBreak(PreviousNode->State))
> + return;
> +
> + StateNode *Node = new (Allocator.Allocate())
> + StateNode(PreviousNode->State, NewLine, PreviousNode);
> + if (!formatChildren(Node->State, NewLine, /*DryRun=*/true, Penalty))
> + return;
> +
> + Penalty += Indenter->addTokenToState(Node->State, NewLine, true);
> +
> + Queue->push(QueueItem(OrderedPenalty(Penalty, *Count), Node));
> + ++(*Count);
> +}
> +
> +bool UnwrappedLineFormatter::formatChildren(LineState &State, bool
> NewLine,
> + bool DryRun, unsigned
> &Penalty) {
> + FormatToken &Previous = *State.NextToken->Previous;
> + const FormatToken *LBrace = State.NextToken->getPreviousNonComment();
> + if (!LBrace || LBrace->isNot(tok::l_brace) || LBrace->BlockKind !=
> BK_Block ||
> + Previous.Children.size() == 0)
> + // The previous token does not open a block. Nothing to do. We don't
> + // assert so that we can simply call this function for all tokens.
> + return true;
> +
> + if (NewLine) {
> + int AdditionalIndent =
> + State.FirstIndent - State.Line->Level * Style.IndentWidth;
> + if (State.Stack.size() < 2 ||
> + !State.Stack[State.Stack.size() - 2].NestedBlockInlined) {
> + AdditionalIndent = State.Stack.back().Indent -
> + Previous.Children[0]->Level * Style.IndentWidth;
> + }
> +
> + Penalty += format(Previous.Children, DryRun, AdditionalIndent,
> + /*FixBadIndentation=*/true);
> + return true;
> + }
> +
> + if (Previous.Children[0]->First->MustBreakBefore)
> + return false;
> +
> + // Cannot merge multiple statements into a single line.
> + if (Previous.Children.size() > 1)
> + return false;
> +
> + // Cannot merge into one line if this line ends on a comment.
> + if (Previous.is(tok::comment))
> + return false;
> +
> + // We can't put the closing "}" on a line with a trailing comment.
> + if (Previous.Children[0]->Last->isTrailingComment())
> + return false;
> +
> + // If the child line exceeds the column limit, we wouldn't want to
> merge it.
> + // We add +2 for the trailing " }".
> + if (Style.ColumnLimit > 0 &&
> + Previous.Children[0]->Last->TotalLength + State.Column + 2 >
> + Style.ColumnLimit)
> + return false;
> +
> + if (!DryRun) {
> + Whitespaces->replaceWhitespace(
> + *Previous.Children[0]->First,
> + /*Newlines=*/0, /*IndentLevel=*/0, /*Spaces=*/1,
> + /*StartOfTokenColumn=*/State.Column, State.Line->InPPDirective);
> + }
> + Penalty += format(*Previous.Children[0], State.Column + 1, DryRun);
> +
> + State.Column += 1 + Previous.Children[0]->Last->TotalLength;
> + return true;
> +}
> +
> +} // namespace format
> +} // namespace clang
>
> Added: cfe/trunk/lib/Format/UnwrappedLineFormatter.h
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/UnwrappedLineFormatter.h?rev=223936&view=auto
>
> ==============================================================================
> --- cfe/trunk/lib/Format/UnwrappedLineFormatter.h (added)
> +++ cfe/trunk/lib/Format/UnwrappedLineFormatter.h Wed Dec 10 13:00:42 2014
> @@ -0,0 +1,168 @@
> +//===--- UnwrappedLineFormatter.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 Implements a combinartorial exploration of all the different
> +/// linebreaks unwrapped lines can be formatted in.
> +///
>
> +//===----------------------------------------------------------------------===//
> +
> +#ifndef LLVM_CLANG_LIB_FORMAT_UNWRAPPEDLINEFORMATTER_H
> +#define LLVM_CLANG_LIB_FORMAT_UNWRAPPEDLINEFORMATTER_H
> +
> +#include "ContinuationIndenter.h"
> +#include "clang/Format/Format.h"
> +#include <map>
> +#include <queue>
> +#include <string>
> +
> +namespace clang {
> +namespace format {
> +
> +class ContinuationIndenter;
> +class WhitespaceManager;
> +
> +class UnwrappedLineFormatter {
> +public:
> + UnwrappedLineFormatter(ContinuationIndenter *Indenter,
> + WhitespaceManager *Whitespaces,
> + const FormatStyle &Style)
> + : Indenter(Indenter), Whitespaces(Whitespaces), Style(Style) {}
> +
> + unsigned format(const SmallVectorImpl<AnnotatedLine *> &Lines, bool
> DryRun,
> + int AdditionalIndent = 0, bool FixBadIndentation =
> false);
> +
> +private:
> + /// \brief Formats an \c AnnotatedLine and returns the penalty.
> + ///
> + /// If \p DryRun is \c false, directly applies the changes.
> + unsigned format(const AnnotatedLine &Line, unsigned FirstIndent,
> + bool DryRun);
> +
> + /// \brief An edge in the solution space from \c Previous->State to \c
> State,
> + /// inserting a newline dependent on the \c NewLine.
> + struct StateNode {
> + StateNode(const LineState &State, bool NewLine, StateNode *Previous)
> + : State(State), NewLine(NewLine), Previous(Previous) {}
> + LineState State;
> + bool NewLine;
> + StateNode *Previous;
> + };
> +
> + /// \brief A pair of <penalty, count> that is used to prioritize the
> BFS on.
> + ///
> + /// In case of equal penalties, we want to prefer states that were
> inserted
> + /// first. During state generation we make sure that we insert states
> first
> + /// that break the line as late as possible.
> + typedef std::pair<unsigned, unsigned> OrderedPenalty;
> +
> + /// \brief An item in the prioritized BFS search queue. The \c
> StateNode's
> + /// \c State has the given \c OrderedPenalty.
> + typedef std::pair<OrderedPenalty, StateNode *> QueueItem;
> +
> + /// \brief The BFS queue type.
> + typedef std::priority_queue<QueueItem, std::vector<QueueItem>,
> + std::greater<QueueItem> > QueueType;
> +
> + /// \brief Get the offset of the line relatively to the level.
> + ///
> + /// For example, 'public:' labels in classes are offset by 1 or 2
> + /// characters to the left from their level.
> + int getIndentOffset(const FormatToken &RootToken) {
> + if (Style.Language == FormatStyle::LK_Java)
> + return 0;
> + if (RootToken.isAccessSpecifier(false) ||
> RootToken.isObjCAccessSpecifier())
> + return Style.AccessModifierOffset;
> + return 0;
> + }
> +
> + /// \brief Add a new line and the required indent before the first Token
> + /// of the \c UnwrappedLine if there was no structural parsing error.
> + void formatFirstToken(FormatToken &RootToken,
> + const AnnotatedLine *PreviousLine, unsigned
> IndentLevel,
> + unsigned Indent, bool InPPDirective);
> +
> + /// \brief Get the indent of \p Level from \p IndentForLevel.
> + ///
> + /// \p IndentForLevel must contain the indent for the level \c l
> + /// at \p IndentForLevel[l], or a value < 0 if the indent for
> + /// that level is unknown.
> + unsigned getIndent(ArrayRef<int> IndentForLevel, unsigned Level);
> +
> + void join(AnnotatedLine &A, const AnnotatedLine &B);
> +
> + unsigned getColumnLimit(bool InPPDirective) const {
> + // In preprocessor directives reserve two chars for trailing " \"
> + return Style.ColumnLimit - (InPPDirective ? 2 : 0);
> + }
> +
> + struct CompareLineStatePointers {
> + bool operator()(LineState *obj1, LineState *obj2) const {
> + return *obj1 < *obj2;
> + }
> + };
> +
> + /// \brief Analyze the entire solution space starting from \p
> InitialState.
> + ///
> + /// This implements a variant of Dijkstra's algorithm on the graph that
> spans
> + /// the solution space (\c LineStates are the nodes). The algorithm
> tries to
> + /// find the shortest path (the one with lowest penalty) from \p
> InitialState
> + /// to a state where all tokens are placed. Returns the penalty.
> + ///
> + /// If \p DryRun is \c false, directly applies the changes.
> + unsigned analyzeSolutionSpace(LineState &InitialState, bool DryRun =
> false);
> +
> + void reconstructPath(LineState &State, StateNode *Current);
> +
> + /// \brief Add the following state to the analysis queue \c Queue.
> + ///
> + /// Assume the current state is \p PreviousNode and has been reached
> with a
> + /// penalty of \p Penalty. Insert a line break if \p NewLine is \c true.
> + void addNextStateToQueue(unsigned Penalty, StateNode *PreviousNode,
> + bool NewLine, unsigned *Count, QueueType
> *Queue);
> +
> + /// \brief If the \p State's next token is an r_brace closing a nested
> block,
> + /// format the nested block before it.
> + ///
> + /// Returns \c true if all children could be placed successfully and
> adapts
> + /// \p Penalty as well as \p State. If \p DryRun is false, also directly
> + /// creates changes using \c Whitespaces.
> + ///
> + /// The crucial idea here is that children always get formatted upon
> + /// encountering the closing brace right after the nested block. Now,
> if we
> + /// are currently trying to keep the "}" on the same line (i.e. \p
> NewLine is
> + /// \c false), the entire block has to be kept on the same line (which
> is only
> + /// possible if it fits on the line, only contains a single statement,
> etc.
> + ///
> + /// If \p NewLine is true, we format the nested block on separate
> lines, i.e.
> + /// break after the "{", format all lines with correct indentation and
> the put
> + /// the closing "}" on yet another new line.
> + ///
> + /// This enables us to keep the simple structure of the
> + /// \c UnwrappedLineFormatter, where we only have two options for each
> token:
> + /// break or don't break.
> + bool formatChildren(LineState &State, bool NewLine, bool DryRun,
> + unsigned &Penalty);
> +
> + ContinuationIndenter *Indenter;
> + WhitespaceManager *Whitespaces;
> + FormatStyle Style;
> +
> + llvm::SpecificBumpPtrAllocator<StateNode> Allocator;
> +
> + // Cache to store the penalty of formatting a vector of AnnotatedLines
> + // starting from a specific additional offset. Improves performance if
> there
> + // are many nested blocks.
> + std::map<std::pair<const SmallVectorImpl<AnnotatedLine *> *, unsigned>,
> + unsigned> PenaltyCache;
> +};
> +} // end namespace format
> +} // end namespace clang
> +
> +#endif // LLVM_CLANG_LIB_FORMAT_UNWRAPPEDLINEFORMATTER_H
>
>
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20141210/9dbbfa55/attachment.html>
More information about the cfe-commits
mailing list