Index: pkg/analyzer/lib/src/generated/parser.dart |
diff --git a/pkg/analyzer/lib/src/generated/parser.dart b/pkg/analyzer/lib/src/generated/parser.dart |
index 4a4823fea536e72d1d6ec0e7ba9f9169bcccb007..80dcb71a77466841344d2f9aee1926c414350672 100644 |
--- a/pkg/analyzer/lib/src/generated/parser.dart |
+++ b/pkg/analyzer/lib/src/generated/parser.dart |
@@ -3430,18 +3430,21 @@ class Parser { |
/** |
* Return the content of a string with the given literal representation. The |
- * [lexeme] is the literal representation of the string. The flag [first] is |
- * `true` if this is the first token in a string literal. The flag [last] is |
+ * [lexeme] is the literal representation of the string. The flag [isFirst] is |
+ * `true` if this is the first token in a string literal. The flag [isLast] is |
* `true` if this is the last token in a string literal. |
*/ |
- String _computeStringValue(String lexeme, bool first, bool last) { |
+ String _computeStringValue(String lexeme, bool isFirst, bool isLast) { |
bool isRaw = false; |
int start = 0; |
- if (first) { |
+ if (isFirst) { |
if (StringUtilities.startsWith4(lexeme, 0, 0x72, 0x22, 0x22, 0x22) || |
StringUtilities.startsWith4(lexeme, 0, 0x72, 0x27, 0x27, 0x27)) { |
isRaw = true; |
start += 4; |
+ if (isFirst) { |
+ start = _trimInitialWhitespace(lexeme, start); |
+ } |
} else if (StringUtilities.startsWith2(lexeme, 0, 0x72, 0x22) || |
StringUtilities.startsWith2(lexeme, 0, 0x72, 0x27)) { |
isRaw = true; |
@@ -3449,13 +3452,16 @@ class Parser { |
} else if (StringUtilities.startsWith3(lexeme, 0, 0x22, 0x22, 0x22) || |
StringUtilities.startsWith3(lexeme, 0, 0x27, 0x27, 0x27)) { |
start += 3; |
+ if (isFirst) { |
+ start = _trimInitialWhitespace(lexeme, start); |
+ } |
} else if (StringUtilities.startsWithChar(lexeme, 0x22) || |
StringUtilities.startsWithChar(lexeme, 0x27)) { |
start += 1; |
} |
} |
int end = lexeme.length; |
- if (last) { |
+ if (isLast) { |
if (StringUtilities.endsWith3(lexeme, 0x22, 0x22, 0x22) || |
StringUtilities.endsWith3(lexeme, 0x27, 0x27, 0x27)) { |
end -= 3; |
@@ -3466,7 +3472,7 @@ class Parser { |
} |
if (end - start + 1 < 0) { |
AnalysisEngine.instance.logger.logError( |
- "Internal error: computeStringValue($lexeme, $first, $last)"); |
+ "Internal error: computeStringValue($lexeme, $isFirst, $isLast)"); |
return ""; |
} |
if (isRaw) { |
@@ -8250,6 +8256,46 @@ class Parser { |
} |
/** |
+ * Given the [lexeme] for a multi-line string whose content begins at the |
+ * given [start] index, return the index of the first character that is |
+ * included in the value of the string. According to the specification: |
+ * |
+ * If the first line of a multiline string consists solely of the whitespace |
+ * characters defined by the production WHITESPACE 20.1), possibly prefixed |
+ * by \, then that line is ignored, including the new line at its end. |
+ */ |
+ int _trimInitialWhitespace(String lexeme, int start) { |
+ int length = lexeme.length; |
+ int index = start; |
+ while (index < length) { |
+ int currentChar = lexeme.codeUnitAt(index); |
+ if (currentChar == 0x0D) { |
+ if (index + 1 < length && lexeme.codeUnitAt(index + 1) == 0x0A) { |
+ return index + 2; |
+ } |
+ return index + 1; |
+ } else if (currentChar == 0x0A) { |
+ return index + 1; |
+ } else if (currentChar == 0x5C) { |
+ if (index + 1 >= length) { |
+ return start; |
+ } |
+ currentChar = lexeme.codeUnitAt(index + 1); |
+ if (currentChar != 0x0D && |
+ currentChar != 0x0A && |
+ currentChar != 0x09 && |
+ currentChar != 0x20) { |
+ return start; |
+ } |
+ } else if (currentChar != 0x09 && currentChar != 0x20) { |
+ return start; |
+ } |
+ index++; |
+ } |
+ return start; |
+ } |
+ |
+ /** |
* Decrements the error reporting lock level. If level is more than `0`, then |
* [reportError] wont report any error. |
*/ |