Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit eb7661b

Browse files
author
Dart CI
committed
Version 2.15.0-11.0.dev
Merge commit '5cec85d5ce49d13105e593f8fe6afb576ca5a3c2' into 'dev'
2 parents 3272e5c + 5cec85d commit eb7661b

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+1124
-424
lines changed

.dart_tool/package_config.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
"constraint, update this by running tools/generate_package_config.dart."
1212
],
1313
"configVersion": 2,
14-
"generated": "2021-08-05T11:33:04.746536",
14+
"generated": "2021-08-10T10:51:47.272341",
1515
"generator": "tools/generate_package_config.dart",
1616
"packages": [
1717
{
@@ -659,7 +659,7 @@
659659
"name": "status_file",
660660
"rootUri": "../pkg/status_file",
661661
"packageUri": "lib/",
662-
"languageVersion": "2.3"
662+
"languageVersion": "2.12"
663663
},
664664
{
665665
"name": "stream_channel",

pkg/dart_internal/pubspec.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name: dart_internal
2-
version: 0.2.1
2+
version: 0.2.2
33
repository: https://github.com/dart-lang/sdk/tree/master/pkg/dart_internal
44
description: >-
55
This package is not intended for wide use. It provides a temporary API to
@@ -9,4 +9,4 @@ description: >-
99
environment:
1010
# Restrict the upper bound so that we can remove support for this in a later
1111
# version of the SDK without it being a breaking change.
12-
sdk: ">=2.12.0 <2.15.0"
12+
sdk: ">=2.12.0 <2.16.0"

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

Lines changed: 88 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,20 @@ abstract class DartDebugAdapter<T extends DartLaunchRequestArguments>
138138
/// have been called.
139139
late final bool isAttach;
140140

141+
/// A list of evaluateNames for InstanceRef IDs.
142+
///
143+
/// When providing variables for fields/getters or items in maps/arrays, we
144+
/// need to provide an expression to the client that evaluates to that
145+
/// variable so that functionality like "Add to Watch" or "Copy Value" can
146+
/// work. For example, if a user expands a list named `myList` then the 1st
147+
/// [Variable] returned should have an evaluateName of `myList[0]`. The `foo`
148+
/// getter of that object would then have an evaluateName of `myList[0].foo`.
149+
///
150+
/// Since those expressions aren't round-tripped as child variables are
151+
/// requested we build them up as we send variables out, so we can append to
152+
/// them when returning elements/map entries/fields/getters.
153+
final _evaluateNamesForInstanceRefIds = <String, String>{};
154+
141155
/// A list of all possible project paths that should be considered the users
142156
/// own code.
143157
///
@@ -219,6 +233,26 @@ abstract class DartDebugAdapter<T extends DartLaunchRequestArguments>
219233
// sendResponse();
220234
}
221235

236+
/// Builds an evaluateName given a parent VM InstanceRef ID and a suffix.
237+
///
238+
/// If [parentInstanceRefId] is `null`, or we have no evaluateName for it,
239+
/// will return null.
240+
String? buildEvaluateName(
241+
String suffix, {
242+
required String? parentInstanceRefId,
243+
}) {
244+
final parentEvaluateName =
245+
_evaluateNamesForInstanceRefIds[parentInstanceRefId];
246+
return combineEvaluateName(parentEvaluateName, suffix);
247+
}
248+
249+
/// Builds an evaluateName given a prefix and a suffix.
250+
///
251+
/// If [prefix] is null, will return be null.
252+
String? combineEvaluateName(String? prefix, String suffix) {
253+
return prefix != null ? '$prefix$suffix' : null;
254+
}
255+
222256
/// configurationDone is called by the client when it has finished sending
223257
/// any initial configuration (such as breakpoints and exception pause
224258
/// settings).
@@ -489,11 +523,14 @@ abstract class DartDebugAdapter<T extends DartLaunchRequestArguments>
489523
result,
490524
allowCallingToString: evaluateToStringInDebugViews,
491525
);
492-
// TODO(dantup): We may need to store `expression` with this data
493-
// to allow building nested evaluateNames.
526+
494527
final variablesReference =
495528
_converter.isSimpleKind(result.kind) ? 0 : thread.storeData(result);
496529

