From 62d86f2dc520be4c6da19bc20b0e495eb73fce05 Mon Sep 17 00:00:00 2001 From: Thays Grazia Date: Sat, 8 Oct 2022 12:55:20 -0300 Subject: [PATCH 01/11] The description of an object that has ToString implemented should be the result of the ToString and not the type name. --- .../BrowserDebugProxy/JObjectValueCreator.cs | 12 ++++++++++++ .../DebuggerTestSuite/CustomViewTests.cs | 19 +++++++++++++++++++ .../debugger/DebuggerTestSuite/MiscTests.cs | 2 +- .../tests/debugger-test/debugger-test.cs | 13 +++++++++++++ 4 files changed, 45 insertions(+), 1 deletion(-) diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/JObjectValueCreator.cs b/src/mono/wasm/debugger/BrowserDebugProxy/JObjectValueCreator.cs index 8d62ab3c5b9522..a30bd98ba8b1e8 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/JObjectValueCreator.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/JObjectValueCreator.cs @@ -293,6 +293,18 @@ private async Task ReadAsObjectValue(MonoBinaryReader retDebuggerCmdRea return Create(value: className, type: "symbol", description: className); } } + var typeInfo = await _sdbAgent.GetTypeInfo(type_id[0], token); + if (typeInfo != null && typeInfo.Name != "object") + { + MethodInfo methodInfo = typeInfo.Info.Methods.FirstOrDefault(m => m.Name == "ToString"); + if (methodInfo != null) + { + int[] methodIds = await _sdbAgent.GetMethodIdsByName(type_id[0], "ToString", token); + var toString = await _sdbAgent.InvokeMethod(objectId, methodIds[0], isValueType: false, token); + if (toString["value"]?["value"] != null) + description = toString["value"]?["value"].Value(); + } + } return Create(value: null, type: "object", description: description, className: className, objectId: $"dotnet:object:{objectId}"); } diff --git a/src/mono/wasm/debugger/DebuggerTestSuite/CustomViewTests.cs b/src/mono/wasm/debugger/DebuggerTestSuite/CustomViewTests.cs index 1617a37053b10f..c38c85380fba04 100644 --- a/src/mono/wasm/debugger/DebuggerTestSuite/CustomViewTests.cs +++ b/src/mono/wasm/debugger/DebuggerTestSuite/CustomViewTests.cs @@ -106,5 +106,24 @@ async Task CheckProperties(JObject pause_location) Assert.True(task.Result); } } + + [ConditionalFact(nameof(RunningOnChrome))] + public async Task InspectObjectOfTypeWithToStringOverwritten() + { + var expression = $"{{ invoke_static_method('[debugger-test] ToStringOverwritten:Run'); }}"; + + await EvaluateAndCheck( + "window.setTimeout(function() {" + expression + "; }, 1);", + "dotnet://debugger-test.dll/debugger-test.cs", 1384, 8, + "ToStringOverwritten.Run", + wait_for_event_fn: async (pause_location) => + { + var id = pause_location["callFrames"][0]["callFrameId"].Value(); + await EvaluateOnCallFrameAndCheck(id, + ("a", TObject("ToStringOverwritten", description:"hithays")) + ); + } + ); + } } } diff --git a/src/mono/wasm/debugger/DebuggerTestSuite/MiscTests.cs b/src/mono/wasm/debugger/DebuggerTestSuite/MiscTests.cs index d0f8be8e660d85..a22b82a5d8d880 100644 --- a/src/mono/wasm/debugger/DebuggerTestSuite/MiscTests.cs +++ b/src/mono/wasm/debugger/DebuggerTestSuite/MiscTests.cs @@ -713,7 +713,7 @@ public async Task PreviousFrameForAReflectedCall() => await CheckInspectLocalsAt await CheckProps(frame_locals, new { - mi = TObject("System.Reflection.RuntimeMethodInfo"), //this is what is returned when debugging desktop apps using VS + mi = TObject("System.Reflection.RuntimeMethodInfo", description: "Void SimpleStaticMethod(System.DateTime, System.String)"), //this is what is returned when debugging desktop apps using VS dt = TDateTime(new DateTime(4210, 3, 4, 5, 6, 7)), i = TNumber(4), strings = TArray("string[]", "string[1]"), diff --git a/src/mono/wasm/debugger/tests/debugger-test/debugger-test.cs b/src/mono/wasm/debugger/tests/debugger-test/debugger-test.cs index 5e30c999b3304d..27b3cd75ccb68b 100644 --- a/src/mono/wasm/debugger/tests/debugger-test/debugger-test.cs +++ b/src/mono/wasm/debugger/tests/debugger-test/debugger-test.cs @@ -1371,4 +1371,17 @@ public static void CheckArguments(ReadOnlySpan parameters) { System.Diagnostics.Debugger.Break(); } +} + +public class ToStringOverwritten +{ + public override string ToString() + { + return "hithays"; + } + public static void Run() + { + var a = new ToStringOverwritten(); + System.Diagnostics.Debugger.Break(); + } } \ No newline at end of file From 0c124b894bb2353d2b52689e534079a051998612 Mon Sep 17 00:00:00 2001 From: Thays Grazia Date: Sat, 8 Oct 2022 12:58:09 -0300 Subject: [PATCH 02/11] Fix if cannot find ToString method. --- .../debugger/BrowserDebugProxy/JObjectValueCreator.cs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/JObjectValueCreator.cs b/src/mono/wasm/debugger/BrowserDebugProxy/JObjectValueCreator.cs index a30bd98ba8b1e8..00c584eba3429d 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/JObjectValueCreator.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/JObjectValueCreator.cs @@ -300,9 +300,12 @@ private async Task ReadAsObjectValue(MonoBinaryReader retDebuggerCmdRea if (methodInfo != null) { int[] methodIds = await _sdbAgent.GetMethodIdsByName(type_id[0], "ToString", token); - var toString = await _sdbAgent.InvokeMethod(objectId, methodIds[0], isValueType: false, token); - if (toString["value"]?["value"] != null) - description = toString["value"]?["value"].Value(); + if (methodIds.Length > 0) + { + var toString = await _sdbAgent.InvokeMethod(objectId, methodIds[0], isValueType: false, token); + if (toString["value"]?["value"] != null) + description = toString["value"]?["value"].Value(); + } } } return Create(value: null, type: "object", description: description, className: className, objectId: $"dotnet:object:{objectId}"); From 8dcd0d44f768b7ad1bdb07498b1a36ccbb63b6bf Mon Sep 17 00:00:00 2001 From: Thays Grazia Date: Sat, 8 Oct 2022 13:00:22 -0300 Subject: [PATCH 03/11] removing my name of the code --- src/mono/wasm/debugger/DebuggerTestSuite/CustomViewTests.cs | 2 +- src/mono/wasm/debugger/tests/debugger-test/debugger-test.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mono/wasm/debugger/DebuggerTestSuite/CustomViewTests.cs b/src/mono/wasm/debugger/DebuggerTestSuite/CustomViewTests.cs index c38c85380fba04..da00e5ed45602d 100644 --- a/src/mono/wasm/debugger/DebuggerTestSuite/CustomViewTests.cs +++ b/src/mono/wasm/debugger/DebuggerTestSuite/CustomViewTests.cs @@ -120,7 +120,7 @@ await EvaluateAndCheck( { var id = pause_location["callFrames"][0]["callFrameId"].Value(); await EvaluateOnCallFrameAndCheck(id, - ("a", TObject("ToStringOverwritten", description:"hithays")) + ("a", TObject("ToStringOverwritten", description:"hello")) ); } ); diff --git a/src/mono/wasm/debugger/tests/debugger-test/debugger-test.cs b/src/mono/wasm/debugger/tests/debugger-test/debugger-test.cs index 27b3cd75ccb68b..8d219766df4648 100644 --- a/src/mono/wasm/debugger/tests/debugger-test/debugger-test.cs +++ b/src/mono/wasm/debugger/tests/debugger-test/debugger-test.cs @@ -1377,7 +1377,7 @@ public class ToStringOverwritten { public override string ToString() { - return "hithays"; + return "hello"; } public static void Run() { From 87fc1a303664c98afb39f2149b2e8c60071ef2b1 Mon Sep 17 00:00:00 2001 From: Thays Grazia Date: Sun, 9 Oct 2022 18:27:35 -0300 Subject: [PATCH 04/11] Implementing support for inherited classes with ToString overriden. Implement support for value types with ToString overriden. Fix Debugger* is more relevant than ToString --- .../BrowserDebugProxy/JObjectValueCreator.cs | 33 +++++++++++------- .../BrowserDebugProxy/ValueTypeClass.cs | 29 +++++++++++++--- .../DebuggerTestSuite/CustomViewTests.cs | 13 ++++--- .../tests/debugger-test/debugger-test.cs | 34 +++++++++++++++++-- 4 files changed, 84 insertions(+), 25 deletions(-) diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/JObjectValueCreator.cs b/src/mono/wasm/debugger/BrowserDebugProxy/JObjectValueCreator.cs index 00c584eba3429d..6efa3e9eb612a2 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/JObjectValueCreator.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/JObjectValueCreator.cs @@ -269,18 +269,18 @@ async Task GetNullObjectClassName() private async Task ReadAsObjectValue(MonoBinaryReader retDebuggerCmdReader, int typeIdFromAttribute, bool forDebuggerDisplayAttribute, CancellationToken token) { var objectId = retDebuggerCmdReader.ReadInt32(); - var type_id = await _sdbAgent.GetTypeIdsForObject(objectId, false, token); - string className = await _sdbAgent.GetTypeName(type_id[0], token); + var typeIds = await _sdbAgent.GetTypeIdsForObject(objectId, true, token); + string className = await _sdbAgent.GetTypeName(typeIds[0], token); string debuggerDisplayAttribute = null; if (!forDebuggerDisplayAttribute) debuggerDisplayAttribute = await _sdbAgent.GetValueFromDebuggerDisplayAttribute( - new DotnetObjectId("object", objectId), type_id[0], token); + new DotnetObjectId("object", objectId), typeIds[0], token); var description = className.ToString(); if (debuggerDisplayAttribute != null) description = debuggerDisplayAttribute; - if (await _sdbAgent.IsDelegate(objectId, token)) + else if (await _sdbAgent.IsDelegate(objectId, token)) { if (typeIdFromAttribute != -1) { @@ -293,18 +293,25 @@ private async Task ReadAsObjectValue(MonoBinaryReader retDebuggerCmdRea return Create(value: className, type: "symbol", description: className); } } - var typeInfo = await _sdbAgent.GetTypeInfo(type_id[0], token); - if (typeInfo != null && typeInfo.Name != "object") + else { - MethodInfo methodInfo = typeInfo.Info.Methods.FirstOrDefault(m => m.Name == "ToString"); - if (methodInfo != null) + foreach (var typeId in typeIds) { - int[] methodIds = await _sdbAgent.GetMethodIdsByName(type_id[0], "ToString", token); - if (methodIds.Length > 0) + var typeInfo = await _sdbAgent.GetTypeInfo(typeId, token); + if (typeInfo != null && typeInfo.Name != "object") { - var toString = await _sdbAgent.InvokeMethod(objectId, methodIds[0], isValueType: false, token); - if (toString["value"]?["value"] != null) - description = toString["value"]?["value"].Value(); + MethodInfo methodInfo = typeInfo.Info.Methods.FirstOrDefault(m => m.Name == "ToString"); + if (methodInfo != null) + { + int[] methodIds = await _sdbAgent.GetMethodIdsByName(typeId, "ToString", token); + if (methodIds != null && methodIds.Length > 0) + { + var toString = await _sdbAgent.InvokeMethod(objectId, methodIds[0], isValueType: false, token); + if (toString["value"]?["value"] != null) + description = toString["value"]?["value"].Value(); + } + break; + } } } } diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/ValueTypeClass.cs b/src/mono/wasm/debugger/BrowserDebugProxy/ValueTypeClass.cs index 865785bf51e862..c2ba52c063c945 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/ValueTypeClass.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/ValueTypeClass.cs @@ -110,17 +110,32 @@ JObject GetFieldWithMetadata(FieldTypeClass field, JObject fieldValue, bool isSt return fieldValue; } } + public async Task ToString(MonoSDBHelper sdbAgent, CancellationToken token) + { + var typeInfo = await sdbAgent.GetTypeInfo(TypeId, token); + if (typeInfo == null) + return null; + if (typeInfo.Name == "object") + return null; + Microsoft.WebAssembly.Diagnostics.MethodInfo methodInfo = typeInfo.Info.Methods.FirstOrDefault(m => m.Name == "ToString"); + if (!IsEnum && methodInfo == null) + return null; + int[] methodIds = await sdbAgent.GetMethodIdsByName(TypeId, "ToString", token); + if (methodIds == null) + return null; + var retMethod = await sdbAgent.InvokeMethod(Buffer, methodIds[0], token, "methodRet"); + return retMethod["value"]?["value"].Value(); + } public async Task ToJObject(MonoSDBHelper sdbAgent, bool forDebuggerDisplayAttribute, CancellationToken token) { string description = className; if (ShouldAutoInvokeToString(className) || IsEnum) { - int[] methodIds = await sdbAgent.GetMethodIdsByName(TypeId, "ToString", token); - if (methodIds == null) + var toString = await ToString(sdbAgent, token); + if (toString == null) throw new InternalErrorException($"Cannot find method 'ToString' on typeId = {TypeId}"); - var retMethod = await sdbAgent.InvokeMethod(Buffer, methodIds[0], token, "methodRet"); - description = retMethod["value"]?["value"].Value(); + description = toString; if (className.Equals("System.Guid")) description = description.ToUpperInvariant(); //to keep the old behavior } @@ -129,6 +144,12 @@ public async Task ToJObject(MonoSDBHelper sdbAgent, bool forDebuggerDis string displayString = await sdbAgent.GetValueFromDebuggerDisplayAttribute(Id, TypeId, token); if (displayString != null) description = displayString; + else + { + var toString = await ToString(sdbAgent, token); + if (toString != null) + description = toString; + } } return JObjectValueCreator.Create( IsEnum ? fields[0]["value"] : null, diff --git a/src/mono/wasm/debugger/DebuggerTestSuite/CustomViewTests.cs b/src/mono/wasm/debugger/DebuggerTestSuite/CustomViewTests.cs index da00e5ed45602d..13b47a572e58e0 100644 --- a/src/mono/wasm/debugger/DebuggerTestSuite/CustomViewTests.cs +++ b/src/mono/wasm/debugger/DebuggerTestSuite/CustomViewTests.cs @@ -108,19 +108,22 @@ async Task CheckProperties(JObject pause_location) } [ConditionalFact(nameof(RunningOnChrome))] - public async Task InspectObjectOfTypeWithToStringOverwritten() + public async Task InspectObjectOfTypeWithToStringOverriden() { - var expression = $"{{ invoke_static_method('[debugger-test] ToStringOverwritten:Run'); }}"; + var expression = $"{{ invoke_static_method('[debugger-test] ToStringOverriden:Run'); }}"; await EvaluateAndCheck( "window.setTimeout(function() {" + expression + "; }, 1);", - "dotnet://debugger-test.dll/debugger-test.cs", 1384, 8, - "ToStringOverwritten.Run", + "dotnet://debugger-test.dll/debugger-test.cs", 1412, 8, + "ToStringOverriden.Run", wait_for_event_fn: async (pause_location) => { var id = pause_location["callFrames"][0]["callFrameId"].Value(); await EvaluateOnCallFrameAndCheck(id, - ("a", TObject("ToStringOverwritten", description:"hello")) + ("a", TObject("ToStringOverriden", description:"helloToStringOverriden")), + ("b", TObject("ToStringOverriden.ToStringOverridenB", description:"helloToStringOverridenA")), + ("c", TObject("ToStringOverriden.ToStringOverridenD", description:"helloToStringOverridenD")), + ("d", TObject("ToStringOverriden.ToStringOverridenE", description:"helloToStringOverridenE")) ); } ); diff --git a/src/mono/wasm/debugger/tests/debugger-test/debugger-test.cs b/src/mono/wasm/debugger/tests/debugger-test/debugger-test.cs index 8d219766df4648..e44e02cdaf37bb 100644 --- a/src/mono/wasm/debugger/tests/debugger-test/debugger-test.cs +++ b/src/mono/wasm/debugger/tests/debugger-test/debugger-test.cs @@ -1373,15 +1373,43 @@ public static void CheckArguments(ReadOnlySpan parameters) } } -public class ToStringOverwritten +public class ToStringOverriden { + class ToStringOverridenA { + public override string ToString() + { + return "helloToStringOverridenA"; + } + } + class ToStringOverridenB: ToStringOverridenA {} + + class ToStringOverridenC {} + class ToStringOverridenD: ToStringOverridenC + { + public override string ToString() + { + return "helloToStringOverridenD"; + } + } + + struct ToStringOverridenE + { + public override string ToString() + { + return "helloToStringOverridenE"; + } + } + public override string ToString() { - return "hello"; + return "helloToStringOverriden"; } public static void Run() { - var a = new ToStringOverwritten(); + var a = new ToStringOverriden(); + var b = new ToStringOverridenB(); + var c = new ToStringOverridenD(); + var d = new ToStringOverridenE(); System.Diagnostics.Debugger.Break(); } } \ No newline at end of file From eabbc6b6fde20cfbf3f13dc28308adb1038498e5 Mon Sep 17 00:00:00 2001 From: Thays Grazia Date: Sun, 9 Oct 2022 19:37:06 -0300 Subject: [PATCH 05/11] Fix test cases. --- .../BrowserDebugProxy/JObjectValueCreator.cs | 53 ++++++++++++------- .../BrowserDebugProxy/MonoSDBHelper.cs | 2 +- .../BrowserDebugProxy/ValueTypeClass.cs | 12 ++++- 3 files changed, 44 insertions(+), 23 deletions(-) diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/JObjectValueCreator.cs b/src/mono/wasm/debugger/BrowserDebugProxy/JObjectValueCreator.cs index 6efa3e9eb612a2..564c567011257e 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/JObjectValueCreator.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/JObjectValueCreator.cs @@ -265,7 +265,36 @@ async Task GetNullObjectClassName() return className; } } - + private async Task ToString(List typeIds, int objectId, CancellationToken token) + { + string description = ""; + try { + foreach (var typeId in typeIds) + { + var typeInfo = await _sdbAgent.GetTypeInfo(typeId, token); + if (typeInfo != null && typeInfo.Name != "object") + { + MethodInfo methodInfo = typeInfo.Info.Methods.FirstOrDefault(m => m.Name == "ToString"); + if (methodInfo != null) + { + int[] methodIds = await _sdbAgent.GetMethodIdsByName(typeId, "ToString", token); + if (methodIds != null && methodIds.Length > 0) + { + var toString = await _sdbAgent.InvokeMethod(objectId, methodIds[0], isValueType: false, token); + if (toString["value"]?["value"] != null) + description = toString["value"]?["value"].Value(); + } + break; + } + } + } + } + catch (Exception e) + { + _logger.LogDebug($"Error while evaluating ToString method: {e}"); + } + return description; + } private async Task ReadAsObjectValue(MonoBinaryReader retDebuggerCmdReader, int typeIdFromAttribute, bool forDebuggerDisplayAttribute, CancellationToken token) { var objectId = retDebuggerCmdReader.ReadInt32(); @@ -295,25 +324,9 @@ private async Task ReadAsObjectValue(MonoBinaryReader retDebuggerCmdRea } else { - foreach (var typeId in typeIds) - { - var typeInfo = await _sdbAgent.GetTypeInfo(typeId, token); - if (typeInfo != null && typeInfo.Name != "object") - { - MethodInfo methodInfo = typeInfo.Info.Methods.FirstOrDefault(m => m.Name == "ToString"); - if (methodInfo != null) - { - int[] methodIds = await _sdbAgent.GetMethodIdsByName(typeId, "ToString", token); - if (methodIds != null && methodIds.Length > 0) - { - var toString = await _sdbAgent.InvokeMethod(objectId, methodIds[0], isValueType: false, token); - if (toString["value"]?["value"] != null) - description = toString["value"]?["value"].Value(); - } - break; - } - } - } + var toString = await ToString(typeIds, objectId, token); + if (toString != "") + description = toString; } return Create(value: null, type: "object", description: description, className: className, objectId: $"dotnet:object:{objectId}"); } diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs b/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs index 902d339da852d4..d998874f0a657c 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs @@ -787,7 +787,7 @@ internal sealed class MonoSDBHelper private DebugStore store; private SessionId sessionId; - private readonly ILogger logger; + internal readonly ILogger logger; private static readonly Regex regexForAsyncLocals = new (@"\<([^)]*)\>", RegexOptions.Singleline); private static readonly Regex regexForAsyncMethodName = new (@"\<([^>]*)\>([d][_][_])([0-9]*)", RegexOptions.Compiled); private static readonly Regex regexForGenericArgs = new (@"[`][0-9]+", RegexOptions.Compiled); diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/ValueTypeClass.cs b/src/mono/wasm/debugger/BrowserDebugProxy/ValueTypeClass.cs index c2ba52c063c945..1c1839d413b3ed 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/ValueTypeClass.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/ValueTypeClass.cs @@ -11,6 +11,7 @@ using System.Threading.Tasks; using Microsoft.WebAssembly.Diagnostics; using Newtonsoft.Json.Linq; +using Microsoft.Extensions.Logging; namespace BrowserDebugProxy { @@ -123,8 +124,15 @@ public async Task ToString(MonoSDBHelper sdbAgent, CancellationToken tok int[] methodIds = await sdbAgent.GetMethodIdsByName(TypeId, "ToString", token); if (methodIds == null) return null; - var retMethod = await sdbAgent.InvokeMethod(Buffer, methodIds[0], token, "methodRet"); - return retMethod["value"]?["value"].Value(); + try { + var retMethod = await sdbAgent.InvokeMethod(Buffer, methodIds[0], token, "methodRet"); + return retMethod["value"]?["value"].Value(); + } + catch (Exception e) + { + sdbAgent.logger.LogDebug($"Error while evaluating ToString method: {e}"); + } + return null; } public async Task ToJObject(MonoSDBHelper sdbAgent, bool forDebuggerDisplayAttribute, CancellationToken token) From 7d9698ac538e9819ec9f702bdc0ba7dc59156c85 Mon Sep 17 00:00:00 2001 From: Thays Grazia Date: Sun, 9 Oct 2022 21:08:40 -0300 Subject: [PATCH 06/11] Apply suggestions from code review Co-authored-by: Ankit Jain --- .../wasm/debugger/BrowserDebugProxy/JObjectValueCreator.cs | 3 ++- src/mono/wasm/debugger/BrowserDebugProxy/ValueTypeClass.cs | 1 + src/mono/wasm/debugger/tests/debugger-test/debugger-test.cs | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/JObjectValueCreator.cs b/src/mono/wasm/debugger/BrowserDebugProxy/JObjectValueCreator.cs index 564c567011257e..e4fd26489500e0 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/JObjectValueCreator.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/JObjectValueCreator.cs @@ -272,7 +272,8 @@ private async Task ToString(List typeIds, int objectId, Cancellatio foreach (var typeId in typeIds) { var typeInfo = await _sdbAgent.GetTypeInfo(typeId, token); - if (typeInfo != null && typeInfo.Name != "object") + if (typeInfo == null || typeInfo.Name == "object") + continue; { MethodInfo methodInfo = typeInfo.Info.Methods.FirstOrDefault(m => m.Name == "ToString"); if (methodInfo != null) diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/ValueTypeClass.cs b/src/mono/wasm/debugger/BrowserDebugProxy/ValueTypeClass.cs index 1c1839d413b3ed..8326132ed3d8b8 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/ValueTypeClass.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/ValueTypeClass.cs @@ -111,6 +111,7 @@ JObject GetFieldWithMetadata(FieldTypeClass field, JObject fieldValue, bool isSt return fieldValue; } } + public async Task ToString(MonoSDBHelper sdbAgent, CancellationToken token) { var typeInfo = await sdbAgent.GetTypeInfo(TypeId, token); diff --git a/src/mono/wasm/debugger/tests/debugger-test/debugger-test.cs b/src/mono/wasm/debugger/tests/debugger-test/debugger-test.cs index e44e02cdaf37bb..3f8787050c0493 100644 --- a/src/mono/wasm/debugger/tests/debugger-test/debugger-test.cs +++ b/src/mono/wasm/debugger/tests/debugger-test/debugger-test.cs @@ -1392,7 +1392,7 @@ public override string ToString() } } - struct ToStringOverridenE + struct ToStringOverridenE { public override string ToString() { From 451b4ec2c9152dcc140327056cb9c0f8b2aa7a88 Mon Sep 17 00:00:00 2001 From: Thays Grazia Date: Sun, 9 Oct 2022 22:08:04 -0300 Subject: [PATCH 07/11] Adding more tests and addressing @radical comments --- .../BrowserDebugProxy/JObjectValueCreator.cs | 25 +++++--- .../MemberReferenceResolver.cs | 7 ++- .../BrowserDebugProxy/MonoSDBHelper.cs | 6 +- .../BrowserDebugProxy/ValueTypeClass.cs | 23 ++++--- .../DebuggerTestSuite/CustomViewTests.cs | 11 +++- .../tests/debugger-test/debugger-test.cs | 62 +++++++++++++++++++ 6 files changed, 110 insertions(+), 24 deletions(-) diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/JObjectValueCreator.cs b/src/mono/wasm/debugger/BrowserDebugProxy/JObjectValueCreator.cs index e4fd26489500e0..7179d26bf8b441 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/JObjectValueCreator.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/JObjectValueCreator.cs @@ -9,6 +9,7 @@ using BrowserDebugProxy; using Microsoft.Extensions.Logging; using Newtonsoft.Json.Linq; +using System.Reflection; namespace Microsoft.WebAssembly.Diagnostics; @@ -265,7 +266,7 @@ async Task GetNullObjectClassName() return className; } } - private async Task ToString(List typeIds, int objectId, CancellationToken token) + private async Task InvokeToStringAsync(List typeIds, int objectId, CancellationToken token) { string description = ""; try { @@ -278,12 +279,20 @@ private async Task ToString(List typeIds, int objectId, Cancellatio MethodInfo methodInfo = typeInfo.Info.Methods.FirstOrDefault(m => m.Name == "ToString"); if (methodInfo != null) { - int[] methodIds = await _sdbAgent.GetMethodIdsByName(typeId, "ToString", token); - if (methodIds != null && methodIds.Length > 0) + int[] methodIds = await _sdbAgent.GetMethodIdsByName(typeId, "ToString", BindingFlags.DeclaredOnly, token); + if (methodIds != null) { - var toString = await _sdbAgent.InvokeMethod(objectId, methodIds[0], isValueType: false, token); - if (toString["value"]?["value"] != null) - description = toString["value"]?["value"].Value(); + foreach (var methodId in methodIds) + { + var methodInfoFromRuntime = await _sdbAgent.GetMethodInfo(methodId, token); + if (methodInfoFromRuntime.Info.GetParametersInfo().Length > 0) + continue; + var toString = await _sdbAgent.InvokeMethod(objectId, methodId, isValueType: false, token); + if (toString["value"]?["value"] != null) + { + description = toString["value"]?["value"].Value(); + } + } } break; } @@ -299,7 +308,7 @@ private async Task ToString(List typeIds, int objectId, Cancellatio private async Task ReadAsObjectValue(MonoBinaryReader retDebuggerCmdReader, int typeIdFromAttribute, bool forDebuggerDisplayAttribute, CancellationToken token) { var objectId = retDebuggerCmdReader.ReadInt32(); - var typeIds = await _sdbAgent.GetTypeIdsForObject(objectId, true, token); + var typeIds = await _sdbAgent.GetTypeIdsForObject(objectId, withParents: true, token); string className = await _sdbAgent.GetTypeName(typeIds[0], token); string debuggerDisplayAttribute = null; if (!forDebuggerDisplayAttribute) @@ -325,7 +334,7 @@ private async Task ReadAsObjectValue(MonoBinaryReader retDebuggerCmdRea } else { - var toString = await ToString(typeIds, objectId, token); + var toString = await InvokeToStringAsync(typeIds, objectId, token); if (toString != "") description = toString; } diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/MemberReferenceResolver.cs b/src/mono/wasm/debugger/BrowserDebugProxy/MemberReferenceResolver.cs index 92afb5b2d28fba..8cd27c6e27b938 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/MemberReferenceResolver.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/MemberReferenceResolver.cs @@ -15,6 +15,7 @@ using System.Net.WebSockets; using BrowserDebugProxy; using System.Globalization; +using System.Reflection; namespace Microsoft.WebAssembly.Diagnostics { @@ -458,7 +459,7 @@ public async Task Resolve(ElementAccessExpressionSyntax elementAccess, return await ExpressionEvaluator.EvaluateSimpleExpression(this, eaFormatted, elementAccessStr, variableDefinitions, logger, token); } var typeIds = await context.SdbAgent.GetTypeIdsForObject(objectId.Value, true, token); - int[] methodIds = await context.SdbAgent.GetMethodIdsByName(typeIds[0], "ToArray", token); + int[] methodIds = await context.SdbAgent.GetMethodIdsByName(typeIds[0], "ToArray", BindingFlags.Default, token); // ToArray should not have an overload, but if user defined it, take the default one: without params if (methodIds == null) throw new InvalidOperationException($"Type '{rootObject?["className"]?.Value()}' cannot be indexed."); @@ -560,7 +561,7 @@ public async Task Resolve(InvocationExpressionSyntax method, Dictionary { typeIds = await context.SdbAgent.GetTypeIdsForObject(objectId.Value, true, token); } - int[] methodIds = await context.SdbAgent.GetMethodIdsByName(typeIds[0], methodName, token); + int[] methodIds = await context.SdbAgent.GetMethodIdsByName(typeIds[0], methodName, BindingFlags.Default, token); if (methodIds == null) { //try to search on System.Linq.Enumerable @@ -666,7 +667,7 @@ async Task FindMethodIdOnLinqEnumerable(IList typeIds, string methodNa } } - int[] newMethodIds = await context.SdbAgent.GetMethodIdsByName(linqTypeId, methodName, token); + int[] newMethodIds = await context.SdbAgent.GetMethodIdsByName(linqTypeId, methodName, BindingFlags.Default, token); if (newMethodIds == null) return 0; diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs b/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs index d998874f0a657c..ecf305f7b3fd72 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs @@ -1737,7 +1737,7 @@ public async Task GetTypeIdFromToken(int assemblyId, int typeToken, Cancell return retDebuggerCmdReader.ReadInt32(); } - public async Task GetMethodIdsByName(int type_id, string method_name, CancellationToken token) + public async Task GetMethodIdsByName(int type_id, string method_name, BindingFlags extraFlags, CancellationToken token) { if (type_id <= 0) throw new DebuggerAgentException($"Invalid type_id {type_id} (method_name: {method_name}"); @@ -1745,7 +1745,7 @@ public async Task GetMethodIdsByName(int type_id, string method_name, Can using var commandParamsWriter = new MonoBinaryWriter(); commandParamsWriter.Write((int)type_id); commandParamsWriter.Write(method_name); - commandParamsWriter.Write((int)(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static)); + commandParamsWriter.Write((int)(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static | extraFlags)); commandParamsWriter.Write((int)1); //case sensitive using var retDebuggerCmdReader = await SendDebuggerAgentCommand(CmdType.GetMethodsByNameFlags, commandParamsWriter, token); var nMethods = retDebuggerCmdReader.ReadInt32(); @@ -2169,7 +2169,7 @@ private async Task FindDebuggerProxyConstructorIdFor(int typeId, Cancellati break; cAttrTypeId = genericTypeId; } - int[] methodIds = await GetMethodIdsByName(cAttrTypeId, ".ctor", token); + int[] methodIds = await GetMethodIdsByName(cAttrTypeId, ".ctor", BindingFlags.Default, token); if (methodIds != null) methodId = methodIds[0]; break; diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/ValueTypeClass.cs b/src/mono/wasm/debugger/BrowserDebugProxy/ValueTypeClass.cs index 8326132ed3d8b8..71af18510fadd1 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/ValueTypeClass.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/ValueTypeClass.cs @@ -112,7 +112,7 @@ JObject GetFieldWithMetadata(FieldTypeClass field, JObject fieldValue, bool isSt } } - public async Task ToString(MonoSDBHelper sdbAgent, CancellationToken token) + public async Task InvokeToStringAsync(MonoSDBHelper sdbAgent, CancellationToken token) { var typeInfo = await sdbAgent.GetTypeInfo(TypeId, token); if (typeInfo == null) @@ -122,12 +122,18 @@ public async Task ToString(MonoSDBHelper sdbAgent, CancellationToken tok Microsoft.WebAssembly.Diagnostics.MethodInfo methodInfo = typeInfo.Info.Methods.FirstOrDefault(m => m.Name == "ToString"); if (!IsEnum && methodInfo == null) return null; - int[] methodIds = await sdbAgent.GetMethodIdsByName(TypeId, "ToString", token); + int[] methodIds = await sdbAgent.GetMethodIdsByName(TypeId, "ToString", IsEnum ? BindingFlags.Default : BindingFlags.DeclaredOnly, token); if (methodIds == null) return null; try { - var retMethod = await sdbAgent.InvokeMethod(Buffer, methodIds[0], token, "methodRet"); - return retMethod["value"]?["value"].Value(); + foreach (var methodId in methodIds) + { + var methodInfoFromRuntime = await sdbAgent.GetMethodInfo(methodId, token); + if (methodInfoFromRuntime.Info.GetParametersInfo().Length > 0) + continue; + var retMethod = await sdbAgent.InvokeMethod(Buffer, methodId, token, "methodRet"); + return retMethod["value"]?["value"].Value(); + } } catch (Exception e) { @@ -141,10 +147,11 @@ public async Task ToJObject(MonoSDBHelper sdbAgent, bool forDebuggerDis string description = className; if (ShouldAutoInvokeToString(className) || IsEnum) { - var toString = await ToString(sdbAgent, token); + var toString = await InvokeToStringAsync(sdbAgent, token); if (toString == null) - throw new InternalErrorException($"Cannot find method 'ToString' on typeId = {TypeId}"); - description = toString; + sdbAgent.logger.LogDebug($"Error while evaluating ToString method on typeId = {TypeId}"); + else + description = toString; if (className.Equals("System.Guid")) description = description.ToUpperInvariant(); //to keep the old behavior } @@ -155,7 +162,7 @@ public async Task ToJObject(MonoSDBHelper sdbAgent, bool forDebuggerDis description = displayString; else { - var toString = await ToString(sdbAgent, token); + var toString = await InvokeToStringAsync(sdbAgent, token); if (toString != null) description = toString; } diff --git a/src/mono/wasm/debugger/DebuggerTestSuite/CustomViewTests.cs b/src/mono/wasm/debugger/DebuggerTestSuite/CustomViewTests.cs index 13b47a572e58e0..e76ac7c22e8e7a 100644 --- a/src/mono/wasm/debugger/DebuggerTestSuite/CustomViewTests.cs +++ b/src/mono/wasm/debugger/DebuggerTestSuite/CustomViewTests.cs @@ -114,7 +114,7 @@ public async Task InspectObjectOfTypeWithToStringOverriden() await EvaluateAndCheck( "window.setTimeout(function() {" + expression + "; }, 1);", - "dotnet://debugger-test.dll/debugger-test.cs", 1412, 8, + "dotnet://debugger-test.dll/debugger-test.cs", 1474, 8, "ToStringOverriden.Run", wait_for_event_fn: async (pause_location) => { @@ -123,7 +123,14 @@ await EvaluateOnCallFrameAndCheck(id, ("a", TObject("ToStringOverriden", description:"helloToStringOverriden")), ("b", TObject("ToStringOverriden.ToStringOverridenB", description:"helloToStringOverridenA")), ("c", TObject("ToStringOverriden.ToStringOverridenD", description:"helloToStringOverridenD")), - ("d", TObject("ToStringOverriden.ToStringOverridenE", description:"helloToStringOverridenE")) + ("d", TObject("ToStringOverriden.ToStringOverridenE", description:"helloToStringOverridenE")), + ("e", TObject("ToStringOverriden.ToStringOverridenB", description:"helloToStringOverridenA")), + ("f", TObject("ToStringOverriden.ToStringOverridenB", description:"helloToStringOverridenA")), + ("g", TObject("ToStringOverriden.ToStringOverridenG", description:"helloToStringOverridenG")), + ("h", TObject("ToStringOverriden.ToStringOverridenH", description:"helloToStringOverridenH")), + ("i", TObject("ToStringOverriden.ToStringOverridenI", description:"ToStringOverriden.ToStringOverridenI")), + ("j", TObject("ToStringOverriden.ToStringOverridenJ", description:"helloToStringOverridenJ")), + ("k", TObject("ToStringOverriden.ToStringOverridenK", description:"ToStringOverriden.ToStringOverridenK")) ); } ); diff --git a/src/mono/wasm/debugger/tests/debugger-test/debugger-test.cs b/src/mono/wasm/debugger/tests/debugger-test/debugger-test.cs index 3f8787050c0493..8239023ef2d4ca 100644 --- a/src/mono/wasm/debugger/tests/debugger-test/debugger-test.cs +++ b/src/mono/wasm/debugger/tests/debugger-test/debugger-test.cs @@ -1400,6 +1400,61 @@ public override string ToString() } } + class ToStringOverridenF + { + public override string ToString() + { + return "helloToStringOverridenF"; + } + } + class ToStringOverridenG: ToStringOverridenF + { + public override string ToString() + { + return "helloToStringOverridenG"; + } + } + + class ToStringOverridenH + { + public override string ToString() + { + return "helloToStringOverridenH"; + } + public string ToString(bool withParms = true) + { + return "helloToStringOverridenHWrong"; + } + } + + class ToStringOverridenI + { + public string ToString(bool withParms = true) + { + return "helloToStringOverridenIWrong"; + } + } + + struct ToStringOverridenJ + { + public override string ToString() + { + return "helloToStringOverridenJ"; + } + public string ToString(bool withParms = true) + { + return "helloToStringOverridenJWrong"; + } + } + + struct ToStringOverridenK + { + public string ToString(bool withParms = true) + { + return "helloToStringOverridenKWrong"; + } + } + public override string ToString() { return "helloToStringOverriden"; @@ -1410,6 +1465,13 @@ public static void Run() var b = new ToStringOverridenB(); var c = new ToStringOverridenD(); var d = new ToStringOverridenE(); + ToStringOverridenA e = new ToStringOverridenB(); + object f = new ToStringOverridenB(); + var g = new ToStringOverridenG(); + var h = new ToStringOverridenH(); + var i = new ToStringOverridenI(); + var j = new ToStringOverridenJ(); + var k = new ToStringOverridenK(); System.Diagnostics.Debugger.Break(); } } \ No newline at end of file From eadebf0ac5c90d7a195a5904ae193d3319ea5303 Mon Sep 17 00:00:00 2001 From: Thays Grazia Date: Mon, 10 Oct 2022 10:18:46 -0300 Subject: [PATCH 08/11] Adding tests for record --- .../DebuggerTestSuite/CustomViewTests.cs | 7 +++-- .../tests/debugger-test/debugger-test.cs | 31 +++++++++++++++++++ 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/src/mono/wasm/debugger/DebuggerTestSuite/CustomViewTests.cs b/src/mono/wasm/debugger/DebuggerTestSuite/CustomViewTests.cs index e76ac7c22e8e7a..48f4f0a70804c1 100644 --- a/src/mono/wasm/debugger/DebuggerTestSuite/CustomViewTests.cs +++ b/src/mono/wasm/debugger/DebuggerTestSuite/CustomViewTests.cs @@ -114,7 +114,7 @@ public async Task InspectObjectOfTypeWithToStringOverriden() await EvaluateAndCheck( "window.setTimeout(function() {" + expression + "; }, 1);", - "dotnet://debugger-test.dll/debugger-test.cs", 1474, 8, + "dotnet://debugger-test.dll/debugger-test.cs", 1505, 8, "ToStringOverriden.Run", wait_for_event_fn: async (pause_location) => { @@ -130,7 +130,10 @@ await EvaluateOnCallFrameAndCheck(id, ("h", TObject("ToStringOverriden.ToStringOverridenH", description:"helloToStringOverridenH")), ("i", TObject("ToStringOverriden.ToStringOverridenI", description:"ToStringOverriden.ToStringOverridenI")), ("j", TObject("ToStringOverriden.ToStringOverridenJ", description:"helloToStringOverridenJ")), - ("k", TObject("ToStringOverriden.ToStringOverridenK", description:"ToStringOverriden.ToStringOverridenK")) + ("k", TObject("ToStringOverriden.ToStringOverridenK", description:"ToStringOverriden.ToStringOverridenK")), + ("l", TObject("ToStringOverriden.ToStringOverridenL", description:"helloToStringOverridenL")), + ("m", TObject("ToStringOverriden.ToStringOverridenM", description:"ToStringOverridenM { }")), + ("n", TObject("ToStringOverriden.ToStringOverridenN", description:"helloToStringOverridenN")) ); } ); diff --git a/src/mono/wasm/debugger/tests/debugger-test/debugger-test.cs b/src/mono/wasm/debugger/tests/debugger-test/debugger-test.cs index 8239023ef2d4ca..325fc7d76ad859 100644 --- a/src/mono/wasm/debugger/tests/debugger-test/debugger-test.cs +++ b/src/mono/wasm/debugger/tests/debugger-test/debugger-test.cs @@ -1455,6 +1455,34 @@ public string ToString(bool withParms = true) } } + record ToStringOverridenL + { + public override string ToString() + { + return "helloToStringOverridenL"; + } + } + + record ToStringOverridenM + { + public string ToString(bool withParms = true) + { + return "helloToStringOverridenMWrong"; + } + } + + record ToStringOverridenN + { + public override string ToString() + { + return "helloToStringOverridenN"; + } + public string ToString(bool withParms = true) + { + return "helloToStringOverridenNWrong"; + } + } + public override string ToString() { return "helloToStringOverriden"; @@ -1472,6 +1500,9 @@ public static void Run() var i = new ToStringOverridenI(); var j = new ToStringOverridenJ(); var k = new ToStringOverridenK(); + var l = new ToStringOverridenL(); + var m = new ToStringOverridenM(); + var n = new ToStringOverridenN(); System.Diagnostics.Debugger.Break(); } } \ No newline at end of file From 99b24293ffea1955dd80053329c918e353f4a087 Mon Sep 17 00:00:00 2001 From: Thays Grazia Date: Mon, 10 Oct 2022 15:46:05 -0300 Subject: [PATCH 09/11] Moving implementation of InvokeToStringAsync to sdbhelper and reuse it on objects and valuetypes. --- .../BrowserDebugProxy/JObjectValueCreator.cs | 44 ++----------------- .../BrowserDebugProxy/MonoSDBHelper.cs | 37 ++++++++++++++++ .../BrowserDebugProxy/ValueTypeClass.cs | 34 +------------- 3 files changed, 42 insertions(+), 73 deletions(-) diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/JObjectValueCreator.cs b/src/mono/wasm/debugger/BrowserDebugProxy/JObjectValueCreator.cs index 7179d26bf8b441..4bc5219e59acf0 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/JObjectValueCreator.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/JObjectValueCreator.cs @@ -266,45 +266,7 @@ async Task GetNullObjectClassName() return className; } } - private async Task InvokeToStringAsync(List typeIds, int objectId, CancellationToken token) - { - string description = ""; - try { - foreach (var typeId in typeIds) - { - var typeInfo = await _sdbAgent.GetTypeInfo(typeId, token); - if (typeInfo == null || typeInfo.Name == "object") - continue; - { - MethodInfo methodInfo = typeInfo.Info.Methods.FirstOrDefault(m => m.Name == "ToString"); - if (methodInfo != null) - { - int[] methodIds = await _sdbAgent.GetMethodIdsByName(typeId, "ToString", BindingFlags.DeclaredOnly, token); - if (methodIds != null) - { - foreach (var methodId in methodIds) - { - var methodInfoFromRuntime = await _sdbAgent.GetMethodInfo(methodId, token); - if (methodInfoFromRuntime.Info.GetParametersInfo().Length > 0) - continue; - var toString = await _sdbAgent.InvokeMethod(objectId, methodId, isValueType: false, token); - if (toString["value"]?["value"] != null) - { - description = toString["value"]?["value"].Value(); - } - } - } - break; - } - } - } - } - catch (Exception e) - { - _logger.LogDebug($"Error while evaluating ToString method: {e}"); - } - return description; - } + private async Task ReadAsObjectValue(MonoBinaryReader retDebuggerCmdReader, int typeIdFromAttribute, bool forDebuggerDisplayAttribute, CancellationToken token) { var objectId = retDebuggerCmdReader.ReadInt32(); @@ -334,8 +296,8 @@ private async Task ReadAsObjectValue(MonoBinaryReader retDebuggerCmdRea } else { - var toString = await InvokeToStringAsync(typeIds, objectId, token); - if (toString != "") + var toString = await _sdbAgent.InvokeToStringAsync(typeIds, false, false, objectId, BindingFlags.DeclaredOnly, token); + if (toString != null) description = toString; } return Create(value: null, type: "object", description: description, className: className, objectId: $"dotnet:object:{objectId}"); diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs b/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs index ecf305f7b3fd72..52424ae5cfbd14 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs @@ -1839,6 +1839,43 @@ public Task InvokeMethod(DotnetObjectId dotnetObjectId, CancellationTok : throw new ArgumentException($"Cannot invoke method with id {methodId} on {dotnetObjectId}", nameof(dotnetObjectId)); } + public async Task InvokeToStringAsync(List typeIds, bool isValueType, bool isEnum, int objectId, BindingFlags extraFlags, CancellationToken token) + { + try + { + foreach (var typeId in typeIds) + { + var typeInfo = await GetTypeInfo(typeId, token); + if (typeInfo == null) + continue; + if (typeInfo.Name == "object") + continue; + Microsoft.WebAssembly.Diagnostics.MethodInfo methodInfo = typeInfo.Info.Methods.FirstOrDefault(m => m.Name == "ToString"); + if (isEnum != true && methodInfo == null) + continue; + int[] methodIds = await GetMethodIdsByName(typeId, "ToString", extraFlags, token); + if (methodIds == null) + continue; + foreach (var methodId in methodIds) + { + var methodInfoFromRuntime = await GetMethodInfo(methodId, token); + if (methodInfoFromRuntime.Info.GetParametersInfo().Length > 0) + continue; + var retMethod = await InvokeMethod(objectId, methodId, isValueType, token); + return retMethod["value"]?["value"].Value(); + } + } + return null; + } + catch (Exception e) + { + logger.LogDebug($"Error while evaluating ToString method: {e}"); + } + return null; + } + + + public async Task GetPropertyMethodIdByName(int typeId, string propertyName, CancellationToken token) { using var retDebuggerCmdReader = await GetTypePropertiesReader(typeId, token); diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/ValueTypeClass.cs b/src/mono/wasm/debugger/BrowserDebugProxy/ValueTypeClass.cs index 71af18510fadd1..cfb1bbefb1ada2 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/ValueTypeClass.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/ValueTypeClass.cs @@ -112,42 +112,12 @@ JObject GetFieldWithMetadata(FieldTypeClass field, JObject fieldValue, bool isSt } } - public async Task InvokeToStringAsync(MonoSDBHelper sdbAgent, CancellationToken token) - { - var typeInfo = await sdbAgent.GetTypeInfo(TypeId, token); - if (typeInfo == null) - return null; - if (typeInfo.Name == "object") - return null; - Microsoft.WebAssembly.Diagnostics.MethodInfo methodInfo = typeInfo.Info.Methods.FirstOrDefault(m => m.Name == "ToString"); - if (!IsEnum && methodInfo == null) - return null; - int[] methodIds = await sdbAgent.GetMethodIdsByName(TypeId, "ToString", IsEnum ? BindingFlags.Default : BindingFlags.DeclaredOnly, token); - if (methodIds == null) - return null; - try { - foreach (var methodId in methodIds) - { - var methodInfoFromRuntime = await sdbAgent.GetMethodInfo(methodId, token); - if (methodInfoFromRuntime.Info.GetParametersInfo().Length > 0) - continue; - var retMethod = await sdbAgent.InvokeMethod(Buffer, methodId, token, "methodRet"); - return retMethod["value"]?["value"].Value(); - } - } - catch (Exception e) - { - sdbAgent.logger.LogDebug($"Error while evaluating ToString method: {e}"); - } - return null; - } - public async Task ToJObject(MonoSDBHelper sdbAgent, bool forDebuggerDisplayAttribute, CancellationToken token) { string description = className; if (ShouldAutoInvokeToString(className) || IsEnum) { - var toString = await InvokeToStringAsync(sdbAgent, token); + var toString = await sdbAgent.InvokeToStringAsync(new List(){TypeId}, true, IsEnum, Id.Value, IsEnum ? BindingFlags.Default : BindingFlags.DeclaredOnly, token); if (toString == null) sdbAgent.logger.LogDebug($"Error while evaluating ToString method on typeId = {TypeId}"); else @@ -162,7 +132,7 @@ public async Task ToJObject(MonoSDBHelper sdbAgent, bool forDebuggerDis description = displayString; else { - var toString = await InvokeToStringAsync(sdbAgent, token); + var toString = await sdbAgent.InvokeToStringAsync(new List(){TypeId}, true, IsEnum, Id.Value, IsEnum ? BindingFlags.Default : BindingFlags.DeclaredOnly, token); if (toString != null) description = toString; } From d11ed8f598b7718e11fe0120d619eac869bc25e9 Mon Sep 17 00:00:00 2001 From: Thays Grazia Date: Mon, 10 Oct 2022 16:20:30 -0300 Subject: [PATCH 10/11] Apply suggestions from code review Co-authored-by: Ankit Jain --- .../wasm/debugger/BrowserDebugProxy/JObjectValueCreator.cs | 3 ++- src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs | 7 +------ src/mono/wasm/debugger/BrowserDebugProxy/ValueTypeClass.cs | 6 ++++-- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/JObjectValueCreator.cs b/src/mono/wasm/debugger/BrowserDebugProxy/JObjectValueCreator.cs index 4bc5219e59acf0..9d09e23d9f94a6 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/JObjectValueCreator.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/JObjectValueCreator.cs @@ -279,8 +279,9 @@ private async Task ReadAsObjectValue(MonoBinaryReader retDebuggerCmdRea var description = className.ToString(); if (debuggerDisplayAttribute != null) + { description = debuggerDisplayAttribute; - + } else if (await _sdbAgent.IsDelegate(objectId, token)) { if (typeIdFromAttribute != -1) diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs b/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs index 52424ae5cfbd14..76ea655305fdb1 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs @@ -1846,9 +1846,7 @@ public async Task InvokeToStringAsync(List typeIds, bool isValueTyp foreach (var typeId in typeIds) { var typeInfo = await GetTypeInfo(typeId, token); - if (typeInfo == null) - continue; - if (typeInfo.Name == "object") + if (typeInfo == null || typeInfo.Name == "object") continue; Microsoft.WebAssembly.Diagnostics.MethodInfo methodInfo = typeInfo.Info.Methods.FirstOrDefault(m => m.Name == "ToString"); if (isEnum != true && methodInfo == null) @@ -1865,7 +1863,6 @@ public async Task InvokeToStringAsync(List typeIds, bool isValueTyp return retMethod["value"]?["value"].Value(); } } - return null; } catch (Exception e) { @@ -1874,8 +1871,6 @@ public async Task InvokeToStringAsync(List typeIds, bool isValueTyp return null; } - - public async Task GetPropertyMethodIdByName(int typeId, string propertyName, CancellationToken token) { using var retDebuggerCmdReader = await GetTypePropertiesReader(typeId, token); diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/ValueTypeClass.cs b/src/mono/wasm/debugger/BrowserDebugProxy/ValueTypeClass.cs index cfb1bbefb1ada2..b79920047858cf 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/ValueTypeClass.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/ValueTypeClass.cs @@ -117,7 +117,7 @@ public async Task ToJObject(MonoSDBHelper sdbAgent, bool forDebuggerDis string description = className; if (ShouldAutoInvokeToString(className) || IsEnum) { - var toString = await sdbAgent.InvokeToStringAsync(new List(){TypeId}, true, IsEnum, Id.Value, IsEnum ? BindingFlags.Default : BindingFlags.DeclaredOnly, token); + var toString = await sdbAgent.InvokeToStringAsync(new int[]{ TypeId }, true, IsEnum, Id.Value, IsEnum ? BindingFlags.Default : BindingFlags.DeclaredOnly, token); if (toString == null) sdbAgent.logger.LogDebug($"Error while evaluating ToString method on typeId = {TypeId}"); else @@ -129,10 +129,12 @@ public async Task ToJObject(MonoSDBHelper sdbAgent, bool forDebuggerDis { string displayString = await sdbAgent.GetValueFromDebuggerDisplayAttribute(Id, TypeId, token); if (displayString != null) + { description = displayString; + } else { - var toString = await sdbAgent.InvokeToStringAsync(new List(){TypeId}, true, IsEnum, Id.Value, IsEnum ? BindingFlags.Default : BindingFlags.DeclaredOnly, token); + var toString = await sdbAgent.InvokeToStringAsync(new int[]{ TypeId }, true, IsEnum, Id.Value, IsEnum ? BindingFlags.Default : BindingFlags.DeclaredOnly, token); if (toString != null) description = toString; } From 794a460cd356441c0245fd0082af022b42f56618 Mon Sep 17 00:00:00 2001 From: Thays Grazia Date: Mon, 10 Oct 2022 16:26:35 -0300 Subject: [PATCH 11/11] Addressing @radical comments. --- .../wasm/debugger/BrowserDebugProxy/JObjectValueCreator.cs | 2 +- src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs | 2 +- src/mono/wasm/debugger/BrowserDebugProxy/ValueTypeClass.cs | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/JObjectValueCreator.cs b/src/mono/wasm/debugger/BrowserDebugProxy/JObjectValueCreator.cs index 9d09e23d9f94a6..03783a7466e8da 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/JObjectValueCreator.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/JObjectValueCreator.cs @@ -297,7 +297,7 @@ private async Task ReadAsObjectValue(MonoBinaryReader retDebuggerCmdRea } else { - var toString = await _sdbAgent.InvokeToStringAsync(typeIds, false, false, objectId, BindingFlags.DeclaredOnly, token); + var toString = await _sdbAgent.InvokeToStringAsync(typeIds, isValueType: false, isEnum: false, objectId, BindingFlags.DeclaredOnly, token); if (toString != null) description = toString; } diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs b/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs index 76ea655305fdb1..074b7c8fc7df93 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs @@ -1839,7 +1839,7 @@ public Task InvokeMethod(DotnetObjectId dotnetObjectId, CancellationTok : throw new ArgumentException($"Cannot invoke method with id {methodId} on {dotnetObjectId}", nameof(dotnetObjectId)); } - public async Task InvokeToStringAsync(List typeIds, bool isValueType, bool isEnum, int objectId, BindingFlags extraFlags, CancellationToken token) + public async Task InvokeToStringAsync(IEnumerable typeIds, bool isValueType, bool isEnum, int objectId, BindingFlags extraFlags, CancellationToken token) { try { diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/ValueTypeClass.cs b/src/mono/wasm/debugger/BrowserDebugProxy/ValueTypeClass.cs index b79920047858cf..bcd34e9b7d0cc7 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/ValueTypeClass.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/ValueTypeClass.cs @@ -117,7 +117,7 @@ public async Task ToJObject(MonoSDBHelper sdbAgent, bool forDebuggerDis string description = className; if (ShouldAutoInvokeToString(className) || IsEnum) { - var toString = await sdbAgent.InvokeToStringAsync(new int[]{ TypeId }, true, IsEnum, Id.Value, IsEnum ? BindingFlags.Default : BindingFlags.DeclaredOnly, token); + var toString = await sdbAgent.InvokeToStringAsync(new int[]{ TypeId }, isValueType: true, IsEnum, Id.Value, IsEnum ? BindingFlags.Default : BindingFlags.DeclaredOnly, token); if (toString == null) sdbAgent.logger.LogDebug($"Error while evaluating ToString method on typeId = {TypeId}"); else @@ -134,7 +134,7 @@ public async Task ToJObject(MonoSDBHelper sdbAgent, bool forDebuggerDis } else { - var toString = await sdbAgent.InvokeToStringAsync(new int[]{ TypeId }, true, IsEnum, Id.Value, IsEnum ? BindingFlags.Default : BindingFlags.DeclaredOnly, token); + var toString = await sdbAgent.InvokeToStringAsync(new int[]{ TypeId }, isValueType: true, IsEnum, Id.Value, IsEnum ? BindingFlags.Default : BindingFlags.DeclaredOnly, token); if (toString != null) description = toString; }