2
2
// for details. All rights reserved. Use of this source code is governed by a
3
3
// BSD-style license that can be found in the LICENSE file.
4
4
5
- // @dart = 2.9
6
-
7
5
import 'dart:math' ;
8
6
9
7
import 'package:vm_service/vm_service.dart' ;
@@ -30,7 +28,7 @@ class InstanceHelper extends Domain {
30
28
31
29
/// Creates an [InstanceRef] for a primitive [RemoteObject] .
32
30
static InstanceRef _primitiveInstanceRef (
33
- String kind, RemoteObject remoteObject) {
31
+ String kind, RemoteObject ? remoteObject) {
34
32
final classRef = classRefFor ('dart:core' , kind);
35
33
return InstanceRef (
36
34
identityHashCode: dartIdFor (remoteObject? .value).hashCode,
@@ -41,21 +39,24 @@ class InstanceHelper extends Domain {
41
39
}
42
40
43
41
/// Creates an [Instance] for a primitive [RemoteObject] .
44
- Instance _primitiveInstance (String kind, RemoteObject remote) {
45
- if (remote? .objectId == null ) return null ;
42
+ Instance ? _primitiveInstance (String kind, RemoteObject ? remote) {
43
+ final objectId = remote? .objectId;
44
+ if (objectId == null ) return null ;
46
45
return Instance (
47
- identityHashCode: remote. objectId.hashCode,
48
- id: remote. objectId,
46
+ identityHashCode: objectId.hashCode,
47
+ id: objectId,
49
48
kind: kind,
50
49
classRef: classRefFor ('dart:core' , kind))
51
- ..valueAsString = '${remote .value }' ;
50
+ ..valueAsString = '${remote ? .value }' ;
52
51
}
53
52
54
- Instance _stringInstanceFor (
55
- RemoteObject remoteObject, int offset, int count) {
53
+ Instance ? _stringInstanceFor (
54
+ RemoteObject ? remoteObject, int ? offset, int ? count) {
56
55
// TODO(#777) Consider a way of not passing the whole string around (in the
57
56
// ID) in order to find a substring.
58
- final fullString = stringFromDartId (remoteObject.objectId);
57
+ final objectId = remoteObject? .objectId;
58
+ if (objectId == null ) return null ;
59
+ final fullString = stringFromDartId (objectId);
59
60
var preview = fullString;
60
61
var truncated = false ;
61
62
if (offset != null || count != null ) {
@@ -76,10 +77,12 @@ class InstanceHelper extends Domain {
76
77
..offset = (truncated ? offset : null );
77
78
}
78
79
79
- Future <Instance > _closureInstanceFor (RemoteObject remoteObject) async {
80
+ Future <Instance ?> _closureInstanceFor (RemoteObject remoteObject) async {
81
+ final objectId = remoteObject.objectId;
82
+ if (objectId == null ) return null ;
80
83
final result = Instance (
81
84
kind: InstanceKind .kClosure,
82
- id: remoteObject. objectId,
85
+ id: objectId,
83
86
identityHashCode: remoteObject.objectId.hashCode,
84
87
classRef: classRefForClosure);
85
88
return result;
@@ -90,27 +93,31 @@ class InstanceHelper extends Domain {
90
93
/// Does a remote eval to get instance information. Returns null if there
91
94
/// isn't a corresponding instance. For enumerable objects, [offset] and
92
95
/// [count] allow retrieving a sub-range of properties.
93
- Future <Instance > instanceFor (RemoteObject remoteObject,
94
- {int offset, int count}) async {
96
+ Future <Instance ? > instanceFor (RemoteObject ? remoteObject,
97
+ {int ? offset, int ? count}) async {
95
98
final primitive = _primitiveInstanceOrNull (remoteObject, offset, count);
96
99
if (primitive != null ) {
97
100
return primitive;
98
101
}
102
+ final objectId = remoteObject? .objectId;
103
+ if (remoteObject == null || objectId == null ) return null ;
99
104
100
105
// TODO: This is checking the JS object ID for the dart pattern we use for
101
106
// VM objects, which seems wrong (and, we catch 'string' types above).
102
- if (isStringId (remoteObject. objectId)) {
107
+ if (isStringId (objectId)) {
103
108
return _stringInstanceFor (remoteObject, offset, count);
104
109
}
105
110
106
111
final metaData = await ClassMetaData .metaDataFor (
107
112
inspector.remoteDebugger, remoteObject, inspector);
108
- final classRef = metaData.classRef;
113
+
114
+ final classRef = metaData? .classRef;
115
+ if (metaData == null || classRef == null ) return null ;
109
116
if (metaData.jsName == 'Function' ) {
110
117
return _closureInstanceFor (remoteObject);
111
118
}
112
119
113
- final properties = await debugger.getProperties (remoteObject. objectId,
120
+ final properties = await debugger.getProperties (objectId,
114
121
offset: offset, count: count, length: metaData.length);
115
122
if (metaData.isSystemList) {
116
123
return await _listInstanceFor (
@@ -125,8 +132,8 @@ class InstanceHelper extends Domain {
125
132
126
133
/// If [remoteObject] represents a primitive, return an [Instance] for it,
127
134
/// otherwise return null.
128
- Instance _primitiveInstanceOrNull (
129
- RemoteObject remoteObject, int offset, int count) {
135
+ Instance ? _primitiveInstanceOrNull (
136
+ RemoteObject ? remoteObject, int ? offset, int ? count) {
130
137
switch (remoteObject? .type ?? 'undefined' ) {
131
138
case 'string' :
132
139
return _stringInstanceFor (remoteObject, offset, count);
@@ -150,7 +157,7 @@ class InstanceHelper extends Domain {
150
157
name: property.name,
151
158
declaredType: InstanceRef (
152
159
kind: InstanceKind .kType,
153
- classRef: instance.classRef,
160
+ classRef: instance? .classRef,
154
161
identityHashCode: createId ().hashCode,
155
162
id: createId ()),
156
163
owner: classRef,
@@ -165,27 +172,37 @@ class InstanceHelper extends Domain {
165
172
166
173
/// Create a plain instance of [classRef] from [remoteObject] and the JS
167
174
/// properties [properties] .
168
- Future <Instance > _plainInstanceFor (ClassRef classRef,
175
+ Future <Instance ? > _plainInstanceFor (ClassRef classRef,
169
176
RemoteObject remoteObject, List <Property > properties) async {
177
+ final objectId = remoteObject.objectId;
178
+ if (objectId == null ) return null ;
170
179
final dartProperties = await _dartFieldsFor (properties, remoteObject);
171
180
var boundFields = await Future .wait (
172
181
dartProperties.map <Future <BoundField >>((p) => _fieldFor (p, classRef)));
173
182
boundFields = boundFields
174
- .where ((bv) => bv != null && ! isNativeJsObject (bv.value as InstanceRef ))
183
+ .where ((bv) => ! isNativeJsObject (bv.value as InstanceRef ))
175
184
.toList ()
176
- ..sort ((a, b) => a.decl.name. compareTo (b.decl.name) );
185
+ ..sort (_compareBoundFields );
177
186
final result = Instance (
178
187
kind: InstanceKind .kPlainInstance,
179
- id: remoteObject. objectId,
188
+ id: objectId,
180
189
identityHashCode: remoteObject.objectId.hashCode,
181
190
classRef: classRef)
182
191
..fields = boundFields;
183
192
return result;
184
193
}
185
194
195
+ int _compareBoundFields (BoundField a, BoundField b) {
196
+ final aName = a.decl? .name;
197
+ final bName = b.decl? .name;
198
+ if (aName == null ) return bName == null ? 0 : - 1 ;
199
+ if (bName == null ) return 1 ;
200
+ return aName.compareTo (bName);
201
+ }
202
+
186
203
/// The associations for a Dart Map or IdentityMap.
187
204
Future <List <MapAssociation >> _mapAssociations (
188
- RemoteObject map, int offset, int count) async {
205
+ RemoteObject map, int ? offset, int ? count) async {
189
206
// We do this in in awkward way because we want the keys and values, but we
190
207
// can't return things by value or some Dart objects will come back as
191
208
// values that we need to be RemoteObject, e.g. a List of int.
@@ -213,25 +230,34 @@ class InstanceHelper extends Domain {
213
230
final valuesInstance =
214
231
await instanceFor (values, offset: offset, count: count);
215
232
final associations = < MapAssociation > [];
216
- Map .fromIterables (keysInstance.elements, valuesInstance.elements)
217
- .forEach ((key, value) {
218
- associations.add (MapAssociation (key: key, value: value));
219
- });
233
+ final keyElements = keysInstance? .elements;
234
+ final valueElements = valuesInstance? .elements;
235
+ if (keyElements != null && valueElements != null ) {
236
+ Map .fromIterables (keyElements, valueElements).forEach ((key, value) {
237
+ associations.add (MapAssociation (key: key, value: value));
238
+ });
239
+ }
220
240
return associations;
221
241
}
222
242
223
243
/// Create a Map instance with class [classRef] from [remoteObject] .
224
- Future <Instance > _mapInstanceFor (ClassRef classRef, RemoteObject remoteObject,
225
- List <Property > _, int offset, int count) async {
244
+ Future <Instance ?> _mapInstanceFor (
245
+ ClassRef classRef,
246
+ RemoteObject remoteObject,
247
+ List <Property > _,
248
+ int ? offset,
249
+ int ? count) async {
250
+ final objectId = remoteObject.objectId;
251
+ if (objectId == null ) return null ;
226
252
// Maps are complicated, do an eval to get keys and values.
227
253
final associations = await _mapAssociations (remoteObject, offset, count);
228
254
final length = (offset == null && count == null )
229
255
? associations.length
230
- : (await instanceRefFor (remoteObject)).length;
256
+ : (await instanceRefFor (remoteObject))? .length;
231
257
return Instance (
232
258
identityHashCode: remoteObject.objectId.hashCode,
233
259
kind: InstanceKind .kMap,
234
- id: remoteObject. objectId,
260
+ id: objectId,
235
261
classRef: classRef)
236
262
..length = length
237
263
..offset = offset
@@ -241,24 +267,26 @@ class InstanceHelper extends Domain {
241
267
242
268
/// Create a List instance of [classRef] from [remoteObject] with the JS
243
269
/// properties [properties] .
244
- Future <Instance > _listInstanceFor (
270
+ Future <Instance ? > _listInstanceFor (
245
271
ClassRef classRef,
246
272
RemoteObject remoteObject,
247
273
List <Property > properties,
248
- int offset,
249
- int count) async {
250
- final numberOfProperties = _lengthOf (properties);
274
+ int ? offset,
275
+ int ? count) async {
276
+ final objectId = remoteObject.objectId;
277
+ if (objectId == null ) return null ;
278
+ final numberOfProperties = _lengthOf (properties) ?? 0 ;
251
279
final length = (offset == null && count == null )
252
280
? numberOfProperties
253
- : (await instanceRefFor (remoteObject)).length;
254
- final indexed =
255
- properties. sublist ( 0 , min (count ?? length, numberOfProperties));
281
+ : (await instanceRefFor (remoteObject))? .length;
282
+ final indexed = properties. sublist (
283
+ 0 , min (count ?? length ?? numberOfProperties , numberOfProperties));
256
284
final fields = await Future .wait (indexed
257
285
.map ((property) async => await _instanceRefForRemote (property.value)));
258
286
return Instance (
259
287
identityHashCode: remoteObject.objectId.hashCode,
260
288
kind: InstanceKind .kList,
261
- id: remoteObject. objectId,
289
+ id: objectId,
262
290
classRef: classRef)
263
291
..length = length
264
292
..elements = fields
@@ -271,9 +299,9 @@ class InstanceHelper extends Domain {
271
299
/// This is only applicable to Lists or Maps, where we expect a length
272
300
/// attribute. Even if a plain instance happens to have a length field, we
273
301
/// don't use it to determine the properties to display.
274
- int _lengthOf (List <Property > properties) {
302
+ int ? _lengthOf (List <Property > properties) {
275
303
final lengthProperty = properties.firstWhere ((p) => p.name == 'length' );
276
- return lengthProperty.value.value as int ;
304
+ return lengthProperty.value? .value as int ? ;
277
305
}
278
306
279
307
/// Filter [allJsProperties] and return a list containing only those
@@ -326,15 +354,15 @@ class InstanceHelper extends Domain {
326
354
/// Create an InstanceRef for an object, which may be a RemoteObject, or may
327
355
/// be something returned by value from Chrome, e.g. number, boolean, or
328
356
/// String.
329
- Future <InstanceRef > instanceRefFor (Object value) {
357
+ Future <InstanceRef ? > instanceRefFor (Object value) {
330
358
final remote = value is RemoteObject
331
359
? value
332
360
: RemoteObject ({'value' : value, 'type' : _chromeType (value)});
333
361
return _instanceRefForRemote (remote);
334
362
}
335
363
336
364
/// The Chrome type for a value.
337
- String _chromeType (Object value) {
365
+ String ? _chromeType (Object ? value) {
338
366
if (value == null ) return null ;
339
367
if (value is String ) return 'string' ;
340
368
if (value is num ) return 'number' ;
@@ -344,15 +372,15 @@ class InstanceHelper extends Domain {
344
372
}
345
373
346
374
/// Create an [InstanceRef] for the given Chrome [remoteObject] .
347
- Future <InstanceRef > _instanceRefForRemote (RemoteObject remoteObject) async {
375
+ Future <InstanceRef ? > _instanceRefForRemote (RemoteObject ? remoteObject) async {
348
376
// If we have a null result, treat it as a reference to null.
349
377
if (remoteObject == null ) {
350
378
return kNullInstanceRef;
351
379
}
352
380
353
381
switch (remoteObject.type) {
354
382
case 'string' :
355
- final stringValue = remoteObject.value as String ;
383
+ final stringValue = remoteObject.value as String ? ;
356
384
// TODO: Support truncation for long strings.
357
385
// TODO(#777): dartIdFor() will return an ID containing the entire
358
386
// string, even if we're truncating the string value here.
@@ -362,15 +390,16 @@ class InstanceHelper extends Domain {
362
390
classRef: classRefForString,
363
391
kind: InstanceKind .kString)
364
392
..valueAsString = stringValue
365
- ..length = stringValue.length;
393
+ ..length = stringValue? .length;
366
394
case 'number' :
367
395
return _primitiveInstanceRef (InstanceKind .kDouble, remoteObject);
368
396
case 'boolean' :
369
397
return _primitiveInstanceRef (InstanceKind .kBool, remoteObject);
370
398
case 'undefined' :
371
399
return _primitiveInstanceRef (InstanceKind .kNull, remoteObject);
372
400
case 'object' :
373
- if (remoteObject.objectId == null ) {
401
+ final objectId = remoteObject.objectId;
402
+ if (objectId == null ) {
374
403
return _primitiveInstanceRef (InstanceKind .kNull, remoteObject);
375
404
}
376
405
final metaData = await ClassMetaData .metaDataFor (
@@ -379,30 +408,34 @@ class InstanceHelper extends Domain {
379
408
if (metaData.isSystemList) {
380
409
return InstanceRef (
381
410
kind: InstanceKind .kList,
382
- id: remoteObject. objectId,
411
+ id: objectId,
383
412
identityHashCode: remoteObject.objectId.hashCode,
384
413
classRef: metaData.classRef)
385
414
..length = metaData.length;
386
415
}
387
416
if (metaData.isSystemMap) {
388
417
return InstanceRef (
389
418
kind: InstanceKind .kMap,
390
- id: remoteObject. objectId,
419
+ id: objectId,
391
420
identityHashCode: remoteObject.objectId.hashCode,
392
421
classRef: metaData.classRef)
393
422
..length = metaData.length;
394
423
}
395
424
return InstanceRef (
396
425
kind: InstanceKind .kPlainInstance,
397
- id: remoteObject. objectId,
426
+ id: objectId,
398
427
identityHashCode: remoteObject.objectId.hashCode,
399
428
classRef: metaData.classRef);
400
429
case 'function' :
401
430
final functionMetaData = await FunctionMetaData .metaDataFor (
402
431
inspector.remoteDebugger, remoteObject);
432
+ final objectId = remoteObject.objectId;
433
+ if (objectId == null ) {
434
+ return _primitiveInstanceRef (InstanceKind .kNull, remoteObject);
435
+ }
403
436
return InstanceRef (
404
437
kind: InstanceKind .kClosure,
405
- id: remoteObject. objectId,
438
+ id: objectId,
406
439
identityHashCode: remoteObject.objectId.hashCode,
407
440
classRef: classRefForClosure)
408
441
// TODO(grouma) - fill this in properly.
0 commit comments