Skip to content

Commit aad32ab

Browse files
DanTupCommit Queue
authored andcommitted
[dds/dap] Improve display of Sets in debug views
- Show "Set (x items)" to match lists and maps - Compute an evaluation name as "x.elementAt(y)" since "x[y]" isn't valid for sets Fixes #60488 Change-Id: Ifb9df6e1d7cf91e2e25a421565d4c5fbb75ca0fc Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/420704 Reviewed-by: Derek Xu <[email protected]> Reviewed-by: Ben Konyi <[email protected]> Commit-Queue: Ben Konyi <[email protected]>
1 parent 43631b2 commit aad32ab

File tree

2 files changed

+75
-15
lines changed

2 files changed

+75
-15
lines changed

pkg/dds/lib/src/dap/protocol_converter.dart

Lines changed: 26 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -102,10 +102,12 @@ class ProtocolConverter {
102102
}
103103
}
104104
return stringValue;
105-
} else if (_isList(ref)) {
105+
} else if (ref.isList) {
106106
return '${ref.kind} (${ref.length} ${ref.length == 1 ? "item" : "items"})';
107-
} else if (_isMap(ref)) {
107+
} else if (ref.isMap) {
108108
return 'Map (${ref.length} ${ref.length == 1 ? "item" : "items"})';
109+
} else if (ref.isSet) {
110+
return 'Set (${ref.length} ${ref.length == 1 ? "item" : "items"})';
109111
} else if (ref.kind == 'Type') {
110112
return 'Type (${ref.name})';
111113
} else {
@@ -145,14 +147,17 @@ class ProtocolConverter {
145147
)
146148
];
147149
} else if (elements != null) {
148-
// For lists, map each item (in the requested subset) to a variable.
150+
// For lists and sets, map each item (in the requested subset) to a
151+
// variable.
149152
// Elements can contain nulls!
150153
final start = startItem ?? 0;
151154
return Future.wait(elements.cast<vm.Response?>().mapIndexed(
152155
(index, response) {
153156
final name = '[${start + index}]';
157+
final nameForEvaluation =
158+
instance.isSet ? '.elementAt(${start + index})' : name;
154159
final itemEvaluateName =
155-
_adapter.combineEvaluateName(evaluateName, name);
160+
_adapter.combineEvaluateName(evaluateName, nameForEvaluation);
156161
if (response is vm.InstanceRef) {
157162
_adapter.storeEvaluateName(response, itemEvaluateName);
158163
}
@@ -209,7 +214,7 @@ class ProtocolConverter {
209214
variablesReference: thread.storeData(VariableData(mapEntry, format)),
210215
);
211216
}));
212-
} else if (_isList(instance) &&
217+
} else if (instance.isList &&
213218
instance.length != null &&
214219
instance.bytes != null) {
215220
final formatter = format ?? const VariableFormat();
@@ -518,7 +523,8 @@ class ProtocolConverter {
518523
allowCallingToString: allowCallingToString,
519524
format: format,
520525
),
521-
indexedVariables: _isList(response) ? response.length : null,
526+
indexedVariables:
527+
response.isList || response.isSet ? response.length : null,
522528
variablesReference: variablesReference,
523529
);
524530
} else if (response is vm.Sentinel) {
@@ -550,15 +556,6 @@ class ProtocolConverter {
550556
}
551557
}
552558

553-
/// Returns whether [ref] is a List kind.
554-
///
555-
/// This includes standard Dart [List], as well as lists from
556-
/// `dart:typed_data` such as `Uint8List`.
557-
bool _isList(vm.InstanceRef ref) => ref.kind?.endsWith('List') ?? false;
558-
559-
/// Returns whether [ref] is a Map kind.
560-
bool _isMap(vm.InstanceRef ref) => ref.kind == 'Map';
561-
562559
/// Converts a VM Service stack frame to a DAP stack frame.
563560
Future<dap.StackFrame> convertVmToDapStackFrame(
564561
ThreadInfo thread,
@@ -820,3 +817,17 @@ class ProtocolConverter {
820817
return null;
821818
}
822819
}
820+
821+
extension on vm.InstanceRef {
822+
/// Whether this instance is a List kind.
823+
///
824+
/// This includes standard Dart [List], as well as lists from
825+
/// `dart:typed_data` such as `Uint8List`.
826+
bool get isList => kind?.endsWith('List') ?? false;
827+
828+
/// Whether this instance is a Map kind.
829+
bool get isMap => kind == 'Map';
830+
831+
/// Whether this instance is a Set kind.
832+
bool get isSet => kind == 'Set';
833+
}

pkg/dds/test/dap/integration/debug_variables_test.dart

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -405,6 +405,55 @@ void main(List<String> args) {
405405
);
406406
});
407407

408+
test('renders a simple set', () async {
409+
final client = dap.client;
410+
final testFile = dap.createTestFile('''
411+
void main(List<String> args) {
412+
final myVariable = {"first", "second", "third", null};
413+
print('Hello!'); $breakpointMarker
414+
}
415+
''');
416+
final breakpointLine = lineWith(testFile, breakpointMarker);
417+
418+
final stop = await client.hitBreakpoint(testFile, breakpointLine);
419+
await client.expectLocalVariable(
420+
stop.threadId!,
421+
expectedName: 'myVariable',
422+
expectedDisplayString: 'Set (4 items)',
423+
expectedIndexedItems: 4,
424+
expectedVariables: '''
425+
[0]: "first", eval: myVariable.elementAt(0)
426+
[1]: "second", eval: myVariable.elementAt(1)
427+
[2]: "third", eval: myVariable.elementAt(2)
428+
[3]: null
429+
''',
430+
);
431+
});
432+
433+
test('renders a simple set subset', () async {
434+
final client = dap.client;
435+
final testFile = dap.createTestFile('''
436+
void main(List<String> args) {
437+
final myVariable = {"first", "second", "third"};
438+
print('Hello!'); $breakpointMarker
439+
}
440+
''');
441+
final breakpointLine = lineWith(testFile, breakpointMarker);
442+
443+
final stop = await client.hitBreakpoint(testFile, breakpointLine);
444+
await client.expectLocalVariable(
445+
stop.threadId!,
446+
expectedName: 'myVariable',
447+
expectedDisplayString: 'Set (3 items)',
448+
expectedIndexedItems: 3,
449+
expectedVariables: '''
450+
[1]: "second", eval: myVariable.elementAt(1)
451+
''',
452+
start: 1,
453+
count: 1,
454+
);
455+
});
456+
408457
test('only calls toString() for 100 items in a list', () async {
409458
final client = dap.client;
410459
// Generate a file that assigns a list of 150 items

0 commit comments

Comments
 (0)