r223936 - clang-format: Factor out UnwrappedLineFormatter into a separate file.
Daniel Jasper
djasper at google.com
Wed Dec 10 11:37:50 PST 2014
file llvm.org/PR21812 (don't feel in a comment-writing-mood just now).
On Wed, Dec 10, 2014 at 8:35 PM, Nico Weber <thakis at chromium.org> wrote:
> 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/0938596f/attachment.html>
More information about the cfe-commits
mailing list