Ensure unterminated string error is reported on visible characters
Change-Id: Ie6321062b71a45293a91a3a50fc4d24b2633235c
Reviewed-on: https://dart-review.googlesource.com/c/80502
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
Commit-Queue: Dan Rubel <danrubel@google.com>
diff --git a/pkg/front_end/lib/src/fasta/scanner/abstract_scanner.dart b/pkg/front_end/lib/src/fasta/scanner/abstract_scanner.dart
index 643a546..91812bb 100644
--- a/pkg/front_end/lib/src/fasta/scanner/abstract_scanner.dart
+++ b/pkg/front_end/lib/src/fasta/scanner/abstract_scanner.dart
@@ -1017,7 +1017,7 @@
/**
* [next] is the first character after the quote.
- * [start] is the scanOffset of the quote.
+ * [quoteStart] is the scanOffset of the quote.
*
* The token contains a substring of the source file, including the
* string quotes, backslashes for escaping. For interpolated strings,
@@ -1027,7 +1027,8 @@
*
* gives StringToken("a $), StringToken(b) and StringToken( c").
*/
- int tokenizeSingleLineString(int next, int quoteChar, int start) {
+ int tokenizeSingleLineString(int next, int quoteChar, int quoteStart) {
+ int start = quoteStart;
bool asciiOnly = true;
while (!identical(next, quoteChar)) {
if (identical(next, $BACKSLASH)) {
@@ -1044,7 +1045,7 @@
identical(next, $CR) ||
identical(next, $EOF))) {
if (!asciiOnly) handleUnicode(start);
- unterminatedString(quoteChar, start,
+ unterminatedString(quoteChar, quoteStart, start,
asciiOnly: asciiOnly, isMultiLine: false, isRaw: false);
return next;
}
@@ -1103,17 +1104,17 @@
return next;
}
- int tokenizeSingleLineRawString(int next, int quoteChar, int start) {
+ int tokenizeSingleLineRawString(int next, int quoteChar, int quoteStart) {
bool asciiOnly = true;
while (next != $EOF) {
if (identical(next, quoteChar)) {
- if (!asciiOnly) handleUnicode(start);
+ if (!asciiOnly) handleUnicode(quoteStart);
next = advance();
- appendSubstringToken(TokenType.STRING, start, asciiOnly);
+ appendSubstringToken(TokenType.STRING, quoteStart, asciiOnly);
return next;
} else if (identical(next, $LF) || identical(next, $CR)) {
- if (!asciiOnly) handleUnicode(start);
- unterminatedString(quoteChar, start,
+ if (!asciiOnly) handleUnicode(quoteStart);
+ unterminatedString(quoteChar, quoteStart, quoteStart,
asciiOnly: asciiOnly, isMultiLine: false, isRaw: true);
return next;
} else if (next > 127) {
@@ -1121,16 +1122,16 @@
}
next = advance();
}
- if (!asciiOnly) handleUnicode(start);
- unterminatedString(quoteChar, start,
+ if (!asciiOnly) handleUnicode(quoteStart);
+ unterminatedString(quoteChar, quoteStart, quoteStart,
asciiOnly: asciiOnly, isMultiLine: false, isRaw: true);
return next;
}
- int tokenizeMultiLineRawString(int quoteChar, int start) {
+ int tokenizeMultiLineRawString(int quoteChar, int quoteStart) {
bool asciiOnlyString = true;
bool asciiOnlyLine = true;
- int unicodeStart = start;
+ int unicodeStart = quoteStart;
int next = advance(); // Advance past the (last) quote (of three).
outer:
while (!identical(next, $EOF)) {
@@ -1156,19 +1157,20 @@
if (identical(next, quoteChar)) {
if (!asciiOnlyLine) handleUnicode(unicodeStart);
next = advance();
- appendSubstringToken(TokenType.STRING, start, asciiOnlyString);
+ appendSubstringToken(TokenType.STRING, quoteStart, asciiOnlyString);
return next;
}
}
}
if (!asciiOnlyLine) handleUnicode(unicodeStart);
- unterminatedString(quoteChar, start,
+ unterminatedString(quoteChar, quoteStart, quoteStart,
asciiOnly: asciiOnlyLine, isMultiLine: true, isRaw: true);
return next;
}
- int tokenizeMultiLineString(int quoteChar, int start, bool raw) {
- if (raw) return tokenizeMultiLineRawString(quoteChar, start);
+ int tokenizeMultiLineString(int quoteChar, int quoteStart, bool raw) {
+ if (raw) return tokenizeMultiLineRawString(quoteChar, quoteStart);
+ int start = quoteStart;
bool asciiOnlyString = true;
bool asciiOnlyLine = true;
int unicodeStart = start;
@@ -1215,7 +1217,7 @@
next = advance();
}
if (!asciiOnlyLine) handleUnicode(unicodeStart);
- unterminatedString(quoteChar, start,
+ unterminatedString(quoteChar, quoteStart, start,
asciiOnly: asciiOnlyString, isMultiLine: true, isRaw: false);
return next;
}
@@ -1230,14 +1232,16 @@
return advanceAfterError(shouldAdvance);
}
- void unterminatedString(int quoteChar, int start,
+ void unterminatedString(int quoteChar, int quoteStart, int start,
{bool asciiOnly, bool isMultiLine, bool isRaw}) {
String suffix = new String.fromCharCodes(
isMultiLine ? [quoteChar, quoteChar, quoteChar] : [quoteChar]);
String prefix = isRaw ? 'r$suffix' : suffix;
appendSyntheticSubstringToken(TokenType.STRING, start, asciiOnly, suffix);
- appendErrorToken(new UnterminatedString(prefix, tokenStart, stringOffset));
+ // Ensure that the error is reported on a visible token
+ int errorStart = tokenStart < stringOffset ? tokenStart : quoteStart;
+ appendErrorToken(new UnterminatedString(prefix, errorStart, stringOffset));
}
int advanceAfterError(bool shouldAdvance) {
diff --git a/pkg/front_end/lib/src/scanner/errors.dart b/pkg/front_end/lib/src/scanner/errors.dart
index 8822805..dc45f52 100644
--- a/pkg/front_end/lib/src/scanner/errors.dart
+++ b/pkg/front_end/lib/src/scanner/errors.dart
@@ -118,8 +118,9 @@
case "UNTERMINATED_STRING_LITERAL":
// TODO(paulberry,ahe): Fasta reports the error location as the entire
// string; analyzer expects the end of the string.
- charOffset = endOffset - 1;
- return _makeError(ScannerErrorCode.UNTERMINATED_STRING_LITERAL, null);
+ reportError(
+ ScannerErrorCode.UNTERMINATED_STRING_LITERAL, endOffset - 1, null);
+ return;
case "UNTERMINATED_MULTI_LINE_COMMENT":
// TODO(paulberry,ahe): Fasta reports the error location as the entire
diff --git a/pkg/front_end/testcases/regress/issue_29976.dart.direct.expect b/pkg/front_end/testcases/regress/issue_29976.dart.direct.expect
index b2fd9b3..e64910f 100644
--- a/pkg/front_end/testcases/regress/issue_29976.dart.direct.expect
+++ b/pkg/front_end/testcases/regress/issue_29976.dart.direct.expect
@@ -13,7 +13,9 @@
// "x${x*"'"é'}x
// ^
//
-// pkg/front_end/testcases/regress/issue_29976.dart:12:1: Error: String starting with " must end with ".
+// pkg/front_end/testcases/regress/issue_29976.dart:9:5: Error: String starting with " must end with ".
+// "x${x*"'"é'}x
+// ^
//
// pkg/front_end/testcases/regress/issue_29976.dart:12:1: Error: Expected a declaration, but got ''.
//
@@ -48,7 +50,9 @@
// "x${x*"'"é'}x
// ^
//
-// pkg/front_end/testcases/regress/issue_29976.dart:12:1: Error: String starting with " must end with ".
+// pkg/front_end/testcases/regress/issue_29976.dart:9:5: Error: String starting with " must end with ".
+// "x${x*"'"é'}x
+// ^
//
// pkg/front_end/testcases/regress/issue_29976.dart:12:1: Error: Expected a declaration, but got ''.
//
diff --git a/pkg/front_end/testcases/regress/issue_29976.dart.direct.transformed.expect b/pkg/front_end/testcases/regress/issue_29976.dart.direct.transformed.expect
index d89579f..286bb14 100644
--- a/pkg/front_end/testcases/regress/issue_29976.dart.direct.transformed.expect
+++ b/pkg/front_end/testcases/regress/issue_29976.dart.direct.transformed.expect
@@ -13,7 +13,9 @@
// "x${x*"'"é'}x
// ^
//
-// pkg/front_end/testcases/regress/issue_29976.dart:12:1: Error: String starting with " must end with ".
+// pkg/front_end/testcases/regress/issue_29976.dart:9:5: Error: String starting with " must end with ".
+// "x${x*"'"é'}x
+// ^
//
// pkg/front_end/testcases/regress/issue_29976.dart:12:1: Error: Expected a declaration, but got ''.
//
diff --git a/pkg/front_end/testcases/regress/issue_29976.dart.outline.expect b/pkg/front_end/testcases/regress/issue_29976.dart.outline.expect
index eb72274..7f8efff 100644
--- a/pkg/front_end/testcases/regress/issue_29976.dart.outline.expect
+++ b/pkg/front_end/testcases/regress/issue_29976.dart.outline.expect
@@ -13,7 +13,9 @@
// "x${x*"'"é'}x
// ^
//
-// pkg/front_end/testcases/regress/issue_29976.dart:12:1: Error: String starting with " must end with ".
+// pkg/front_end/testcases/regress/issue_29976.dart:9:5: Error: String starting with " must end with ".
+// "x${x*"'"é'}x
+// ^
//
// pkg/front_end/testcases/regress/issue_29976.dart:12:1: Error: Expected a declaration, but got ''.
diff --git a/pkg/front_end/testcases/regress/issue_29976.dart.strong.expect b/pkg/front_end/testcases/regress/issue_29976.dart.strong.expect
index e6fed7c..032bd88 100644
--- a/pkg/front_end/testcases/regress/issue_29976.dart.strong.expect
+++ b/pkg/front_end/testcases/regress/issue_29976.dart.strong.expect
@@ -13,7 +13,9 @@
// "x${x*"'"é'}x
// ^
//
-// pkg/front_end/testcases/regress/issue_29976.dart:12:1: Error: String starting with " must end with ".
+// pkg/front_end/testcases/regress/issue_29976.dart:9:5: Error: String starting with " must end with ".
+// "x${x*"'"é'}x
+// ^
//
// pkg/front_end/testcases/regress/issue_29976.dart:12:1: Error: Expected a declaration, but got ''.
//
@@ -48,7 +50,9 @@
// "x${x*"'"é'}x
// ^
//
-// pkg/front_end/testcases/regress/issue_29976.dart:12:1: Error: String starting with " must end with ".
+// pkg/front_end/testcases/regress/issue_29976.dart:9:5: Error: String starting with " must end with ".
+// "x${x*"'"é'}x
+// ^
//
// pkg/front_end/testcases/regress/issue_29976.dart:12:1: Error: Expected a declaration, but got ''.
//
diff --git a/pkg/front_end/testcases/regress/issue_29976.dart.strong.transformed.expect b/pkg/front_end/testcases/regress/issue_29976.dart.strong.transformed.expect
index 2b9588c..7b89520 100644
--- a/pkg/front_end/testcases/regress/issue_29976.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/regress/issue_29976.dart.strong.transformed.expect
@@ -13,7 +13,9 @@
// "x${x*"'"é'}x
// ^
//
-// pkg/front_end/testcases/regress/issue_29976.dart:12:1: Error: String starting with " must end with ".
+// pkg/front_end/testcases/regress/issue_29976.dart:9:5: Error: String starting with " must end with ".
+// "x${x*"'"é'}x
+// ^
//
// pkg/front_end/testcases/regress/issue_29976.dart:12:1: Error: Expected a declaration, but got ''.
//
diff --git a/pkg/front_end/testcases/regress/issue_29982.dart.direct.expect b/pkg/front_end/testcases/regress/issue_29982.dart.direct.expect
index 2a74ae4..861561d 100644
--- a/pkg/front_end/testcases/regress/issue_29982.dart.direct.expect
+++ b/pkg/front_end/testcases/regress/issue_29982.dart.direct.expect
@@ -13,7 +13,9 @@
// print('${eh[éh']}');
// ^
//
-// pkg/front_end/testcases/regress/issue_29982.dart:9:1: Error: String starting with ' must end with '.
+// pkg/front_end/testcases/regress/issue_29982.dart:7:11: Error: String starting with ' must end with '.
+// print('${eh[éh']}');
+// ^
//
// pkg/front_end/testcases/regress/issue_29982.dart:9:1: Error: Expected a declaration, but got ''.
//
@@ -48,7 +50,9 @@
// print('${eh[éh']}');
// ^
//
-// pkg/front_end/testcases/regress/issue_29982.dart:9:1: Error: String starting with ' must end with '.
+// pkg/front_end/testcases/regress/issue_29982.dart:7:11: Error: String starting with ' must end with '.
+// print('${eh[éh']}');
+// ^
//
// pkg/front_end/testcases/regress/issue_29982.dart:9:1: Error: Expected a declaration, but got ''.
//
diff --git a/pkg/front_end/testcases/regress/issue_29982.dart.direct.transformed.expect b/pkg/front_end/testcases/regress/issue_29982.dart.direct.transformed.expect
index e608ced..3c85c4a 100644
--- a/pkg/front_end/testcases/regress/issue_29982.dart.direct.transformed.expect
+++ b/pkg/front_end/testcases/regress/issue_29982.dart.direct.transformed.expect
@@ -13,7 +13,9 @@
// print('${eh[éh']}');
// ^
//
-// pkg/front_end/testcases/regress/issue_29982.dart:9:1: Error: String starting with ' must end with '.
+// pkg/front_end/testcases/regress/issue_29982.dart:7:11: Error: String starting with ' must end with '.
+// print('${eh[éh']}');
+// ^
//
// pkg/front_end/testcases/regress/issue_29982.dart:9:1: Error: Expected a declaration, but got ''.
//
diff --git a/pkg/front_end/testcases/regress/issue_29982.dart.outline.expect b/pkg/front_end/testcases/regress/issue_29982.dart.outline.expect
index 8e9ae53..60e4f5b 100644
--- a/pkg/front_end/testcases/regress/issue_29982.dart.outline.expect
+++ b/pkg/front_end/testcases/regress/issue_29982.dart.outline.expect
@@ -13,7 +13,9 @@
// print('${eh[éh']}');
// ^
//
-// pkg/front_end/testcases/regress/issue_29982.dart:9:1: Error: String starting with ' must end with '.
+// pkg/front_end/testcases/regress/issue_29982.dart:7:11: Error: String starting with ' must end with '.
+// print('${eh[éh']}');
+// ^
//
// pkg/front_end/testcases/regress/issue_29982.dart:9:1: Error: Expected a declaration, but got ''.
diff --git a/pkg/front_end/testcases/regress/issue_29982.dart.strong.expect b/pkg/front_end/testcases/regress/issue_29982.dart.strong.expect
index 7c7d19a..96c2b57 100644
--- a/pkg/front_end/testcases/regress/issue_29982.dart.strong.expect
+++ b/pkg/front_end/testcases/regress/issue_29982.dart.strong.expect
@@ -13,7 +13,9 @@
// print('${eh[éh']}');
// ^
//
-// pkg/front_end/testcases/regress/issue_29982.dart:9:1: Error: String starting with ' must end with '.
+// pkg/front_end/testcases/regress/issue_29982.dart:7:11: Error: String starting with ' must end with '.
+// print('${eh[éh']}');
+// ^
//
// pkg/front_end/testcases/regress/issue_29982.dart:9:1: Error: Expected a declaration, but got ''.
//
@@ -48,7 +50,9 @@
// print('${eh[éh']}');
// ^
//
-// pkg/front_end/testcases/regress/issue_29982.dart:9:1: Error: String starting with ' must end with '.
+// pkg/front_end/testcases/regress/issue_29982.dart:7:11: Error: String starting with ' must end with '.
+// print('${eh[éh']}');
+// ^
//
// pkg/front_end/testcases/regress/issue_29982.dart:9:1: Error: Expected a declaration, but got ''.
//
diff --git a/pkg/front_end/testcases/regress/issue_29982.dart.strong.transformed.expect b/pkg/front_end/testcases/regress/issue_29982.dart.strong.transformed.expect
index 039a91c..9a1c7cd 100644
--- a/pkg/front_end/testcases/regress/issue_29982.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/regress/issue_29982.dart.strong.transformed.expect
@@ -13,7 +13,9 @@
// print('${eh[éh']}');
// ^
//
-// pkg/front_end/testcases/regress/issue_29982.dart:9:1: Error: String starting with ' must end with '.
+// pkg/front_end/testcases/regress/issue_29982.dart:7:11: Error: String starting with ' must end with '.
+// print('${eh[éh']}');
+// ^
//
// pkg/front_end/testcases/regress/issue_29982.dart:9:1: Error: Expected a declaration, but got ''.
//