Skip to content

Commit

Permalink
[wasm][debugger] Fix evaluation of a static class attribute; using cu…
Browse files Browse the repository at this point in the history
…rrent 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]>
  • Loading branch information
ilonatommy and thaystg committed Nov 17, 2021
1 parent 0666ebc commit 10e107d
Show file tree
Hide file tree
Showing 4 changed files with 148 additions and 13 deletions.
17 changes: 10 additions & 7 deletions src/mono/wasm/debugger/BrowserDebugProxy/DebugStore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,8 @@ 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;
Expand All @@ -343,6 +345,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();
Expand Down Expand Up @@ -475,6 +478,7 @@ internal class TypeInfo
private TypeDefinition type;
private List<MethodInfo> methods;
internal int Token { get; }
internal string Namespace { get; }

public TypeInfo(AssemblyInfo assembly, TypeDefinitionHandle typeHandle, TypeDefinition type)
{
Expand All @@ -484,21 +488,20 @@ public TypeInfo(AssemblyInfo assembly, TypeDefinitionHandle typeHandle, TypeDefi
this.type = type;
methods = new List<MethodInfo>();
Name = metadataReader.GetString(type.Name);
var namespaceName = "";
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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,13 +118,35 @@ public async Task<JObject> TryToRunOnLoadedClasses(string varName, CancellationT
}
}
var store = await proxy.LoadStore(sessionId, token);
foreach (var asm in store.assemblies)
var methodInfo = ctx.CallStack.FirstOrDefault(s => s.Id == scopeId)?.Method?.Info;
var classNameToFindWithNamespace =
string.IsNullOrEmpty(methodInfo?.TypeInfo?.Namespace) ?
classNameToFind :
methodInfo.TypeInfo.Namespace + "." + classNameToFind;

var searchResult = await TryFindNameInAssembly(store.assemblies, classNameToFindWithNamespace);
if (searchResult == null)
searchResult = await TryFindNameInAssembly(store.assemblies, classNameToFind);
if (searchResult != null)
typeId = (int)searchResult;

async Task<int?> TryGetTypeIdFromName(string typeName, AssemblyInfo assembly)
{
var type = asm.GetTypeByName(classNameToFind);
if (type != null)
var type = assembly.GetTypeByName(typeName);
if (type == null)
return null;
return await sdbHelper.GetTypeIdFromToken(sessionId, assembly.DebugId, type.Token, token);
}

async Task<int?> TryFindNameInAssembly(List<AssemblyInfo> assemblies, string name)
{
foreach (var asm in assemblies)
{
typeId = await sdbHelper.GetTypeIdFromToken(sessionId, asm.DebugId, type.Token, token);
var typeId = await TryGetTypeIdFromName(name, asm);
if (typeId != null)
return typeId;
}
return null;
}
}
return null;
Expand Down Expand Up @@ -195,12 +217,13 @@ public async Task<JObject> Resolve(string varName, CancellationToken token)
}
else
{
rootObject = await TryToRunOnLoadedClasses(varName, token);
return rootObject;
break;
}
}
}
}
if (rootObject == null)
rootObject = await TryToRunOnLoadedClasses(varName, token);
scopeCache.MemberReferences[varName] = rootObject;
return rootObject;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,12 @@ public static IEnumerable<object[]> InstanceMethodForTypeMembersTestData(string
}
}

public static IEnumerable<object[]> EvaluateStaticClassFromStaticMethodTestData(string type_name)
{
yield return new object[] { type_name, "EvaluateAsyncMethods", "EvaluateAsyncMethods", true };
yield return new object[] { type_name, "EvaluateMethods", "EvaluateMethods", false };
}

[Theory]
[MemberData(nameof(InstanceMethodForTypeMembersTestData), parameters: "DebuggerTests.EvaluateTestsStructWithProperties")]
[MemberData(nameof(InstanceMethodForTypeMembersTestData), parameters: "DebuggerTests.EvaluateTestsClassWithProperties")]
Expand Down Expand Up @@ -700,6 +706,69 @@ await EvaluateOnCallFrameAndCheck(id,
("DebuggerTests.EvaluateStaticClass.StaticPropertyWithError", TString("System.Exception: not implemented")));
});

[Theory]
[MemberData(nameof(EvaluateStaticClassFromStaticMethodTestData), parameters: "DebuggerTests.EvaluateMethodTestsClass")]
[MemberData(nameof(EvaluateStaticClassFromStaticMethodTestData), parameters: "EvaluateMethodTestsClass")]
public async Task EvaluateStaticClassFromStaticMethod(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] {type}:{method}'); }})",
wait_for_event_fn: async (pause_location) =>
{
var id = pause_location["callFrames"][0]["callFrameId"].Value<string>();
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)),
("DebuggerTests.EvaluateStaticClass.StaticProperty1", TString("StaticProperty1")),
("DebuggerTests.EvaluateStaticClass.StaticPropertyWithError", TString("System.Exception: not implemented")));
});

[Fact]
public async Task EvaluateNonStaticClassWithStaticFields() => await CheckInspectLocalsAtBreakpointSite(
"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<string>();
var frame = pause_location["callFrames"][0];
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")));
});

[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<string>();
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<string>();
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",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -408,6 +408,14 @@ 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()
{
var staticClass = new EvaluateNonStaticClassWithStaticFields();
staticClass.run();
}

}
Expand All @@ -419,6 +427,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
Expand Down Expand Up @@ -459,3 +484,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;
}
}
}

0 comments on commit 10e107d

Please sign in to comment.