530+
// Store the expression that gets this object as we may need it to
531+
// compute evaluateNames for child objects later.
532+
storeEvaluateName(result, expression);
533+
497534
sendResponse(EvaluateResponseBody(
498535
result: resultString,
499536
variablesReference: variablesReference,
@@ -663,7 +700,7 @@ abstract class DartDebugAdapter<T extends DartLaunchRequestArguments>
663700
// For local variables, we can just reuse the frameId as variablesReference
664701
// as variablesRequest handles stored data of type `Frame` directly.
665702
scopes.add(Scope(
666-
name: 'Variables',
703+
name: 'Locals',
667704
presentationHint: 'locals',
668705
variablesReference: args.frameId,
669706
expensive: false,
@@ -943,6 +980,14 @@ abstract class DartDebugAdapter<T extends DartLaunchRequestArguments>
943980
sendResponse();
944981
}
945982

983+
/// Stores [evaluateName] as the expression that can be evaluated to get
984+
/// [instanceRef].
985+
void storeEvaluateName(vm.InstanceRef instanceRef, String? evaluateName) {
986+
if (evaluateName != null) {
987+
_evaluateNamesForInstanceRefIds[instanceRef.id!] = evaluateName;
988+
}
989+
}
990+
946991
/// Overridden by sub-classes to handle when the client sends a
947992
/// `terminateRequest` (a request for a graceful shut down).
948993
Future<void> terminateImpl();
@@ -1032,19 +1077,55 @@ abstract class DartDebugAdapter<T extends DartLaunchRequestArguments>
10321077
final vars = vmData.vars;
10331078
if (vars != null) {
10341079
Future<Variable> convert(int index, vm.BoundVariable variable) {
1080+
// Store the expression that gets this object as we may need it to
1081+
// compute evaluateNames for child objects later.
1082+
storeEvaluateName(variable.value, variable.name);
10351083
return _converter.convertVmResponseToVariable(
10361084
thread,
10371085
variable.value,
10381086
name: variable.name,
10391087
allowCallingToString: evaluateToStringInDebugViews &&
10401088
index <= maxToStringsPerEvaluation,
1089+
evaluateName: variable.name,
10411090
);
10421091
}
10431092

10441093
variables.addAll(await Future.wait(vars.mapIndexed(convert)));
1094+
1095+
// Sort the variables by name.
1096+
variables.sortBy((v) => v.name);
1097+
}
1098+
} else if (data is vm.MapAssociation) {
1099+
final key = data.key;
1100+
final value = data.value;
1101+
if (key is vm.InstanceRef && value is vm.InstanceRef) {
1102+
// For a MapAssociation, we create a dummy set of variables for "key" and
1103+
// "value" so that each may be expanded if they are complex values.
1104+
variables.addAll([
1105+
Variable(
1106+
name: 'key',
1107+
value: await _converter.convertVmInstanceRefToDisplayString(
1108+
thread,
1109+
key,
1110+
allowCallingToString: evaluateToStringInDebugViews,
1111+
),
1112+
variablesReference:
1113+
_converter.isSimpleKind(key.kind) ? 0 : thread.storeData(key),
1114+
),
1115+
Variable(
1116+
name: 'value',
1117+
value: await _converter.convertVmInstanceRefToDisplayString(
1118+
thread,
1119+
value,
1120+
allowCallingToString: evaluateToStringInDebugViews,
1121+
),
1122+
variablesReference: _converter.isSimpleKind(value.kind)
1123+
? 0
1124+
: thread.storeData(value),
1125+
evaluateName:
1126+
buildEvaluateName('', parentInstanceRefId: value.id)),
1127+
]);
10451128
}
1046-
} else if (vmData is vm.MapAssociation) {
1047-
// TODO(dantup): Maps
10481129
} else if (vmData is vm.ObjRef) {
10491130
final object =
10501131
await _isolateManager.getObject(storedData.thread.isolate, vmData);
@@ -1056,13 +1137,10 @@ abstract class DartDebugAdapter<T extends DartLaunchRequestArguments>
10561137
variablesReference: 0,
10571138
));
10581139
} else if (object is vm.Instance) {
1059-
// TODO(dantup): evaluateName
1060-
// should be built taking the parent into account, for ex. if
1061-
// args.variablesReference == thread.exceptionReference then we need to
1062-
// use some sythensized variable name like `frameExceptionExpression`.
10631140
variables.addAll(await _converter.convertVmInstanceToVariablesList(
10641141
thread,
10651142
object,
1143+
evaluateName: buildEvaluateName('', parentInstanceRefId: vmData.id),
10661144
allowCallingToString: evaluateToStringInDebugViews,
10671145
startItem: childStart,
10681146
numItems: childCount,
@@ -1076,8 +1154,6 @@ abstract class DartDebugAdapter<T extends DartLaunchRequestArguments>
10761154
}
10771155
}
10781156

1079-
variables.sortBy((v) => v.name);
1080-
10811157
sendResponse(VariablesResponseBody(variables: variables));
10821158
}
10831159

