Skip to content

Commit b697974

Browse files
author
Anna Gringauze
authored
Migrate debugging/inspector.dart to null safety (#1684)
* Migrate debugging/inspector.dart to null safety * Do not crash on null urls for librarires in inspector * Address CR comments and fix typo
1 parent df020b5 commit b697974

File tree

7 files changed

+175
-86
lines changed

7 files changed

+175
-86
lines changed

dwds/lib/src/debugging/debugger.dart

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import 'package:webkit_inspection_protocol/webkit_inspection_protocol.dart'
1212
hide StackTrace;
1313

1414
import '../loaders/strategy.dart';
15-
import '../services/chrome_debug_exception.dart';
1615
import '../utilities/conversions.dart';
1716
import '../utilities/dart_uri.dart';
1817
import '../utilities/domain.dart';
@@ -476,7 +475,7 @@ class Debugger extends Domain {
476475
final range = await _subrange(objectId, offset ?? 0, count ?? 0, length);
477476
rangeId = range.objectId ?? rangeId;
478477
}
479-
final jsProperties = await sendCommandAndvalidateResult<List>(
478+
final jsProperties = await sendCommandAndValidateResult<List>(
480479
_remoteDebugger,
481480
method: 'Runtime.getProperties',
482481
resultField: 'result',
@@ -722,18 +721,15 @@ class Debugger extends Domain {
722721
try {
723722
return await _remoteDebugger.evaluateOnCallFrame(callFrameId, expression);
724723
} on ExceptionDetails catch (e) {
725-
throw ChromeDebugException(
724+
throwChromeDebugException(
726725
e.json,
727726
evalContents: expression,
728-
additionalDetails: {
729-
'Dart expression': expression,
730-
},
731727
);
732728
}
733729
}
734730
}
735731

736-
Future<T> sendCommandAndvalidateResult<T>(
732+
Future<T> sendCommandAndValidateResult<T>(
737733
RemoteDebugger remoteDebugger, {
738734
required String method,
739735
required String resultField,
@@ -868,7 +864,7 @@ class _Breakpoints extends Domain {
868864
// Prevent `Aww, snap!` errors when setting multiple breakpoints
869865
// simultaneously by serializing the requests.
870866
return _pool.withResource(() async {
871-
final breakPointId = await sendCommandAndvalidateResult<String>(
867+
final breakPointId = await sendCommandAndValidateResult<String>(
872868
remoteDebugger,
873869
method: 'Debugger.setBreakpointByUrl',
874870
resultField: 'breakpointId',

dwds/lib/src/debugging/inspector.dart

Lines changed: 84 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,8 @@
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.import 'dart:async';
44

5-
// @dart = 2.9
6-
75
import 'package:async/async.dart';
6+
import 'package:collection/collection.dart';
87
import 'package:logging/logging.dart';
98
import 'package:vm_service/vm_service.dart';
109
import 'package:webkit_inspection_protocol/webkit_inspection_protocol.dart';
@@ -67,9 +66,9 @@ class AppInspector implements AppInspectorInterface {
6766

6867
final ExecutionContext _executionContext;
6968

70-
LibraryHelper _libraryHelper;
71-
ClassHelper _classHelper;
72-
InstanceHelper _instanceHelper;
69+
late final LibraryHelper _libraryHelper;
70+
late final ClassHelper _classHelper;
71+
late final InstanceHelper _instanceHelper;
7372

7473
final AssetReader _assetReader;
7574
final Locations _locations;
@@ -106,15 +105,17 @@ class AppInspector implements AppInspectorInterface {
106105

107106
final libraries = await _libraryHelper.libraryRefs;
108107
isolate.rootLib = await _libraryHelper.rootLib;
109-
isolate.libraries.addAll(libraries);
108+
isolate.libraries?.addAll(libraries);
110109

111110
final scripts = await scriptRefs;
112111

113112
await DartUri.initialize(_sdkConfiguration);
114-
await DartUri.recordAbsoluteUris(libraries.map((lib) => lib.uri));
115-
await DartUri.recordAbsoluteUris(scripts.map((script) => script.uri));
113+
await DartUri.recordAbsoluteUris(
114+
libraries.map((lib) => lib.uri).whereNotNull());
115+
await DartUri.recordAbsoluteUris(
116+
scripts.map((script) => script.uri).whereNotNull());
116117

117-
isolate.extensionRPCs.addAll(await _getExtensionRpcs());
118+
isolate.extensionRPCs?.addAll(await _getExtensionRpcs());
118119
}
119120

120121
static IsolateRef _toIsolateRef(Isolate isolate) => IsolateRef(
@@ -187,7 +188,7 @@ class AppInspector implements AppInspectorInterface {
187188

188189
/// Returns the ID for the execution context or null if not found.
189190
@override
190-
Future<int> get contextId async {
191+
Future<int?> get contextId async {
191192
try {
192193
return await _executionContext.id;
193194
} catch (e, s) {
@@ -236,15 +237,16 @@ class AppInspector implements AppInspectorInterface {
236237
String evalExpression, List<RemoteObject> arguments,
237238
{bool returnByValue = false}) async {
238239
final jsArguments = arguments.map(callArgumentFor).toList();
239-
final result =
240+
final response =
240241
await remoteDebugger.sendCommand('Runtime.callFunctionOn', params: {
241242
'functionDeclaration': evalExpression,
242243
'arguments': jsArguments,
243244
'objectId': receiver.objectId,
244245
'returnByValue': returnByValue,
245246
});
246-
handleErrorIfPresent(result, evalContents: evalExpression);
247-
return RemoteObject(result.result['result'] as Map<String, Object>);
247+
final result =
248+
getResultOrHandleError(response, evalContents: evalExpression);
249+
return RemoteObject(result);
248250
}
249251

250252
/// Calls Chrome's Runtime.callFunctionOn method with a global function.
@@ -255,15 +257,16 @@ class AppInspector implements AppInspectorInterface {
255257
String evalExpression, List<Object> arguments,
256258
{bool returnByValue = false}) async {
257259
final jsArguments = arguments.map(callArgumentFor).toList();
258-
final result =
260+
final response =
259261
await remoteDebugger.sendCommand('Runtime.callFunctionOn', params: {
260262
'functionDeclaration': evalExpression,
261263
'arguments': jsArguments,
262264
'executionContextId': await contextId,
263265
'returnByValue': returnByValue,
264266
});
265-
handleErrorIfPresent(result, evalContents: evalExpression);
266-
return RemoteObject(result.result['result'] as Map<String, Object>);
267+
final result =
268+
getResultOrHandleError(response, evalContents: evalExpression);
269+
return RemoteObject(result);
267270
}
268271

269272
/// Invoke the function named [selector] on the object identified by
@@ -303,26 +306,28 @@ class AppInspector implements AppInspectorInterface {
303306
Future<RemoteObject> jsEvaluate(String expression,
304307
{bool returnByValue = false, bool awaitPromise = false}) async {
305308
// TODO(alanknight): Support a version with arguments if needed.
306-
WipResponse result;
307-
result = await remoteDebugger.sendCommand('Runtime.evaluate', params: {
309+
final response =
310+
await remoteDebugger.sendCommand('Runtime.evaluate', params: {
308311
'expression': expression,
309312
'returnByValue': returnByValue,
310313
'awaitPromise': awaitPromise,
311314
'contextId': await contextId,
312315
});
313-
handleErrorIfPresent(result, evalContents: expression, additionalDetails: {
314-
'Dart expression': expression,
315-
});
316-
return RemoteObject(result.result['result'] as Map<String, dynamic>);
316+
final result = getResultOrHandleError(response, evalContents: expression);
317+
return RemoteObject(result);
317318
}
318319

319320
/// Evaluate the JS function with source [jsFunction] in the context of
320321
/// [library] with [arguments].
321322
Future<RemoteObject> _evaluateInLibrary(
322323
Library library, String jsFunction, List<RemoteObject> arguments) async {
324+
final libraryUri = library.uri;
325+
if (libraryUri == null) {
326+
throwInvalidParam('invoke', 'library uri is null');
327+
}
323328
final findLibrary = '''
324329
(function() {
325-
${globalLoadStrategy.loadLibrarySnippet(library.uri)};
330+
${globalLoadStrategy.loadLibrarySnippet(libraryUri)};
326331
return library;
327332
})();
328333
''';
@@ -339,25 +344,25 @@ class AppInspector implements AppInspectorInterface {
339344
}
340345

341346
@override
342-
Future<InstanceRef> instanceRefFor(Object value) =>
347+
Future<InstanceRef?> instanceRefFor(Object value) =>
343348
_instanceHelper.instanceRefFor(value);
344349

345-
Future<Instance> instanceFor(Object value) =>
350+
Future<Instance?> instanceFor(RemoteObject value) =>
346351
_instanceHelper.instanceFor(value);
347352

348353
@override
349-
Future<LibraryRef> libraryRefFor(String objectId) =>
354+
Future<LibraryRef?> libraryRefFor(String objectId) =>
350355
_libraryHelper.libraryRefFor(objectId);
351356

352357
@override
353-
Future<Library> getLibrary(String objectId) async {
358+
Future<Library?> getLibrary(String objectId) async {
354359
final libraryRef = await libraryRefFor(objectId);
355360
if (libraryRef == null) return null;
356361
return _libraryHelper.libraryFor(libraryRef);
357362
}
358363

359364
@override
360-
Future<Obj> getObject(String objectId, {int offset, int count}) async {
365+
Future<Obj?> getObject(String objectId, {int? offset, int? count}) async {
361366
try {
362367
final library = await getLibrary(objectId);
363368
if (library != null) {
@@ -384,9 +389,13 @@ class AppInspector implements AppInspectorInterface {
384389
'are supported for getObject');
385390
}
386391

387-
Future<Script> _getScript(ScriptRef scriptRef) async {
392+
Future<Script?> _getScript(ScriptRef scriptRef) async {
388393
final libraryId = _scriptIdToLibraryId[scriptRef.id];
389-
final serverPath = DartUri(scriptRef.uri, _root).serverPath;
394+
final scriptUri = scriptRef.uri;
395+
final scriptId = scriptRef.id;
396+
if (libraryId == null || scriptUri == null || scriptId == null) return null;
397+
398+
final serverPath = DartUri(scriptUri, _root).serverPath;
390399
final source = await _assetReader.dartSourceContents(serverPath);
391400
if (source == null) {
392401
throw RPCError('getObject', RPCError.kInvalidParams,
@@ -395,16 +404,17 @@ class AppInspector implements AppInspectorInterface {
395404
return Script(
396405
uri: scriptRef.uri,
397406
library: await libraryRefFor(libraryId),
398-
id: scriptRef.id)
407+
id: scriptId)
399408
..tokenPosTable = await _locations.tokenPosTableFor(serverPath)
400409
..source = source;
401410
}
402411

403412
@override
404-
Future<MemoryUsage> getMemoryUsage() async {
413+
Future<MemoryUsage?> getMemoryUsage() async {
405414
final response = await remoteDebugger.sendCommand('Runtime.getHeapUsage');
406-
407-
final jsUsage = HeapUsage(response.result);
415+
final result = response.result;
416+
if (result == null) return null;
417+
final jsUsage = HeapUsage(result);
408418
return MemoryUsage.parse({
409419
'heapUsage': jsUsage.usedSize,
410420
'heapCapacity': jsUsage.totalSize,
@@ -414,7 +424,7 @@ class AppInspector implements AppInspectorInterface {
414424

415425
/// Returns the [ScriptRef] for the provided Dart server path [uri].
416426
@override
417-
Future<ScriptRef> scriptRefFor(String uri) async {
427+
Future<ScriptRef?> scriptRefFor(String uri) async {
418428
await _populateScriptCaches();
419429
return _serverPathToScriptRef[uri];
420430
}
@@ -423,7 +433,7 @@ class AppInspector implements AppInspectorInterface {
423433
@override
424434
Future<List<ScriptRef>> scriptRefsForLibrary(String libraryId) async {
425435
await _populateScriptCaches();
426-
return _libraryIdToScriptRefs[libraryId];
436+
return _libraryIdToScriptRefs[libraryId] ?? [];
427437
}
428438

429439
/// Return the VM SourceReport for the given parameters.
@@ -432,12 +442,12 @@ class AppInspector implements AppInspectorInterface {
432442
@override
433443
Future<SourceReport> getSourceReport(
434444
List<String> reports, {
435-
String scriptId,
436-
int tokenPos,
437-
int endTokenPos,
438-
bool forceCompile,
439-
bool reportLines,
440-
List<String> libraryFilters,
445+
String? scriptId,
446+
int? tokenPos,
447+
int? endTokenPos,
448+
bool? forceCompile,
449+
bool? reportLines,
450+
List<String>? libraryFilters,
441451
}) {
442452
if (reports.contains(SourceReportKind.kCoverage)) {
443453
throwInvalidParam('getSourceReport',
@@ -457,15 +467,19 @@ class AppInspector implements AppInspectorInterface {
457467
return _getPossibleBreakpoints(scriptId);
458468
}
459469

460-
Future<SourceReport> _getPossibleBreakpoints(String scriptId) async {
470+
Future<SourceReport> _getPossibleBreakpoints(String? scriptId) async {
461471
// TODO(devoncarew): Consider adding some caching for this method.
462472

463473
final scriptRef = scriptWithId(scriptId);
464474
if (scriptRef == null) {
465-
throwInvalidParam('getSourceReport', 'scriptId not found: $scriptId');
475+
throwInvalidParam('getSourceReport', 'scriptRef not found for $scriptId');
476+
}
477+
final scriptUri = scriptRef.uri;
478+
if (scriptUri == null) {
479+
throwInvalidParam('getSourceReport', 'scriptUri not found for $scriptId');
466480
}
467481

468-
final dartUri = DartUri(scriptRef.uri, _root);
482+
final dartUri = DartUri(scriptUri, _root);
469483
final mappedLocations =
470484
await _locations.locationsForDart(dartUri.serverPath);
471485
// Unlike the Dart VM, the token positions match exactly to the possible
@@ -505,7 +519,9 @@ class AppInspector implements AppInspectorInterface {
505519
/// Returns the list of scripts refs cached.
506520
Future<List<ScriptRef>> _populateScriptCaches() async {
507521
return _scriptCacheMemoizer.runOnce(() async {
508-
final libraryUris = [for (var library in isolate.libraries) library.uri];
522+
final libraryUris = [
523+
for (var library in isolate.libraries ?? []) library.uri
524+
];
509525
final scripts = await globalLoadStrategy
510526
.metadataProviderFor(appConnection.request.entrypointPath)
511527
.scripts;
@@ -517,16 +533,24 @@ class AppInspector implements AppInspectorInterface {
517533
final parts = scripts[uri];
518534
final scriptRefs = [
519535
ScriptRef(uri: uri, id: createId()),
520-
for (var part in parts) ScriptRef(uri: part, id: createId())
536+
for (var part in parts ?? []) ScriptRef(uri: part, id: createId())
521537
];
522538
final libraryRef = await _libraryHelper.libraryRefFor(uri);
523-
_libraryIdToScriptRefs.putIfAbsent(libraryRef.id, () => <ScriptRef>[]);
524-
for (var scriptRef in scriptRefs) {
525-
_scriptRefsById[scriptRef.id] = scriptRef;
526-
_scriptIdToLibraryId[scriptRef.id] = libraryRef.id;
527-
_serverPathToScriptRef[DartUri(scriptRef.uri, _root).serverPath] =
528-
scriptRef;
529-
_libraryIdToScriptRefs[libraryRef.id].add(scriptRef);
539+
final libraryId = libraryRef?.id;
540+
if (libraryId != null) {
541+
final libraryIdToScriptRefs = _libraryIdToScriptRefs.putIfAbsent(
542+
libraryId, () => <ScriptRef>[]);
543+
for (var scriptRef in scriptRefs) {
544+
final scriptId = scriptRef.id;
545+
final scriptUri = scriptRef.uri;
546+
if (scriptId != null && scriptUri != null) {
547+
_scriptRefsById[scriptId] = scriptRef;
548+
_scriptIdToLibraryId[scriptId] = libraryId;
549+
_serverPathToScriptRef[DartUri(scriptUri, _root).serverPath] =
550+
scriptRef;
551+
libraryIdToScriptRefs.add(scriptRef);
552+
}
553+
}
530554
}
531555
}
532556
return _scriptRefsById.values.toList();
@@ -535,7 +559,8 @@ class AppInspector implements AppInspectorInterface {
535559

536560
/// Look up the script by id in an isolate.
537561
@override
538-
ScriptRef scriptWithId(String scriptId) => _scriptRefsById[scriptId];
562+
ScriptRef? scriptWithId(String? scriptId) =>
563+
scriptId == null ? null : _scriptRefsById[scriptId];
539564

540565
/// Runs an eval on the page to compute all existing registered extensions.
541566
Future<List<String>> _getExtensionRpcs() async {
@@ -548,11 +573,10 @@ class AppInspector implements AppInspectorInterface {
548573
'contextId': await contextId,
549574
};
550575
try {
551-
final extensionsResult =
576+
final response =
552577
await remoteDebugger.sendCommand('Runtime.evaluate', params: params);
553-
handleErrorIfPresent(extensionsResult, evalContents: expression);
554-
extensionRpcs.addAll(
555-
List.from(extensionsResult.result['result']['value'] as List));
578+
final result = getResultOrHandleError(response, evalContents: expression);
579+
extensionRpcs.addAll(List.from(result['value'] as List? ?? []));
556580
} catch (e, s) {
557581
_logger.severe(
558582
'Error calling Runtime.evaluate with params $params', e, s);
@@ -571,7 +595,7 @@ class AppInspector implements AppInspectorInterface {
571595
} catch (_) {
572596
return description;
573597
}
574-
final mappedStack = mapperResult?.value?.toString();
598+
final mappedStack = mapperResult.value?.toString();
575599
if (mappedStack == null || mappedStack.isEmpty) {
576600
return description;
577601
}

dwds/lib/src/debugging/instance.dart

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,9 @@ class InstanceHelper extends Domain {
275275
int? count) async {
276276
final objectId = remoteObject.objectId;
277277
if (objectId == null) return null;
278+
279+
/// TODO(annagrin): split into cases to make the logic clear.
280+
/// TODO(annagrin): make sure we use offset correctly.
278281
final numberOfProperties = _lengthOf(properties) ?? 0;
279282
final length = (offset == null && count == null)
280283
? numberOfProperties

0 commit comments

Comments
 (0)