clang-format: [JS] Optionally re-quote string literals.

Turns "foo" into 'foo' (or vice versa, depending on configuration).
This makes it more convenient to follow the Google JavaScript style
guide:
https://google.github.io/styleguide/javascriptguide.xml?showone=Strings#Strings

This functionality is behind the option "JavaScriptQuotes", which can be:

  * "leave" (no re-quoting)
  * "single" (change to single quotes)
  * "double" (change to double quotes)

This also changes single quoted JavaScript string literals to be treated
as tok::string_literal, not tok::char_literal, which fixes two unrelated
tests.

Patch by Martin Probst. Thank you.

llvm-svn: 262534
diff --git a/clang/unittests/Format/FormatTestJS.cpp b/clang/unittests/Format/FormatTestJS.cpp
index 39e4ea8..589a7e4 100644
--- a/clang/unittests/Format/FormatTestJS.cpp
+++ b/clang/unittests/Format/FormatTestJS.cpp
@@ -257,7 +257,7 @@
   verifyFormat("f({'a': [{}]});");
 }
 
-TEST_F(FormatTestJS, SingleQuoteStrings) {
+TEST_F(FormatTestJS, SingleQuotedStrings) {
   verifyFormat("this.function('', true);");
 }
 
@@ -883,7 +883,7 @@
   verifyFormat("import {\n"
                "  X,\n"
                "  Y,\n"
-               "} from 'some/long/module.js';",
+               "} from\n    'some/long/module.js';",
                getGoogleJSStyleWithColumns(20));
   verifyFormat("import {X as myLocalX, Y as myLocalY} from 'some/module.js';");
   verifyFormat("import * as lib from 'some/module.js';");
@@ -1094,5 +1094,36 @@
                    getGoogleJSStyleWithColumns(20)));
 }
 
+TEST_F(FormatTestJS, RequoteStringsSingle) {
+  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)));
+  // Removes no-longer needed \ escape from ".
+  EXPECT_EQ("var x = 'fo\"o';", format("var x = \"fo\\\"o\";"));
+  // Code below fits into 15 chars *after* removing the \ escape.
+  EXPECT_EQ("var x = 'fo\"o';",
+            format("var x = \"fo\\\"o\";", getGoogleJSStyleWithColumns(15)));
+}
+
+TEST_F(FormatTestJS, RequoteStringsDouble) {
+  FormatStyle DoubleQuotes = getGoogleStyle(FormatStyle::LK_JavaScript);
+  DoubleQuotes.JavaScriptQuotes = FormatStyle::JSQS_Double;
+  verifyFormat("var x = \"foo\";", DoubleQuotes);
+  EXPECT_EQ("var x = \"foo\";", format("var x = 'foo';", DoubleQuotes));
+  EXPECT_EQ("var x = \"fo'o\";", format("var x = 'fo\\'o';", DoubleQuotes));
+}
+
+TEST_F(FormatTestJS, RequoteStringsLeave) {
+  FormatStyle LeaveQuotes = getGoogleStyle(FormatStyle::LK_JavaScript);
+  LeaveQuotes.JavaScriptQuotes = FormatStyle::JSQS_Leave;
+  verifyFormat("var x = \"foo\";", LeaveQuotes);
+  verifyFormat("var x = 'foo';", LeaveQuotes);
+}
+
 } // end namespace tooling
 } // end namespace clang