r236974 - Refactor the formatter of clang-format.

Daniel Jasper djasper at google.com
Mon May 11 02:09:07 PDT 2015


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/837244ce/attachment.html>


More information about the cfe-commits mailing list