@@ -1172,6 +1248,7 @@ abstract class DartDebugAdapter<T extends DartLaunchRequestArguments>
11721248
// string they logged regardless of the evaluateToStringInDebugViews
11731249
// setting.
11741250
allowCallingToString: true,
1251+
allowTruncatedValue: false,
11751252
includeQuotesAroundString: false,
11761253
);
11771254
}

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -444,6 +444,7 @@ class IsolateManager {
444444
// can add a variables scope for it so it can be examined.
445445
final exception = event.exception;
446446
if (exception != null) {
447+
_adapter.storeEvaluateName(exception, threadExceptionExpression);
447448
thread.exceptionReference = thread.storeData(exception);
448449
}
449450

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

Lines changed: 48 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -61,17 +61,22 @@ class ProtocolConverter {
6161
ThreadInfo thread,
6262
vm.InstanceRef ref, {
6363
required bool allowCallingToString,
64+
bool allowTruncatedValue = true,
6465
bool includeQuotesAroundString = true,
6566
}) async {
6667
final isTruncated = ref.valueAsStringIsTruncated ?? false;
6768
if (ref.kind == vm.InstanceKind.kString && isTruncated) {
68-
// Call toString() if allowed, otherwise (or if it returns null) fall back
69-
// to the truncated value with "…" suffix.
70-
var stringValue = allowCallingToString
69+
// Call toString() if allowed (and we don't already have a value),
70+
// otherwise (or if it returns null) fall back to the truncated value
71+
// with "…" suffix.
72+
var stringValue = allowCallingToString &&
73+
(ref.valueAsString == null || !allowTruncatedValue)
7174
? await _callToString(
7275
thread,
7376
ref,
74-
includeQuotesAroundString: includeQuotesAroundString,
77+
// Quotes are handled below, so they can be wrapped around the
78+
// elipsis.
79+
includeQuotesAroundString: false,
7580
)
7681
: null;
7782
stringValue ??= '${ref.valueAsString}…';
@@ -116,6 +121,7 @@ class ProtocolConverter {
116121
Future<List<dap.Variable>> convertVmInstanceToVariablesList(
117122
ThreadInfo thread,
118123
vm.Instance instance, {
124+
required String? evaluateName,
119125
required bool allowCallingToString,
120126
int? startItem = 0,
121127
int? numItems,
@@ -130,6 +136,8 @@ class ProtocolConverter {
130136
await convertVmResponseToVariable(
131137
thread,
132138
instance,
139+
name: null,
140+
evaluateName: evaluateName,
133141
allowCallingToString: allowCallingToString,
134142
)
135143
];
@@ -143,7 +151,9 @@ class ProtocolConverter {
143151
(index, response) => convertVmResponseToVariable(
144152
thread,
145153
response,
146-
name: '${start + index}',
154+
name: '[${start + index}]',
155+
evaluateName: _adapter.combineEvaluateName(
156+
evaluateName, '[${start + index}]'),
147157
allowCallingToString:
148158
allowCallingToString && index <= maxToStringsPerEvaluation,
149159
),
@@ -158,14 +168,26 @@ class ProtocolConverter {
158168
return Future.wait(associations
159169
.sublist(start, numItems != null ? start + numItems : null)
160170
.mapIndexed((index, mapEntry) async {
171+
final key = mapEntry.key;
172+
final value = mapEntry.value;
161173
final callToString =
162174
allowCallingToString && index <= maxToStringsPerEvaluation;
163-
final keyDisplay = await convertVmResponseToDisplayString(
164-
thread, mapEntry.key,
175+
176+
final keyDisplay = await convertVmResponseToDisplayString(thread, key,
165177
allowCallingToString: callToString);
166178
final valueDisplay = await convertVmResponseToDisplayString(
167-
thread, mapEntry.value,
179+
thread, value,
168180
allowCallingToString: callToString);
181+
182+
// We only provide an evaluateName for the value, and only if the
183+
// key is a simple value.
184+
if (key is vm.InstanceRef &&
185+
value is vm.InstanceRef &&
186+
evaluateName != null &&
187+
isSimpleKind(key.kind)) {
188+
_adapter.storeEvaluateName(value, '$evaluateName[$keyDisplay]');
189+
}
190+
169191
return dap.Variable(
170192
name: '${start + index}',
171193
value: '$keyDisplay -> $valueDisplay',
@@ -175,11 +197,17 @@ class ProtocolConverter {
175197
} else if (fields != null) {
176198
// Otherwise, show the fields from the instance.
177199
final variables = await Future.wait(fields.mapIndexed(
178-
(index, field) async => convertVmResponseToVariable(
179-
thread, field.value,
180-
name: field.decl?.name ?? '<unnamed field>',
200+
(index, field) async {
201+
final name = field.decl?.name;
202+
return convertVmResponseToVariable(thread, field.value,
203+
name: name ?? '<unnamed field>',
204+
evaluateName: name != null
205+
? _adapter.combineEvaluateName(evaluateName, '.$name')
206+
: null,
181207
allowCallingToString:
182-
allowCallingToString && index <= maxToStringsPerEvaluation)));
208+
allowCallingToString && index <= maxToStringsPerEvaluation);
209+
},
210+
));
183211

184212
// Also evaluate the getters if evaluateGettersInDebugViews=true enabled.
185213
final service = _adapter.vmService;
@@ -202,6 +230,8 @@ class ProtocolConverter {
202230
thread,
203231
response,
204232
name: getterName,
233+
evaluateName:
234+
_adapter.combineEvaluateName(evaluateName, '.$getterName'),
205235
allowCallingToString:
206236
allowCallingToString && index <= maxToStringsPerEvaluation,
207237
);
@@ -210,6 +240,9 @@ class ProtocolConverter {
210240
variables.addAll(await Future.wait(getterNames.mapIndexed(evaluate)));
211241
}
212242

243+
// Sort the fields/getters by name.
244+
variables.sortBy((v) => v.name);
245+
213246
return variables;
214247
} else {
215248
// For any other type that we don't produce variables for, return an empty
@@ -254,7 +287,8 @@ class ProtocolConverter {
254287
Future<dap.Variable> convertVmResponseToVariable(
255288
ThreadInfo thread,
256289
vm.Response response, {
257-
String? name,
290+
required String? name,
291+
required String? evaluateName,
258292
required bool allowCallingToString,
259293
}) async {
260294
if (response is vm.InstanceRef) {
@@ -265,6 +299,7 @@ class ProtocolConverter {
265299

266300
return dap.Variable(
267301
name: name ?? response.kind.toString(),
302+
evaluateName: evaluateName,
268303
value: await convertVmResponseToDisplayString(
269304
thread,
270305
response,

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,12 +47,12 @@ void main(List<String> args) {
4747
);
4848

4949
// Check we got a variablesReference that maps on to the fields.
50-
expect(result.variablesReference, greaterThan(0));
50+
expect(result.variablesReference, isPositive);
5151
await client.expectVariables(
5252
result.variablesReference,
5353
'''
54-
isUtc: false
55-
''',
54+
isUtc: false, eval: DateTime(2000, 1, 1).isUtc
55+
''',
5656
);
5757
});
5858

@@ -111,7 +111,7 @@ void main(List<String> args) {
111111
threadExceptionExpression,
112112
'_Exception',
113113
);
114-
expect(result.variablesReference, greaterThan(0));
114+
expect(result.variablesReference, isPositive);
115115
});
116116

117117
test(

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ void main(List<String> args) async {
159159

160160
// SDK sources should have a sourceReference and no path.
161161
expect(topFrame.source!.path, isNull);
162-
expect(topFrame.source!.sourceReference, greaterThan(0));
162+
expect(topFrame.source!.sourceReference, isPositive);
163163

164164
// Source code should contain the implementation/signature of print().
165165
final source = await client.getValidSource(topFrame.source!);

0 commit comments

Comments
 (0)