From fab24e5388c11147b2baa1bdf080e76eb1d13464 Mon Sep 17 00:00:00 2001 From: Ilona Tomkowicz Date: Fri, 5 Nov 2021 11:57:05 +0100 Subject: [PATCH 01/19] Using current namespace as the default place to serach for the resolved class. --- .../debugger/BrowserDebugProxy/DebugStore.cs | 2 + .../MemberReferenceResolver.cs | 37 +++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/DebugStore.cs b/src/mono/wasm/debugger/BrowserDebugProxy/DebugStore.cs index 9fe5205394e24a..4174dedc5290b9 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/DebugStore.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/DebugStore.cs @@ -331,6 +331,7 @@ internal class MethodInfo public bool IsStatic() => (methodDef.Attributes & MethodAttributes.Static) != 0; public int IsAsync { get; set; } public bool IsHiddenFromDebugger { get; } + public TypeInfo TypeInfo { get; } public MethodInfo(AssemblyInfo assembly, MethodDefinitionHandle methodDefHandle, int token, SourceFile source, TypeInfo type, MetadataReader asmMetadataReader, MetadataReader pdbMetadataReader) { this.IsAsync = -1; @@ -343,6 +344,7 @@ public MethodInfo(AssemblyInfo assembly, MethodDefinitionHandle methodDefHandle, this.Name = asmMetadataReader.GetString(methodDef.Name); this.pdbMetadataReader = pdbMetadataReader; this.IsEnCMethod = false; + this.TypeInfo = type; if (!DebugInformation.SequencePointsBlob.IsNil) { var sps = DebugInformation.GetSequencePoints(); diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/MemberReferenceResolver.cs b/src/mono/wasm/debugger/BrowserDebugProxy/MemberReferenceResolver.cs index 5c7b4d3d1405f0..488b6da3175c29 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/MemberReferenceResolver.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/MemberReferenceResolver.cs @@ -119,12 +119,44 @@ public async Task TryToRunOnLoadedClasses(string varName, CancellationT } } var store = await proxy.LoadStore(sessionId, token); + + // first - check the current assembly + var currentFrame = ctx.CallStack.FirstOrDefault(); + var currentAssembly = currentFrame.Method.Info.TypeInfo.assembly; + string namespaceName = currentAssembly.Name; + + // remove .dll from the end + if (namespaceName.Length > 4) + namespaceName = currentAssembly.Name.Remove(currentAssembly.Name.Length - 4); + + // look for classes in the current namespace + var matchingType = currentAssembly.TypesByName.Keys + .Where(k => k == string.Join(".", new string[] { namespaceName, classNameToFind })) + .Select(t => currentAssembly.GetTypeByName(t)) + .FirstOrDefault(); + + // if not found, look in all namespaces in the current assembly + if (matchingType == null) + { + matchingType = currentAssembly.TypesByName.Keys + .Where(k => k == classNameToFind) + .Select(t => currentAssembly.GetTypeByName(t)) + .FirstOrDefault(); + } + if (matchingType != null) + { + typeId = await sdbHelper.GetTypeIdFromToken(sessionId, currentAssembly.DebugId, matchingType.Token, token); + continue; + } + + // if not found in the current assembly, look in the other assemblies foreach (var asm in store.assemblies) { var type = asm.GetTypeByName(classNameToFind); if (type != null) { typeId = await sdbHelper.GetTypeIdFromToken(sessionId, asm.DebugId, type.Token, token); + break; } } } @@ -201,6 +233,11 @@ public async Task Resolve(string varName, CancellationToken token) } } } + else if (rootObject == null) + { + rootObject = await TryToRunOnLoadedClasses(varName, token); + return rootObject; + } } scopeCache.MemberReferences[varName] = rootObject; return rootObject; From 66b56a792d4a60d012857c66377e5987c8721a34 Mon Sep 17 00:00:00 2001 From: Ilona Tomkowicz Date: Fri, 5 Nov 2021 15:59:56 +0100 Subject: [PATCH 02/19] Add tests for static class, static fields and pausing in async method. --- .../EvaluateOnCallFrameTests.cs | 65 ++++++++++++++++++- .../debugger-test/debugger-evaluate-test.cs | 23 +++++++ 2 files changed, 86 insertions(+), 2 deletions(-) diff --git a/src/mono/wasm/debugger/DebuggerTestSuite/EvaluateOnCallFrameTests.cs b/src/mono/wasm/debugger/DebuggerTestSuite/EvaluateOnCallFrameTests.cs index 524ff68fb9e2db..4c0f24350e499b 100644 --- a/src/mono/wasm/debugger/DebuggerTestSuite/EvaluateOnCallFrameTests.cs +++ b/src/mono/wasm/debugger/DebuggerTestSuite/EvaluateOnCallFrameTests.cs @@ -36,6 +36,11 @@ public static IEnumerable InstanceMethodForTypeMembersTestData(string } } + public static IEnumerable EvaluateStaticClassFromAsyncMethodTestData(string type_name) + { + yield return new object[] { type_name, "EvaluateAsyncMethods", "EvaluateAsyncMethods", true }; + } + [Theory] [MemberData(nameof(InstanceMethodForTypeMembersTestData), parameters: "DebuggerTests.EvaluateTestsStructWithProperties")] [MemberData(nameof(InstanceMethodForTypeMembersTestData), parameters: "DebuggerTests.EvaluateTestsClassWithProperties")] @@ -695,6 +700,62 @@ await EvaluateOnCallFrameAndCheck(id, ("DebuggerTests.EvaluateStaticClass.StaticPropertyWithError", TString("System.Exception: not implemented"))); }); + [Fact] + public async Task EvaluateStaticClassFromStaticMethod() => await CheckInspectLocalsAtBreakpointSite( + "DebuggerTests.EvaluateMethodTestsClass", "EvaluateMethods", 1, "EvaluateMethods", + "window.setTimeout(function() { invoke_static_method ('[debugger-test] DebuggerTests.EvaluateMethodTestsClass:EvaluateMethods'); })", + wait_for_event_fn: async (pause_location) => + { + var id = pause_location["callFrames"][0]["callFrameId"].Value(); + + var frame = pause_location["callFrames"][0]; + + await EvaluateOnCallFrameAndCheck(id, + ("DebuggerTests.EvaluateStaticClass.StaticField1", TNumber(10))); + await EvaluateOnCallFrameAndCheck(id, + ("DebuggerTests.EvaluateStaticClass.StaticProperty1", TString("StaticProperty1"))); + await EvaluateOnCallFrameAndCheck(id, + ("DebuggerTests.EvaluateStaticClass.StaticPropertyWithError", TString("System.Exception: not implemented"))); + }); + + [Theory] + [MemberData(nameof(EvaluateStaticClassFromAsyncMethodTestData), parameters: "DebuggerTests.EvaluateMethodTestsClass")] + public async Task EvaluateStaticClassFromAsyncMethod(string type, string method, string bp_function_name, bool is_async) + => await CheckInspectLocalsAtBreakpointSite( + type, method, 1, bp_function_name, + "window.setTimeout(function() { invoke_static_method ('[debugger-test] DebuggerTests.EvaluateMethodTestsClass:EvaluateAsyncMethods'); })", + wait_for_event_fn: async (pause_location) => + { + var id = pause_location["callFrames"][0]["callFrameId"].Value(); + + var frame = pause_location["callFrames"][0]; + + await EvaluateOnCallFrameAndCheck(id, + ("DebuggerTests.EvaluateStaticClass.StaticField1", TNumber(10))); + await EvaluateOnCallFrameAndCheck(id, + ("DebuggerTests.EvaluateStaticClass.StaticProperty1", TString("StaticProperty1"))); + await EvaluateOnCallFrameAndCheck(id, + ("DebuggerTests.EvaluateStaticClass.StaticPropertyWithError", TString("System.Exception: not implemented"))); + }); + + [Fact] + public async Task EvaluateNonStaticClassWithStaticFields() => await CheckInspectLocalsAtBreakpointSite( + "DebuggerTests.EvaluateMethodTestsClass/TestEvaluate", "run", 9, "run", + "window.setTimeout(function() { invoke_static_method ('[debugger-test] DebuggerTests.EvaluateMethodTestsClass:EvaluateMethods'); })", + wait_for_event_fn: async (pause_location) => + { + var id = pause_location["callFrames"][0]["callFrameId"].Value(); + + var frame = pause_location["callFrames"][0]; + + await EvaluateOnCallFrameAndCheck(id, + ("DebuggerTests.EvaluateNonStaticClassWithStaticFields.StaticField1", TNumber(10))); + await EvaluateOnCallFrameAndCheck(id, + ("DebuggerTests.EvaluateNonStaticClassWithStaticFields.StaticProperty1", TString("StaticProperty1"))); + await EvaluateOnCallFrameAndCheck(id, + ("DebuggerTests.EvaluateNonStaticClassWithStaticFields.StaticPropertyWithError", TString("System.Exception: not implemented"))); + }); + [Fact] public async Task EvaluateStaticClassInvalidField() => await CheckInspectLocalsAtBreakpointSite( "DebuggerTests.EvaluateMethodTestsClass/TestEvaluate", "run", 9, "run", @@ -712,8 +773,8 @@ public async Task EvaluateStaticClassInvalidField() => await CheckInspectLocalsA AssertEqual("Failed to resolve member access for DebuggerTests.InvalidEvaluateStaticClass.StaticProperty2", res.Error["result"]?["description"]?.Value(), "wrong error message"); }); - [Fact] - public async Task AsyncLocalsInContinueWithBlock() => await CheckInspectLocalsAtBreakpointSite( + [Fact] + public async Task AsyncLocalsInContinueWithBlock() => await CheckInspectLocalsAtBreakpointSite( "DebuggerTests.AsyncTests.ContinueWithTests", "ContinueWithStaticAsync", 4, "b__3_0", "window.setTimeout(function() { invoke_static_method('[debugger-test] DebuggerTests.AsyncTests.ContinueWithTests:RunAsync'); })", wait_for_event_fn: async (pause_location) => 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 74153fa3793761..0eb950705352bd 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 @@ -405,6 +405,12 @@ public static void EvaluateMethods() f.run(100, 200, "9000", "test", 45); } + public static void EvaluateAsyncMethods() + { + var staticClass = new EvaluateNonStaticClassWithStaticFields(); + staticClass.run(); + } + } public static class EvaluateStaticClass @@ -414,6 +420,23 @@ public static class EvaluateStaticClass public static string StaticPropertyWithError => throw new Exception("not implemented"); } + public class EvaluateNonStaticClassWithStaticFields + { + public static int StaticField1 = 10; + public static string StaticProperty1 => "StaticProperty1"; + public static string StaticPropertyWithError => throw new Exception("not implemented"); + + private int HelperMethod() + { + return 5; + } + + public async void run() + { + var makeAwaitable = await Task.Run(() => HelperMethod()); + } + } + public class EvaluateLocalsWithElementAccessTests { public class TestEvaluate From 782a10748d1cc893e597faf3d71a1f0922c188f2 Mon Sep 17 00:00:00 2001 From: Ilona Tomkowicz Date: Mon, 8 Nov 2021 17:08:07 +0100 Subject: [PATCH 03/19] Added tests for class evaluation. --- .../debugger/DebuggerTestSuite/EvaluateOnCallFrameTests.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/mono/wasm/debugger/DebuggerTestSuite/EvaluateOnCallFrameTests.cs b/src/mono/wasm/debugger/DebuggerTestSuite/EvaluateOnCallFrameTests.cs index 4c0f24350e499b..bae52df2adeffd 100644 --- a/src/mono/wasm/debugger/DebuggerTestSuite/EvaluateOnCallFrameTests.cs +++ b/src/mono/wasm/debugger/DebuggerTestSuite/EvaluateOnCallFrameTests.cs @@ -692,6 +692,7 @@ public async Task EvaluateStaticClass() => await CheckInspectLocalsAtBreakpointS var frame = pause_location["callFrames"][0]; + await EvaluateOnCallFrame(id, "DebuggerTests.EvaluateStaticClass", expect_ok: true); await EvaluateOnCallFrameAndCheck(id, ("DebuggerTests.EvaluateStaticClass.StaticField1", TNumber(10))); await EvaluateOnCallFrameAndCheck(id, @@ -710,6 +711,7 @@ public async Task EvaluateStaticClassFromStaticMethod() => await CheckInspectLoc var frame = pause_location["callFrames"][0]; + await EvaluateOnCallFrame(id, "DebuggerTests.EvaluateStaticClass", expect_ok: true); await EvaluateOnCallFrameAndCheck(id, ("DebuggerTests.EvaluateStaticClass.StaticField1", TNumber(10))); await EvaluateOnCallFrameAndCheck(id, @@ -730,6 +732,7 @@ public async Task EvaluateStaticClassFromAsyncMethod(string type, string method, var frame = pause_location["callFrames"][0]; + await EvaluateOnCallFrame(id, "DebuggerTests.EvaluateStaticClass", expect_ok: true); await EvaluateOnCallFrameAndCheck(id, ("DebuggerTests.EvaluateStaticClass.StaticField1", TNumber(10))); await EvaluateOnCallFrameAndCheck(id, @@ -748,6 +751,7 @@ public async Task EvaluateNonStaticClassWithStaticFields() => await CheckInspect var frame = pause_location["callFrames"][0]; + await EvaluateOnCallFrame(id, "DebuggerTests.EvaluateNonStaticClassWithStaticFields", expect_ok: true); await EvaluateOnCallFrameAndCheck(id, ("DebuggerTests.EvaluateNonStaticClassWithStaticFields.StaticField1", TNumber(10))); await EvaluateOnCallFrameAndCheck(id, From 4119de3829ade4c8d9a296316b57ab07f4b8a3cc Mon Sep 17 00:00:00 2001 From: "DESKTOP-GEPIA6N\\Thays" Date: Mon, 8 Nov 2021 17:29:52 -0300 Subject: [PATCH 04/19] Fixing support to the current namespace and adding tests for it --- .../debugger/BrowserDebugProxy/DebugStore.cs | 16 ++++---- .../MemberReferenceResolver.cs | 37 +++---------------- .../EvaluateOnCallFrameTests.cs | 18 +++++++++ 3 files changed, 32 insertions(+), 39 deletions(-) diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/DebugStore.cs b/src/mono/wasm/debugger/BrowserDebugProxy/DebugStore.cs index 4174dedc5290b9..a90722814f824e 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/DebugStore.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/DebugStore.cs @@ -477,7 +477,7 @@ internal class TypeInfo private TypeDefinition type; private List methods; internal int Token { get; } - + internal string Namespace { get; } public TypeInfo(AssemblyInfo assembly, TypeDefinitionHandle typeHandle, TypeDefinition type) { this.assembly = assembly; @@ -486,21 +486,21 @@ public TypeInfo(AssemblyInfo assembly, TypeDefinitionHandle typeHandle, TypeDefi this.type = type; methods = new List(); Name = metadataReader.GetString(type.Name); - var namespaceName = ""; + Namespace = ""; if (type.IsNested) { var declaringType = metadataReader.GetTypeDefinition(type.GetDeclaringType()); Name = metadataReader.GetString(declaringType.Name) + "/" + Name; - namespaceName = metadataReader.GetString(declaringType.Namespace); + Namespace = metadataReader.GetString(declaringType.Namespace); } else { - namespaceName = metadataReader.GetString(type.Namespace); + Namespace = metadataReader.GetString(type.Namespace); } - - if (namespaceName.Length > 0) - namespaceName += "."; - FullName = namespaceName + Name; + if (Namespace.Length > 0) + FullName = Namespace + "." + Name; + else + FullName = Name; } public TypeInfo(AssemblyInfo assembly, string name) diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/MemberReferenceResolver.cs b/src/mono/wasm/debugger/BrowserDebugProxy/MemberReferenceResolver.cs index 488b6da3175c29..1046b97afeb81e 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/MemberReferenceResolver.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/MemberReferenceResolver.cs @@ -119,40 +119,15 @@ public async Task TryToRunOnLoadedClasses(string varName, CancellationT } } var store = await proxy.LoadStore(sessionId, token); - - // first - check the current assembly - var currentFrame = ctx.CallStack.FirstOrDefault(); - var currentAssembly = currentFrame.Method.Info.TypeInfo.assembly; - string namespaceName = currentAssembly.Name; - - // remove .dll from the end - if (namespaceName.Length > 4) - namespaceName = currentAssembly.Name.Remove(currentAssembly.Name.Length - 4); - - // look for classes in the current namespace - var matchingType = currentAssembly.TypesByName.Keys - .Where(k => k == string.Join(".", new string[] { namespaceName, classNameToFind })) - .Select(t => currentAssembly.GetTypeByName(t)) - .FirstOrDefault(); - - // if not found, look in all namespaces in the current assembly - if (matchingType == null) - { - matchingType = currentAssembly.TypesByName.Keys - .Where(k => k == classNameToFind) - .Select(t => currentAssembly.GetTypeByName(t)) - .FirstOrDefault(); - } - if (matchingType != null) - { - typeId = await sdbHelper.GetTypeIdFromToken(sessionId, currentAssembly.DebugId, matchingType.Token, token); - continue; - } - - // if not found in the current assembly, look in the other assemblies foreach (var asm in store.assemblies) { var type = asm.GetTypeByName(classNameToFind); + if (type == null) //search in the current namespace + { + var namespaceName = ctx.CallStack.FirstOrDefault().Method.Info.TypeInfo.Namespace; + var classNameToFindWithNamespace = namespaceName + "." + classNameToFind; + type = asm.GetTypeByName(classNameToFindWithNamespace); + } if (type != null) { typeId = await sdbHelper.GetTypeIdFromToken(sessionId, asm.DebugId, type.Token, token); diff --git a/src/mono/wasm/debugger/DebuggerTestSuite/EvaluateOnCallFrameTests.cs b/src/mono/wasm/debugger/DebuggerTestSuite/EvaluateOnCallFrameTests.cs index 4c0f24350e499b..b2b5618799f7f6 100644 --- a/src/mono/wasm/debugger/DebuggerTestSuite/EvaluateOnCallFrameTests.cs +++ b/src/mono/wasm/debugger/DebuggerTestSuite/EvaluateOnCallFrameTests.cs @@ -710,6 +710,12 @@ public async Task EvaluateStaticClassFromStaticMethod() => await CheckInspectLoc var frame = pause_location["callFrames"][0]; + await EvaluateOnCallFrameAndCheck(id, + ("EvaluateStaticClass.StaticField1", TNumber(10))); + await EvaluateOnCallFrameAndCheck(id, + ("EvaluateStaticClass.StaticProperty1", TString("StaticProperty1"))); + await EvaluateOnCallFrameAndCheck(id, + ("EvaluateStaticClass.StaticPropertyWithError", TString("System.Exception: not implemented"))); await EvaluateOnCallFrameAndCheck(id, ("DebuggerTests.EvaluateStaticClass.StaticField1", TNumber(10))); await EvaluateOnCallFrameAndCheck(id, @@ -730,6 +736,12 @@ public async Task EvaluateStaticClassFromAsyncMethod(string type, string method, var frame = pause_location["callFrames"][0]; + await EvaluateOnCallFrameAndCheck(id, + ("EvaluateStaticClass.StaticField1", TNumber(10))); + await EvaluateOnCallFrameAndCheck(id, + ("EvaluateStaticClass.StaticProperty1", TString("StaticProperty1"))); + await EvaluateOnCallFrameAndCheck(id, + ("EvaluateStaticClass.StaticPropertyWithError", TString("System.Exception: not implemented"))); await EvaluateOnCallFrameAndCheck(id, ("DebuggerTests.EvaluateStaticClass.StaticField1", TNumber(10))); await EvaluateOnCallFrameAndCheck(id, @@ -754,6 +766,12 @@ await EvaluateOnCallFrameAndCheck(id, ("DebuggerTests.EvaluateNonStaticClassWithStaticFields.StaticProperty1", TString("StaticProperty1"))); await EvaluateOnCallFrameAndCheck(id, ("DebuggerTests.EvaluateNonStaticClassWithStaticFields.StaticPropertyWithError", TString("System.Exception: not implemented"))); + await EvaluateOnCallFrameAndCheck(id, + ("EvaluateNonStaticClassWithStaticFields.StaticField1", TNumber(10))); + await EvaluateOnCallFrameAndCheck(id, + ("EvaluateNonStaticClassWithStaticFields.StaticProperty1", TString("StaticProperty1"))); + await EvaluateOnCallFrameAndCheck(id, + ("EvaluateNonStaticClassWithStaticFields.StaticPropertyWithError", TString("System.Exception: not implemented"))); }); [Fact] From ee19014c8aec41521c2e69769fd4fc271a4dae33 Mon Sep 17 00:00:00 2001 From: Ilona Tomkowicz Date: Tue, 9 Nov 2021 13:52:44 +0100 Subject: [PATCH 05/19] Assuing that we search within the current assembly first. Removed tests that fail in Consol App. --- .../MemberReferenceResolver.cs | 18 +++++++++++------- .../EvaluateOnCallFrameTests.cs | 11 +++++------ 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/MemberReferenceResolver.cs b/src/mono/wasm/debugger/BrowserDebugProxy/MemberReferenceResolver.cs index 1046b97afeb81e..6cd8184ffcdf49 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/MemberReferenceResolver.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/MemberReferenceResolver.cs @@ -119,15 +119,19 @@ public async Task TryToRunOnLoadedClasses(string varName, CancellationT } } var store = await proxy.LoadStore(sessionId, token); + var info = ctx.CallStack.FirstOrDefault().Method.Info; + var currentAssembly = info.Assembly; + var namespaceName = info.TypeInfo.Namespace; + var classNameToFindWithNamespace = namespaceName + "." + classNameToFind; + var type = currentAssembly.GetTypeByName(classNameToFindWithNamespace); + if (type != null) + { + typeId = await sdbHelper.GetTypeIdFromToken(sessionId, currentAssembly.DebugId, type.Token, token); + continue; + } foreach (var asm in store.assemblies) { - var type = asm.GetTypeByName(classNameToFind); - if (type == null) //search in the current namespace - { - var namespaceName = ctx.CallStack.FirstOrDefault().Method.Info.TypeInfo.Namespace; - var classNameToFindWithNamespace = namespaceName + "." + classNameToFind; - type = asm.GetTypeByName(classNameToFindWithNamespace); - } + type = asm.GetTypeByName(classNameToFind); if (type != null) { typeId = await sdbHelper.GetTypeIdFromToken(sessionId, asm.DebugId, type.Token, token); diff --git a/src/mono/wasm/debugger/DebuggerTestSuite/EvaluateOnCallFrameTests.cs b/src/mono/wasm/debugger/DebuggerTestSuite/EvaluateOnCallFrameTests.cs index e51acbc85426e9..b6cc12cf8343b5 100644 --- a/src/mono/wasm/debugger/DebuggerTestSuite/EvaluateOnCallFrameTests.cs +++ b/src/mono/wasm/debugger/DebuggerTestSuite/EvaluateOnCallFrameTests.cs @@ -692,7 +692,6 @@ public async Task EvaluateStaticClass() => await CheckInspectLocalsAtBreakpointS var frame = pause_location["callFrames"][0]; - await EvaluateOnCallFrame(id, "DebuggerTests.EvaluateStaticClass", expect_ok: true); await EvaluateOnCallFrameAndCheck(id, ("DebuggerTests.EvaluateStaticClass.StaticField1", TNumber(10))); await EvaluateOnCallFrameAndCheck(id, @@ -711,7 +710,6 @@ public async Task EvaluateStaticClassFromStaticMethod() => await CheckInspectLoc var frame = pause_location["callFrames"][0]; - await EvaluateOnCallFrame(id, "DebuggerTests.EvaluateStaticClass", expect_ok: true); await EvaluateOnCallFrameAndCheck(id, ("EvaluateStaticClass.StaticField1", TNumber(10))); await EvaluateOnCallFrameAndCheck(id, @@ -738,7 +736,6 @@ public async Task EvaluateStaticClassFromAsyncMethod(string type, string method, var frame = pause_location["callFrames"][0]; - await EvaluateOnCallFrame(id, "DebuggerTests.EvaluateStaticClass", expect_ok: true); await EvaluateOnCallFrameAndCheck(id, ("EvaluateStaticClass.StaticField1", TNumber(10))); await EvaluateOnCallFrameAndCheck(id, @@ -755,15 +752,17 @@ await EvaluateOnCallFrameAndCheck(id, [Fact] public async Task EvaluateNonStaticClassWithStaticFields() => await CheckInspectLocalsAtBreakpointSite( - "DebuggerTests.EvaluateMethodTestsClass/TestEvaluate", "run", 9, "run", - "window.setTimeout(function() { invoke_static_method ('[debugger-test] DebuggerTests.EvaluateMethodTestsClass:EvaluateMethods'); })", + "DebuggerTests.EvaluateMethodTestsClass", "EvaluateAsyncMethods", 3, "EvaluateAsyncMethods", + "window.setTimeout(function() { invoke_static_method ('[debugger-test] DebuggerTests.EvaluateMethodTestsClass:EvaluateAsyncMethods'); })", wait_for_event_fn: async (pause_location) => { var id = pause_location["callFrames"][0]["callFrameId"].Value(); var frame = pause_location["callFrames"][0]; - await EvaluateOnCallFrame(id, "DebuggerTests.EvaluateNonStaticClassWithStaticFields", expect_ok: true); + await EvaluateOnCallFrame(id, "staticClass", expect_ok: true); + await EvaluateOnCallFrameAndCheck(id, + ("staticClass", TObject("DebuggerTests.EvaluateNonStaticClassWithStaticFields", is_null: false))); await EvaluateOnCallFrameAndCheck(id, ("DebuggerTests.EvaluateNonStaticClassWithStaticFields.StaticField1", TNumber(10))); await EvaluateOnCallFrameAndCheck(id, From 89bdc490b858d0fda64e6278fd2159c45d381859 Mon Sep 17 00:00:00 2001 From: Ilona Tomkowicz Date: Tue, 9 Nov 2021 15:00:56 +0100 Subject: [PATCH 06/19] Remove a test-duplicate that was not testing static class or static fields. --- .../debugger/DebuggerTestSuite/EvaluateOnCallFrameTests.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/mono/wasm/debugger/DebuggerTestSuite/EvaluateOnCallFrameTests.cs b/src/mono/wasm/debugger/DebuggerTestSuite/EvaluateOnCallFrameTests.cs index b6cc12cf8343b5..9ca68ebfe0a459 100644 --- a/src/mono/wasm/debugger/DebuggerTestSuite/EvaluateOnCallFrameTests.cs +++ b/src/mono/wasm/debugger/DebuggerTestSuite/EvaluateOnCallFrameTests.cs @@ -760,9 +760,6 @@ public async Task EvaluateNonStaticClassWithStaticFields() => await CheckInspect var frame = pause_location["callFrames"][0]; - await EvaluateOnCallFrame(id, "staticClass", expect_ok: true); - await EvaluateOnCallFrameAndCheck(id, - ("staticClass", TObject("DebuggerTests.EvaluateNonStaticClassWithStaticFields", is_null: false))); await EvaluateOnCallFrameAndCheck(id, ("DebuggerTests.EvaluateNonStaticClassWithStaticFields.StaticField1", TNumber(10))); await EvaluateOnCallFrameAndCheck(id, From 5ce0f57bb5c548a3411071582095066e8b0cce07 Mon Sep 17 00:00:00 2001 From: Ilona Tomkowicz Date: Tue, 9 Nov 2021 15:06:41 +0100 Subject: [PATCH 07/19] Fixing indentation. --- .../debugger/DebuggerTestSuite/EvaluateOnCallFrameTests.cs | 4 ++-- .../debugger/tests/debugger-test/debugger-evaluate-test.cs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/mono/wasm/debugger/DebuggerTestSuite/EvaluateOnCallFrameTests.cs b/src/mono/wasm/debugger/DebuggerTestSuite/EvaluateOnCallFrameTests.cs index 9ca68ebfe0a459..4b92beab381ef5 100644 --- a/src/mono/wasm/debugger/DebuggerTestSuite/EvaluateOnCallFrameTests.cs +++ b/src/mono/wasm/debugger/DebuggerTestSuite/EvaluateOnCallFrameTests.cs @@ -791,8 +791,8 @@ public async Task EvaluateStaticClassInvalidField() => await CheckInspectLocalsA AssertEqual("Failed to resolve member access for DebuggerTests.InvalidEvaluateStaticClass.StaticProperty2", res.Error["result"]?["description"]?.Value(), "wrong error message"); }); - [Fact] - public async Task AsyncLocalsInContinueWithBlock() => await CheckInspectLocalsAtBreakpointSite( + [Fact] + public async Task AsyncLocalsInContinueWithBlock() => await CheckInspectLocalsAtBreakpointSite( "DebuggerTests.AsyncTests.ContinueWithTests", "ContinueWithStaticAsync", 4, "b__3_0", "window.setTimeout(function() { invoke_static_method('[debugger-test] DebuggerTests.AsyncTests.ContinueWithTests:RunAsync'); })", wait_for_event_fn: async (pause_location) => 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 0eb950705352bd..a065cc9b9a2ff8 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 @@ -424,7 +424,7 @@ public class EvaluateNonStaticClassWithStaticFields { public static int StaticField1 = 10; public static string StaticProperty1 => "StaticProperty1"; - public static string StaticPropertyWithError => throw new Exception("not implemented"); + public static string StaticPropertyWithError => throw new Exception("not implemented"); private int HelperMethod() { From 62d18b692a71307c0978867cc6d450b0ad9d0bc3 Mon Sep 17 00:00:00 2001 From: Ilona Tomkowicz Date: Tue, 9 Nov 2021 15:10:02 +0100 Subject: [PATCH 08/19] Refixing indentation. --- .../wasm/debugger/tests/debugger-test/debugger-evaluate-test.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 a065cc9b9a2ff8..c44e5b85688fcf 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 @@ -424,7 +424,7 @@ public class EvaluateNonStaticClassWithStaticFields { public static int StaticField1 = 10; public static string StaticProperty1 => "StaticProperty1"; - public static string StaticPropertyWithError => throw new Exception("not implemented"); + public static string StaticPropertyWithError => throw new Exception("not implemented"); private int HelperMethod() { From ce177fd44c33651f477d4e594edb17d97ee32f3b Mon Sep 17 00:00:00 2001 From: Ilona Tomkowicz Date: Tue, 9 Nov 2021 15:24:29 +0100 Subject: [PATCH 09/19] Refix indentations again. --- .../debugger/tests/debugger-test/debugger-evaluate-test.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) 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 c44e5b85688fcf..a00b1310604782 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 @@ -427,9 +427,9 @@ public class EvaluateNonStaticClassWithStaticFields public static string StaticPropertyWithError => throw new Exception("not implemented"); private int HelperMethod() - { - return 5; - } + { + return 5; + } public async void run() { From cb324022860c70e22e71f69422121fd3534594d3 Mon Sep 17 00:00:00 2001 From: Ilona Tomkowicz Date: Wed, 10 Nov 2021 14:33:21 +0100 Subject: [PATCH 10/19] Applied the advice about adding new blank lines. --- src/mono/wasm/debugger/BrowserDebugProxy/DebugStore.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/DebugStore.cs b/src/mono/wasm/debugger/BrowserDebugProxy/DebugStore.cs index a90722814f824e..6ca97d9c4785f6 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/DebugStore.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/DebugStore.cs @@ -332,6 +332,7 @@ internal class MethodInfo public int IsAsync { get; set; } public bool IsHiddenFromDebugger { get; } public TypeInfo TypeInfo { get; } + public MethodInfo(AssemblyInfo assembly, MethodDefinitionHandle methodDefHandle, int token, SourceFile source, TypeInfo type, MetadataReader asmMetadataReader, MetadataReader pdbMetadataReader) { this.IsAsync = -1; @@ -478,6 +479,7 @@ internal class TypeInfo private List methods; internal int Token { get; } internal string Namespace { get; } + public TypeInfo(AssemblyInfo assembly, TypeDefinitionHandle typeHandle, TypeDefinition type) { this.assembly = assembly; @@ -486,7 +488,6 @@ public TypeInfo(AssemblyInfo assembly, TypeDefinitionHandle typeHandle, TypeDefi this.type = type; methods = new List(); Name = metadataReader.GetString(type.Name); - Namespace = ""; if (type.IsNested) { var declaringType = metadataReader.GetTypeDefinition(type.GetDeclaringType()); From ed2577eab1da2c87a867bc52a260adf99b9903ad Mon Sep 17 00:00:00 2001 From: Ilona Tomkowicz Date: Wed, 10 Nov 2021 16:34:18 +0100 Subject: [PATCH 11/19] Changed the current assembly check. --- .../BrowserDebugProxy/MemberReferenceResolver.cs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/MemberReferenceResolver.cs b/src/mono/wasm/debugger/BrowserDebugProxy/MemberReferenceResolver.cs index 6cd8184ffcdf49..4d1a702546d582 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/MemberReferenceResolver.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/MemberReferenceResolver.cs @@ -120,21 +120,20 @@ public async Task TryToRunOnLoadedClasses(string varName, CancellationT } var store = await proxy.LoadStore(sessionId, token); var info = ctx.CallStack.FirstOrDefault().Method.Info; - var currentAssembly = info.Assembly; - var namespaceName = info.TypeInfo.Namespace; - var classNameToFindWithNamespace = namespaceName + "." + classNameToFind; - var type = currentAssembly.GetTypeByName(classNameToFindWithNamespace); + var namespaceName = string.IsNullOrEmpty(info.TypeInfo.Namespace) ? classNameToFind : info.TypeInfo.Namespace + "." + classNameToFind; + var type = info.Assembly.GetTypeByName(namespaceName); if (type != null) { - typeId = await sdbHelper.GetTypeIdFromToken(sessionId, currentAssembly.DebugId, type.Token, token); + typeId = await sdbHelper.GetTypeIdFromToken(sessionId, info.Assembly.DebugId, type.Token, token); continue; } + foreach (var asm in store.assemblies) { type = asm.GetTypeByName(classNameToFind); if (type != null) { - typeId = await sdbHelper.GetTypeIdFromToken(sessionId, asm.DebugId, type.Token, token); + typeId = await sdbHelper.GetTypeIdFromToken(sessionId, info.Assembly.DebugId, type.Token, token); break; } } From 01f46d5b7aa7b7b2e9dc721d26d0fd815ff5d110 Mon Sep 17 00:00:00 2001 From: Ilona Tomkowicz Date: Wed, 10 Nov 2021 17:02:54 +0100 Subject: [PATCH 12/19] Extracting the check from the loop. One time check is enough. --- .../BrowserDebugProxy/MemberReferenceResolver.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/MemberReferenceResolver.cs b/src/mono/wasm/debugger/BrowserDebugProxy/MemberReferenceResolver.cs index 4d1a702546d582..64a1bdf386fb3c 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/MemberReferenceResolver.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/MemberReferenceResolver.cs @@ -211,11 +211,11 @@ public async Task Resolve(string varName, CancellationToken token) } } } - else if (rootObject == null) - { - rootObject = await TryToRunOnLoadedClasses(varName, token); - return rootObject; - } + } + if (rootObject == null) + { + rootObject = await TryToRunOnLoadedClasses(varName, token); + return rootObject; } scopeCache.MemberReferences[varName] = rootObject; return rootObject; From d14367d206d6ea14ffa9ff5794bdd10836784358 Mon Sep 17 00:00:00 2001 From: Ilona Tomkowicz Date: Wed, 10 Nov 2021 17:03:28 +0100 Subject: [PATCH 13/19] Simplifying multiple test cases into one call. --- .../EvaluateOnCallFrameTests.cs | 44 ++++++------------- 1 file changed, 14 insertions(+), 30 deletions(-) diff --git a/src/mono/wasm/debugger/DebuggerTestSuite/EvaluateOnCallFrameTests.cs b/src/mono/wasm/debugger/DebuggerTestSuite/EvaluateOnCallFrameTests.cs index 4b92beab381ef5..fa2fa1c28b3f23 100644 --- a/src/mono/wasm/debugger/DebuggerTestSuite/EvaluateOnCallFrameTests.cs +++ b/src/mono/wasm/debugger/DebuggerTestSuite/EvaluateOnCallFrameTests.cs @@ -711,16 +711,10 @@ public async Task EvaluateStaticClassFromStaticMethod() => await CheckInspectLoc var frame = pause_location["callFrames"][0]; await EvaluateOnCallFrameAndCheck(id, - ("EvaluateStaticClass.StaticField1", TNumber(10))); - await EvaluateOnCallFrameAndCheck(id, - ("EvaluateStaticClass.StaticProperty1", TString("StaticProperty1"))); - await EvaluateOnCallFrameAndCheck(id, - ("EvaluateStaticClass.StaticPropertyWithError", TString("System.Exception: not implemented"))); - await EvaluateOnCallFrameAndCheck(id, - ("DebuggerTests.EvaluateStaticClass.StaticField1", TNumber(10))); - await EvaluateOnCallFrameAndCheck(id, - ("DebuggerTests.EvaluateStaticClass.StaticProperty1", TString("StaticProperty1"))); - await EvaluateOnCallFrameAndCheck(id, + ("EvaluateStaticClass.StaticProperty1", TString("StaticProperty1")), + ("EvaluateStaticClass.StaticPropertyWithError", TString("System.Exception: not implemented")), + ("DebuggerTests.EvaluateStaticClass.StaticField1", TNumber(10)), + ("DebuggerTests.EvaluateStaticClass.StaticProperty1", TString("StaticProperty1")), ("DebuggerTests.EvaluateStaticClass.StaticPropertyWithError", TString("System.Exception: not implemented"))); }); @@ -737,16 +731,11 @@ public async Task EvaluateStaticClassFromAsyncMethod(string type, string method, var frame = pause_location["callFrames"][0]; await EvaluateOnCallFrameAndCheck(id, - ("EvaluateStaticClass.StaticField1", TNumber(10))); - await EvaluateOnCallFrameAndCheck(id, - ("EvaluateStaticClass.StaticProperty1", TString("StaticProperty1"))); - await EvaluateOnCallFrameAndCheck(id, - ("EvaluateStaticClass.StaticPropertyWithError", TString("System.Exception: not implemented"))); - await EvaluateOnCallFrameAndCheck(id, - ("DebuggerTests.EvaluateStaticClass.StaticField1", TNumber(10))); - await EvaluateOnCallFrameAndCheck(id, - ("DebuggerTests.EvaluateStaticClass.StaticProperty1", TString("StaticProperty1"))); - await EvaluateOnCallFrameAndCheck(id, + ("EvaluateStaticClass.StaticField1", TNumber(10)), + ("EvaluateStaticClass.StaticProperty1", TString("StaticProperty1")), + ("EvaluateStaticClass.StaticPropertyWithError", TString("System.Exception: not implemented")), + ("DebuggerTests.EvaluateStaticClass.StaticField1", TNumber(10)), + ("DebuggerTests.EvaluateStaticClass.StaticProperty1", TString("StaticProperty1")), ("DebuggerTests.EvaluateStaticClass.StaticPropertyWithError", TString("System.Exception: not implemented"))); }); @@ -761,16 +750,11 @@ public async Task EvaluateNonStaticClassWithStaticFields() => await CheckInspect var frame = pause_location["callFrames"][0]; await EvaluateOnCallFrameAndCheck(id, - ("DebuggerTests.EvaluateNonStaticClassWithStaticFields.StaticField1", TNumber(10))); - await EvaluateOnCallFrameAndCheck(id, - ("DebuggerTests.EvaluateNonStaticClassWithStaticFields.StaticProperty1", TString("StaticProperty1"))); - await EvaluateOnCallFrameAndCheck(id, - ("DebuggerTests.EvaluateNonStaticClassWithStaticFields.StaticPropertyWithError", TString("System.Exception: not implemented"))); - await EvaluateOnCallFrameAndCheck(id, - ("EvaluateNonStaticClassWithStaticFields.StaticField1", TNumber(10))); - await EvaluateOnCallFrameAndCheck(id, - ("EvaluateNonStaticClassWithStaticFields.StaticProperty1", TString("StaticProperty1"))); - await EvaluateOnCallFrameAndCheck(id, + ("DebuggerTests.EvaluateNonStaticClassWithStaticFields.StaticField1", TNumber(10)), + ("DebuggerTests.EvaluateNonStaticClassWithStaticFields.StaticProperty1", TString("StaticProperty1")), + ("DebuggerTests.EvaluateNonStaticClassWithStaticFields.StaticPropertyWithError", TString("System.Exception: not implemented")), + ("EvaluateNonStaticClassWithStaticFields.StaticField1", TNumber(10)), + ("EvaluateNonStaticClassWithStaticFields.StaticProperty1", TString("StaticProperty1")), ("EvaluateNonStaticClassWithStaticFields.StaticPropertyWithError", TString("System.Exception: not implemented"))); }); From 8a823808b901a1d57038ef555f2d811d60b242ea Mon Sep 17 00:00:00 2001 From: Ilona Tomkowicz Date: Thu, 11 Nov 2021 10:05:30 +0100 Subject: [PATCH 14/19] Using local function as per review suggestion. --- .../MemberReferenceResolver.cs | 24 ++++++++++--------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/MemberReferenceResolver.cs b/src/mono/wasm/debugger/BrowserDebugProxy/MemberReferenceResolver.cs index 64a1bdf386fb3c..406a9246696b11 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/MemberReferenceResolver.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/MemberReferenceResolver.cs @@ -120,22 +120,24 @@ public async Task TryToRunOnLoadedClasses(string varName, CancellationT } var store = await proxy.LoadStore(sessionId, token); var info = ctx.CallStack.FirstOrDefault().Method.Info; - var namespaceName = string.IsNullOrEmpty(info.TypeInfo.Namespace) ? classNameToFind : info.TypeInfo.Namespace + "." + classNameToFind; - var type = info.Assembly.GetTypeByName(namespaceName); - if (type != null) - { - typeId = await sdbHelper.GetTypeIdFromToken(sessionId, info.Assembly.DebugId, type.Token, token); + var classNameToFindWithNamespace = string.IsNullOrEmpty(info.TypeInfo.Namespace) ? classNameToFind : info.TypeInfo.Namespace + "." + classNameToFind; + if (await TryGetTypeIdFromName(classNameToFindWithNamespace, info.Assembly)) continue; - } foreach (var asm in store.assemblies) { - type = asm.GetTypeByName(classNameToFind); - if (type != null) - { - typeId = await sdbHelper.GetTypeIdFromToken(sessionId, info.Assembly.DebugId, type.Token, token); + if (await TryGetTypeIdFromName(classNameToFind, asm)) break; - } + } + + async Task TryGetTypeIdFromName(string typeName, AssemblyInfo assembly) + { + var type = assembly.GetTypeByName(typeName); + if (type == null) + return false; + + typeId = await sdbHelper.GetTypeIdFromToken(sessionId, assembly.DebugId, type.Token, token); + return true; } } return null; From 7f24d478be8128e523b11fad642cb1458b3abc1c Mon Sep 17 00:00:00 2001 From: Ilona Tomkowicz Date: Thu, 11 Nov 2021 10:13:42 +0100 Subject: [PATCH 15/19] Added test that was skipped by mistake. --- .../wasm/debugger/DebuggerTestSuite/EvaluateOnCallFrameTests.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/mono/wasm/debugger/DebuggerTestSuite/EvaluateOnCallFrameTests.cs b/src/mono/wasm/debugger/DebuggerTestSuite/EvaluateOnCallFrameTests.cs index fa2fa1c28b3f23..d13cff819953c5 100644 --- a/src/mono/wasm/debugger/DebuggerTestSuite/EvaluateOnCallFrameTests.cs +++ b/src/mono/wasm/debugger/DebuggerTestSuite/EvaluateOnCallFrameTests.cs @@ -711,6 +711,7 @@ public async Task EvaluateStaticClassFromStaticMethod() => await CheckInspectLoc var frame = pause_location["callFrames"][0]; await EvaluateOnCallFrameAndCheck(id, + ("EvaluateStaticClass.StaticField1", TNumber(10)), ("EvaluateStaticClass.StaticProperty1", TString("StaticProperty1")), ("EvaluateStaticClass.StaticPropertyWithError", TString("System.Exception: not implemented")), ("DebuggerTests.EvaluateStaticClass.StaticField1", TNumber(10)), From 367c4312fb06b1c62d0fe02b09ed6d584e864f09 Mon Sep 17 00:00:00 2001 From: Ilona Tomkowicz Date: Thu, 11 Nov 2021 10:15:59 +0100 Subject: [PATCH 16/19] Added looking for the namespace in all assemblies because there is a chance it will be located out of the current assembly. --- .../debugger/BrowserDebugProxy/MemberReferenceResolver.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/MemberReferenceResolver.cs b/src/mono/wasm/debugger/BrowserDebugProxy/MemberReferenceResolver.cs index 406a9246696b11..df7520cfec2fdc 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/MemberReferenceResolver.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/MemberReferenceResolver.cs @@ -121,13 +121,13 @@ public async Task TryToRunOnLoadedClasses(string varName, CancellationT var store = await proxy.LoadStore(sessionId, token); var info = ctx.CallStack.FirstOrDefault().Method.Info; var classNameToFindWithNamespace = string.IsNullOrEmpty(info.TypeInfo.Namespace) ? classNameToFind : info.TypeInfo.Namespace + "." + classNameToFind; - if (await TryGetTypeIdFromName(classNameToFindWithNamespace, info.Assembly)) - continue; foreach (var asm in store.assemblies) { if (await TryGetTypeIdFromName(classNameToFind, asm)) break; + if (await TryGetTypeIdFromName(classNameToFindWithNamespace, asm)) + break; } async Task TryGetTypeIdFromName(string typeName, AssemblyInfo assembly) From 55479c8e3a8a3739baef104f99705b506b07de97 Mon Sep 17 00:00:00 2001 From: Ilona Tomkowicz Date: Thu, 11 Nov 2021 11:17:37 +0100 Subject: [PATCH 17/19] Extracting value based on the current frame, not the top of stack location. --- .../BrowserDebugProxy/MemberReferenceResolver.cs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/MemberReferenceResolver.cs b/src/mono/wasm/debugger/BrowserDebugProxy/MemberReferenceResolver.cs index df7520cfec2fdc..beb2903c360d8d 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/MemberReferenceResolver.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/MemberReferenceResolver.cs @@ -119,15 +119,18 @@ public async Task TryToRunOnLoadedClasses(string varName, CancellationT } } var store = await proxy.LoadStore(sessionId, token); - var info = ctx.CallStack.FirstOrDefault().Method.Info; - var classNameToFindWithNamespace = string.IsNullOrEmpty(info.TypeInfo.Namespace) ? classNameToFind : info.TypeInfo.Namespace + "." + classNameToFind; + var info = ctx.CallStack.FirstOrDefault(s => s.Id == scopeId).Method.Info; + var classNameToFindWithNamespace = + string.IsNullOrEmpty(info.TypeInfo.Namespace) ? + classNameToFind : + info.TypeInfo.Namespace + "." + classNameToFind; foreach (var asm in store.assemblies) { - if (await TryGetTypeIdFromName(classNameToFind, asm)) - break; if (await TryGetTypeIdFromName(classNameToFindWithNamespace, asm)) break; + if (await TryGetTypeIdFromName(classNameToFind, asm)) + break; } async Task TryGetTypeIdFromName(string typeName, AssemblyInfo assembly) From 5f5cdf627da6eeaa173a68541c402dec53049ff2 Mon Sep 17 00:00:00 2001 From: Ilona Tomkowicz Date: Thu, 11 Nov 2021 12:57:01 +0100 Subject: [PATCH 18/19] Test for classes evaluated from different frames. --- .../EvaluateOnCallFrameTests.cs | 24 ++++++++++++++++++- .../debugger-test/debugger-evaluate-test.cs | 17 +++++++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/src/mono/wasm/debugger/DebuggerTestSuite/EvaluateOnCallFrameTests.cs b/src/mono/wasm/debugger/DebuggerTestSuite/EvaluateOnCallFrameTests.cs index d13cff819953c5..e7da3d4bfa59c7 100644 --- a/src/mono/wasm/debugger/DebuggerTestSuite/EvaluateOnCallFrameTests.cs +++ b/src/mono/wasm/debugger/DebuggerTestSuite/EvaluateOnCallFrameTests.cs @@ -758,7 +758,29 @@ await EvaluateOnCallFrameAndCheck(id, ("EvaluateNonStaticClassWithStaticFields.StaticProperty1", TString("StaticProperty1")), ("EvaluateNonStaticClassWithStaticFields.StaticPropertyWithError", TString("System.Exception: not implemented"))); }); - + + [Fact] + public async Task EvaluateStaticClassesFromDifferentNamespaceInDifferentFrames() => await CheckInspectLocalsAtBreakpointSite( + "DebuggerTestsV2.EvaluateStaticClass", "Run", 1, "Run", + "window.setTimeout(function() { invoke_static_method ('[debugger-test] DebuggerTests.EvaluateMethodTestsClass:EvaluateMethods'); })", + wait_for_event_fn: async (pause_location) => + { + var id_top = pause_location["callFrames"][0]["callFrameId"].Value(); + var frame = pause_location["callFrames"][0]; + + await EvaluateOnCallFrameAndCheck(id_top, + ("EvaluateStaticClass.StaticField1", TNumber(20)), + ("EvaluateStaticClass.StaticProperty1", TString("StaticProperty2")), + ("EvaluateStaticClass.StaticPropertyWithError", TString("System.Exception: not implemented"))); + + var id_second = pause_location["callFrames"][1]["callFrameId"].Value(); + + await EvaluateOnCallFrameAndCheck(id_second, + ("EvaluateStaticClass.StaticField1", TNumber(10)), + ("EvaluateStaticClass.StaticProperty1", TString("StaticProperty1")), + ("EvaluateStaticClass.StaticPropertyWithError", TString("System.Exception: not implemented"))); + }); + [Fact] public async Task EvaluateStaticClassInvalidField() => await CheckInspectLocalsAtBreakpointSite( "DebuggerTests.EvaluateMethodTestsClass/TestEvaluate", "run", 9, "run", 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 a00b1310604782..0d8cd9ada90460 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 @@ -403,6 +403,8 @@ public static void EvaluateMethods() { TestEvaluate f = new TestEvaluate(); f.run(100, 200, "9000", "test", 45); + DebuggerTestsV2.EvaluateStaticClass.Run(); + var a = 0; } public static void EvaluateAsyncMethods() @@ -477,3 +479,18 @@ public static void EvaluateLocals() } } + +namespace DebuggerTestsV2 +{ + public static class EvaluateStaticClass + { + public static int StaticField1 = 20; + public static string StaticProperty1 => "StaticProperty2"; + public static string StaticPropertyWithError => throw new Exception("not implemented"); + + public static void Run() + { + var a = 0; + } + } +} \ No newline at end of file From d020d36f145d24245d1256036cc0926419dc8c11 Mon Sep 17 00:00:00 2001 From: Ankit Jain Date: Sat, 13 Nov 2021 04:47:12 -0500 Subject: [PATCH 19/19] [wasm] MemberReferenceResolver: rework a bit to fix some cases --- .../MemberReferenceResolver.cs | 220 +++++++++++------- .../EvaluateOnCallFrameTests.cs | 28 ++- .../debugger-test/debugger-evaluate-test.cs | 6 +- 3 files changed, 155 insertions(+), 99 deletions(-) diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/MemberReferenceResolver.cs b/src/mono/wasm/debugger/BrowserDebugProxy/MemberReferenceResolver.cs index beb2903c360d8d..47d0f2a627c630 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/MemberReferenceResolver.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/MemberReferenceResolver.cs @@ -6,7 +6,6 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Logging; -using Newtonsoft.Json; using Newtonsoft.Json.Linq; using System.IO; using Microsoft.CodeAnalysis.CSharp.Syntax; @@ -82,68 +81,86 @@ public async Task GetValueFromObject(JToken objRet, CancellationToken t return null; } - public async Task TryToRunOnLoadedClasses(string varName, CancellationToken token) + public async Task<(JObject containerObject, string remaining)> ResolveStaticMembersInStaticTypes(string varName, CancellationToken token) { string classNameToFind = ""; string[] parts = varName.Split("."); - var typeId = -1; - foreach (string part in parts) + var store = await proxy.LoadStore(sessionId, token); + var methodInfo = ctx.CallStack.FirstOrDefault(s => s.Id == scopeId).Method.Info; + + int typeId = -1; + for (int i = 0; i < parts.Length; i++) { + string part = parts[i].Trim(); + if (classNameToFind.Length > 0) classNameToFind += "."; - classNameToFind += part.Trim(); + classNameToFind += part; + if (typeId != -1) { - var fields = await sdbHelper.GetTypeFields(sessionId, typeId, token); - foreach (var field in fields) - { - if (field.Name == part.Trim()) - { - var isInitialized = await sdbHelper.TypeIsInitialized(sessionId, typeId, token); - if (isInitialized == 0) - { - isInitialized = await sdbHelper.TypeInitialize(sessionId, typeId, token); - } - var valueRet = await sdbHelper.GetFieldValue(sessionId, typeId, field.Id, token); - return await GetValueFromObject(valueRet, token); - } - } - var methodId = await sdbHelper.GetPropertyMethodIdByName(sessionId, typeId, part.Trim(), token); - if (methodId != -1) + string remaining = null; + JObject memberObject = await FindStaticMemberInType(part, typeId); + if (memberObject != null && i < parts.Length - 1) + remaining = string.Join('.', parts[(i+1)..]); + + return (memberObject, remaining); + } + + if (!string.IsNullOrEmpty(methodInfo.TypeInfo.Namespace)) + typeId = await FindStaticTypeId(methodInfo.TypeInfo.Namespace + "." + classNameToFind); + if (typeId == -1) + typeId = await FindStaticTypeId(classNameToFind); + } + + return (null, null); + + async Task FindStaticMemberInType(string name, int typeId) + { + var fields = await sdbHelper.GetTypeFields(sessionId, typeId, token); + foreach (var field in fields) + { + if (field.Name != name) + continue; + + var isInitialized = await sdbHelper.TypeIsInitialized(sessionId, typeId, token); + if (isInitialized == 0) { - var commandParamsObj = new MemoryStream(); - var commandParamsObjWriter = new MonoBinaryWriter(commandParamsObj); - commandParamsObjWriter.Write(0); //param count - var retMethod = await sdbHelper.InvokeMethod(sessionId, commandParamsObj.ToArray(), methodId, "methodRet", token); - return await GetValueFromObject(retMethod, token); + isInitialized = await sdbHelper.TypeInitialize(sessionId, typeId, token); } + var valueRet = await sdbHelper.GetFieldValue(sessionId, typeId, field.Id, token); + + return await GetValueFromObject(valueRet, token); } - var store = await proxy.LoadStore(sessionId, token); - var info = ctx.CallStack.FirstOrDefault(s => s.Id == scopeId).Method.Info; - var classNameToFindWithNamespace = - string.IsNullOrEmpty(info.TypeInfo.Namespace) ? - classNameToFind : - info.TypeInfo.Namespace + "." + classNameToFind; - foreach (var asm in store.assemblies) + var methodId = await sdbHelper.GetPropertyMethodIdByName(sessionId, typeId, name, token); + if (methodId != -1) { - if (await TryGetTypeIdFromName(classNameToFindWithNamespace, asm)) - break; - if (await TryGetTypeIdFromName(classNameToFind, asm)) - break; + var commandParamsObj = new MemoryStream(); + var commandParamsObjWriter = new MonoBinaryWriter(commandParamsObj); + commandParamsObjWriter.Write(0); //param count + var retMethod = await sdbHelper.InvokeMethod(sessionId, commandParamsObj.ToArray(), methodId, "methodRet", token); + return await GetValueFromObject(retMethod, token); } - async Task TryGetTypeIdFromName(string typeName, AssemblyInfo assembly) + return null; + } + + async Task FindStaticTypeId(string typeName) + { + foreach (var asm in store.assemblies) { - var type = assembly.GetTypeByName(typeName); + var type = asm.GetTypeByName(typeName); if (type == null) - return false; + continue; - typeId = await sdbHelper.GetTypeIdFromToken(sessionId, assembly.DebugId, type.Token, token); - return true; + int id = await sdbHelper.GetTypeIdFromToken(sessionId, asm.DebugId, type.Token, token); + if (id != -1) + return id; } + + return -1; } - return null; } // Checks Locals, followed by `this` @@ -153,9 +170,6 @@ public async Task Resolve(string varName, CancellationToken token) if (varName.Contains('(')) return null; - string[] parts = varName.Split("."); - JObject rootObject = null; - if (scopeCache.MemberReferences.TryGetValue(varName, out JObject ret)) { return ret; } @@ -164,26 +178,36 @@ public async Task Resolve(string varName, CancellationToken token) return await GetValueFromObject(valueRet, token); } - foreach (string part in parts) + string[] parts = varName.Split("."); + if (parts.Length == 0) + return null; + + JObject retObject = await ResolveAsLocalOrThisMember(parts[0]); + if (retObject != null && parts.Length > 1) + retObject = await ResolveAsInstanceMember(string.Join('.', parts[1..]), retObject); + + if (retObject == null) { - string partTrimmed = part.Trim(); - if (partTrimmed == "") - return null; - if (rootObject != null) + (retObject, string remaining) = await ResolveStaticMembersInStaticTypes(varName, token); + if (!string.IsNullOrEmpty(remaining)) { - if (rootObject?["subtype"]?.Value() == "null") - return null; - if (DotnetObjectId.TryParse(rootObject?["objectId"]?.Value(), out DotnetObjectId objectId)) + if (retObject?["subtype"]?.Value() == "null") { - var rootResObj = await proxy.RuntimeGetPropertiesInternal(sessionId, objectId, null, token); - var objRet = rootResObj.FirstOrDefault(objPropAttr => objPropAttr["name"].Value() == partTrimmed); - if (objRet == null) - return null; - - rootObject = await GetValueFromObject(objRet, token); + // NRE on null.$remaining + retObject = null; + } + else + { + retObject = await ResolveAsInstanceMember(remaining, retObject); } - continue; } + } + + scopeCache.MemberReferences[varName] = retObject; + return retObject; + + async Task ResolveAsLocalOrThisMember(string name) + { if (scopeCache.Locals.Count == 0 && !localsFetched) { Result scope_res = await proxy.GetScopeProperties(sessionId, scopeId, token); @@ -191,39 +215,61 @@ public async Task Resolve(string varName, CancellationToken token) throw new Exception($"BUG: Unable to get properties for scope: {scopeId}. {scope_res}"); localsFetched = true; } - if (scopeCache.Locals.TryGetValue(partTrimmed, out JObject obj)) - { - rootObject = obj["value"]?.Value(); - } - else if (scopeCache.Locals.TryGetValue("this", out JObject objThis)) + + if (scopeCache.Locals.TryGetValue(name, out JObject obj)) + return obj["value"]?.Value(); + + if (!scopeCache.Locals.TryGetValue("this", out JObject objThis)) + return null; + + if (!DotnetObjectId.TryParse(objThis?["value"]?["objectId"]?.Value(), out DotnetObjectId objectId)) + return null; + + var rootResObj = await proxy.RuntimeGetPropertiesInternal(sessionId, objectId, null, token); + var objRet = rootResObj.FirstOrDefault(objPropAttr => objPropAttr["name"].Value() == name); + if (objRet != null) + return await GetValueFromObject(objRet, token); + + return null; + } + + async Task ResolveAsInstanceMember(string expr, JObject baseObject) + { + JObject resolvedObject = baseObject; + string[] parts = expr.Split('.'); + for (int i = 0; i < parts.Length; i++) { - if (partTrimmed == "this") - { - rootObject = objThis?["value"].Value(); - } - else if (DotnetObjectId.TryParse(objThis?["value"]?["objectId"]?.Value(), out DotnetObjectId objectId)) + string partTrimmed = parts[i].Trim(); + if (partTrimmed.Length == 0) + return null; + + if (!DotnetObjectId.TryParse(resolvedObject?["objectId"]?.Value(), out DotnetObjectId objectId)) + return null; + + var resolvedResObj = await proxy.RuntimeGetPropertiesInternal(sessionId, objectId, null, token); + var objRet = resolvedResObj.FirstOrDefault(objPropAttr => objPropAttr["name"].Value() == partTrimmed); + if (objRet == null) + return null; + + resolvedObject = await GetValueFromObject(objRet, token); + if (resolvedObject == null) + return null; + + if (resolvedObject["subtype"]?.Value() == "null") { - var rootResObj = await proxy.RuntimeGetPropertiesInternal(sessionId, objectId, null, token); - var objRet = rootResObj.FirstOrDefault(objPropAttr => objPropAttr["name"].Value() == partTrimmed); - if (objRet != null) + if (i < parts.Length - 1) { - rootObject = await GetValueFromObject(objRet, token); - } - else - { - rootObject = await TryToRunOnLoadedClasses(varName, token); - return rootObject; + // there is some parts remaining, and can't + // do null.$remaining + return null; } + + return resolvedObject; } } + + return resolvedObject; } - if (rootObject == null) - { - rootObject = await TryToRunOnLoadedClasses(varName, token); - return rootObject; - } - scopeCache.MemberReferences[varName] = rootObject; - return rootObject; } public async Task Resolve(ElementAccessExpressionSyntax elementAccess, Dictionary memberAccessValues, JObject indexObject, CancellationToken token) diff --git a/src/mono/wasm/debugger/DebuggerTestSuite/EvaluateOnCallFrameTests.cs b/src/mono/wasm/debugger/DebuggerTestSuite/EvaluateOnCallFrameTests.cs index e7da3d4bfa59c7..5579e501127621 100644 --- a/src/mono/wasm/debugger/DebuggerTestSuite/EvaluateOnCallFrameTests.cs +++ b/src/mono/wasm/debugger/DebuggerTestSuite/EvaluateOnCallFrameTests.cs @@ -442,6 +442,10 @@ await EvaluateOnCallFrameFail(id, //BUG: TODO: //("a)", "CompilationError"), + ("this.c.e", "ReferenceError"), // this.. + ("this.e.a", "ReferenceError"), // this.. + ("this.dt.e", "ReferenceError"), // this.. + ("this.a.", "ReferenceError"), ("a.", "ReferenceError"), @@ -465,6 +469,9 @@ public async Task NegativeTestsInStaticMethod() => await CheckInspectLocalsAtBre var id = pause_location["callFrames"][0]["callFrameId"].Value(); await EvaluateOnCallFrameFail(id, + ("EvaluateStaticClass.f_s.c", "ReferenceError"), // .. + ("EvaluateStaticClass.NonExistant.f_s.c", "ReferenceError"), // ... + ("NonExistant.f_s.dateTime", "ReferenceError"), // .... ("me.foo", "ReferenceError"), ("this", "ReferenceError"), ("this.NullIfAIsNotZero.foo", "ReferenceError")); @@ -693,10 +700,11 @@ public async Task EvaluateStaticClass() => await CheckInspectLocalsAtBreakpointS var frame = pause_location["callFrames"][0]; await EvaluateOnCallFrameAndCheck(id, - ("DebuggerTests.EvaluateStaticClass.StaticField1", TNumber(10))); - await EvaluateOnCallFrameAndCheck(id, - ("DebuggerTests.EvaluateStaticClass.StaticProperty1", TString("StaticProperty1"))); - await EvaluateOnCallFrameAndCheck(id, + ("EvaluateStaticClass.StaticDTProperty1.Hour", TNumber(4)), // .. + ("EvaluateStaticClass.StaticDTField1.Hour", TNumber(3)), // .. + ("EvaluateStaticClass.StaticDTField1.Date.Year", TNumber(2000)), // ... + ("DebuggerTests.EvaluateStaticClass.StaticField1", TNumber(10)), + ("DebuggerTests.EvaluateStaticClass.StaticProperty1", TString("StaticProperty1")), ("DebuggerTests.EvaluateStaticClass.StaticPropertyWithError", TString("System.Exception: not implemented"))); }); @@ -769,16 +777,16 @@ public async Task EvaluateStaticClassesFromDifferentNamespaceInDifferentFrames() var frame = pause_location["callFrames"][0]; await EvaluateOnCallFrameAndCheck(id_top, - ("EvaluateStaticClass.StaticField1", TNumber(20)), - ("EvaluateStaticClass.StaticProperty1", TString("StaticProperty2")), - ("EvaluateStaticClass.StaticPropertyWithError", TString("System.Exception: not implemented"))); + ("EvaluateStaticClass.StaticField1", TNumber(20)), + ("EvaluateStaticClass.StaticProperty1", TString("StaticProperty2")), + ("EvaluateStaticClass.StaticPropertyWithError", TString("System.Exception: not implemented"))); var id_second = pause_location["callFrames"][1]["callFrameId"].Value(); await EvaluateOnCallFrameAndCheck(id_second, - ("EvaluateStaticClass.StaticField1", TNumber(10)), - ("EvaluateStaticClass.StaticProperty1", TString("StaticProperty1")), - ("EvaluateStaticClass.StaticPropertyWithError", TString("System.Exception: not implemented"))); + ("EvaluateStaticClass.StaticField1", TNumber(10)), + ("EvaluateStaticClass.StaticProperty1", TString("StaticProperty1")), + ("EvaluateStaticClass.StaticPropertyWithError", TString("System.Exception: not implemented"))); }); [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 0d8cd9ada90460..86c23a320edb24 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 @@ -418,7 +418,9 @@ public static void EvaluateAsyncMethods() public static class EvaluateStaticClass { public static int StaticField1 = 10; + public static DateTime StaticDTField1 = new DateTime(2000, 5, 4, 3, 2, 1); public static string StaticProperty1 => "StaticProperty1"; + public static DateTime StaticDTProperty1 => new DateTime(2000, 8, 1, 4, 7, 1); public static string StaticPropertyWithError => throw new Exception("not implemented"); } @@ -466,7 +468,7 @@ public void run() textListOfLists = new List> { textList, textList }; idx0 = 0; idx1 = 1; - } + } } public static void EvaluateLocals() @@ -493,4 +495,4 @@ public static void Run() var a = 0; } } -} \ No newline at end of file +}