| Index: pkg/dev_compiler/tool/input_sdk/private/js_string.dart
|
| diff --git a/pkg/dev_compiler/tool/input_sdk/private/js_string.dart b/pkg/dev_compiler/tool/input_sdk/private/js_string.dart
|
| index bb9ddc7d7db5315318971aaf354212f5ea2a8596..08a9edb7bb5260cb900dc523232f559223a00166 100644
|
| --- a/pkg/dev_compiler/tool/input_sdk/private/js_string.dart
|
| +++ b/pkg/dev_compiler/tool/input_sdk/private/js_string.dart
|
| @@ -14,33 +14,35 @@ part of dart._interceptors;
|
| class JSString extends Interceptor implements String, JSIndexable<String> {
|
| const JSString();
|
|
|
| - int codeUnitAt(int index) {
|
| + @notNull
|
| + int codeUnitAt(@nullCheck int index) {
|
| // Suppress 2nd null check on index and null check on length
|
| // (JS String.length cannot be null).
|
| - if (index == null ||
|
| - JS('int', '#', index) < 0 ||
|
| - JS('int', '#', index) >= JS('int', '#.length', this)) {
|
| - throw diagnoseIndexError(this, index);
|
| + final len = this.length;
|
| + if (index < 0 || index >= len) {
|
| + throw new RangeError.index(index, this, 'index', null, len);
|
| }
|
| return JS('int', r'#.charCodeAt(#)', this, index);
|
| }
|
|
|
| - Iterable<Match> allMatches(String string, [int start = 0]) {
|
| - checkString(string);
|
| - checkInt(start);
|
| - if (0 > start || start > string.length) {
|
| - throw new RangeError.range(start, 0, string.length);
|
| + @notNull
|
| + Iterable<Match> allMatches(@nullCheck String string,
|
| + [@nullCheck int start = 0]) {
|
| + final len = string.length;
|
| + if (0 > start || start > len) {
|
| + throw new RangeError.range(start, 0, len);
|
| }
|
| return allMatchesInStringUnchecked(this, string, start);
|
| }
|
|
|
| - Match matchAsPrefix(String string, [int start = 0]) {
|
| - if (start < 0 || start > string.length) {
|
| - throw new RangeError.range(start, 0, string.length);
|
| + Match matchAsPrefix(@nullCheck String string, [@nullCheck int start = 0]) {
|
| + final stringLength = JS('int', '#.length', string);
|
| + if (start < 0 || start > stringLength) {
|
| + throw new RangeError.range(start, 0, stringLength);
|
| }
|
| - if (start + this.length > string.length) return null;
|
| - // TODO(lrn): See if this can be optimized.
|
| - for (int i = 0; i < this.length; i++) {
|
| + final thisLength = JS('int', '#.length', this);
|
| + if (start + thisLength > stringLength) return null;
|
| + for (int i = 0; i < thisLength; i++) {
|
| if (string.codeUnitAt(start + i) != this.codeUnitAt(i)) {
|
| return null;
|
| }
|
| @@ -48,49 +50,52 @@ class JSString extends Interceptor implements String, JSIndexable<String> {
|
| return new StringMatch(start, string, this);
|
| }
|
|
|
| - String operator +(String other) {
|
| - if (other is! String) throw new ArgumentError.value(other);
|
| + @notNull
|
| + String operator +(@nullCheck String other) {
|
| return JS('String', r'# + #', this, other);
|
| }
|
|
|
| - bool endsWith(String other) {
|
| - checkString(other);
|
| - int otherLength = other.length;
|
| - if (otherLength > length) return false;
|
| - return other == substring(length - otherLength);
|
| + @notNull
|
| + bool endsWith(@nullCheck String other) {
|
| + var otherLength = other.length;
|
| + var thisLength = this.length;
|
| + if (otherLength > thisLength) return false;
|
| + return other == substring(thisLength - otherLength);
|
| }
|
|
|
| - String replaceAll(Pattern from, String to) {
|
| - checkString(to);
|
| + @notNull
|
| + String replaceAll(Pattern from, @nullCheck String to) {
|
| return stringReplaceAllUnchecked(this, from, to);
|
| }
|
|
|
| + @notNull
|
| String replaceAllMapped(Pattern from, String convert(Match match)) {
|
| return this.splitMapJoin(from, onMatch: convert);
|
| }
|
|
|
| + @notNull
|
| String splitMapJoin(Pattern from,
|
| {String onMatch(Match match), String onNonMatch(String nonMatch)}) {
|
| return stringReplaceAllFuncUnchecked(this, from, onMatch, onNonMatch);
|
| }
|
|
|
| - String replaceFirst(Pattern from, String to, [int startIndex = 0]) {
|
| - checkString(to);
|
| - checkInt(startIndex);
|
| + @notNull
|
| + String replaceFirst(Pattern from, @nullCheck String to,
|
| + [@nullCheck int startIndex = 0]) {
|
| RangeError.checkValueInInterval(startIndex, 0, this.length, "startIndex");
|
| return stringReplaceFirstUnchecked(this, from, to, startIndex);
|
| }
|
|
|
| - String replaceFirstMapped(Pattern from, String replace(Match match),
|
| - [int startIndex = 0]) {
|
| - checkNull(replace);
|
| - checkInt(startIndex);
|
| + @notNull
|
| + String replaceFirstMapped(
|
| + Pattern from, @nullCheck String replace(Match match),
|
| + [@nullCheck int startIndex = 0]) {
|
| RangeError.checkValueInInterval(startIndex, 0, this.length, "startIndex");
|
| return stringReplaceFirstMappedUnchecked(this, from, replace, startIndex);
|
| }
|
|
|
| - List<String> split(Pattern pattern) {
|
| - checkNull(pattern);
|
| + @notNull
|
| + List<String> split(@nullCheck Pattern pattern) {
|
| if (pattern is String) {
|
| return JS('JSExtendableArray', r'#.split(#)', this, pattern);
|
| } else if (pattern is JSSyntaxRegExp && regExpCaptureCount(pattern) == 0) {
|
| @@ -101,14 +106,14 @@ class JSString extends Interceptor implements String, JSIndexable<String> {
|
| }
|
| }
|
|
|
| - String replaceRange(int start, int end, String replacement) {
|
| - checkString(replacement);
|
| - checkInt(start);
|
| + @notNull
|
| + String replaceRange(
|
| + @nullCheck int start, int end, @nullCheck String replacement) {
|
| end = RangeError.checkValidRange(start, end, this.length);
|
| - checkInt(end);
|
| return stringReplaceRangeUnchecked(this, start, end, replacement);
|
| }
|
|
|
| + @notNull
|
| List<String> _defaultSplit(Pattern pattern) {
|
| List<String> result = <String>[];
|
| // End of most recent match. That is, start of next part to add to result.
|
| @@ -117,7 +122,9 @@ class JSString extends Interceptor implements String, JSIndexable<String> {
|
| // Set >0, so no match on the empty string causes the result to be [""].
|
| int length = 1;
|
| for (var match in pattern.allMatches(this)) {
|
| + @notNull
|
| int matchStart = match.start;
|
| + @notNull
|
| int matchEnd = match.end;
|
| length = matchEnd - matchStart;
|
| if (length == 0 && start == matchStart) {
|
| @@ -137,7 +144,8 @@ class JSString extends Interceptor implements String, JSIndexable<String> {
|
| return result;
|
| }
|
|
|
| - bool startsWith(Pattern pattern, [int index = 0]) {
|
| + @notNull
|
| + bool startsWith(Pattern pattern, [@nullCheck int index = 0]) {
|
| // Suppress null check on length and all but the first
|
| // reference to index.
|
| int length = JS('int', '#.length', this);
|
| @@ -147,27 +155,29 @@ class JSString extends Interceptor implements String, JSIndexable<String> {
|
| if (pattern is String) {
|
| String other = pattern;
|
| int otherLength = JS('int', '#.length', other);
|
| - int endIndex = JS('int', '#', index) + otherLength;
|
| + int endIndex = index + otherLength;
|
| if (endIndex > length) return false;
|
| return other == JS('String', r'#.substring(#, #)', this, index, endIndex);
|
| }
|
| return pattern.matchAsPrefix(this, index) != null;
|
| }
|
|
|
| - String substring(int startIndex, [int endIndex]) {
|
| - checkInt(startIndex);
|
| - if (endIndex == null) endIndex = length;
|
| - checkInt(endIndex);
|
| + @notNull
|
| + String substring(@nullCheck int startIndex, [int _endIndex]) {
|
| + var length = this.length;
|
| + final endIndex = _endIndex ?? length;
|
| if (startIndex < 0) throw new RangeError.value(startIndex);
|
| if (startIndex > endIndex) throw new RangeError.value(startIndex);
|
| if (endIndex > length) throw new RangeError.value(endIndex);
|
| return JS('String', r'#.substring(#, #)', this, startIndex, endIndex);
|
| }
|
|
|
| + @notNull
|
| String toLowerCase() {
|
| return JS('String', r'#.toLowerCase()', this);
|
| }
|
|
|
| + @notNull
|
| String toUpperCase() {
|
| return JS('String', r'#.toUpperCase()', this);
|
| }
|
| @@ -187,7 +197,8 @@ class JSString extends Interceptor implements String, JSIndexable<String> {
|
| // 3000 ; White_Space # Zs IDEOGRAPHIC SPACE
|
| //
|
| // BOM: 0xFEFF
|
| - static bool _isWhitespace(int codeUnit) {
|
| + @notNull
|
| + static bool _isWhitespace(@notNull int codeUnit) {
|
| // Most codeUnits should be less than 256. Special case with a smaller
|
| // switch.
|
| if (codeUnit < 256) {
|
| @@ -233,10 +244,12 @@ class JSString extends Interceptor implements String, JSIndexable<String> {
|
|
|
| /// Finds the index of the first non-whitespace character, or the
|
| /// end of the string. Start looking at position [index].
|
| - static int _skipLeadingWhitespace(String string, int index) {
|
| + @notNull
|
| + static int _skipLeadingWhitespace(String string, @nullCheck int index) {
|
| const int SPACE = 0x20;
|
| const int CARRIAGE_RETURN = 0x0D;
|
| - while (index < string.length) {
|
| + var stringLength = string.length;
|
| + while (index < stringLength) {
|
| int codeUnit = string.codeUnitAt(index);
|
| if (codeUnit != SPACE &&
|
| codeUnit != CARRIAGE_RETURN &&
|
| @@ -250,7 +263,8 @@ class JSString extends Interceptor implements String, JSIndexable<String> {
|
|
|
| /// Finds the index after the last non-whitespace character, or 0.
|
| /// Start looking at position [index - 1].
|
| - static int _skipTrailingWhitespace(String string, int index) {
|
| + @notNull
|
| + static int _skipTrailingWhitespace(String string, @nullCheck int index) {
|
| const int SPACE = 0x20;
|
| const int CARRIAGE_RETURN = 0x0D;
|
| while (index > 0) {
|
| @@ -268,34 +282,37 @@ class JSString extends Interceptor implements String, JSIndexable<String> {
|
| // Dart2js can't use JavaScript trim directly,
|
| // because JavaScript does not trim
|
| // the NEXT LINE (NEL) character (0x85).
|
| + @notNull
|
| String trim() {
|
| const int NEL = 0x85;
|
|
|
| // Start by doing JS trim. Then check if it leaves a NEL at
|
| // either end of the string.
|
| - String result = JS('String', '#.trim()', this);
|
| - if (result.length == 0) return result;
|
| + final result = JS('String', '#.trim()', this);
|
| + final length = result.length;
|
| + if (length == 0) return result;
|
| int firstCode = result.codeUnitAt(0);
|
| int startIndex = 0;
|
| if (firstCode == NEL) {
|
| startIndex = _skipLeadingWhitespace(result, 1);
|
| - if (startIndex == result.length) return "";
|
| + if (startIndex == length) return "";
|
| }
|
|
|
| - int endIndex = result.length;
|
| + int endIndex = length;
|
| // We know that there is at least one character that is non-whitespace.
|
| // Therefore we don't need to verify that endIndex > startIndex.
|
| int lastCode = result.codeUnitAt(endIndex - 1);
|
| if (lastCode == NEL) {
|
| endIndex = _skipTrailingWhitespace(result, endIndex - 1);
|
| }
|
| - if (startIndex == 0 && endIndex == result.length) return result;
|
| + if (startIndex == 0 && endIndex == length) return result;
|
| return JS('String', r'#.substring(#, #)', result, startIndex, endIndex);
|
| }
|
|
|
| // Dart2js can't use JavaScript trimLeft directly,
|
| // because it is not in ES5, so not every browser implements it,
|
| // and because those that do will not trim the NEXT LINE character (0x85).
|
| + @notNull
|
| String trimLeft() {
|
| const int NEL = 0x85;
|
|
|
| @@ -322,13 +339,15 @@ class JSString extends Interceptor implements String, JSIndexable<String> {
|
| // Dart2js can't use JavaScript trimRight directly,
|
| // because it is not in ES5 and because JavaScript does not trim
|
| // the NEXT LINE character (0x85).
|
| + @notNull
|
| String trimRight() {
|
| const int NEL = 0x85;
|
|
|
| // Start by doing JS trim. Then check if it leaves a NEL or BOM at
|
| // the end of the string.
|
| String result;
|
| - int endIndex;
|
| + @notNull
|
| + int endIndex = 0;
|
| // trimRight is implemented by Firefox and Chrome/Blink,
|
| // so use it if it is there.
|
| if (JS('bool', 'typeof #.trimRight != "undefined"', this)) {
|
| @@ -349,8 +368,9 @@ class JSString extends Interceptor implements String, JSIndexable<String> {
|
| return JS('String', r'#.substring(#, #)', result, 0, endIndex);
|
| }
|
|
|
| - String operator *(int times) {
|
| - if (0 >= times) return ''; // Unnecessary but hoists argument type check.
|
| + @notNull
|
| + String operator *(@nullCheck int times) {
|
| + if (0 >= times) return '';
|
| if (times == 1 || this.length == 0) return this;
|
| if (times != JS('int', '# >>> 0', times)) {
|
| // times >= 2^32. We can't create a string that big.
|
| @@ -367,25 +387,28 @@ class JSString extends Interceptor implements String, JSIndexable<String> {
|
| return result;
|
| }
|
|
|
| - String padLeft(int width, [String padding = ' ']) {
|
| + @notNull
|
| + String padLeft(@nullCheck int width, [String padding = ' ']) {
|
| int delta = width - this.length;
|
| if (delta <= 0) return this;
|
| return padding * delta + this;
|
| }
|
|
|
| - String padRight(int width, [String padding = ' ']) {
|
| + @notNull
|
| + String padRight(@nullCheck int width, [String padding = ' ']) {
|
| int delta = width - this.length;
|
| if (delta <= 0) return this;
|
| return this + padding * delta;
|
| }
|
|
|
| + @notNull
|
| List<int> get codeUnits => new CodeUnits(this);
|
|
|
| + @notNull
|
| Runes get runes => new Runes(this);
|
|
|
| - int indexOf(Pattern pattern, [int start = 0]) {
|
| - checkNull(pattern);
|
| - if (start is! int) throw argumentErrorValue(start);
|
| + @notNull
|
| + int indexOf(@nullCheck Pattern pattern, [@nullCheck int start = 0]) {
|
| if (start < 0 || start > this.length) {
|
| throw new RangeError.range(start, 0, this.length);
|
| }
|
| @@ -397,25 +420,24 @@ class JSString extends Interceptor implements String, JSIndexable<String> {
|
| Match match = firstMatchAfter(re, this, start);
|
| return (match == null) ? -1 : match.start;
|
| }
|
| - for (int i = start; i <= this.length; i++) {
|
| + var length = this.length;
|
| + for (int i = start; i <= length; i++) {
|
| if (pattern.matchAsPrefix(this, i) != null) return i;
|
| }
|
| return -1;
|
| }
|
|
|
| - int lastIndexOf(Pattern pattern, [int start]) {
|
| - checkNull(pattern);
|
| - if (start == null) {
|
| - start = length;
|
| - } else if (start is! int) {
|
| - throw argumentErrorValue(start);
|
| - } else if (start < 0 || start > this.length) {
|
| - throw new RangeError.range(start, 0, this.length);
|
| + @notNull
|
| + int lastIndexOf(@nullCheck Pattern pattern, [int _start]) {
|
| + var length = this.length;
|
| + var start = _start ?? length;
|
| + if (start < 0 || start > length) {
|
| + throw new RangeError.range(start, 0, length);
|
| }
|
| if (pattern is String) {
|
| String other = pattern;
|
| - if (start + other.length > this.length) {
|
| - start = this.length - other.length;
|
| + if (start + other.length > length) {
|
| + start = length - other.length;
|
| }
|
| return stringLastIndexOfUnchecked(this, other, start);
|
| }
|
| @@ -425,24 +447,27 @@ class JSString extends Interceptor implements String, JSIndexable<String> {
|
| return -1;
|
| }
|
|
|
| - bool contains(Pattern other, [int startIndex = 0]) {
|
| - checkNull(other);
|
| + @notNull
|
| + bool contains(@nullCheck Pattern other, [@nullCheck int startIndex = 0]) {
|
| if (startIndex < 0 || startIndex > this.length) {
|
| throw new RangeError.range(startIndex, 0, this.length);
|
| }
|
| return stringContainsUnchecked(this, other, startIndex);
|
| }
|
|
|
| + @notNull
|
| bool get isEmpty => JS('int', '#.length', this) == 0;
|
|
|
| + @notNull
|
| bool get isNotEmpty => !isEmpty;
|
|
|
| - int compareTo(String other) {
|
| - if (other == null) throw argumentErrorValue(other);
|
| + @notNull
|
| + int compareTo(@nullCheck String other) {
|
| return this == other ? 0 : JS('bool', r'# < #', this, other) ? -1 : 1;
|
| }
|
|
|
| // Note: if you change this, also change the function [S].
|
| + @notNull
|
| String toString() => this;
|
|
|
| /**
|
| @@ -451,6 +476,7 @@ class JSString extends Interceptor implements String, JSIndexable<String> {
|
| *
|
| * [1]: http://en.wikipedia.org/wiki/Jenkins_hash_function
|
| */
|
| + @notNull
|
| int get hashCode {
|
| // TODO(ahe): This method shouldn't have to use JS. Update when our
|
| // optimizations are smarter.
|
| @@ -466,14 +492,15 @@ class JSString extends Interceptor implements String, JSIndexable<String> {
|
| return 0x1fffffff & (hash + ((0x00003fff & hash) << 15));
|
| }
|
|
|
| + @notNull
|
| Type get runtimeType => String;
|
|
|
| + @notNull
|
| int get length => JS('int', r'#.length', this);
|
|
|
| - String operator [](int index) {
|
| - if (index == null ||
|
| - JS('int', '#', index) >= JS('int', '#.length', this) ||
|
| - JS('int', '#', index) < 0) {
|
| + @notNull
|
| + String operator [](@nullCheck int index) {
|
| + if (index >= JS('int', '#.length', this) || index < 0) {
|
| throw diagnoseIndexError(this, index);
|
| }
|
| return JS('String', '#[#]', this, index);
|
|
|