Skip to content

Commit 10e107d

Browse files
ilonatommythaystg
andauthored
[wasm][debugger] Fix evaluation of a static class attribute; using current namespace for evaluation (#61252)
* Using current namespace as the default place to serach for the resolved class. * Add tests for static class, static fields and pausing in async method. * Added tests for class evaluation. * Fixing support to the current namespace and adding tests for it * Assuing that we search within the current assembly first. Removed tests that fail in Consol App. * Remove a test-duplicate that was not testing static class or static fields. * Fixing indentation. * Refixing indentation. * Refix indentations again. * Applied the advice about adding new blank lines. * Changed the current assembly check. * Extracting the check from the loop. One time check is enough. * Simplifying multiple test cases into one call. * Using local function as per review suggestion. * Added test that was skipped by mistake. * Added looking for the namespace in all assemblies because there is a chance it will be located out of the current assembly. * Extracting value based on the current frame, not the top of stack location. * Test for classes evaluated from different frames. * Fixing indentation and spaces. * Applied review comments for values evaluation. * Compressed two tests into one with MemberData. * Added test case of type without namespace (failing). * Addressed Ankit advices from the review. Co-authored-by: DESKTOP-GEPIA6N\Thays <[email protected]>
1 parent 0666ebc commit 10e107d

File tree

4 files changed

+148
-13
lines changed

4 files changed

+148
-13
lines changed

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

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,8 @@ internal class MethodInfo
331331
public bool IsStatic() => (methodDef.Attributes & MethodAttributes.Static) != 0;
332332
public int IsAsync { get; set; }
333333
public bool IsHiddenFromDebugger { get; }
334+
public TypeInfo TypeInfo { get; }
335+
334336
public MethodInfo(AssemblyInfo assembly, MethodDefinitionHandle methodDefHandle, int token, SourceFile source, TypeInfo type, MetadataReader asmMetadataReader, MetadataReader pdbMetadataReader)
335337
{
336338
this.IsAsync = -1;
@@ -343,6 +345,7 @@ public MethodInfo(AssemblyInfo assembly, MethodDefinitionHandle methodDefHandle,
343345
this.Name = asmMetadataReader.GetString(methodDef.Name);
344346
this.pdbMetadataReader = pdbMetadataReader;
345347
this.IsEnCMethod = false;
348+
this.TypeInfo = type;
346349
if (!DebugInformation.SequencePointsBlob.IsNil)
347350
{
348351
var sps = DebugInformation.GetSequencePoints();
@@ -475,6 +478,7 @@ internal class TypeInfo
475478
private TypeDefinition type;
476479
private List<MethodInfo> methods;
477480
internal int Token { get; }
481+
internal string Namespace { get; }
478482

479483
public TypeInfo(AssemblyInfo assembly, TypeDefinitionHandle typeHandle, TypeDefinition type)
480484
{
@@ -484,21 +488,20 @@ public TypeInfo(AssemblyInfo assembly, TypeDefinitionHandle typeHandle, TypeDefi
484488
this.type = type;
485489
methods = new List<MethodInfo>();
486490
Name = metadataReader.GetString(type.Name);
487-
var namespaceName = "";
488491
if (type.IsNested)
489492
{
490493
var declaringType = metadataReader.GetTypeDefinition(type.GetDeclaringType());
491494
Name = metadataReader.GetString(declaringType.Name) + "/" + Name;
492-
namespaceName = metadataReader.GetString(declaringType.Namespace);
495+
Namespace = metadataReader.GetString(declaringType.Namespace);
493496
}
494497
else
495498
{
496-
namespaceName = metadataReader.GetString(type.Namespace);
499+
Namespace = metadataReader.GetString(type.Namespace);
497500
}
498-
499-
if (namespaceName.Length > 0)
500-
namespaceName += ".";
501-
FullName = namespaceName + Name;
501+
if (Namespace.Length > 0)
502+
FullName = Namespace + "." + Name;
503+
else
504+
FullName = Name;
502505
}
503506

504507
public TypeInfo(AssemblyInfo assembly, string name)

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

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -118,13 +118,35 @@ public async Task<JObject> TryToRunOnLoadedClasses(string varName, CancellationT
118118
}
119119
}
120120
var store = await proxy.LoadStore(sessionId, token);
121-
foreach (var asm in store.assemblies)
121+
var methodInfo = ctx.CallStack.FirstOrDefault(s => s.Id == scopeId)?.Method?.Info;
122+
var classNameToFindWithNamespace =
123+
string.IsNullOrEmpty(methodInfo?.TypeInfo?.Namespace) ?
124+
classNameToFind :
125+
methodInfo.TypeInfo.Namespace + "." + classNameToFind;
126+
127+
var searchResult = await TryFindNameInAssembly(store.assemblies, classNameToFindWithNamespace);
128+
if (searchResult == null)
129+
searchResult = await TryFindNameInAssembly(store.assemblies, classNameToFind);
130+
if (searchResult != null)
131+
typeId = (int)searchResult;
132+
133+
async Task<int?> TryGetTypeIdFromName(string typeName, AssemblyInfo assembly)
122134
{
123-
var type = asm.GetTypeByName(classNameToFind);
124-
if (type != null)
135+
var type = assembly.GetTypeByName(typeName);
136+
if (type == null)
137+
return null;
138+
return await sdbHelper.GetTypeIdFromToken(sessionId, assembly.DebugId, type.Token, token);
139+
}
140+
141+
async Task<int?> TryFindNameInAssembly(List<AssemblyInfo> assemblies, string name)
142+
{
143+
foreach (var asm in assemblies)
125144
{
126-
typeId = await sdbHelper.GetTypeIdFromToken(sessionId, asm.DebugId, type.Token, token);
145+
var typeId = await TryGetTypeIdFromName(name, asm);
146+
if (typeId != null)
147+
return typeId;
127148
}
149+
return null;
128150
}
129151
}
130152
return null;
@@ -195,12 +217,13 @@ public async Task<JObject> Resolve(string varName, CancellationToken token)
195217
}
196218
else
197219
{
198-
rootObject = await TryToRunOnLoadedClasses(varName, token);
199-
return rootObject;
220+
break;
200221
}
201222
}
202223
}
203224
}
225+
if (rootObject == null)
226+
rootObject = await TryToRunOnLoadedClasses(varName, token);
204227
scopeCache.MemberReferences[varName] = rootObject;
205228
return rootObject;
206229
}

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

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,12 @@ public static IEnumerable<object[]> InstanceMethodForTypeMembersTestData(string
3636
}
3737
}
3838

