r236974 - Refactor the formatter of clang-format.

Manuel Klimek klimek at google.com
Mon May 11 01:21:36 PDT 2015


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





More information about the cfe-commits mailing list