[cfe-commits] r172403 - /cfe/trunk/lib/Format/Format.cpp

Daniel Jasper djasper at google.com
Mon Jan 14 05:08:07 PST 2013


Author: djasper
Date: Mon Jan 14 07:08:07 2013
New Revision: 172403

URL: http://llvm.org/viewvc/llvm-project?rev=172403&view=rev
Log:
Refactor datastructure used in clang-format.

Main difference, add an AnnotatedLine class to hold information about a
line while formatting. At the same time degrade the UnwrappedLine class
to a class solely used for communicating between the UnwrappedLineParser
and the Formatter.

No functional changes intended.

Modified:
    cfe/trunk/lib/Format/Format.cpp

Modified: cfe/trunk/lib/Format/Format.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/Format.cpp?rev=172403&r1=172402&r2=172403&view=diff
==============================================================================
--- cfe/trunk/lib/Format/Format.cpp (original)
+++ cfe/trunk/lib/Format/Format.cpp Mon Jan 14 07:08:07 2013
@@ -93,6 +93,19 @@
   AnnotatedToken *Parent;
 };
 
+class AnnotatedLine {
+public:
+  AnnotatedLine(const FormatToken &FormatTok, unsigned Level,
+                bool InPPDirective)
+      : First(FormatTok), Level(Level), InPPDirective(InPPDirective) {}
+  AnnotatedToken First;
+  AnnotatedToken *Last;
+
+  LineType Type;
+  unsigned Level;
+  bool InPPDirective;
+};
+
 static prec::Level getPrecedence(const AnnotatedToken &Tok) {
   return getBinOpPrecedence(Tok.FormatTok.Tok.getKind(), true, true);
 }
@@ -168,11 +181,13 @@
                                        NewLineText + std::string(Spaces, ' ')));
 }
 
