[PATCH] Split long lines in multi-line comments.

Alexander Kornienko alexfh at google.com
Fri Mar 15 12:09:16 PDT 2013


Hi djasper, klimek,

This is implementation for /* */ comments only.

http://llvm-reviews.chandlerc.com/D547

Files:
  lib/Format/Format.cpp
  unittests/Format/FormatTest.cpp

Index: lib/Format/Format.cpp
===================================================================
--- lib/Format/Format.cpp
+++ lib/Format/Format.cpp
@@ -146,7 +146,7 @@
       alignComments();
 
     if (Tok.Type == TT_BlockComment)
-      indentBlockComment(Tok.FormatTok, Spaces);
+      indentBlockComment(Tok.FormatTok, Spaces, Style);
 
     storeReplacement(Tok.FormatTok, getNewLineText(NewLines, Spaces));
   }
@@ -193,33 +193,89 @@
   }
 
 private:
-  void indentBlockComment(const FormatToken &Tok, int Indent) {
+  StringRef findCommonPrefix(ArrayRef<StringRef> Lines) {
+    if (Lines.size() < 3)
+      return "";
+    StringRef Prefix(Lines[1].data(), Lines[1].find_first_not_of(" *"));
+    for (size_t i = 2; i < Lines.size(); ++i) {
+      for (size_t j = 0; j < Prefix.size() && j < Lines[i].size(); ++j)
+        if (Prefix[j] != Lines[i][j]) {
+          Prefix = Prefix.substr(0, j);
+          break;
+        }
+    }
+    return Prefix;
+  }
+
+  bool safeToSplitLine(StringRef Line) {
+    return Line.find_first_of("/\\:<>()[]{}*&%") == StringRef::npos;
+  }
+
+  void indentBlockComment(const FormatToken &Tok, int Indent,
+                          const FormatStyle &Style) {
     SourceLocation TokenLoc = Tok.Tok.getLocation();
-    int IndentDelta = Indent - SourceMgr.getSpellingColumnNumber(TokenLoc) + 1;
-    const char *Start = SourceMgr.getCharacterData(TokenLoc);
-    const char *Current = Start;
-    const char *TokEnd = Current + Tok.TokenLength;
-    llvm::SmallVector<SourceLocation, 16> LineStarts;
-    while (Current < TokEnd) {
-      if (*Current == '\n') {
-        ++Current;
-        LineStarts.push_back(TokenLoc.getLocWithOffset(Current - Start));
-        // If we need to outdent the line, check that it's indented enough.
-        for (int i = 0; i < -IndentDelta; ++i, ++Current)
-          if (Current >= TokEnd || *Current != ' ')
-            return;
-      } else {
-        ++Current;
+    int TokenIndent = SourceMgr.getSpellingColumnNumber(TokenLoc) - 1;
+    int IndentDelta = Indent - TokenIndent;
+    StringRef Text(SourceMgr.getCharacterData(TokenLoc), Tok.TokenLength);
+    SmallVector<StringRef, 16> Lines;
+    Text.split(Lines, "\n");
+
+    if (IndentDelta > 0) {
+      std::string WhiteSpace(IndentDelta, ' ');
+      for (size_t i = 1; i < Lines.size(); ++i) {
+        Replaces.insert(tooling::Replacement(
+            SourceMgr, TokenLoc.getLocWithOffset(Lines[i].data() - Text.data()),
+            0, WhiteSpace));
+      }
+    } else if (IndentDelta < 0) {
+      std::string WhiteSpace(-IndentDelta, ' ');
+      // Check that the line is indented enough.
+      for (size_t i = 1; i < Lines.size(); ++i) {
+        if (!Lines[i].startswith(WhiteSpace))
+          return;
+      }
+      for (size_t i = 1; i < Lines.size(); ++i) {
+        Replaces.insert(tooling::Replacement(
+            SourceMgr, TokenLoc.getLocWithOffset(Lines[i].data() - Text.data()),
+            -IndentDelta, ""));
       }
     }
 
-    for (size_t i = 0; i < LineStarts.size(); ++i) {
-      if (IndentDelta > 0)
-        Replaces.insert(tooling::Replacement(SourceMgr, LineStarts[i], 0,
-                                             std::string(IndentDelta, ' ')));
-      else if (IndentDelta < 0)
-        Replaces.insert(
-            tooling::Replacement(SourceMgr, LineStarts[i], -IndentDelta, ""));
+    // Split long lines in comments.
+    StringRef Prefix = findCommonPrefix(Lines);
+    size_t ColumnLimit = Style.ColumnLimit - Prefix.size() - IndentDelta;
+    std::string NewLine("\n");
+    if (IndentDelta < 0)
+      NewLine += Prefix.substr(-IndentDelta).str();
+    else
+      NewLine += std::string(IndentDelta, ' ') + Prefix.str();
+
+    if (Prefix.endswith("*")) {
+      NewLine += " ";
+      --ColumnLimit;
+    }
+
+    for (size_t i = 1; i < Lines.size(); ++i) {
+      StringRef Line = Lines[i].substr(Prefix.size());
+      if (Line.size() <= ColumnLimit || !safeToSplitLine(Line))
+        continue;
+      while (Line.size() > ColumnLimit) {
+        size_t SpacePos = Line.find_last_of(" ", ColumnLimit + 1);
+        if (SpacePos == StringRef::npos)
+          break;
+        size_t BreakPos = Line.find_last_not_of(" ", SpacePos);
+        if (BreakPos == StringRef::npos)
+          break;
+
+        ++BreakPos;
+
+        Replaces.insert(tooling::Replacement(
+            SourceMgr,
+            TokenLoc.getLocWithOffset(Line.data() + BreakPos - Text.data()),
+            SpacePos - BreakPos + 1, NewLine));
+
+        Line = Line.substr(SpacePos).ltrim();
+      }
     }
   }
 
Index: unittests/Format/FormatTest.cpp
===================================================================
--- unittests/Format/FormatTest.cpp
+++ unittests/Format/FormatTest.cpp
@@ -651,6 +651,63 @@
                    " */"));
 }
 
+TEST_F(FormatTest, SplitsLongLinesInComments) {
+  EXPECT_EQ("/*\n"
+            "This is a long\n"
+            "comment that doesn't\n"
+            "fit on one line.   \n"
+            "*/",
+            format("/*\n"
+                   "This is a long      "
+                   "comment that doesn't "
+                   "fit on one line.   \n"
+                   "*/", getLLVMStyleWithColumns(20)));
+  EXPECT_EQ("/*\n"
+            " * This is a long\n"
+            " * comment that\n"
+            " * doesn't fit on\n"
+            " * one line.\n"
+            " */",
+            format("/*\n"
+                   " * This is a long comment that doesn't fit on one line.\n"
+                   " */", getLLVMStyleWithColumns(20)));
+  EXPECT_EQ("{\n"
+            "  /*\n"
+            "  This is another\n"
+            "  long comment that\n"
+            "  doesn't fit on one\n"
+            "  line\n"
+            "  */\n"
+            "}",
+            format("{\n"
+                   "/*\n"
+                   "This is another long comment that doesn't fit on one line\n"
+                   "*/\n"
+                   "}", getLLVMStyleWithColumns(20)));
+  EXPECT_EQ("{\n"
+            "  /*\n"
+            "   * This is\n"
+            "   * another comment\n"
+            "   * that doesn't\n"
+            "   * fit on one line\n"
+            "   */\n"
+            "}",
+            format("{\n"
+                   "/*\n"
+                   " * This is another comment that doesn't fit on one line\n"
+                   " */\n"
+                   "}", getLLVMStyleWithColumns(20)));
+  EXPECT_EQ("/*\n"
+            " * This is a long\n"
+            " * comment that\n"
+            " * doesn't fit on\n"
+            " * one line\n"
+            " */",
+            format("   /*\n"
+                   "    * This is a long comment that doesn't fit on one line\n"
+                   "    */", getLLVMStyleWithColumns(20)));
+}
+
 TEST_F(FormatTest, CommentsInStaticInitializers) {
   EXPECT_EQ(
       "static SomeType type = { aaaaaaaaaaaaaaaaaaaa, /* comment */\n"
-------------- next part --------------
A non-text attachment was scrubbed...
Name: D547.1.patch
Type: text/x-patch
Size: 6935 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20130315/cf538bbe/attachment.bin>


More information about the cfe-commits mailing list