Skip to content

Commit c71ad8c

Browse files
thaystgradical
andauthored
[wasm][debugger] Adding support to receive evaluationOptions from dap. (#71464)
* Adding support to receive evaluationOptions from dap. * Update src/mono/wasm/debugger/BrowserDebugProxy/MemberObjectsExplorer.cs Co-authored-by: Ankit Jain <radical@gmail.com> * Adding tests. * Fix merge * fix tests. Co-authored-by: Ankit Jain <radical@gmail.com>
1 parent 5b8ebea commit c71ad8c

File tree

6 files changed

+96
-30
lines changed

6 files changed

+96
-30
lines changed

src/mono/wasm/debugger/BrowserDebugProxy/DevToolsHelper.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -426,6 +426,8 @@ public ExecutionContext(MonoSDBHelper sdbAgent, int id, object auxData, PauseOnE
426426

427427
public object AuxData { get; set; }
428428

429+
public bool AutoEvaluateProperties { get; set; }
430+
429431
public PauseOnExceptionsKind PauseOnExceptions { get; set; }
430432

431433
public List<Frame> CallStack { get; set; }

src/mono/wasm/debugger/BrowserDebugProxy/MemberObjectsExplorer.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -457,7 +457,7 @@ async Task AddProperty(
457457
{
458458
try
459459
{
460-
propRet = await sdbHelper.InvokeMethod(getterParamsBuffer, getMethodId, token, name: propNameWithSufix);
460+
propRet = await sdbHelper.InvokeMethod(getterParamsBuffer, getMethodId, token, name: propNameWithSufix, isPropertyStatic && !isValueType);
461461
}
462462
catch (Exception)
463463
{

src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -503,6 +503,21 @@ protected override async Task<bool> AcceptCommand(MessageId id, JObject parms, C
503503
return false;
504504
}
505505

506+
case "Runtime.callFunctionOn":
507+
{
508+
try {
509+
return await CallOnFunction(id, args, token);
510+
}
511+
catch (Exception ex) {
512+
logger.LogDebug($"Runtime.callFunctionOn failed for {id} with args {args}: {ex}");
513+
SendResponse(id,
514+
Result.Exception(new ArgumentException(
515+
$"Runtime.callFunctionOn not supported with ({args["objectId"]}).")),
516+
token);
517+
return true;
518+
}
519+
}
520+
506521
// Protocol extensions
507522
case "DotnetDebugger.setDebuggerProperty":
508523
{
@@ -552,19 +567,25 @@ protected override async Task<bool> AcceptCommand(MessageId id, JObject parms, C
552567
SendResponse(id, await GetMethodLocation(id, args, token), token);
553568
return true;
554569
}
555-
case "Runtime.callFunctionOn":
570+
case "DotnetDebugger.setEvaluationOptions":
556571
{
572+
//receive the available options from DAP to variables, stack and evaluate commands.
557573
try {
558-
return await CallOnFunction(id, args, token);
574+
if (args["options"]?["noFuncEval"]?.Value<bool>() == true)
575+
context.AutoEvaluateProperties = false;
576+
else
577+
context.AutoEvaluateProperties = true;
578+
SendResponse(id, Result.OkFromObject(new { }), token);
559579
}
560-
catch (Exception ex) {
561-
logger.LogDebug($"Runtime.callFunctionOn failed for {id} with args {args}: {ex}");
580+
catch (Exception ex)
581+
{
582+
logger.LogDebug($"DotnetDebugger.setEvaluationOptions failed for {id} with args {args}: {ex}");
562583
SendResponse(id,
563584
Result.Exception(new ArgumentException(
564-
$"Runtime.callFunctionOn not supported with ({args["objectId"]}).")),
585+
$"DotnetDebugger.setEvaluationOptions got incorrect argument ({args})")),
565586
token);
566-
return true;
567587
}
588+
return true;
568589
}
569590
}
570591
// for Dotnetdebugger.* messages, treat them as handled, thus not passing them on to the browser
@@ -737,6 +758,8 @@ internal async Task<ValueOrError<GetMembersResult>> RuntimeGetObjectMembers(Sess
737758
if (args["forDebuggerDisplayAttribute"]?.Value<bool>() == true)
738759
getObjectOptions |= GetObjectCommandOptions.ForDebuggerDisplayAttribute;
739760
}
761+
if (context.AutoEvaluateProperties)
762+
getObjectOptions |= GetObjectCommandOptions.AutoExpandable;
740763
if (JustMyCode)
741764
getObjectOptions |= GetObjectCommandOptions.JustMyCode;
742765
try

src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1821,11 +1821,12 @@ public async Task<string> GetDelegateMethodDescription(int objectId, Cancellatio
18211821
return $"{returnType} {methodName} {parameters}";
18221822
}
18231823

1824-
public async Task<JObject> InvokeMethod(ArraySegment<byte> argsBuffer, int methodId, CancellationToken token, string name = null)
1824+
public async Task<JObject> InvokeMethod(ArraySegment<byte> argsBuffer, int methodId, CancellationToken token, string name = null, bool isMethodStatic = false)
18251825
{
18261826
using var commandParamsWriter = new MonoBinaryWriter();
18271827
commandParamsWriter.Write(methodId);
1828-
commandParamsWriter.Write(argsBuffer);
1828+
if (!isMethodStatic)
1829+
commandParamsWriter.Write(argsBuffer);
18291830
commandParamsWriter.Write(0);
18301831
using var retDebuggerCmdReader = await SendDebuggerAgentCommand(CmdVM.InvokeMethod, commandParamsWriter, token);
18311832
retDebuggerCmdReader.ReadByte(); //number of objects returned.

src/mono/wasm/debugger/BrowserDebugProxy/ValueTypeClass.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ namespace BrowserDebugProxy
1717
{
1818
internal sealed class ValueTypeClass
1919
{
20-
private readonly bool autoExpand;
20+
private bool autoExpand;
2121
private JArray proxy;
2222
private GetMembersResult _combinedResult;
2323
private bool propertiesExpanded;
@@ -201,6 +201,8 @@ public async Task<JArray> GetProxy(MonoSDBHelper sdbHelper, CancellationToken to
201201
public async Task<GetMembersResult> GetMemberValues(
202202
MonoSDBHelper sdbHelper, GetObjectCommandOptions getObjectOptions, bool sortByAccessLevel, bool includeStatic, CancellationToken token)
203203
{
204+
if (getObjectOptions.HasFlag(GetObjectCommandOptions.AutoExpandable) && !getObjectOptions.HasFlag(GetObjectCommandOptions.AccessorPropertiesOnly))
205+
autoExpand = true;
204206
// 1
205207
if (!propertiesExpanded)
206208
{

src/mono/wasm/debugger/DebuggerTestSuite/GetPropertiesTests.cs

Lines changed: 58 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,13 @@ namespace DebuggerTests
1515
{
1616
public class GetPropertiesTests : DebuggerTests
1717
{
18+
public enum AutoEvaluate
19+
{
20+
On,
21+
Off,
22+
Unset,
23+
}
24+
1825
public GetPropertiesTests(ITestOutputHelper testOutput) : base(testOutput)
1926
{}
2027

@@ -253,24 +260,8 @@ public GetPropertiesTests(ITestOutputHelper testOutput) : base(testOutput)
253260
[MemberData(nameof(ClassGetPropertiesTestData), parameters: false)]
254261
[MemberData(nameof(StructGetPropertiesTestData), parameters: true)]
255262
[MemberData(nameof(StructGetPropertiesTestData), parameters: false)]
256-
public async Task InspectTypeInheritedMembers(string type_name, bool? own_properties, bool? accessors_only, string[] expected_names, Dictionary<string, (JObject, bool)> all_props, bool is_async) => await CheckInspectLocalsAtBreakpointSite(
257-
$"DebuggerTests.GetPropertiesTests.{type_name}",
258-
$"InstanceMethod{(is_async ? "Async" : "")}", 1, $"DebuggerTests.GetPropertiesTests.{type_name}." + (is_async ? "InstanceMethodAsync" : "InstanceMethod"),
259-
$"window.setTimeout(function() {{ invoke_static_method_async ('[debugger-test] DebuggerTests.GetPropertiesTests.{type_name}:run'); }})",
260-
wait_for_event_fn: async (pause_location) =>
261-
{
262-
var frame_id = pause_location["callFrames"][0]["callFrameId"].Value<string>();
263-
var frame_locals = await GetProperties(frame_id);
264-
var this_obj = GetAndAssertObjectWithName(frame_locals, "this");
265-
var this_props = await GetProperties(this_obj["value"]?["objectId"]?.Value<string>(), own_properties: own_properties, accessors_only: accessors_only);
266-
267-
AssertHasOnlyExpectedProperties(expected_names, this_props.Values<JObject>());
268-
await CheckExpectedProperties(expected_names, name => GetAndAssertObjectWithName(this_props, name), all_props);
269-
270-
// indexer properties shouldn't show up here
271-
var item = this_props.FirstOrDefault(jt => jt["name"]?.Value<string>() == "Item");
272-
Assert.Null(item);
273-
});
263+
public async Task InspectTypeInheritedMembers(string type_name, bool? own_properties, bool? accessors_only, string[] expected_names, Dictionary<string, (JObject, bool)> all_props, bool is_async) =>
264+
await InspectTypeInheritedMembersInternal(type_name, own_properties, accessors_only, expected_names, all_props, is_async, AutoEvaluate.Unset);
274265

275266
public static IEnumerable<object[]> MembersForLocalNestedStructData(bool is_async)
276267
=> StructGetPropertiesTestData(false).Select(datum => datum[1..]);
@@ -444,7 +435,7 @@ await EvaluateOnCallFrameAndCheck(frame_id,
444435
);
445436
}
446437

447-
private async Task CheckExpectedProperties(string[] expected_names, Func<string, JToken> get_actual_prop, Dictionary<string, (JObject, bool)> all_props)
438+
private async Task CheckExpectedProperties(string[] expected_names, Func<string, JToken> get_actual_prop, Dictionary<string, (JObject, bool)> all_props, bool autoEvaluate = false)
448439
{
449440
foreach (var exp_name in expected_names)
450441
{
@@ -463,7 +454,13 @@ private async Task CheckExpectedProperties(string[] expected_names, Func<string,
463454
// from `{name: "..", value: {}, ..}
464455
// but for getters we actually have: `{name: "..", get: {..} }`
465456
// and no `value`
466-
await CheckValue(actual_prop, exp_prop, exp_name);
457+
if (!autoEvaluate)
458+
await CheckValue(actual_prop, exp_prop, exp_name);
459+
else
460+
{
461+
if (exp_prop["value"].Type != JTokenType.Null)
462+
await CheckValue(actual_prop["value"], exp_prop["value"], exp_name);
463+
}
467464
}
468465
else
469466
{
@@ -623,5 +620,46 @@ await CheckInspectLocalsAtBreakpointSite(
623620
await CheckProps(pubInternalAndProtected, expectedPublicInternalAndProtected, "result");
624621
await CheckProps(priv, expectedPriv, "private");
625622
});
623+
624+
[ConditionalTheory(nameof(RunningOnChrome))]
625+
[MemberData(nameof(ClassGetPropertiesTestData), parameters: true)]
626+
[MemberData(nameof(ClassGetPropertiesTestData), parameters: false)]
627+
[MemberData(nameof(StructGetPropertiesTestData), parameters: true)]
628+
[MemberData(nameof(StructGetPropertiesTestData), parameters: false)]
629+
public async Task InspectTypeInheritedMembersAutoEvaluateOn(string type_name, bool? own_properties, bool? accessors_only, string[] expected_names, Dictionary<string, (JObject, bool)> all_props, bool is_async) =>
630+
await InspectTypeInheritedMembersInternal(type_name, own_properties, accessors_only, expected_names, all_props, is_async, AutoEvaluate.On);
631+
632+
[ConditionalTheory(nameof(RunningOnChrome))]
633+
[MemberData(nameof(ClassGetPropertiesTestData), parameters: true)]
634+
[MemberData(nameof(ClassGetPropertiesTestData), parameters: false)]
635+
[MemberData(nameof(StructGetPropertiesTestData), parameters: true)]
636+
[MemberData(nameof(StructGetPropertiesTestData), parameters: false)]
637+
public async Task InspectTypeInheritedMembersAutoEvaluateOff(string type_name, bool? own_properties, bool? accessors_only, string[] expected_names, Dictionary<string, (JObject, bool)> all_props, bool is_async) =>
638+
await InspectTypeInheritedMembersInternal(type_name, own_properties, accessors_only, expected_names, all_props, is_async, AutoEvaluate.Off);
639+
640+
public async Task InspectTypeInheritedMembersInternal(string type_name, bool? own_properties, bool? accessors_only, string[] expected_names, Dictionary<string, (JObject, bool)> all_props, bool is_async, AutoEvaluate auto_evaluate_status)
641+
{
642+
if (auto_evaluate_status == AutoEvaluate.On)
643+
await cli.SendCommand("DotnetDebugger.setEvaluationOptions", JObject.FromObject(new { options = new { noFuncEval = false } }), token);
644+
else if (auto_evaluate_status == AutoEvaluate.Off)
645+
await cli.SendCommand("DotnetDebugger.setEvaluationOptions", JObject.FromObject(new { options = new { noFuncEval = true } }), token);
646+
await CheckInspectLocalsAtBreakpointSite(
647+
$"DebuggerTests.GetPropertiesTests.{type_name}",
648+
$"InstanceMethod{(is_async ? "Async" : "")}", 1, $"DebuggerTests.GetPropertiesTests.{type_name}." + (is_async ? "InstanceMethodAsync" : "InstanceMethod"),
649+
$"window.setTimeout(function() {{ invoke_static_method_async ('[debugger-test] DebuggerTests.GetPropertiesTests.{type_name}:run'); }})",
650+
wait_for_event_fn: async (pause_location) =>
651+
{
652+
var frame_id = pause_location["callFrames"][0]["callFrameId"].Value<string>();
653+
var frame_locals = await GetProperties(frame_id);
654+
var this_obj = GetAndAssertObjectWithName(frame_locals, "this");
655+
var this_props = await GetProperties(this_obj["value"]?["objectId"]?.Value<string>(), own_properties: own_properties, accessors_only: accessors_only);
656+
AssertHasOnlyExpectedProperties(expected_names, this_props.Values<JObject>());
657+
await CheckExpectedProperties(expected_names, name => GetAndAssertObjectWithName(this_props, name), all_props, auto_evaluate_status == AutoEvaluate.On);
658+
659+
// indexer properties shouldn't show up here
660+
var item = this_props.FirstOrDefault(jt => jt["name"]?.Value<string>() == "Item");
661+
Assert.Null(item);
662+
});
663+
}
626664
}
627665
}

0 commit comments

Comments
 (0)