blob: 0c6bc4de44f2a67d38f1fc8ba48b7aad9a6f5357 [file] [log] [blame]
// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
// @dart = 2.9
import 'package:webkit_inspection_protocol/webkit_inspection_protocol.dart';
import '../utilities/objects.dart';
import 'debugger.dart';
// TODO(sdk/issues/44262) - use an alternative way to identify synthetic
// variables.
final ddcTemporaryVariableRegExp = RegExp(r'^(t[0-9]+\$?[0-9]*|__t\$\w*)$');
/// Find the visible Dart properties from a JS Scope Chain, coming from the
/// scopeChain attribute of a Chrome CallFrame corresponding to [frame].
///
/// See chromedevtools.github.io/devtools-protocol/tot/Debugger#type-CallFrame.
Future<List<Property>> visibleProperties({
Debugger debugger,
WipCallFrame frame,
}) async {
var allProperties = <Property>[];
if (frame.thisObject != null && frame.thisObject.type != 'undefined') {
allProperties.add(
Property({
'name': 'this',
'value': frame.thisObject,
}),
);
}
// TODO: Try and populate all the property info for the scopes in one backend
// call. Along with some other optimizations (caching classRef lookups), we'd
// end up averaging one backend call per frame.
// Iterate to least specific scope last to help preserve order in the local
// variables view when stepping.
for (var scope in filterScopes(frame).reversed) {
final properties = await debugger.getProperties(scope.object.objectId);
allProperties.addAll(properties);
}
if (frame.returnValue != null && frame.returnValue.type != 'undefined') {
allProperties.add(
Property({
'name': 'return',
'value': frame.returnValue,
}),
);
}
allProperties.removeWhere((property) {
final value = property.value;
// TODO(#786) Handle these correctly rather than just suppressing them.
// We should never see a raw JS class. The only case where this happens is a
// Dart generic function, where the type arguments get passed in as
// parameters. Hide those.
return (value.type == 'function' &&
value.description.startsWith('class ')) ||
(ddcTemporaryVariableRegExp.hasMatch(property.name)) ||
(value.type == 'object' && value.description == 'dart.LegacyType.new');
});
return allProperties;
}
/// Filters the provided frame scopes to those that are pertinent for Dart
/// debugging.
List<WipScope> filterScopes(WipCallFrame frame) {
var scopes = frame.getScopeChain().toList();
// Remove outer scopes up to and including the Dart SDK.
while (
scopes.isNotEmpty && !(scopes.last.name?.startsWith('load__') ?? false)) {
scopes.removeLast();
}
if (scopes.isNotEmpty) scopes.removeLast();
return scopes;
}