Support for double width characters.

Summary: Only works for UTF-8-encoded files.

Reviewers: djasper

Reviewed By: djasper

CC: cfe-commits, klimek

Differential Revision: http://llvm-reviews.chandlerc.com/D1311

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@187935 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Format/BreakableToken.cpp b/lib/Format/BreakableToken.cpp
index 3b29137..c2365f1 100644
--- a/lib/Format/BreakableToken.cpp
+++ b/lib/Format/BreakableToken.cpp
@@ -20,6 +20,7 @@
 #include "clang/Format/Format.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/Support/Debug.h"
+#include "llvm/Support/Locale.h"
 #include <algorithm>
 
 namespace clang {
@@ -38,6 +39,15 @@
   }
 }
 
+static unsigned columnWidth(StringRef Text, encoding::Encoding Encoding) {
+  if (Encoding == encoding::Encoding_UTF8) {
+    int ContentWidth = llvm::sys::locale::columnWidth(Text);
+    if (ContentWidth >= 0)
+      return ContentWidth;
+  }
+  return encoding::getCodePointCount(Text, Encoding);
+}
+
 static BreakableToken::Split getCommentSplit(StringRef Text,
                                              unsigned ContentStartColumn,
                                              unsigned ColumnLimit,
@@ -49,9 +59,12 @@
   unsigned MaxSplitBytes = 0;
 
   for (unsigned NumChars = 0;
-       NumChars < MaxSplit && MaxSplitBytes < Text.size(); ++NumChars)
-    MaxSplitBytes +=
+       NumChars < MaxSplit && MaxSplitBytes < Text.size();) {
+    unsigned NumBytes =
         encoding::getCodePointNumBytes(Text[MaxSplitBytes], Encoding);
+    NumChars += columnWidth(Text.substr(MaxSplitBytes, NumBytes), Encoding);
+    MaxSplitBytes += NumBytes;
+  }
 
   StringRef::size_type SpaceOffset = Text.find_last_of(Blanks, MaxSplitBytes);
   if (SpaceOffset == StringRef::npos ||
@@ -84,9 +97,8 @@
     return BreakableToken::Split(StringRef::npos, 0);
   if (ColumnLimit <= ContentStartColumn)
     return BreakableToken::Split(StringRef::npos, 0);
-  unsigned MaxSplit =
-      std::min<unsigned>(ColumnLimit - ContentStartColumn,
-                         encoding::getCodePointCount(Text, Encoding) - 1);
+  unsigned MaxSplit = std::min<unsigned>(ColumnLimit - ContentStartColumn,
+                                         columnWidth(Text, Encoding) - 1);
   StringRef::size_type SpaceOffset = 0;
   StringRef::size_type SlashOffset = 0;
   StringRef::size_type WordStartOffset = 0;
@@ -98,7 +110,7 @@
       Chars += Advance;
     } else {
       Advance = encoding::getCodePointNumBytes(Text[0], Encoding);
-      Chars += 1;
+      Chars += columnWidth(Text.substr(0, Advance), Encoding);
     }
 
     if (Chars > MaxSplit)
@@ -131,7 +143,7 @@
 unsigned BreakableSingleLineToken::getLineLengthAfterSplit(
     unsigned LineIndex, unsigned Offset, StringRef::size_type Length) const {
   return StartColumn + Prefix.size() + Postfix.size() +
-         encoding::getCodePointCount(Line.substr(Offset, Length), Encoding);
+         columnWidth(Line.substr(Offset, Length), Encoding);
 }
 
 BreakableSingleLineToken::BreakableSingleLineToken(
@@ -329,8 +341,7 @@
 unsigned BreakableBlockComment::getLineLengthAfterSplit(
     unsigned LineIndex, unsigned Offset, StringRef::size_type Length) const {
   return getContentStartColumn(LineIndex, Offset) +
-         encoding::getCodePointCount(Lines[LineIndex].substr(Offset, Length),
-                                     Encoding) +
+         columnWidth(Lines[LineIndex].substr(Offset, Length), Encoding) +
          // The last line gets a "*/" postfix.
          (LineIndex + 1 == Lines.size() ? 2 : 0);
 }