@@ -52,6 +52,7 @@ class ListBuilder<E> {
5252
5353 /// As [List] .
5454 void operator []= (int index, E element) {
55+ _maybeCheckElement (element);
5556 _safeList[index] = element;
5657 }
5758
@@ -60,6 +61,7 @@ class ListBuilder<E> {
6061
6162 /// As [List.first] .
6263 set first (E value) {
64+ _maybeCheckElement (value);
6365 _safeList.first = value;
6466 }
6567
@@ -68,6 +70,7 @@ class ListBuilder<E> {
6870
6971 /// As [List.last] .
7072 set last (E value) {
73+ _maybeCheckElement (value);
7174 _safeList.last = value;
7275 }
7376
@@ -82,12 +85,26 @@ class ListBuilder<E> {
8285
8386 /// As [List.add] .
8487 void add (E value) {
88+ _maybeCheckElement (value);
8589 _safeList.add (value);
8690 }
8791
8892 /// As [List.addAll] .
8993 void addAll (Iterable <E > iterable) {
90- _safeList.addAll (iterable);
94+ // Add directly to the underlying `List` then check elements there, for
95+ // performance. Roll back the changes if validation fails.
96+ var safeList = _safeList;
97+ var lengthBefore = safeList.length;
98+ safeList.addAll (iterable);
99+ if (! _needsNullCheck) return ;
100+ try {
101+ for (var i = lengthBefore; i != safeList.length; ++ i) {
102+ _checkElement (safeList[i]);
103+ }
104+ } catch (_) {
105+ safeList.removeRange (lengthBefore, safeList.length);
106+ rethrow ;
107+ }
91108 }
92109
93110 /// As [List.reversed] , but updates the builder in place. Returns nothing.
@@ -113,16 +130,33 @@ class ListBuilder<E> {
113130
114131 /// As [List.insert] .
115132 void insert (int index, E element) {
133+ _maybeCheckElement (element);
116134 _safeList.insert (index, element);
117135 }
118136
119137 /// As [List.insertAll] .
120138 void insertAll (int index, Iterable <E > iterable) {
121- _safeList.insertAll (index, iterable);
139+ // Add directly to the underlying `List` then check elements there, for
140+ // performance. Roll back the changes if validation fails.
141+ var safeList = _safeList;
142+ var lengthBefore = safeList.length;
143+ safeList.insertAll (index, iterable);
144+ if (! _needsNullCheck) return ;
145+ var insertedLength = safeList.length - lengthBefore;
146+ try {
147+ for (var i = index; i != index + insertedLength; ++ i) {
148+ _checkElement (safeList[i]);
149+ }
150+ } catch (_) {
151+ safeList.removeRange (index, index + insertedLength);
152+ rethrow ;
153+ }
122154 }
123155
124156 /// As [List.setAll] .
125157 void setAll (int index, Iterable <E > iterable) {
158+ iterable = evaluateIterable (iterable);
159+ _maybeCheckElements (iterable);
126160 _safeList.setAll (index, iterable);
127161 }
128162
@@ -154,6 +188,8 @@ class ListBuilder<E> {
154188
155189 /// As [List.setRange] .
156190 void setRange (int start, int end, Iterable <E > iterable, [int skipCount = 0 ]) {
191+ iterable = evaluateIterable (iterable);
192+ _maybeCheckElements (iterable);
157193 _safeList.setRange (start, end, iterable, skipCount);
158194 }
159195
@@ -164,19 +200,24 @@ class ListBuilder<E> {
164200
165201 /// As [List.fillRange] , but requires a value.
166202 void fillRange (int start, int end, E fillValue) {
203+ _maybeCheckElement (fillValue);
167204 _safeList.fillRange (start, end, fillValue);
168205 }
169206
170207 /// As [List.replaceRange] .
171208 void replaceRange (int start, int end, Iterable <E > iterable) {
209+ iterable = evaluateIterable (iterable);
210+ _maybeCheckElements (iterable);
172211 _safeList.replaceRange (start, end, iterable);
173212 }
174213
175214 // Based on Iterable.
176215
177216 /// As [Iterable.map] , but updates the builder in place. Returns nothing.
178217 void map (E Function (E ) f) {
179- _setSafeList (_list.map (f).toList (growable: true ));
218+ var result = _list.map (f).toList (growable: true );
219+ _maybeCheckElements (result);
220+ _setSafeList (result);
180221 }
181222
182223 /// As [Iterable.where] , but updates the builder in place. Returns nothing.
@@ -186,7 +227,9 @@ class ListBuilder<E> {
186227
187228 /// As [Iterable.expand] , but updates the builder in place. Returns nothing.
188229 void expand (Iterable <E > Function (E ) f) {
189- _setSafeList (_list.expand (f).toList (growable: true ));
230+ var result = _list.expand (f).toList (growable: true );
231+ _maybeCheckElements (result);
232+ _setSafeList (result);
190233 }
191234
192235 /// As [Iterable.take] , but updates the builder in place. Returns nothing.
@@ -231,4 +274,23 @@ class ListBuilder<E> {
231274 }
232275 return _list;
233276 }
277+
278+ bool get _needsNullCheck => ! isSoundMode && null is ! E ;
279+
280+ void _maybeCheckElement (E element) {
281+ if (_needsNullCheck) _checkElement (element);
282+ }
283+
284+ void _checkElement (E element) {
285+ if (identical (element, null )) {
286+ throw ArgumentError ('null element' );
287+ }
288+ }
289+
290+ void _maybeCheckElements (Iterable <E > elements) {
291+ if (! _needsNullCheck) return ;
292+ for (var element in elements) {
293+ _checkElement (element);
294+ }
295+ }
234296}
0 commit comments