Skip to content

Commit 7b701d5

Browse files
committed
[Lexer] Improve diagnostics for single-quote string literal
Ignore the contents of interpolation.
1 parent e6e55c2 commit 7b701d5

File tree

2 files changed

+31
-23
lines changed

2 files changed

+31
-23
lines changed

lib/Parse/Lexer.cpp

Lines changed: 28 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1799,32 +1799,37 @@ void Lexer::lexStringLiteral(unsigned CustomDelimiterLen) {
17991799
"Single quoted string cannot have custom delimitor, nor multiline");
18001800
assert(*TokStart == '\'' && CurPtr[-1] == '\'');
18011801

1802-
StringRef orig(TokStart, CurPtr - TokStart);
1803-
llvm::SmallString<32> replacement;
1804-
replacement += '"';
1805-
std::string str = orig.slice(1, orig.size() - 1).str();
1806-
std::string quot = "\"";
1807-
size_t pos = 0;
1808-
while (pos != str.length()) {
1809-
if (str.at(pos) == '\\') {
1810-
if (str.at(pos + 1) == '\'') {
1811-
// Un-escape escaped single quotes.
1812-
str.replace(pos, 2, "'");
1813-
++pos;
1814-
} else {
1815-
// Skip over escaped characters.
1816-
pos += 2;
1802+
SmallString<32> replacement;
1803+
replacement.push_back('"');
1804+
const char *Ptr = TokStart + 1;
1805+
const char *OutputPtr = Ptr;
1806+
1807+
while (*Ptr++ != '\'') {
1808+
if (Ptr[-1] == '\\') {
1809+
if (*Ptr == '\'') {
1810+
replacement.append(OutputPtr, Ptr - 1);
1811+
OutputPtr = Ptr + 1;
1812+
// Un-escape single quotes.
1813+
replacement.push_back('\'');
1814+
} else if (*Ptr == '(') {
1815+
// Preserve the contents of interpolation.
1816+
Ptr = skipToEndOfInterpolatedExpression(Ptr + 1, replacement.end(),
1817+
/*IsMultiline=*/false);
1818+
assert(*Ptr == ')');
18171819
}
1818-
} else if (str.at(pos) == '"') {
1819-
str.replace(pos, 1, "\\\"");
1820-
// Advance past the newly added ["\""].
1821-
pos += 2;
1822-
} else {
1823-
++pos;
1820+
// Skip over escaped characters.
1821+
++Ptr;
1822+
} else if (Ptr[-1] == '"') {
1823+
replacement.append(OutputPtr, Ptr - 1);
1824+
OutputPtr = Ptr;
1825+
// Escape double quotes.
1826+
replacement.append("\\\"");
18241827
}
18251828
}
1826-
replacement += StringRef(str);
1827-
replacement += '"';
1829+
assert(Ptr == CurPtr);
1830+
replacement.append(OutputPtr, Ptr - 1);
1831+
replacement.push_back('"');
1832+
18281833
diagnose(TokStart, diag::lex_single_quote_string)
18291834
.fixItReplaceChars(getSourceLoc(TokStart), getSourceLoc(CurPtr),
18301835
replacement);

test/expr/expressions.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -505,6 +505,9 @@ func testSingleQuoteStringLiterals() {
505505
_ = 'ab\nc' // expected-error{{single-quoted string literal found, use '"'}}{{7-14="ab\\nc"}}
506506

507507
_ = "abc\('def')" // expected-error{{single-quoted string literal found, use '"'}}{{13-18="def"}}
508+
_ = 'ab\("c")' // expected-error{{single-quoted string literal found, use '"'}}{{7-17="ab\\("c")"}}
509+
_ = 'a\('b')c' // expected-error{{single-quoted string literal found, use '"'}}{{7-17="a\\('b')c"}}
510+
// expected-error@-1{{single-quoted string literal found, use '"'}}{{11-14="b"}}
508511

509512
_ = "abc' // expected-error{{unterminated string literal}}
510513
_ = 'abc" // expected-error{{unterminated string literal}}

0 commit comments

Comments
 (0)