-/// \brief Checks whether the (remaining) \c UnwrappedLine starting with
-/// \p RootToken fits into \p Limit columns.
-static bool fitsIntoLimit(const AnnotatedToken &RootToken, unsigned Limit) {
+/// \brief Calculates whether the (remaining) \c AnnotatedLine starting with
+/// \p RootToken fits into \p Limit columns on a single line.
+///
+/// If true, sets \p Length to the required length.
+static bool fitsIntoLimit(const AnnotatedToken &RootToken,
+                          unsigned Limit, unsigned* Length = 0) {
   unsigned Columns = RootToken.FormatTok.TokenLength;
-  bool FitsOnALine = true;
   const AnnotatedToken *Tok = &RootToken;
   while (!Tok->Children.empty()) {
     Tok = &Tok->Children[0];
@@ -181,11 +196,13 @@
     // needs to be put on a new line if the line needs to be split.
     if (Columns > Limit ||
         (Tok->MustBreakBefore && Tok->Type != TT_CtorInitializerColon)) {
-      FitsOnALine = false;
-      break;
+      // FIXME: Remove this hack.
+      return false;
     }
   }
-  return FitsOnALine;
+  if (Length != 0)
+    *Length = Columns;
+  return true;
 }
 
 /// \brief Returns if a token is an Objective-C selector name.
@@ -200,7 +217,7 @@
 class UnwrappedLineFormatter {
 public:
   UnwrappedLineFormatter(const FormatStyle &Style, SourceManager &SourceMgr,
-                         const UnwrappedLine &Line, unsigned FirstIndent,
+                         const AnnotatedLine &Line, unsigned FirstIndent,
                          bool FitsOnALine, const AnnotatedToken &RootToken,
                          tooling::Replacements &Replaces, bool StructuralError)
       : Style(Style), SourceMgr(SourceMgr), Line(Line),
@@ -599,7 +616,7 @@
 
   FormatStyle Style;
   SourceManager &SourceMgr;
-  const UnwrappedLine &Line;
+  const AnnotatedLine &Line;
   const unsigned FirstIndent;
   const bool FitsOnALine;
   const AnnotatedToken &RootToken;
@@ -616,10 +633,9 @@
 /// \c UnwrappedLine.
 class TokenAnnotator {
 public:
-  TokenAnnotator(const UnwrappedLine &Line, const FormatStyle &Style,
-                 SourceManager &SourceMgr, Lexer &Lex)
-      : Style(Style), SourceMgr(SourceMgr), Lex(Lex),
-        RootToken(Line.RootToken) {}
+  TokenAnnotator(const FormatStyle &Style, SourceManager &SourceMgr, Lexer &Lex,
+                 AnnotatedLine &Line)
+      : Style(Style), SourceMgr(SourceMgr), Lex(Lex), Line(Line) {}
 
   /// \brief A parser that gathers additional information about tokens.
   ///
@@ -888,7 +904,9 @@
   };
 
   void createAnnotatedTokens(AnnotatedToken &Current) {
-    if (!Current.FormatTok.Children.empty()) {
+    if (Current.FormatTok.Children.empty()) {
+      Line.Last = &Current;
+    } else {
       Current.Children.push_back(AnnotatedToken(Current.FormatTok.Children[0]));
       Current.Children.back().Parent = &Current;
       createAnnotatedTokens(Current.Children.back());
@@ -917,34 +935,30 @@
       calculateExtraInformation(Current.Children[0]);
   }
 
-  bool annotate() {
-    createAnnotatedTokens(RootToken);
-
-    AnnotatingParser Parser(RootToken);
-    CurrentLineType = Parser.parseLine();
-    if (CurrentLineType == LT_Invalid)
-      return false;
-
-    determineTokenTypes(RootToken, /*IsRHS=*/false);
-
-    if (RootToken.Type == TT_ObjCMethodSpecifier)
-      CurrentLineType = LT_ObjCMethodDecl;
-    else if (RootToken.Type == TT_ObjCDecl)
-      CurrentLineType = LT_ObjCDecl;
-    else if (RootToken.Type == TT_ObjCProperty)
-      CurrentLineType = LT_ObjCProperty;
-
-    if (!RootToken.Children.empty())
-      calculateExtraInformation(RootToken.Children[0]);
-    return true;
-  }
-
-  LineType getLineType() {
-    return CurrentLineType;
-  }
+  void annotate() {
+    Line.Last = &Line.First;
+    createAnnotatedTokens(Line.First);
+
+    AnnotatingParser Parser(Line.First);
+    Line.Type = Parser.parseLine();
+    if (Line.Type == LT_Invalid)
+      return;
+
+    determineTokenTypes(Line.First, /*IsRHS=*/false);
+
+    if (Line.First.Type == TT_ObjCMethodSpecifier)
+      Line.Type = LT_ObjCMethodDecl;
+    else if (Line.First.Type == TT_ObjCDecl)
+      Line.Type = LT_ObjCDecl;
+    else if (Line.First.Type == TT_ObjCProperty)
+      Line.Type = LT_ObjCProperty;
+
+    Line.First.SpaceRequiredBefore = true;
+    Line.First.MustBreakBefore = Line.First.FormatTok.MustBreakBefore;
+    Line.First.CanBreakBefore = Line.First.MustBreakBefore;
 
-  const AnnotatedToken &getRootToken() {
-    return RootToken;
+    if (!Line.First.Children.empty())
+      calculateExtraInformation(Line.First.Children[0]);
   }
 
 private:
@@ -1079,7 +1093,7 @@
       return false;
     if (Right.is(tok::less) &&
         (Left.is(tok::kw_template) ||
-         (CurrentLineType == LT_ObjCDecl && Style.ObjCSpaceBeforeProtocolList)))
+         (Line.Type == LT_ObjCDecl && Style.ObjCSpaceBeforeProtocolList)))
       return true;
     if (Left.is(tok::arrow) || Right.is(tok::arrow))
       return false;
@@ -1119,7 +1133,7 @@
     if (Left.is(tok::l_paren))
       return false;
     if (Right.is(tok::l_paren)) {
-      return CurrentLineType == LT_ObjCDecl || Left.is(tok::kw_if) ||
+      return Line.Type == LT_ObjCDecl || Left.is(tok::kw_if) ||
              Left.is(tok::kw_for) || Left.is(tok::kw_while) ||
              Left.is(tok::kw_switch) || Left.is(tok::kw_return) ||
              Left.is(tok::kw_catch) || Left.is(tok::kw_new) ||
@@ -1134,7 +1148,7 @@
   }
 
   bool spaceRequiredBefore(const AnnotatedToken &Tok) {
-    if (CurrentLineType == LT_ObjCMethodDecl) {
+    if (Line.Type == LT_ObjCMethodDecl) {
       if (Tok.is(tok::identifier) && !Tok.Children.empty() &&
           Tok.Children[0].is(tok::colon) && Tok.Parent->is(tok::identifier))
         return true;
@@ -1151,7 +1165,7 @@
         // Don't space between ':' and '('
         return false;
     }
-    if (CurrentLineType == LT_ObjCProperty &&
+    if (Line.Type == LT_ObjCProperty &&
         (Tok.is(tok::equal) || Tok.Parent->is(tok::equal)))
       return false;
 
@@ -1167,7 +1181,7 @@
     if (Tok.Parent->Type == TT_OverloadedOperator)
       return false;
     if (Tok.is(tok::colon))
-      return RootToken.isNot(tok::kw_case) && !Tok.Children.empty() &&
+      return Line.First.isNot(tok::kw_case) && !Tok.Children.empty() &&
              Tok.Type != TT_ObjCMethodExpr;
     if (Tok.Parent->Type == TT_UnaryOperator ||
         Tok.Parent->Type == TT_CastRParen)
@@ -1185,7 +1199,7 @@
       return true;
     if (Tok.Parent->Type == TT_TemplateCloser && Tok.is(tok::l_paren))
       return false;
-    if (Tok.is(tok::less) && RootToken.is(tok::hash))
+    if (Tok.is(tok::less) && Line.First.is(tok::hash))
       return true;
     if (Tok.Type == TT_TrailingUnaryOperator)
       return false;
@@ -1194,7 +1208,7 @@
 
   bool canBreakBefore(const AnnotatedToken &Right) {
     const AnnotatedToken &Left = *Right.Parent;
-    if (CurrentLineType == LT_ObjCMethodDecl) {
+    if (Line.Type == LT_ObjCMethodDecl) {
       if (Right.is(tok::identifier) && !Right.Children.empty() &&
           Right.Children[0].is(tok::colon) && Left.is(tok::identifier))
         return true;
@@ -1221,7 +1235,7 @@
     if (Left.Type == TT_PointerOrReference || Left.Type == TT_TemplateCloser ||
         Left.Type == TT_UnaryOperator || Right.Type == TT_ConditionalExpr)
       return false;
-    if (Left.is(tok::equal) && CurrentLineType == LT_VirtualFunctionDecl)
+    if (Left.is(tok::equal) && Line.Type == LT_VirtualFunctionDecl)
       return false;
 
     if (Right.is(tok::comment))
@@ -1246,8 +1260,7 @@
   FormatStyle Style;
   SourceManager &SourceMgr;
   Lexer &Lex;
-  LineType CurrentLineType;
-  AnnotatedToken RootToken;
+  AnnotatedLine &Line;
 };
 
 class LexerBasedFormatTokenSource : public FormatTokenSource {
@@ -1347,35 +1360,32 @@
     UnwrappedLineParser Parser(Diag, Style, Tokens, *this);
     StructuralError = Parser.parse();
     unsigned PreviousEndOfLineColumn = 0;
-    for (std::vector<UnwrappedLine>::iterator I = UnwrappedLines.begin(),
-                                              E = UnwrappedLines.end();
+    for (unsigned i = 0, e = AnnotatedLines.size(); i != e; ++i) {
+      TokenAnnotator Annotator(Style, SourceMgr, Lex, AnnotatedLines[i]);
+      Annotator.annotate();
+    }
+    for (std::vector<AnnotatedLine>::iterator I = AnnotatedLines.begin(),
+                                              E = AnnotatedLines.end();
          I != E; ++I) {
-      const UnwrappedLine &TheLine = *I;
-      if (touchesRanges(TheLine)) {
-        OwningPtr<TokenAnnotator> AnnotatedLine(
-            new TokenAnnotator(TheLine, Style, SourceMgr, Lex));
-        if (!AnnotatedLine->annotate())
-          break;
-        unsigned Indent = formatFirstToken(AnnotatedLine->getRootToken(),
-                                           TheLine.Level, TheLine.InPPDirective,
+      const AnnotatedLine &TheLine = *I;
+      if (touchesRanges(TheLine) && TheLine.Type != LT_Invalid) {
+        unsigned Indent = formatFirstToken(TheLine.First, TheLine.Level,
+                                           TheLine.InPPDirective,
                                            PreviousEndOfLineColumn);
-
-        UnwrappedLine Line(TheLine);
-        bool FitsOnALine = tryFitMultipleLinesInOne(Indent, Line, AnnotatedLine,
-                                                    I, E);
-        UnwrappedLineFormatter Formatter(
-            Style, SourceMgr, Line, Indent, FitsOnALine,
-            AnnotatedLine->getRootToken(), Replaces, StructuralError);
+        bool FitsOnALine = tryFitMultipleLinesInOne(Indent, I, E);
+        UnwrappedLineFormatter Formatter(Style, SourceMgr, TheLine, Indent,
+                                         FitsOnALine, TheLine.First, Replaces,
+                                         StructuralError);
         PreviousEndOfLineColumn = Formatter.format();
       } else {
         // If we did not reformat this unwrapped line, the column at the end of
         // the last token is unchanged - thus, we can calculate the end of the
         // last token, and return the result.
-        const FormatToken *Last = getLastInLine(TheLine);
         PreviousEndOfLineColumn =
-            SourceMgr.getSpellingColumnNumber(Last->Tok.getLocation()) +
-            Lex.MeasureTokenLength(Last->Tok.getLocation(), SourceMgr,
-                                   Lex.getLangOpts()) -
+            SourceMgr.getSpellingColumnNumber(
+                TheLine.Last->FormatTok.Tok.getLocation()) +
+            Lex.MeasureTokenLength(TheLine.Last->FormatTok.Tok.getLocation(),
+                                   SourceMgr, Lex.getLangOpts()) -
             1;
       }
     }
@@ -1389,81 +1399,85 @@
   /// if possible; note that \c I will be incremented when lines are merged.
   ///
   /// Returns whether the resulting \c Line can fit in a single line.
-  bool tryFitMultipleLinesInOne(unsigned Indent, UnwrappedLine &Line,
-                                OwningPtr<TokenAnnotator> &AnnotatedLine,
-                                std::vector<UnwrappedLine>::iterator &I,
-                                std::vector<UnwrappedLine>::iterator E) {
+  bool tryFitMultipleLinesInOne(unsigned Indent,
+                                std::vector<AnnotatedLine>::iterator &I,
+                                std::vector<AnnotatedLine>::iterator E) {
     unsigned Limit = Style.ColumnLimit - (I->InPPDirective ? 1 : 0) - Indent;
 
     // Check whether the UnwrappedLine can be put onto a single line. If
     // so, this is bound to be the optimal solution (by definition) and we
     // don't need to analyze the entire solution space.
-    bool FitsOnALine = fitsIntoLimit(AnnotatedLine->getRootToken(), Limit);
-    if (!FitsOnALine || I + 1 == E || I + 2 == E)
-      return FitsOnALine;
+    unsigned LengthLine1 = 0;
+    if (!fitsIntoLimit(I->First, Limit, &LengthLine1))
+      return false;
 
-    // Try to merge the next two lines if possible.
-    UnwrappedLine Combined(Line);
+    // Check that we still have three lines and they fit into the limit.
+    if (I + 1 == E || I + 2 == E)
+      return true;
+    unsigned LengthLine2 = 0;
+    unsigned LengthLine3 = 0;
+    if (!fitsIntoLimit((I + 1)->First, Limit, &LengthLine2) ||
+        !fitsIntoLimit((I + 2)->First, Limit, &LengthLine3))
+      return true;
+    if (LengthLine1 + LengthLine2 + LengthLine3 + 2 > Limit) // Two spaces.
+      return true;
 
     // First, check that the current line allows merging. This is the case if
     // we're not in a control flow statement and the last token is an opening
     // brace.
-    FormatToken *Last = &Combined.RootToken;
+    AnnotatedLine& Line = *I;
     bool AllowedTokens =
-        Last->Tok.isNot(tok::kw_if) && Last->Tok.isNot(tok::kw_while) &&
-        Last->Tok.isNot(tok::kw_do) && Last->Tok.isNot(tok::r_brace) &&
-        Last->Tok.isNot(tok::kw_else) && Last->Tok.isNot(tok::kw_try) &&
-        Last->Tok.isNot(tok::kw_catch) && Last->Tok.isNot(tok::kw_for) &&
+        Line.First.isNot(tok::kw_if) && Line.First.isNot(tok::kw_while) &&
+        Line.First.isNot(tok::kw_do) && Line.First.isNot(tok::r_brace) &&
+        Line.First.isNot(tok::kw_else) && Line.First.isNot(tok::kw_try) &&
+        Line.First.isNot(tok::kw_catch) && Line.First.isNot(tok::kw_for) &&
         // This gets rid of all ObjC @ keywords and methods.
-        Last->Tok.isNot(tok::at) && Last->Tok.isNot(tok::minus) &&
-        Last->Tok.isNot(tok::plus);
-    while (!Last->Children.empty())
-      Last = &Last->Children.back();
-    if (!Last->Tok.is(tok::l_brace))
-      return FitsOnALine;
+        Line.First.isNot(tok::at) && Line.First.isNot(tok::minus) &&
+        Line.First.isNot(tok::plus);
+    if (Line.Last->isNot(tok::l_brace) || !AllowedTokens)
+      return true;
 
     // Second, check that the next line does not contain any braces - if it
     // does, readability declines when putting it into a single line.
-    const FormatToken *Next = &(I + 1)->RootToken;
-    while (Next) {
-      AllowedTokens = AllowedTokens && !Next->Tok.is(tok::l_brace) &&
-                      !Next->Tok.is(tok::r_brace);
-      Last->Children.push_back(*Next);
-      Last = &Last->Children[0];
-      Last->Children.clear();
-      Next = Next->Children.empty() ? NULL : &Next->Children.back();
-    }
+    const AnnotatedToken *Tok = &(I + 1)->First;
+    if ((I + 1)->Last->Type == TT_LineComment || Tok->MustBreakBefore)
+      return true;
+    do {
+      if (Tok->is(tok::l_brace) || Tok->is(tok::r_brace))
+        return true;
+      Tok = Tok->Children.empty() ? NULL : &Tok->Children.back();
+    } while (Tok != NULL);
 
     // Last, check that the third line contains a single closing brace.
-    Next = &(I + 2)->RootToken;
-    AllowedTokens = AllowedTokens && Next->Tok.is(tok::r_brace);
-    if (!Next->Children.empty() || !AllowedTokens)
-      return FitsOnALine;
-    Last->Children.push_back(*Next);
-
-    OwningPtr<TokenAnnotator> CombinedAnnotator(
-        new TokenAnnotator(Combined, Style, SourceMgr, Lex));
-    if (CombinedAnnotator->annotate() &&
-        fitsIntoLimit(CombinedAnnotator->getRootToken(), Limit)) {
-      // If the merged line fits, we use that instead and skip the next two
-      // lines.
-      AnnotatedLine.reset(CombinedAnnotator.take());
-      Line = Combined;
-      I += 2;
-    }
-    return FitsOnALine;
-  }
-
-  const FormatToken *getLastInLine(const UnwrappedLine &TheLine) {
-    const FormatToken *Last = &TheLine.RootToken;
-    while (!Last->Children.empty())
-      Last = &Last->Children.back();
-    return Last;
-  }
-
-  bool touchesRanges(const UnwrappedLine &TheLine) {
-    const FormatToken *First = &TheLine.RootToken;
-    const FormatToken *Last = getLastInLine(TheLine);
+    Tok = &(I + 2)->First;
+    if (!Tok->Children.empty() || Tok->isNot(tok::r_brace) ||
+        Tok->MustBreakBefore)
+      return true;
+
+    // If the merged line fits, we use that instead and skip the next two lines.
+    Line.Last->Children.push_back((I + 1)->First);
+    while (!Line.Last->Children.empty()) {
+      Line.Last->Children[0].Parent = Line.Last;
+      Line.Last = &Line.Last->Children[0];
+    }
+
+    join(Line, *(I + 1));
+    join(Line, *(I + 2));
+    I += 2;
+    return true;
+  }
+
+  void join(AnnotatedLine &A, const AnnotatedLine &B) {
+    A.Last->Children.push_back(B.First);
+    while (!A.Last->Children.empty()) {
+      A.Last->Children[0].Parent = A.Last;
+      A.Last = &A.Last->Children[0];
+    }
+  }
+
+  bool touchesRanges(const AnnotatedLine &TheLine) {
+    const FormatToken *First = &TheLine.First.FormatTok;
+    const FormatToken *Last = &TheLine.Last->FormatTok;
     CharSourceRange LineRange = CharSourceRange::getTokenRange(
                                     First->Tok.getLocation(),
                                     Last->Tok.getLocation());
@@ -1478,7 +1492,8 @@
   }
 
   virtual void consumeUnwrappedLine(const UnwrappedLine &TheLine) {
-    UnwrappedLines.push_back(TheLine);
+    AnnotatedLines.push_back(
+        AnnotatedLine(TheLine.RootToken, TheLine.Level, TheLine.InPPDirective));
   }
 
   /// \brief Add a new line and the required indent before the first Token
@@ -1526,7 +1541,7 @@
   SourceManager &SourceMgr;
   tooling::Replacements Replaces;
   std::vector<CharSourceRange> Ranges;
-  std::vector<UnwrappedLine> UnwrappedLines;
+  std::vector<AnnotatedLine> AnnotatedLines;
   bool StructuralError;
 };
 





More information about the cfe-commits mailing list