summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--clang/lib/Format/Format.cpp108
-rw-r--r--clang/unittests/Format/FormatTestJS.cpp8
2 files changed, 72 insertions, 44 deletions
diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp
index 625f8554def..7fea162d5a7 100644
--- a/clang/lib/Format/Format.cpp
+++ b/clang/lib/Format/Format.cpp
@@ -792,47 +792,25 @@ std::string configurationAsText(const FormatStyle &Style) {
namespace {
-class Formatter : public TokenAnalyzer {
+class JavaScriptRequoter : public TokenAnalyzer {
public:
- Formatter(const Environment &Env, const FormatStyle &Style,
- bool *IncompleteFormat)
- : TokenAnalyzer(Env, Style), IncompleteFormat(IncompleteFormat) {}
+ JavaScriptRequoter(const Environment &Env, const FormatStyle &Style)
+ : TokenAnalyzer(Env, Style) {}
tooling::Replacements
analyze(TokenAnnotator &Annotator,
SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
FormatTokenLexer &Tokens) override {
- tooling::Replacements RequoteReplaces;
- deriveLocalStyle(AnnotatedLines);
AffectedRangeMgr.computeAffectedLines(AnnotatedLines.begin(),
AnnotatedLines.end());
-
- if (Style.Language == FormatStyle::LK_JavaScript &&
- Style.JavaScriptQuotes != FormatStyle::JSQS_Leave)
- requoteJSStringLiteral(AnnotatedLines, RequoteReplaces);
-
- for (unsigned i = 0, e = AnnotatedLines.size(); i != e; ++i) {
- Annotator.calculateFormattingInformation(*AnnotatedLines[i]);
- }
-
- Annotator.setCommentLineLevels(AnnotatedLines);
-
- WhitespaceManager Whitespaces(
- Env.getSourceManager(), Style,
- inputUsesCRLF(Env.getSourceManager().getBufferData(Env.getFileID())));
- ContinuationIndenter Indenter(Style, Tokens.getKeywords(),
- Env.getSourceManager(), Whitespaces, Encoding,
- BinPackInconclusiveFunctions);
- UnwrappedLineFormatter(&Indenter, &Whitespaces, Style, Tokens.getKeywords(),
- IncompleteFormat)
- .format(AnnotatedLines);
- return RequoteReplaces.merge(Whitespaces.generateReplacements());
+ tooling::Replacements Result;
+ requoteJSStringLiteral(AnnotatedLines, Result);
+ return Result;
}
private:
- // If the last token is a double/single-quoted string literal, generates a
- // replacement with a single/double quoted string literal, re-escaping the
- // contents in the process.
+ // Replaces double/single-quoted string literal as appropriate, re-escaping
+ // the contents in the process.
void requoteJSStringLiteral(SmallVectorImpl<AnnotatedLine *> &Lines,
tooling::Replacements &Result) {
for (AnnotatedLine *Line : Lines) {
@@ -844,8 +822,7 @@ private:
StringRef Input = FormatTok->TokenText;
if (FormatTok->Finalized || !FormatTok->isStringLiteral() ||
// NB: testing for not starting with a double quote to avoid
- // breaking
- // `template strings`.
+ // breaking `template strings`.
(Style.JavaScriptQuotes == FormatStyle::JSQS_Single &&
!Input.startswith("\"")) ||
(Style.JavaScriptQuotes == FormatStyle::JSQS_Double &&
@@ -870,7 +847,6 @@ private:
IsSingle ? "'" : "\"");
// Escape internal quotes.
- size_t ColumnWidth = FormatTok->TokenText.size();
bool Escaped = false;
for (size_t i = 1; i < Input.size() - 1; i++) {
switch (Input[i]) {
@@ -880,7 +856,6 @@ private:
(!IsSingle && Input[i + 1] == '\''))) {
// Remove this \, it's escaping a " or ' that no longer needs
// escaping
- ColumnWidth--;
Replace(Start.getLocWithOffset(i), 1, "");
continue;
}
@@ -891,7 +866,6 @@ private:
if (!Escaped && IsSingle == (Input[i] == '\'')) {
// Escape the quote.
Replace(Start.getLocWithOffset(i), 0, "\\");
- ColumnWidth++;
}
Escaped = false;
break;
@@ -900,16 +874,46 @@ private:
break;
}
}
-
- // For formatting, count the number of non-escaped single quotes in them
- // and adjust ColumnWidth to take the added escapes into account.
- // FIXME(martinprobst): this might conflict with code breaking a long
- // string literal (which clang-format doesn't do, yet). For that to
- // work, this code would have to modify TokenText directly.
- FormatTok->ColumnWidth = ColumnWidth;
}
}
}
+};
+
+class Formatter : public TokenAnalyzer {
+public:
+ Formatter(const Environment &Env, const FormatStyle &Style,
+ bool *IncompleteFormat)
+ : TokenAnalyzer(Env, Style), IncompleteFormat(IncompleteFormat) {}
+
+ tooling::Replacements
+ analyze(TokenAnnotator &Annotator,
+ SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
+ FormatTokenLexer &Tokens) override {
+ tooling::Replacements Result;
+ deriveLocalStyle(AnnotatedLines);
+ AffectedRangeMgr.computeAffectedLines(AnnotatedLines.begin(),
+ AnnotatedLines.end());
+ for (unsigned i = 0, e = AnnotatedLines.size(); i != e; ++i) {
+ Annotator.calculateFormattingInformation(*AnnotatedLines[i]);
+ }
+ Annotator.setCommentLineLevels(AnnotatedLines);
+
+ WhitespaceManager Whitespaces(
+ Env.getSourceManager(), Style,
+ inputUsesCRLF(Env.getSourceManager().getBufferData(Env.getFileID())));
+ ContinuationIndenter Indenter(Style, Tokens.getKeywords(),
+ Env.getSourceManager(), Whitespaces, Encoding,
+ BinPackInconclusiveFunctions);
+ UnwrappedLineFormatter(&Indenter, &Whitespaces, Style, Tokens.getKeywords(),
+ IncompleteFormat)
+ .format(AnnotatedLines);
+ for (const auto &R : Whitespaces.generateReplacements())
+ if (Result.add(R))
+ return Result;
+ return Result;
+ }
+
+private:
static bool inputUsesCRLF(StringRef Text) {
return Text.count('\r') * 2 > Text.count('\n');
@@ -1691,8 +1695,24 @@ tooling::Replacements reformat(const FormatStyle &Style, StringRef Code,
if (Expanded.DisableFormat)
return tooling::Replacements();
- std::unique_ptr<Environment> Env =
- Environment::CreateVirtualEnvironment(Code, FileName, Ranges);
+ auto Env = Environment::CreateVirtualEnvironment(Code, FileName, Ranges);
+
+ if (Style.Language == FormatStyle::LK_JavaScript &&
+ Style.JavaScriptQuotes != FormatStyle::JSQS_Leave) {
+ JavaScriptRequoter Requoter(*Env, Expanded);
+ tooling::Replacements Requotes = Requoter.process();
+ if (!Requotes.empty()) {
+ auto NewCode = applyAllReplacements(Code, Requotes);
+ if (NewCode) {
+ auto NewEnv = Environment::CreateVirtualEnvironment(
+ *NewCode, FileName,
+ tooling::calculateRangesAfterReplacements(Requotes, Ranges));
+ Formatter Format(*NewEnv, Expanded, IncompleteFormat);
+ return Requotes.merge(Format.process());
+ }
+ }
+ }
+
Formatter Format(*Env, Expanded, IncompleteFormat);
return Format.process();
}
diff --git a/clang/unittests/Format/FormatTestJS.cpp b/clang/unittests/Format/FormatTestJS.cpp
index 569f0657617..22ed04f6304 100644
--- a/clang/unittests/Format/FormatTestJS.cpp
+++ b/clang/unittests/Format/FormatTestJS.cpp
@@ -1342,6 +1342,14 @@ TEST_F(FormatTestJS, RequoteAndIndent) {
" 'double quoted string that needs wrapping');",
"let x = someVeryLongFunctionThatGoesOnAndOn("
"\"double quoted string that needs wrapping\");");
+
+ verifyFormat("let x =\n"
+ " 'foo\\'oo';\n"
+ "let x =\n"
+ " 'foo\\'oo';",
+ "let x=\"foo'oo\";\n"
+ "let x=\"foo'oo\";",
+ getGoogleJSStyleWithColumns(15));
}
TEST_F(FormatTestJS, RequoteStringsDouble) {
OpenPOWER on IntegriCloud