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