diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/DevToolsHelper.cs b/src/mono/wasm/debugger/BrowserDebugProxy/DevToolsHelper.cs index f28b972d28bb3..8d08275c7bb90 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/DevToolsHelper.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/DevToolsHelper.cs @@ -66,13 +66,15 @@ internal class DotnetObjectId public string Scheme { get; } public int Value { get; } public int SubValue { get; set; } + public bool IsValueType { get; set; } public static bool TryParse(JToken jToken, out DotnetObjectId objectId) => TryParse(jToken?.Value(), out objectId); public static bool TryParse(string id, out DotnetObjectId objectId) { objectId = null; - try { + try + { if (id == null) return false; @@ -88,12 +90,13 @@ public static bool TryParse(string id, out DotnetObjectId objectId) switch (objectId.Scheme) { case "methodId": - { - parts = id.Split(":"); - if (parts.Length > 3) + if (parts.Length > 4) + { objectId.SubValue = int.Parse(parts[3]); - break; - } + objectId.IsValueType = parts[4] == "ValueType"; + return true; + } + return false; } return true; } diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/MemberReferenceResolver.cs b/src/mono/wasm/debugger/BrowserDebugProxy/MemberReferenceResolver.cs index b9f5c8e4dbb4b..1f136d84d18b9 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/MemberReferenceResolver.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/MemberReferenceResolver.cs @@ -360,7 +360,7 @@ public async Task Resolve(ElementAccessExpressionSyntax elementAccess, case "object": var typeIds = await context.SdbAgent.GetTypeIdFromObject(objectId.Value, true, token); int methodId = await context.SdbAgent.GetMethodIdByName(typeIds[0], "ToArray", token); - var toArrayRetMethod = await context.SdbAgent.InvokeMethodInObject(objectId.Value, methodId, elementAccess.Expression.ToString(), token); + var toArrayRetMethod = await context.SdbAgent.InvokeMethodInObject(objectId, methodId, elementAccess.Expression.ToString(), token); rootObject = await GetValueFromObject(toArrayRetMethod, token); DotnetObjectId.TryParse(rootObject?["objectId"]?.Value(), out DotnetObjectId arrayObjectId); rootObject["value"] = await context.SdbAgent.GetArrayValues(arrayObjectId.Value, token); diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs b/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs index f269430a6d950..5440e59af4d76 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs @@ -761,7 +761,7 @@ internal async Task> RuntimeGetPropertiesInternal(SessionId return resValType switch { null => ValueOrError.WithError($"Could not get properties for {objectId}"), - _ => ValueOrError.WithValue(sortByAccessLevel ? JObject.FromObject(new { result = resValType }) : resValType) + _ => ValueOrError.WithValue(resValType) }; } case "array": @@ -771,7 +771,7 @@ internal async Task> RuntimeGetPropertiesInternal(SessionId } case "methodId": { - var resMethod = await context.SdbAgent.InvokeMethodInObject(objectId.Value, objectId.SubValue, null, token); + var resMethod = await context.SdbAgent.InvokeMethodInObject(objectId, objectId.SubValue, null, token); return ValueOrError.WithValue(sortByAccessLevel ? JObject.FromObject(new { result = new JArray(resMethod) }) : new JArray(resMethod)); } case "object": @@ -799,7 +799,8 @@ internal async Task> RuntimeGetPropertiesInternal(SessionId return ValueOrError.WithError($"RuntimeGetProperties: unknown object id scheme: {objectId.Scheme}"); } } - catch (Exception ex) { + catch (Exception ex) + { return ValueOrError.WithError($"RuntimeGetProperties: Failed to get properties for {objectId}: {ex}"); } } diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs b/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs index f8ad79aa8a8f7..473f22eeeb0d1 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs @@ -1601,13 +1601,12 @@ public async Task InvokeMethod(ArraySegment valueTypeBuffer, int return await CreateJObjectForVariableValue(retDebuggerCmdReader, varName, false, -1, false, token); } - public async Task InvokeMethodInObject(int objectId, int methodId, string varName, CancellationToken token) + public async Task InvokeMethodInObject(DotnetObjectId objectId, int methodId, string varName, CancellationToken token) { - valueTypes.TryGetValue(objectId, out var valueType); - if (valueType != null) - return await InvokeMethod(valueType.valueTypeBuffer, methodId, varName, token); + if (objectId.IsValueType) + return await InvokeMethod(valueTypes[objectId.Value].valueTypeBuffer, methodId, varName, token); using var commandParamsObjWriter = new MonoBinaryWriter(); - commandParamsObjWriter.Write(ElementType.Class, objectId); + commandParamsObjWriter.Write(ElementType.Class, objectId.Value); return await InvokeMethod(commandParamsObjWriter.GetParameterBuffer(), methodId, varName, token); } @@ -2655,7 +2654,7 @@ async Task GetProperties(JArray props, List fields, int case DebuggerBrowsableState.RootHidden: DotnetObjectId rootObjId; DotnetObjectId.TryParse(p["get"]["objectId"].Value(), out rootObjId); - var rootObject = await InvokeMethodInObject(rootObjId.Value, rootObjId.SubValue, propName, token); + var rootObject = await InvokeMethodInObject(rootObjId, rootObjId.SubValue, propName, token); await AppendRootHiddenChildren(rootObject, regularProps); break; case DebuggerBrowsableState.Collapsed: diff --git a/src/mono/wasm/debugger/DebuggerTestSuite/EvaluateOnCallFrameTests.cs b/src/mono/wasm/debugger/DebuggerTestSuite/EvaluateOnCallFrameTests.cs index 3c012012651bb..6512d3ab9aaae 100644 --- a/src/mono/wasm/debugger/DebuggerTestSuite/EvaluateOnCallFrameTests.cs +++ b/src/mono/wasm/debugger/DebuggerTestSuite/EvaluateOnCallFrameTests.cs @@ -999,23 +999,42 @@ await RuntimeEvaluateAndCheck( [Fact] public async Task EvaluateProtectionLevels() => await CheckInspectLocalsAtBreakpointSite( - "DebuggerTests.EvaluateProtectionLevels", "Evaluate", 2, "Evaluate", - "window.setTimeout(function() { invoke_static_method ('[debugger-test] DebuggerTests.EvaluateProtectionLevels:Evaluate'); })", + "DebuggerTests.GetPropertiesTests.DerivedClass", "InstanceMethod", 1, "InstanceMethod", + "window.setTimeout(function() { invoke_static_method ('[debugger-test] DebuggerTests.GetPropertiesTests.DerivedClass:run'); })", wait_for_event_fn: async (pause_location) => - { - var id = pause_location["callFrames"][0]["callFrameId"].Value(); - var (obj, _) = await EvaluateOnCallFrame(id, "testClass"); - var (pub, internalAndProtected, priv) = await GetPropertiesSortedByProtectionLevels(obj["objectId"]?.Value()); - - Assert.True(pub[0] != null); - Assert.True(internalAndProtected[0] != null); - Assert.True(internalAndProtected[1] != null); - Assert.True(priv[0] != null); - - Assert.Equal(pub[0]["value"]["value"], "public"); - Assert.Equal(internalAndProtected[0]["value"]["value"], "internal"); - Assert.Equal(internalAndProtected[1]["value"]["value"], "protected"); - Assert.Equal(priv[0]["value"]["value"], "private"); + { + var id = pause_location["callFrames"][0]["callFrameId"].Value(); + var (obj, _) = await EvaluateOnCallFrame(id, "this"); + var (pub, internalAndProtected, priv) = await GetPropertiesSortedByProtectionLevels(obj["objectId"]?.Value()); + + await CheckProps(pub, new + { + a = TNumber(4), + Base_AutoStringPropertyForOverrideWithField = TString("DerivedClass#Base_AutoStringPropertyForOverrideWithField"), + Base_GetterForOverrideWithField = TString("DerivedClass#Base_GetterForOverrideWithField"), + BaseBase_MemberForOverride = TString("DerivedClass#BaseBase_MemberForOverride"), + DateTime = TGetter("DateTime", TDateTime(new DateTime(2200, 5, 6, 7, 18, 9))), + _DTProp = TGetter("_DTProp", TDateTime(new DateTime(2200, 5, 6, 7, 8, 9))), + FirstName = TGetter("FirstName", TString("DerivedClass#FirstName")), + _base_dateTime = TGetter("_base_dateTime", TDateTime(new DateTime(2134, 5, 7, 1, 9, 2))), + LastName = TGetter("LastName", TString("BaseClass#LastName")) + }, "public"); + + await CheckProps(internalAndProtected, new + { + base_num = TNumber(5) + }, "internalAndProtected"); + + await CheckProps(priv, new + { + _stringField = TString("DerivedClass#_stringField"), + _dateTime = TDateTime(new DateTime(2020, 7, 6, 5, 4, 3)), + AutoStringProperty = TString("DerivedClass#AutoStringProperty"), + StringPropertyForOverrideWithAutoProperty = TString("DerivedClass#StringPropertyForOverrideWithAutoProperty"), + _base_name = TString("private_name"), + Base_AutoStringProperty = TString("base#Base_AutoStringProperty"), + DateTimeForOverride = TGetter("DateTimeForOverride", TDateTime(new DateTime(2190, 9, 7, 5, 3, 2))) + }, "private"); }); [Fact] @@ -1027,17 +1046,10 @@ public async Task StructureGetters() => await CheckInspectLocalsAtBreakpointSit var id = pause_location["callFrames"][0]["callFrameId"].Value(); var (obj, _) = await EvaluateOnCallFrame(id, "s"); var props = await GetProperties(obj["objectId"]?.Value()); - await CheckProps(props, new { Id = TGetter("Id", TNumber(123)) }, "s#1"); - - var getter = props.FirstOrDefault(p => p["name"]?.Value() == "Id"); - Assert.NotNull(getter); - var getterId = getter["get"]["objectId"]?.Value(); - var getterProps = await GetProperties(getterId); - Assert.Equal(getterProps[0]?["value"]?["value"]?.Value(), 123); }); [Fact] diff --git a/src/mono/wasm/debugger/tests/debugger-test/debugger-evaluate-test.cs b/src/mono/wasm/debugger/tests/debugger-test/debugger-evaluate-test.cs index baa6bac36b157..80db1d2c310ee 100644 --- a/src/mono/wasm/debugger/tests/debugger-test/debugger-evaluate-test.cs +++ b/src/mono/wasm/debugger/tests/debugger-test/debugger-evaluate-test.cs @@ -823,27 +823,6 @@ public static void Evaluate() } } - public static class EvaluateProtectionLevels - { - public class TestClass - { - public string fieldPublic = "public"; - private string fieldPrivate = "private"; - internal string fieldInternal = "internal"; - protected string fieldProtected = "protected"; - - public TestClass() - { - var a = fieldPrivate; - } - } - - public static void Evaluate() - { - var testClass = new TestClass(); - } - } - public static class StructureGetters { public struct Point