Skip to content

Commit 8034962

Browse files
authored
Merge pull request #11204 from DougGregor/lex-multiline-nlescape-last-4.0
[4.0] [SE-0182][Lexer] Diagnose escaped newline at the end of the last line in multiline string
2 parents ce46aef + b664f90 commit 8034962

File tree

5 files changed

+158
-8
lines changed

5 files changed

+158
-8
lines changed

include/swift/AST/DiagnosticsParse.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,8 @@ NOTE(lex_multiline_string_indent_should_match_here,none,
142142
"should match %select{space|tab}0 here", (unsigned))
143143
NOTE(lex_multiline_string_indent_change_line,none,
144144
"change indentation of %select{this line|these lines}0 to match closing delimiter", (bool))
145+
ERROR(lex_escaped_newline_at_lastline,none,
146+
"escaped newline at the last line is not allowed", ())
145147

146148
ERROR(lex_invalid_character,none,
147149
"invalid character in source file", ())

lib/Parse/Lexer.cpp

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1424,13 +1424,28 @@ getMultilineTrailingIndent(const Token &Str, DiagnosticEngine *Diags) {
14241424
continue;
14251425
case '\n':
14261426
case '\r': {
1427-
auto bytes = start + 1;
1428-
auto length = end-(start+1);
1429-
1430-
auto bytesLoc = Lexer::getSourceLoc(bytes);
1431-
auto string = StringRef(bytes, length);
1432-
1433-
return std::make_tuple(string, bytesLoc);
1427+
start++;
1428+
auto startLoc = Lexer::getSourceLoc(start);
1429+
auto string = StringRef(start, end - start);
1430+
1431+
// Disallow escaped newline in the last line.
1432+
if (Diags) {
1433+
auto *Ptr = start - 1;
1434+
if (*Ptr == '\n') --Ptr;
1435+
if (*Ptr == '\r') --Ptr;
1436+
auto *LineEnd = Ptr + 1;
1437+
while (Ptr > begin && (*Ptr == ' ' || *Ptr == '\t')) --Ptr;
1438+
if (*Ptr == '\\') {
1439+
auto escapeLoc = Lexer::getSourceLoc(Ptr);
1440+
bool invalid = true;
1441+
while (*--Ptr == '\\') invalid = !invalid;
1442+
if (invalid)
1443+
Diags->diagnose(escapeLoc, diag::lex_escaped_newline_at_lastline)
1444+
.fixItRemoveChars(escapeLoc, Lexer::getSourceLoc(LineEnd));
1445+
}
1446+
}
1447+
1448+
return std::make_tuple(string, startLoc);
14341449
}
14351450
default:
14361451
sawNonWhitespace = true;

test/Parse/multiline_errors.swift

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,21 @@ _ = """
2828
// expected-note@-1{{should match tab here}}
2929
// expected-note@-3{{change indentation of this line to match closing delimiter}} {{1-1= }}
3030

31+
_ = """
32+
\(42
33+
)
34+
""" // expected-error@-1{{insufficient indentation of line in multi-line string literal}}
35+
// expected-note@-1{{should match space here}}
36+
// expected-note@-3{{change indentation of this line to match closing delimiter}} {{1-1= }}
37+
38+
_ = """
39+
Foo
40+
\
41+
Bar
42+
""" // expected-error@-2{{insufficient indentation of line in multi-line string literal}}
43+
// expected-note@-1{{should match space here}}
44+
// expected-note@-4{{change indentation of this line to match closing delimiter}} {{1-1= }}
45+
3146
// a tab is not the same as multiple spaces for de-indentation
3247
_ = """
3348
Thirteen
@@ -126,3 +141,46 @@ _ = """
126141
line two
127142
"""
128143
// expected-error@-3 {{invalid escape sequence in literal}}
144+
145+
_ = """
146+
line one
147+
line two\
148+
"""
149+
// expected-error@-2 {{escaped newline at the last line is not allowed}} {{11-12=}}
150+
151+
_ = """
152+
\\\
153+
"""
154+
// expected-error@-2 {{escaped newline at the last line is not allowed}} {{5-10=}}
155+
156+
_ = """
157+
\(42)\
158+
"""
159+
// expected-error@-2 {{escaped newline at the last line is not allowed}} {{8-11=}}
160+
161+
_ = """
162+
foo\
163+
"""
164+
// expected-error@-2 {{escaped newline at the last line is not allowed}} {{6-7=}}
165+
166+
_ = """
167+
foo\ """
168+
// expected-error@-1 {{escaped newline at the last line is not allowed}} {{6-7=}}
169+
170+
_ = """
171+
foo\
172+
""" // OK because LF + CR is two new lines.
173+
174+
_ = """
175+
\
176+
"""
177+
// expected-error@-2 {{escaped newline at the last line is not allowed}} {{1-2=}}
178+
// expected-error@-3{{insufficient indentation of line in multi-line string literal}}
179+
// expected-note@-3{{should match space here}}
180+
// expected-note@-5{{change indentation of this line to match closing delimiter}} {{1-1= }}
181+
182+
_ = """\
183+
"""
184+
// FIXME: Bad diagnostics
185+
// expected-error@-3 {{multi-line string literal content must begin on a new line}}
186+
// expected-error@-4 {{escaped newline at the last line is not allowed}} {{8-9=}}

test/Parse/multiline_normalize_newline.swift

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
// RUN: %target-swift-frontend -dump-parse %s 2>&1 | %FileCheck %s
2+
3+
// CR
4+
_ = """"""
5+
//CHECK: string_literal_expr {{.*}} value=""
6+
7+
_ = """ test """
8+
//CHECK: string_literal_expr {{.*}} value="test"
9+
10+
// CR+LF
11+
_ = """
12+
"""
13+
//CHECK: string_literal_expr {{.*}} value=""
14+
15+
_ = """
16+
test
17+
"""
18+
//CHECK: string_literal_expr {{.*}} value="test"
19+
20+
// CR+LF
21+
_ = """
22+
"""
23+
//CHECK: string_literal_expr {{.*}} value=""
24+
_ = """
25+
test
26+
test
27+
"""
28+
//CHECK: string_literal_expr {{.*}} value="test\ntest"
29+
30+
// LF+CR
31+
_ = """
32+
foo
33+
foo
34+
"""
35+
//CHECK: string_literal_expr {{.*}} value="\nfoo\n\nfoo\n"
36+
37+
// LF+CR+LF
38+
_ = """
39+
40+
foo
41+
42+
foo
43+
44+
"""
45+
//CHECK: string_literal_expr {{.*}} value="\nfoo\n\nfoo\n"
46+
47+
// Mixed no-indent.
48+
_ = """
49+
<LF
50+
<LF<CR
51+
<CR+LF
52+
"""
53+
//CHECK: string_literal_expr {{.*}} value="<LF\n<LF\n<CR\n<CR+LF"
54+
55+
// Mixed indent.
56+
_ = """
57+
<LF
58+
<LF <CR
59+
<CR+LF
60+
"""
61+
//CHECK: string_literal_expr {{.*}} value="<LF\n<LF\n<CR\n<CR+LF"
62+
63+
// Empty line CR, CR+LF, LF.
64+
_ = """
65+
foo
66+
67+
68+
bar
69+
"""
70+
//CHECK: string_literal_expr {{.*}} value="foo\n\n\n\nbar"

test/Parse/multiline_string.swift

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,11 @@ _ = """
8282
"""
8383
// CHECK: "\\"
8484

85+
_ = """
86+
\\
87+
"""
88+
// CHECK: "\\"
89+
8590
_ = """
8691
8792
ABC
@@ -122,7 +127,7 @@ _ = """
122127
\("""
123128
substring2 \
124129
substring3
125-
""")\
130+
""")
126131
""") \
127132
whitepsace
128133
"""

0 commit comments

Comments
 (0)