mprobst updated this revision to Diff 48945.
mprobst marked an inline comment as done.
mprobst added a comment.

- Move code closer together by piping Replacements into the FormatTokenLexer.


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"
@@ -766,13 +767,13 @@
 class FormatTokenLexer {
 public:
   FormatTokenLexer(SourceManager &SourceMgr, FileID ID, FormatStyle &Style,
-                   encoding::Encoding Encoding)
+                   encoding::Encoding Encoding, tooling::Replacements &Replaces)
       : FormatTok(nullptr), IsFirstToken(true), GreaterStashed(false),
         LessStashed(false), Column(0), TrailingWhitespace(0),
         SourceMgr(SourceMgr), ID(ID), Style(Style),
         IdentTable(getFormattingLangOpts(Style)), Keywords(IdentTable),
-        Encoding(Encoding), FirstInLineIndex(0), FormattingDisabled(false),
-        MacroBlockBeginRegex(Style.MacroBlockBegin),
+        Encoding(Encoding), Replaces(Replaces), FirstInLineIndex(0),
+        FormattingDisabled(false), MacroBlockBeginRegex(Style.MacroBlockBegin),
         MacroBlockEndRegex(Style.MacroBlockEnd) {
     Lex.reset(new Lexer(ID, SourceMgr.getBuffer(ID), SourceMgr,
                         getFormattingLangOpts(Style)));
@@ -791,6 +792,8 @@
       if (Style.Language == FormatStyle::LK_JavaScript)
         tryParseJSRegexLiteral();
       tryMergePreviousTokens();
+      if (Style.Language == FormatStyle::LK_JavaScript)
+        tryRequoteJSStringLiteral();
       if (Tokens.back()->NewlinesBefore > 0 || Tokens.back()->IsMultiline)
         FirstInLineIndex = Tokens.size() - 1;
     } while (Tokens.back()->Tok.isNot(tok::eof));
@@ -1061,6 +1064,48 @@
     return false;
   }
 
+  // If the last token is a double-quoted string literal, generates a
+  // replacement with a single quoted string literal, escaping the contents in
+  // the process.
+  void tryRequoteJSStringLiteral() {
+    FormatToken *FormatTok = Tokens.back();
+    if (!FormatTok->isStringLiteral() || !FormatTok->TokenText.startswith("\""))
+      return;
+
+    StringRef Input = FormatTok->TokenText;
+    size_t ColumnWidth = FormatTok->TokenText.size();
+    std::string Res("'");
+    llvm::raw_string_ostream Out(Res);
+    bool Escaped = false;
+    for (size_t i = 1; i < Input.size() - 1; i++) {
+      switch (Input[i]) {
+      case '\\':
+        Escaped = !Escaped;
+        break;
+      case '\'':
+        if (!Escaped) {
+          Out << '\\';
+          ColumnWidth++;
+        }
+        Escaped = false;
+        break;
+      default:
+        Escaped = false;
+        break;
+      }
+      Out << Input[i];
+    }
+    Out << '\'';
+
+    // For formatting, count the number of non-escaped single quotes in them
+    // and adjust ColumnWidth to take the added escapes into account.
+    FormatTok->ColumnWidth = ColumnWidth;
+
+    SourceRange Range(FormatTok->Tok.getLocation(), FormatTok->Tok.getEndLoc());
+    Replaces.insert(tooling::Replacement(
+        SourceMgr, CharSourceRange::getCharRange(Range), Out.str()));
+  }
+
   bool tryMerge_TMacro() {
     if (Tokens.size() < 4)
       return false;
@@ -1359,6 +1404,7 @@
   IdentifierTable IdentTable;
   AdditionalKeywords Keywords;
   encoding::Encoding Encoding;
+  tooling::Replacements &Replaces;
   llvm::SpecificBumpPtrAllocator<FormatToken> Allocator;
   // Index (in 'Tokens') of the last token that starts a new line.
   unsigned FirstInLineIndex;
@@ -1443,7 +1489,7 @@
 
   tooling::Replacements format(bool *IncompleteFormat) {
     tooling::Replacements Result;
-    FormatTokenLexer Tokens(SourceMgr, ID, Style, Encoding);
+    FormatTokenLexer Tokens(SourceMgr, ID, Style, Encoding, Result);
 
     UnwrappedLineParser Parser(Style, Tokens.getKeywords(), Tokens.lex(),
                                *this);
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to