mprobst updated this revision to Diff 48338.
mprobst added a comment.

Fixed typo.


http://reviews.llvm.org/D17385

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

Index: unittests/Format/FormatTestJS.cpp
===================================================================
--- unittests/Format/FormatTestJS.cpp
+++ unittests/Format/FormatTestJS.cpp
@@ -250,7 +250,7 @@
   verifyFormat("f({'a': [{}]});");
 }
 
-TEST_F(FormatTestJS, SingleQuoteStrings) {
+TEST_F(FormatTestJS, SingleQuotedStrings) {
   verifyFormat("this.function('', true);");
 }
 
@@ -1085,5 +1085,16 @@
                    getGoogleJSStyleWithColumns(20)));
 }
 
+TEST_F(FormatTestJS, RequoteDoubleQuotedStrings) {
+  EXPECT_EQ("var x = 'foo';", format("var x = \"foo\";"));
+  EXPECT_EQ("var x = 'fo\\'o\\'';", format("var x = \"fo'o'\";"));
+  EXPECT_EQ("var x = 'fo\\'o\\'';", format("var x = \"fo\\'o'\";"));
+  EXPECT_EQ("var x =\n"
+            "    'foo\\'';",
+            // Code below is 15 chars wide, doesn't fit into the line with the
+            // \ escape added.
+            format("var x = \"foo'\";", getGoogleJSStyleWithColumns(15)));
+}
+
 } // end namespace tooling
 } // end namespace clang
Index: lib/Format/Format.cpp
===================================================================
--- lib/Format/Format.cpp
+++ lib/Format/Format.cpp
@@ -30,6 +30,7 @@
 #include "llvm/Support/Regex.h"
 #include "llvm/Support/YAMLTraits.h"
 #include <queue>
+#include <sstream>
 #include <string>
 
 #define DEBUG_TYPE "format-formatter"
@@ -1328,6 +1329,35 @@
       Column = FormatTok->LastLineColumnWidth;
     }
 
+    if (Style.Language == FormatStyle::LK_JavaScript &&
+        FormatTok->isStringLiteral() && FormatTok->TokenText.startswith("\"")) {
+      // Double quoted JavaScript strings get requoted as single quoted below.
+      // For formatting, count the number of non-escaped single quotes in them
+      // and adjust ColumnWidth to take the later added escapes into account.
+
+      StringRef Input = FormatTok->TokenText;
+      bool Escaped = false;
+      size_t ColumnWidth = FormatTok->TokenText.size();
+      for (size_t i = 0; i != Input.size(); ++i) {
+        switch (Input[i]) {
+        case '\\':
+          Escaped = !Escaped;
+          break;
+        case '\'':
+          if (!Escaped) {
+            // Will later need to insert a \ to escape the double quote.
+            ColumnWidth++;
+          }
+          Escaped = false;
+          break;
+        default:
+          Escaped = false;
+          break;
+        }
+      }
+      FormatTok->ColumnWidth = ColumnWidth;
+    }
+
     if (Style.Language == FormatStyle::LK_Cpp) {
       if (!(Tokens.size() > 0 && Tokens.back()->Tok.getIdentifierInfo() &&
             Tokens.back()->Tok.getIdentifierInfo()->getPPKeywordID() ==
@@ -1495,7 +1525,12 @@
     UnwrappedLineFormatter(&Indenter, &Whitespaces, Style, Tokens.getKeywords(),
                            IncompleteFormat)
         .format(AnnotatedLines);
-    return Whitespaces.generateReplacements();
+    tooling::Replacements Replaces = Whitespaces.generateReplacements();
+    if (Style.Language == FormatStyle::LK_JavaScript) {
+      FormatToken *Tok = (*AnnotatedLines.begin())->First;
+      requoteJSStringLiterals(Replaces, Tok);
+    }
+    return Replaces;
   }
 
 private:
@@ -1538,6 +1573,42 @@
     return SomeLineAffected;
   }
 
+  // Finds all double-quoted string literals, and replaces them with single
+  // quoted string literals, escaping the contents in the process.
+  // The width of the extra \ escapes is taken into account in getNextToken.
+  void requoteJSStringLiterals(tooling::Replacements &Replaces,
+                               FormatToken *Current) {
+    for (; Current != nullptr; Current = Current->Next) {
+      if (!Current->isStringLiteral() || !Current->TokenText.startswith("\""))
+        continue;
+      StringRef Input = Current->TokenText;
+      std::stringstream Res;
+      Res << '\'';
+      bool escaped = false;
+      for (size_t i = 1; i < Input.size() - 1; i++) {
+        switch (Input[i]) {
+        case '\\':
+          escaped = !escaped;
+          break;
+        case '\'':
+          if (!escaped) {
+            Res << '\\';
+          }
+          escaped = false;
+          break;
+        default:
+          escaped = false;
+          break;
+        }
+        Res << Input[i];
+      }
+      Res << '\'';
+      SourceRange Range(Current->Tok.getLocation(), Current->Tok.getEndLoc());
+      Replaces.insert(tooling::Replacement(
+          SourceMgr, CharSourceRange::getCharRange(Range), Res.str()));
+    }
+  }
+
   // Determines whether 'Line' is affected by the SourceRanges given as input.
   // Returns \c true if line or one if its children is affected.
   bool nonPPLineAffected(AnnotatedLine *Line,
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to