39+
public static IEnumerable<object[]> EvaluateStaticClassFromStaticMethodTestData(string type_name)
40+
{
41+
yield return new object[] { type_name, "EvaluateAsyncMethods", "EvaluateAsyncMethods", true };
42+
yield return new object[] { type_name, "EvaluateMethods", "EvaluateMethods", false };
43+
}
44+
3945
[Theory]
4046
[MemberData(nameof(InstanceMethodForTypeMembersTestData), parameters: "DebuggerTests.EvaluateTestsStructWithProperties")]
4147
[MemberData(nameof(InstanceMethodForTypeMembersTestData), parameters: "DebuggerTests.EvaluateTestsClassWithProperties")]
@@ -700,6 +706,69 @@ await EvaluateOnCallFrameAndCheck(id,
700706
("DebuggerTests.EvaluateStaticClass.StaticPropertyWithError", TString("System.Exception: not implemented")));
701707
});
702708

709+
[Theory]
710+
[MemberData(nameof(EvaluateStaticClassFromStaticMethodTestData), parameters: "DebuggerTests.EvaluateMethodTestsClass")]
711+
[MemberData(nameof(EvaluateStaticClassFromStaticMethodTestData), parameters: "EvaluateMethodTestsClass")]
712+
public async Task EvaluateStaticClassFromStaticMethod(string type, string method, string bp_function_name, bool is_async)
713+
=> await CheckInspectLocalsAtBreakpointSite(
714+
type, method, 1, bp_function_name,
715+
$"window.setTimeout(function() {{ invoke_static_method ('[debugger-test] {type}:{method}'); }})",
716+
wait_for_event_fn: async (pause_location) =>
717+
{
718+
var id = pause_location["callFrames"][0]["callFrameId"].Value<string>();
719+
720+
var frame = pause_location["callFrames"][0];
721+
722+
await EvaluateOnCallFrameAndCheck(id,
723+
("EvaluateStaticClass.StaticField1", TNumber(10)),
724+
("EvaluateStaticClass.StaticProperty1", TString("StaticProperty1")),
725+
("EvaluateStaticClass.StaticPropertyWithError", TString("System.Exception: not implemented")),
726+
("DebuggerTests.EvaluateStaticClass.StaticField1", TNumber(10)),
727+
("DebuggerTests.EvaluateStaticClass.StaticProperty1", TString("StaticProperty1")),
728+
("DebuggerTests.EvaluateStaticClass.StaticPropertyWithError", TString("System.Exception: not implemented")));
729+
});
730+
731+
[Fact]
732+
public async Task EvaluateNonStaticClassWithStaticFields() => await CheckInspectLocalsAtBreakpointSite(
733+
"DebuggerTests.EvaluateMethodTestsClass", "EvaluateAsyncMethods", 3, "EvaluateAsyncMethods",
734+
"window.setTimeout(function() { invoke_static_method ('[debugger-test] DebuggerTests.EvaluateMethodTestsClass:EvaluateAsyncMethods'); })",
735+
wait_for_event_fn: async (pause_location) =>
736+
{
737+
var id = pause_location["callFrames"][0]["callFrameId"].Value<string>();
738+
739+
var frame = pause_location["callFrames"][0];
740+
741+
await EvaluateOnCallFrameAndCheck(id,
742+
("DebuggerTests.EvaluateNonStaticClassWithStaticFields.StaticField1", TNumber(10)),
743+
("DebuggerTests.EvaluateNonStaticClassWithStaticFields.StaticProperty1", TString("StaticProperty1")),
744+
("DebuggerTests.EvaluateNonStaticClassWithStaticFields.StaticPropertyWithError", TString("System.Exception: not implemented")),
745+
("EvaluateNonStaticClassWithStaticFields.StaticField1", TNumber(10)),
746+
("EvaluateNonStaticClassWithStaticFields.StaticProperty1", TString("StaticProperty1")),
747+
("EvaluateNonStaticClassWithStaticFields.StaticPropertyWithError", TString("System.Exception: not implemented")));
748+
});
749+
750+
[Fact]
751+
public async Task EvaluateStaticClassesFromDifferentNamespaceInDifferentFrames() => await CheckInspectLocalsAtBreakpointSite(
752+
"DebuggerTestsV2.EvaluateStaticClass", "Run", 1, "Run",
753+
"window.setTimeout(function() { invoke_static_method ('[debugger-test] DebuggerTests.EvaluateMethodTestsClass:EvaluateMethods'); })",
754+
wait_for_event_fn: async (pause_location) =>
755+
{
756+
var id_top = pause_location["callFrames"][0]["callFrameId"].Value<string>();
757+
var frame = pause_location["callFrames"][0];
758+
759+
await EvaluateOnCallFrameAndCheck(id_top,
760+
("EvaluateStaticClass.StaticField1", TNumber(20)),
761+
("EvaluateStaticClass.StaticProperty1", TString("StaticProperty2")),
762+
("EvaluateStaticClass.StaticPropertyWithError", TString("System.Exception: not implemented")));
763+
764+
var id_second = pause_location["callFrames"][1]["callFrameId"].Value<string>();
765+
766+
await EvaluateOnCallFrameAndCheck(id_second,
767+
("EvaluateStaticClass.StaticField1", TNumber(10)),
768+
("EvaluateStaticClass.StaticProperty1", TString("StaticProperty1")),
769+
("EvaluateStaticClass.StaticPropertyWithError", TString("System.Exception: not implemented")));
770+
});
771+
703772
[Fact]
704773
public async Task EvaluateStaticClassInvalidField() => await CheckInspectLocalsAtBreakpointSite(
705774
"DebuggerTests.EvaluateMethodTestsClass/TestEvaluate", "run", 9, "run",

src/mono/wasm/debugger/tests/debugger-test/debugger-evaluate-test.cs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -408,6 +408,14 @@ public static void EvaluateMethods()
408408
{
409409
TestEvaluate f = new TestEvaluate();
410410
f.run(100, 200, "9000", "test", 45);
411+
DebuggerTestsV2.EvaluateStaticClass.Run();
412+
var a = 0;
413+
}
414+
415+
public static void EvaluateAsyncMethods()
416+
{
417+
var staticClass = new EvaluateNonStaticClassWithStaticFields();
418+
staticClass.run();
411419
}
412420

413421
}
@@ -419,6 +427,23 @@ public static class EvaluateStaticClass
419427
public static string StaticPropertyWithError => throw new Exception("not implemented");
420428
}
421429

430+
public class EvaluateNonStaticClassWithStaticFields
431+
{
432+
public static int StaticField1 = 10;
433+
public static string StaticProperty1 => "StaticProperty1";
434+
public static string StaticPropertyWithError => throw new Exception("not implemented");
435+
436+
private int HelperMethod()
437+
{
438+
return 5;
439+
}
440+
441+
public async void run()
442+
{
443+
var makeAwaitable = await Task.Run(() => HelperMethod());
444+
}
445+
}
446+
422447
public class EvaluateLocalsWithElementAccessTests
423448
{
424449
public class TestEvaluate
@@ -459,3 +484,18 @@ public static void EvaluateLocals()
459484
}
460485

461486
}
487+
488+
namespace DebuggerTestsV2
489+
{
490+
public static class EvaluateStaticClass
491+
{
492+
public static int StaticField1 = 20;
493+
public static string StaticProperty1 => "StaticProperty2";
494+
public static string StaticPropertyWithError => throw new Exception("not implemented");
495+
496+
public static void Run()
497+
{
498+
var a = 0;
499+
}
500+
}
501+
}

0 commit comments

Comments
 (0)