Skip to content

Commit 34a3eb3

Browse files
author
Anna Gringauze
authored
Migrate expression evaluator to null safety (#1686)
* Migrate debugging/inspector.dart to null safety * Migrate expression evaluator to null safety * format * Fix failing tests * Undo unnecessary move of urlForScriptId from debugger to inspector * Undo unnecessary changes in fakes.dart
1 parent 8aadd89 commit 34a3eb3

File tree

3 files changed

+54
-49
lines changed

3 files changed

+54
-49
lines changed

dwds/lib/src/services/chrome_proxy_service.dart

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -458,16 +458,6 @@ ${globalLoadStrategy.loadModuleSnippet}("dart_sdk").developer.invokeExtension(
458458
await isCompilerInitialized;
459459
_checkIsolate('evaluateInFrame', isolateId);
460460

461-
if (scope != null) {
462-
// TODO(annagrin): Implement scope support.
463-
// Issue: https://github.com/dart-lang/webdev/issues/1344
464-
throw RPCError(
465-
'evaluateInFrame',
466-
RPCError.kInvalidRequest,
467-
'Expression evaluation with scope is not supported '
468-
'for this configuration.');
469-
}
470-
471461
return await _getEvaluationResult(
472462
() => _expressionEvaluator.evaluateExpressionInFrame(
473463
isolateId, frameIndex, expression, scope),

dwds/lib/src/services/expression_evaluator.dart

Lines changed: 41 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22
// for details. All rights reserved. Use of this source code is governed by a
33
// BSD-style license that can be found in the LICENSE file.
44

5-
// @dart = 2.9
6-
75
import 'package:dwds/src/utilities/domain.dart';
86
import 'package:logging/logging.dart';
97
import 'package:webkit_inspection_protocol/webkit_inspection_protocol.dart';
@@ -78,19 +76,18 @@ class ExpressionEvaluator {
7876
String isolateId,
7977
String libraryUri,
8078
String expression,
81-
Map<String, String> scope,
79+
Map<String, String>? scope,
8280
) async {
8381
scope ??= {};
84-
if (_compiler == null) {
85-
return _createError(ErrorKind.internal,
86-
'ExpressionEvaluator needs an ExpressionCompiler');
87-
}
8882

89-
if (expression == null || expression.isEmpty) {
83+
if (expression.isEmpty) {
9084
return _createError(ErrorKind.invalidInput, expression);
9185
}
9286

9387
final module = await _modules.moduleForlibrary(libraryUri);
88+
if (module == null) {
89+
return _createError(ErrorKind.internal, 'no module for $libraryUri');
90+
}
9491

9592
// Wrap the expression in a lambda so we can call it as a function.
9693
expression = _createDartLambda(expression, scope.keys);
@@ -132,13 +129,17 @@ class ExpressionEvaluator {
132129
/// [frameIndex] JavaScript frame to evaluate the expression in.
133130
/// [expression] dart expression to evaluate.
134131
Future<RemoteObject> evaluateExpressionInFrame(String isolateId,
135-
int frameIndex, String expression, Map<String, String> scope) async {
136-
if (_compiler == null) {
137-
return _createError(ErrorKind.internal,
138-
'ExpressionEvaluator needs an ExpressionCompiler');
132+
int frameIndex, String expression, Map<String, String>? scope) async {
133+
if (scope != null) {
134+
// TODO(annagrin): Implement scope support.
135+
// Issue: https://github.com/dart-lang/webdev/issues/1344
136+
return _createError(
137+
ErrorKind.internal,
138+
'Using scope for expression evaluation in frame '
139+
'is not supported.');
139140
}
140141

141-
if (expression == null || expression.isEmpty) {
142+
if (expression.isEmpty) {
142143
return _createError(ErrorKind.invalidInput, expression);
143144
}
144145

@@ -158,7 +159,11 @@ class ExpressionEvaluator {
158159
final jsScope = await _collectLocalJsScope(jsFrame);
159160

160161
// Find corresponding dart location and scope.
161-
final url = _urlForScriptId(jsScriptId);
162+
final url = _debugger.urlForScriptId(jsScriptId);
163+
if (url == null) {
164+
return _createError(
165+
ErrorKind.internal, 'Cannot find url for JS script: $jsScriptId');
166+
}
162167
final locationMap = await _locations.locationForJs(url, jsLine, jsColumn);
163168
if (locationMap == null) {
164169
return _createError(
@@ -171,13 +176,20 @@ class ExpressionEvaluator {
171176
}
172177

173178
final dartLocation = locationMap.dartLocation;
174-
final libraryUri =
175-
await _modules.libraryForSource(dartLocation.uri.serverPath);
179+
final dartSourcePath = dartLocation.uri.serverPath;
180+
final libraryUri = await _modules.libraryForSource(dartSourcePath);
181+
if (libraryUri == null) {
182+
return _createError(
183+
ErrorKind.internal, 'no libraryUri for $dartSourcePath');
184+
}
176185

177-
final currentModule =
178-
await _modules.moduleForSource(dartLocation.uri.serverPath);
186+
final module = await _modules.moduleForlibrary(libraryUri.toString());
187+
if (module == null) {
188+
return _createError(
189+
ErrorKind.internal, 'no module for $libraryUri ($dartSourcePath)');
190+
}
179191

180-
_logger.finest('Evaluating "$expression" at $currentModule, '
192+
_logger.finest('Evaluating "$expression" at $module, '
181193
'$libraryUri:${dartLocation.line}:${dartLocation.column}');
182194

183195
// Compile expression using an expression compiler, such as
@@ -189,7 +201,7 @@ class ExpressionEvaluator {
189201
dartLocation.column,
190202
{},
191203
jsScope,
192-
currentModule,
204+
module,
193205
expression);
194206

195207
final isError = compilationResult.isError;
@@ -267,7 +279,9 @@ class ExpressionEvaluator {
267279
for (var p in variables) {
268280
final name = p.name;
269281
final value = p.value;
270-
if (!_isUndefined(value)) {
282+
// TODO: null values represent variables optimized by v8.
283+
// Show that to the user.
284+
if (name != null && value != null && !_isUndefined(value)) {
271285
jsScope[name] = name;
272286
}
273287
}
@@ -276,17 +290,17 @@ class ExpressionEvaluator {
276290
// skip library and main scope
277291
final scopeChain = filterScopes(frame).reversed;
278292
for (var scope in scopeChain) {
279-
final scopeProperties =
280-
await _debugger.getProperties(scope.object.objectId);
281-
282-
collectVariables(scope.scope, scopeProperties);
293+
final objectId = scope.object.objectId;
294+
if (objectId != null) {
295+
final scopeProperties = await _debugger.getProperties(objectId);
296+
collectVariables(scope.scope, scopeProperties);
297+
}
283298
}
284299

285300
return jsScope;
286301
}
287302

288-
bool _isUndefined(RemoteObject value) =>
289-
value == null || value.type == 'undefined';
303+
bool _isUndefined(RemoteObject value) => value.type == 'undefined';
290304

291305
/// Strip try/catch incorrectly added by the expression compiler.
292306
/// TODO: remove adding try/catch block in expression compiler.
@@ -346,8 +360,4 @@ class ExpressionEvaluator {
346360

347361
String _createDartLambda(String expression, Iterable<String> params) =>
348362
'(${params.join(', ')}) => $expression';
349-
350-
/// Returns Chrome script uri for Chrome script ID.
351-
String _urlForScriptId(String scriptId) =>
352-
_inspector.remoteDebugger.scripts[scriptId]?.url;
353363
}

dwds/test/evaluate_common.dart

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -145,15 +145,20 @@ void testAll({
145145
isolate.id, event.topFrame.index, 'MainClass(0)');
146146

147147
final param = object as InstanceRef;
148+
final result = await setup.service.evaluateInFrame(
149+
isolate.id,
150+
event.topFrame.index,
151+
't.toString()',
152+
scope: {'t': param.id},
153+
);
148154

149-
await expectLater(
150-
() => setup.service.evaluateInFrame(
151-
isolate.id,
152-
event.topFrame.index,
153-
't.toString()',
154-
scope: {'t': param.id},
155-
),
156-
throwsRPCError);
155+
expect(
156+
result,
157+
isA<ErrorRef>().having(
158+
(instance) => instance.message,
159+
'message',
160+
contains('Using scope for expression evaluation '
161+
'in frame is not supported')));
157162
});
158163
});
159164

0 commit comments

Comments
 (0)