r236974 - Refactor the formatter of clang-format.
Manuel Klimek
klimek at google.com
Mon May 11 02:20:10 PDT 2015
I thought I did that :)
On Mon, May 11, 2015 at 11:09 AM Daniel Jasper <djasper at google.com> wrote:
> Generally makes sense to fix the patch description if the content of the
> patch changes significantly ;-).
>
> On Mon, May 11, 2015 at 10:21 AM, Manuel Klimek <klimek at google.com> wrote:
>
>> Author: klimek
>> Date: Mon May 11 03:21:35 2015
>> New Revision: 236974
>>
>> URL: http://llvm.org/viewvc/llvm-project?rev=236974&view=rev
>> Log:
>> Refactor the formatter of clang-format.
>>
>> Pull various parts of the UnwrappedLineFormatter into their own
>> abstractions. NFC.
>>
>> There are two things left for subsequent changes (to keep this
>> reasonably small)
>> - the UnwrappedLineFormatter now has a bad name
>> - the UnwrappedLineFormatter::format function is still too large
>>
>> Modified:
>> cfe/trunk/lib/Format/Format.cpp
>> cfe/trunk/lib/Format/UnwrappedLineFormatter.cpp
>> cfe/trunk/lib/Format/UnwrappedLineFormatter.h
>>
>> Modified: cfe/trunk/lib/Format/Format.cpp
>> URL:
>> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/Format.cpp?rev=236974&r1=236973&r2=236974&view=diff
>>
>> ==============================================================================
>> --- cfe/trunk/lib/Format/Format.cpp (original)
>> +++ cfe/trunk/lib/Format/Format.cpp Mon May 11 03:21:35 2015
>> @@ -1269,9 +1269,9 @@ public:
>> ContinuationIndenter Indenter(Style, Tokens.getKeywords(), SourceMgr,
>> Whitespaces, Encoding,
>> BinPackInconclusiveFunctions);
>> - UnwrappedLineFormatter Formatter(&Indenter, &Whitespaces, Style,
>> - Tokens.getKeywords(),
>> IncompleteFormat);
>> - Formatter.format(AnnotatedLines, /*DryRun=*/false);
>> + UnwrappedLineFormatter(&Indenter, &Whitespaces, Style,
>> Tokens.getKeywords(),
>> + IncompleteFormat)
>> + .format(AnnotatedLines);
>> return Whitespaces.generateReplacements();
>> }
>>
>>
>> Modified: cfe/trunk/lib/Format/UnwrappedLineFormatter.cpp
>> URL:
>> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/UnwrappedLineFormatter.cpp?rev=236974&r1=236973&r2=236974&view=diff
>>
>> ==============================================================================
>> --- cfe/trunk/lib/Format/UnwrappedLineFormatter.cpp (original)
>> +++ cfe/trunk/lib/Format/UnwrappedLineFormatter.cpp Mon May 11 03:21:35
>> 2015
>> @@ -151,8 +151,8 @@ private:
>> 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))
>> + 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) &&
>> @@ -161,9 +161,10 @@ private:
>> return 1;
>> }
>>
>> - unsigned tryMergeShortCaseLabels(
>> - SmallVectorImpl<AnnotatedLine *>::const_iterator I,
>> - SmallVectorImpl<AnnotatedLine *>::const_iterator E, unsigned
>> Limit) {
>> + 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;
>> @@ -307,40 +308,346 @@ private:
>> const AdditionalKeywords &Keywords;
>> };
>>
>> -class NoColumnLimitFormatter {
>> +static void markFinalized(FormatToken *Tok) {
>> + for (; Tok; Tok = Tok->Next) {
>> + Tok->Finalized = true;
>> + for (AnnotatedLine *Child : Tok->Children)
>> + markFinalized(Child->First);
>> + }
>> +}
>> +
>> +#ifndef NDEBUG
>> +static void printLineState(const LineState &State) {
>> + llvm::dbgs() << "State: ";
>> + for (const ParenState &P : State.Stack) {
>> + llvm::dbgs() << P.Indent << "|" << P.LastSpace << "|" <<
>> P.NestedBlockIndent
>> + << " ";
>> + }
>> + llvm::dbgs() << State.NextToken->TokenText << "\n";
>> +}
>> +#endif
>> +
>> +/// \brief Base class for classes that format one \c AnnotatedLine.
>> +class LineFormatter {
>> +public:
>> + LineFormatter(ContinuationIndenter *Indenter, WhitespaceManager
>> *Whitespaces,
>> + const FormatStyle &Style,
>> + UnwrappedLineFormatter *BlockFormatter)
>> + : Indenter(Indenter), Whitespaces(Whitespaces), Style(Style),
>> + BlockFormatter(BlockFormatter) {}
>> + virtual ~LineFormatter() {}
>> +
>> + /// \brief Formats an \c AnnotatedLine and returns the penalty.
>> + ///
>> + /// If \p DryRun is \c false, directly applies the changes.
>> + virtual unsigned formatLine(const AnnotatedLine &Line, unsigned
>> FirstIndent,
>> + bool DryRun) = 0;
>> +
>> +protected:
>> + /// \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) {
>> + const FormatToken *LBrace = State.NextToken->getPreviousNonComment();
>> + FormatToken &Previous = *State.NextToken->Previous;
>> + 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.Stack.back().Indent -
>> + Previous.Children[0]->Level *
>> Style.IndentWidth;
>> +
>> + Penalty +=
>> + BlockFormatter->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 += formatLine(*Previous.Children[0], State.Column + 1,
>> DryRun);
>> +
>> + State.Column += 1 + Previous.Children[0]->Last->TotalLength;
>> + return true;
>> + }
>> +
>> + ContinuationIndenter *Indenter;
>> +
>> +private:
>> + WhitespaceManager *Whitespaces;
>> + const FormatStyle &Style;
>> + UnwrappedLineFormatter *BlockFormatter;
>> +};
>> +
>> +/// \brief Formatter that keeps the existing line breaks.
>> +class NoColumnLimitLineFormatter : public LineFormatter {
>> public:
>> - NoColumnLimitFormatter(ContinuationIndenter *Indenter,
>> - UnwrappedLineFormatter *Formatter)
>> - : Indenter(Indenter), Formatter(Formatter) {}
>> -
>> - /// \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) {
>> + NoColumnLimitLineFormatter(ContinuationIndenter *Indenter,
>> + WhitespaceManager *Whitespaces,
>> + const FormatStyle &Style,
>> + UnwrappedLineFormatter *BlockFormatter)
>> + : LineFormatter(Indenter, Whitespaces, Style, BlockFormatter) {}
>> +
>> + /// \brief Formats the line, simply keeping all of the input's line
>> breaking
>> + /// decisions.
>> + unsigned formatLine(const AnnotatedLine &Line, unsigned FirstIndent,
>> + bool DryRun) override {
>> + assert(!DryRun);
>> LineState State =
>> - Indenter->getInitialState(FirstIndent, Line, /*DryRun=*/false);
>> + Indenter->getInitialState(FirstIndent, &Line, /*DryRun=*/false);
>> while (State.NextToken) {
>> bool Newline =
>> Indenter->mustBreak(State) ||
>> (Indenter->canBreak(State) && State.NextToken->NewlinesBefore
>> > 0);
>> unsigned Penalty = 0;
>> - Formatter->formatChildren(State, Newline, /*DryRun=*/false,
>> Penalty);
>> + formatChildren(State, Newline, /*DryRun=*/false, Penalty);
>> Indenter->addTokenToState(State, Newline, /*DryRun=*/false);
>> }
>> + return 0;
>> }
>> +};
>>
>> -private:
>> - ContinuationIndenter *Indenter;
>> - UnwrappedLineFormatter *Formatter;
>> +/// \brief Formatter that puts all tokens into a single line without
>> breaks.
>> +class NoLineBreakFormatter : public LineFormatter {
>> +public:
>> + NoLineBreakFormatter(ContinuationIndenter *Indenter,
>> + WhitespaceManager *Whitespaces, const FormatStyle
>> &Style,
>> + UnwrappedLineFormatter *BlockFormatter)
>> + : LineFormatter(Indenter, Whitespaces, Style, BlockFormatter) {}
>> +
>> + /// \brief Puts all tokens into a single line.
>> + unsigned formatLine(const AnnotatedLine &Line, unsigned FirstIndent,
>> + bool DryRun) {
>> + unsigned Penalty = 0;
>> + LineState State = Indenter->getInitialState(FirstIndent, &Line,
>> DryRun);
>> + while (State.NextToken) {
>> + formatChildren(State, /*Newline=*/false, DryRun, Penalty);
>> + Indenter->addTokenToState(State, /*Newline=*/false, DryRun);
>> + }
>> + return Penalty;
>> + }
>> };
>>
>> +/// \brief Finds the best way to break lines.
>> +class OptimizingLineFormatter : public LineFormatter {
>> +public:
>> + OptimizingLineFormatter(ContinuationIndenter *Indenter,
>> + WhitespaceManager *Whitespaces,
>> + const FormatStyle &Style,
>> + UnwrappedLineFormatter *BlockFormatter)
>> + : LineFormatter(Indenter, Whitespaces, Style, BlockFormatter) {}
>> +
>> + /// \brief Formats the line by finding the best line breaks with line
>> lengths
>> + /// below the column limit.
>> + unsigned formatLine(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;
>>
>> -static void markFinalized(FormatToken *Tok) {
>> - for (; Tok; Tok = Tok->Next) {
>> - Tok->Finalized = true;
>> - for (AnnotatedLine *Child : Tok->Children)
>> - markFinalized(Child->First);
>> + // Find best solution in solution space.
>> + return analyzeSolutionSpace(State, DryRun);
>> + }
>> +
>> +private:
>> + struct CompareLineStatePointers {
>> + bool operator()(LineState *obj1, LineState *obj2) const {
>> + return *obj1 < *obj2;
>> + }
>> + };
>> +
>> + /// \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 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 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 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) {
>> + 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;
>> + }
>> +
>> + /// \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 Applies the best formatting by reconstructing the path in
>> the
>> + /// solution space that leads to \c Best.
>> + void reconstructPath(LineState &State, StateNode *Best) {
>> + std::deque<StateNode *> Path;
>> + // We do not need a break before the initial token.
>> + while (Best->Previous) {
>> + Path.push_front(Best);
>> + Best = Best->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({
>> + printLineState((*I)->Previous->State);
>> + if ((*I)->NewLine) {
>> + llvm::dbgs() << "Penalty for placing "
>> + << (*I)->Previous->State.NextToken->Tok.getName()
>> << ": "
>> + << Penalty << "\n";
>> + }
>> + });
>> + }
>> }
>> -}
>> +
>> + llvm::SpecificBumpPtrAllocator<StateNode> Allocator;
>> +};
>>
>> } // namespace
>>
>> @@ -431,17 +738,14 @@ UnwrappedLineFormatter::format(const Sma
>>
>> 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, Penalty);
>> - Indenter->addTokenToState(State, /*Newline=*/false, DryRun);
>> - }
>> + Penalty += NoLineBreakFormatter(Indenter, Whitespaces, Style,
>> this)
>> + .formatLine(TheLine, Indent, DryRun);
>> } else if (Style.ColumnLimit == 0) {
>> - NoColumnLimitFormatter Formatter(Indenter, this);
>> - if (!DryRun)
>> - Formatter.format(Indent, &TheLine);
>> + NoColumnLimitLineFormatter(Indenter, Whitespaces, Style, this)
>> + .formatLine(TheLine, Indent, DryRun);
>> } else {
>> - Penalty += format(TheLine, Indent, DryRun);
>> + Penalty += OptimizingLineFormatter(Indenter, Whitespaces, Style,
>> this)
>> + .formatLine(TheLine, Indent, DryRun);
>> }
>>
>> if (!TheLine.InPPDirective)
>> @@ -486,19 +790,6 @@ UnwrappedLineFormatter::format(const Sma
>> 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,
>> @@ -567,174 +858,5 @@ void UnwrappedLineFormatter::join(Annota
>> }
>> }
>>
>> -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;
>> -}
>> -
>> -#ifndef NDEBUG
>> -static void printLineState(const LineState &State) {
>> - llvm::dbgs() << "State: ";
>> - for (const ParenState &P : State.Stack) {
>> - llvm::dbgs() << P.Indent << "|" << P.LastSpace << "|" <<
>> P.NestedBlockIndent
>> - << " ";
>> - }
>> - llvm::dbgs() << State.NextToken->TokenText << "\n";
>> -}
>> -#endif
>> -
>> -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({
>> - printLineState((*I)->Previous->State);
>> - 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) {
>> - const FormatToken *LBrace = State.NextToken->getPreviousNonComment();
>> - FormatToken &Previous = *State.NextToken->Previous;
>> - 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.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
>>
>> Modified: cfe/trunk/lib/Format/UnwrappedLineFormatter.h
>> URL:
>> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/UnwrappedLineFormatter.h?rev=236974&r1=236973&r2=236974&view=diff
>>
>> ==============================================================================
>> --- cfe/trunk/lib/Format/UnwrappedLineFormatter.h (original)
>> +++ cfe/trunk/lib/Format/UnwrappedLineFormatter.h Mon May 11 03:21:35 2015
>> @@ -38,65 +38,12 @@ public:
>> : Indenter(Indenter), Whitespaces(Whitespaces), Style(Style),
>> Keywords(Keywords), IncompleteFormat(IncompleteFormat) {}
>>
>> - unsigned format(const SmallVectorImpl<AnnotatedLine *> &Lines, bool
>> DryRun,
>> - int AdditionalIndent = 0, bool FixBadIndentation =
>> false);
>> -
>> -
>> - /// \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);
>> + /// \brief Format the current block and return the penalty.
>> + unsigned format(const SmallVectorImpl<AnnotatedLine *> &Lines,
>> + bool DryRun = false, 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
>> @@ -133,44 +80,16 @@ private:
>> 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);
>> -
>> - ContinuationIndenter *Indenter;
>> - WhitespaceManager *Whitespaces;
>> - FormatStyle Style;
>> - const AdditionalKeywords &Keywords;
>> -
>> - 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;
>>
>> + ContinuationIndenter *Indenter;
>> + WhitespaceManager *Whitespaces;
>> + const FormatStyle &Style;
>> + const AdditionalKeywords &Keywords;
>> bool *IncompleteFormat;
>> };
>> } // end namespace format
>>
>>
>> _______________________________________________
>> 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/20150511/18fa28ba/attachment.html>
More information about the cfe-commits
mailing list