Skip to content

Commit e382db3

Browse files
author
Anna Gringauze
authored
Fix failures on displaying getters (#2343)
* Fix test faliures * Update changelog * Fixe analyzer errors * Display type instanses as common instances * Added getters checks to instance tests * Fixed analyzer errors * Add dart:_rti to the list of sdk libraries * Fix failing tests * Fixed failing tests
1 parent a5ad753 commit e382db3

File tree

10 files changed

+582
-231
lines changed

10 files changed

+582
-231
lines changed

dwds/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
- Send untruncated `dart:developer` logs to debugging clients. - [#2333](https://github.com/dart-lang/webdev/pull/2333)
88
- Enabling tests that run with the DDC module system and exposing `utilities/ddc_names.dart` - [#2295](https://github.com/dart-lang/webdev/pull/2295)
9+
- Fix errors on displaying getters. - [#2343](https://github.com/dart-lang/webdev/pull/2343)
910

1011
## 23.1.1
1112

dwds/lib/src/debugging/instance.dart

Lines changed: 37 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -238,29 +238,49 @@ class InstanceHelper extends Domain {
238238
final objectId = remoteObject.objectId;
239239
if (objectId == null) return null;
240240

241+
final fields = await _getInstanceFields(
242+
metaData,
243+
remoteObject,
244+
offset: offset,
245+
count: count,
246+
);
247+
248+
final result = Instance(
249+
kind: InstanceKind.kPlainInstance,
250+
id: objectId,
251+
identityHashCode: remoteObject.objectId.hashCode,
252+
classRef: metaData.classRef,
253+
fields: fields,
254+
);
255+
return result;
256+
}
257+
258+
Future<List<BoundField>> _getInstanceFields(
259+
ClassMetaData metaData,
260+
RemoteObject remoteObject, {
261+
int? offset,
262+
int? count,
263+
}) async {
264+
final objectId = remoteObject.objectId;
265+
if (objectId == null) throw StateError('Object id is null for instance');
266+
241267
final properties = await inspector.getProperties(
242268
objectId,
243269
offset: offset,
244270
count: count,
245271
length: metaData.length,
246272
);
273+
247274
final dartProperties = await _dartFieldsFor(properties, remoteObject);
248-
var boundFields = await Future.wait(
275+
final boundFields = await Future.wait(
249276
dartProperties
250277
.map<Future<BoundField>>((p) => _fieldFor(p, metaData.classRef)),
251278
);
252-
boundFields = boundFields
279+
280+
return boundFields
253281
.where((bv) => inspector.isDisplayableObject(bv.value))
254282
.toList()
255283
..sort(_compareBoundFields);
256-
final result = Instance(
257-
kind: InstanceKind.kPlainInstance,
258-
id: objectId,
259-
identityHashCode: remoteObject.objectId.hashCode,
260-
classRef: metaData.classRef,
261-
fields: boundFields,
262-
);
263-
return result;
264284
}
265285

266286
int _compareBoundFields(BoundField a, BoundField b) {
@@ -700,7 +720,13 @@ class InstanceHelper extends Domain {
700720
final objectId = remoteObject.objectId;
701721
if (objectId == null) return null;
702722

703-
final fields = await _typeFields(metaData.classRef, remoteObject);
723+
final fields = await _getInstanceFields(
724+
metaData,
725+
remoteObject,
726+
offset: offset,
727+
count: count,
728+
);
729+
704730
return Instance(
705731
identityHashCode: objectId.hashCode,
706732
kind: InstanceKind.kType,
@@ -714,36 +740,6 @@ class InstanceHelper extends Domain {
714740
);
715741
}
716742

717-
/// The field types for a Dart RecordType.
718-
///
719-
/// Returns a range of [count] field types, if available, starting from
720-
/// the [offset].
721-
///
722-
/// If [offset] is `null`, assumes 0 offset.
723-
/// If [count] is `null`, return all field types starting from the offset.
724-
Future<List<BoundField>> _typeFields(
725-
ClassRef classRef,
726-
RemoteObject type,
727-
) async {
728-
// Present the type as an instance of `core.Type` class and
729-
// hide the internal implementation.
730-
final expression = _jsRuntimeFunctionCall('getTypeFields(this)');
731-
732-
final result = await inspector.jsCallFunctionOn(type, expression, []);
733-
final hashCodeObject = await inspector.loadField(result, 'hashCode');
734-
final runtimeTypeObject = await inspector.loadField(result, 'runtimeType');
735-
736-
final properties = [
737-
Property({'name': 'hashCode', 'value': hashCodeObject}),
738-
Property({'name': 'runtimeType', 'value': runtimeTypeObject}),
739-
];
740-
741-
final boundFields = await Future.wait(
742-
properties.map<Future<BoundField>>((p) => _fieldFor(p, classRef)),
743-
);
744-
return boundFields;
745-
}
746-
747743
/// Return the available count of elements in the requested range.
748744
/// Return `null` if the range includes the whole object.
749745
/// [count] is the range length requested by the `getObject` call.

dwds/lib/src/debugging/metadata/provider.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ class MetadataProvider {
4444
'dart:_js_primitives',
4545
'dart:_metadata',
4646
'dart:_native_typed_data',
47+
'dart:_rti',
4748
'dart:async',
4849
'dart:collection',
4950
'dart:convert',

dwds/lib/src/services/chrome_proxy_service.dart

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -618,7 +618,35 @@ ${globalToolConfiguration.loadStrategy.loadModuleSnippet}("dart_sdk").developer.
618618
await isCompilerInitialized;
619619
_checkIsolate('evaluate', isolateId);
620620

621-
final library = await inspector.getLibrary(targetId);
621+
late Obj object;
622+
try {
623+
object = await inspector.getObject(targetId);
624+
} catch (_) {
625+
return ErrorRef(
626+
kind: 'error',
627+
message: 'Evaluate is called on an unsupported target:'
628+
'$targetId',
629+
id: createId(),
630+
);
631+
}
632+
633+
final library =
634+
object is Library ? object : inspector.isolate.rootLib;
635+
636+
if (object is Instance) {
637+
// Evaluate is called on a target - convert this to a dart
638+
// expression and scope by adding a target variable to the
639+
// expression and the scope, for example:
640+
//
641+
// Library: 'package:hello_world/main.dart'
642+
// Expression: 'hashCode' => 'x.hashCode'
643+
// Scope: {} => { 'x' : targetId }
644+
645+
final target = _newVariableForScope(scope);
646+
expression = '$target.$expression';
647+
scope = (scope ?? {})..addAll({target: targetId});
648+
}
649+
622650
return await _getEvaluationResult(
623651
isolateId,
624652
() => evaluator.evaluateExpression(
@@ -631,7 +659,7 @@ ${globalToolConfiguration.loadStrategy.loadModuleSnippet}("dart_sdk").developer.
631659
);
632660
}
633661
throw RPCError(
634-
'evaluateInFrame',
662+
'evaluate',
635663
RPCErrorKind.kInvalidRequest.code,
636664
'Expression evaluation is not supported for this configuration.',
637665
);
@@ -640,6 +668,15 @@ ${globalToolConfiguration.loadStrategy.loadModuleSnippet}("dart_sdk").developer.
640668
);
641669
}
642670

671+
String _newVariableForScope(Map<String, String>? scope) {
672+
// Find a new variable not in scope.
673+
var candidate = 'x';
674+
while (scope?.containsKey(candidate) ?? false) {
675+
candidate += '\$1';
676+
}
677+
return candidate;
678+
}
679+
643680
@override
644681
Future<Response> evaluateInFrame(
645682
String isolateId,

dwds/test/evaluate_common.dart

Lines changed: 43 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -321,7 +321,7 @@ void testAll({
321321
await getInstanceRef(event.topFrame!.index!, 'stream');
322322
final instance = await getInstance(instanceRef);
323323

324-
expect(instance, matchInstance('_AsBroadcastStream<int>'));
324+
expect(instance, matchInstanceClassName('_AsBroadcastStream<int>'));
325325
});
326326
});
327327

@@ -668,24 +668,24 @@ void testAll({
668668
tearDown(() async {});
669669

670670
evaluate(
671-
libraryId,
671+
targetId,
672672
expr, {
673673
scope,
674674
}) async =>
675675
await context.service.evaluate(
676676
isolateId,
677-
libraryId,
677+
targetId,
678678
expr,
679679
scope: scope,
680680
);
681681

682682
getInstanceRef(
683-
libraryId,
683+
targetId,
684684
expr, {
685685
scope,
686686
}) async {
687687
final result = await evaluate(
688-
libraryId,
688+
targetId,
689689
expr,
690690
scope: scope,
691691
);
@@ -699,6 +699,28 @@ void testAll({
699699
return isolate.rootLib!.id!;
700700
}
701701

702+
test(
703+
'RecordType getters',
704+
() async {
705+
final libraryId = getRootLibraryId();
706+
707+
final type = await getInstanceRef(libraryId, '(0,1).runtimeType');
708+
final result = await getInstanceRef(type.id, 'hashCode');
709+
710+
expect(result, matchInstanceRefKind('Double'));
711+
},
712+
skip: 'https://github.com/dart-lang/sdk/issues/54609',
713+
);
714+
715+
test('Object getters', () async {
716+
final libraryId = getRootLibraryId();
717+
718+
final type = await getInstanceRef(libraryId, 'Object()');
719+
final result = await getInstanceRef(type.id, 'hashCode');
720+
721+
expect(result, matchInstanceRefKind('Double'));
722+
});
723+
702724
test('with scope', () async {
703725
final libraryId = getRootLibraryId();
704726

@@ -762,15 +784,13 @@ void testAll({
762784
final evaluation2 = evaluate(libraryId, 'MainClass(1,1).toString()');
763785

764786
final results = await Future.wait([evaluation1, evaluation2]);
765-
766787
expect(
767788
results[0],
768-
matchErrorRef(contains('No batch result object ID')),
769-
);
770-
expect(
771-
results[1],
772-
matchErrorRef(contains('No batch result object ID')),
789+
matchErrorRef(
790+
contains('Evaluate is called on an unsupported target'),
791+
),
773792
);
793+
expect(results[1], matchInstanceRef('1, 1'));
774794
});
775795

776796
test('with scope override', () async {
@@ -902,13 +922,20 @@ Future<String> _setBreakpointInInjectedClient(WipDebugger debugger) async {
902922
return result.json['result']['breakpointId'];
903923
}
904924

905-
Matcher matchInstanceRef(dynamic value) => isA<InstanceRef>().having(
906-
(instance) => instance.valueAsString,
907-
'valueAsString',
908-
value,
925+
Matcher matchInstanceRefKind(String kind) =>
926+
isA<InstanceRef>().having((instance) => instance.kind, 'kind', kind);
927+
928+
Matcher matchInstanceRef(dynamic value) => isA<InstanceRef>()
929+
.having((instance) => instance.valueAsString, 'valueAsString', value);
930+
931+
Matcher matchInstanceClassName(dynamic className) => isA<Instance>().having(
932+
(instance) => instance.classRef!.name,
933+
'class name',
934+
className,
909935
);
910936

911-
Matcher matchInstance(dynamic className) => isA<Instance>().having(
937+
Matcher matchInstanceRefClassName(dynamic className) =>
938+
isA<InstanceRef>().having(
912939
(instance) => instance.classRef!.name,
913940
'class name',
914941
className,

dwds/test/instances/common/instance_inspection_common.dart

Lines changed: 48 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -189,14 +189,32 @@ void runTests({
189189
final instanceId = instanceRef.id!;
190190
expect(await getObject(instanceId), matchListInstance(type: 'int'));
191191

192-
expect(await getFields(instanceRef), [0, 1, 2]);
193-
expect(await getFields(instanceRef, offset: 1, count: 0), []);
194-
expect(await getFields(instanceRef, offset: 0), [0, 1, 2]);
195-
expect(await getFields(instanceRef, offset: 0, count: 1), [0]);
196-
expect(await getFields(instanceRef, offset: 1), [1, 2]);
197-
expect(await getFields(instanceRef, offset: 1, count: 1), [1]);
198-
expect(await getFields(instanceRef, offset: 1, count: 3), [1, 2]);
199-
expect(await getFields(instanceRef, offset: 3, count: 3), []);
192+
expect(
193+
await getFields(instanceRef),
194+
{0: 0.0, 1: 1.0, 2: 2.0},
195+
);
196+
expect(await getFields(instanceRef, offset: 1, count: 0), {});
197+
expect(
198+
await getFields(instanceRef, offset: 0),
199+
{0: 0.0, 1: 1.0, 2: 2.0},
200+
);
201+
expect(
202+
await getFields(instanceRef, offset: 0, count: 1),
203+
{0: 0.0},
204+
);
205+
expect(
206+
await getFields(instanceRef, offset: 1),
207+
{0: 1.0, 1: 2.0},
208+
);
209+
expect(
210+
await getFields(instanceRef, offset: 1, count: 1),
211+
{0: 1.0},
212+
);
213+
expect(
214+
await getFields(instanceRef, offset: 1, count: 3),
215+
{0: 1.0, 1: 2.0},
216+
);
217+
expect(await getFields(instanceRef, offset: 3, count: 3), {});
200218
});
201219
});
202220

@@ -284,13 +302,28 @@ void runTests({
284302
matchSetInstance(type: '_HashSet<int>'),
285303
);
286304

287-
expect(await getFields(instanceRef), [1, 4, 5, 7]);
288-
expect(await getFields(instanceRef, offset: 0), [1, 4, 5, 7]);
289-
expect(await getFields(instanceRef, offset: 1, count: 2), [4, 5]);
290-
expect(await getFields(instanceRef, offset: 2), [5, 7]);
291-
expect(await getFields(instanceRef, offset: 2, count: 10), [5, 7]);
292-
expect(await getFields(instanceRef, offset: 1, count: 0), []);
293-
expect(await getFields(instanceRef, offset: 10, count: 2), []);
305+
expect(
306+
await getFields(instanceRef),
307+
{0: 1.0, 1: 4.0, 2: 5.0, 3: 7.0},
308+
);
309+
expect(
310+
await getFields(instanceRef, offset: 0),
311+
{0: 1.0, 1: 4.0, 2: 5.0, 3: 7.0},
312+
);
313+
expect(
314+
await getFields(instanceRef, offset: 1, count: 2),
315+
{0: 4.0, 1: 5.0},
316+
);
317+
expect(
318+
await getFields(instanceRef, offset: 2),
319+
{0: 5.0, 1: 7.0},
320+
);
321+
expect(
322+
await getFields(instanceRef, offset: 2, count: 10),
323+
{0: 5.0, 1: 7.0},
324+
);
325+
expect(await getFields(instanceRef, offset: 1, count: 0), {});
326+
expect(await getFields(instanceRef, offset: 10, count: 2), {});
294327
});
295328
});
296329

dwds/test/instances/common/patterns_inspection_common.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ void runTests({
105105
final frame = event.topFrame!;
106106
final frameIndex = frame.index!;
107107
final instanceRef = await getInstanceRef(frameIndex, 'obj');
108-
expect(await getFields(instanceRef), [0, 1]);
108+
expect(await getFields(instanceRef), {0: 0.0, 1: 1.0});
109109

110110
expect(await getFrameVariables(frame), {
111111
'obj': matchListInstance(type: 'int'),

0 commit comments

Comments
 (0)