Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[wasm][debugger] Fix evaluation of a static class attribute; using current namespace for evaluation #61252

Merged
merged 24 commits into from
Nov 17, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
fab24e5
Using current namespace as the default place to serach for the resolv…
ilonatommy Nov 5, 2021
66b56a7
Add tests for static class, static fields and pausing in async method.
ilonatommy Nov 5, 2021
782a107
Added tests for class evaluation.
ilonatommy Nov 8, 2021
4119de3
Fixing support to the current namespace and adding tests for it
thaystg Nov 8, 2021
e275144
Merge branch 'add-static-attribute-support' of https://github.com/ilo…
ilonatommy Nov 9, 2021
ee19014
Assuing that we search within the current assembly first. Removed tes…
ilonatommy Nov 9, 2021
89bdc49
Remove a test-duplicate that was not testing static class or static f…
ilonatommy Nov 9, 2021
5ce0f57
Fixing indentation.
ilonatommy Nov 9, 2021
62d18b6
Refixing indentation.
ilonatommy Nov 9, 2021
ce177fd
Refix indentations again.
ilonatommy Nov 9, 2021
cb32402
Applied the advice about adding new blank lines.
ilonatommy Nov 10, 2021
ed2577e
Changed the current assembly check.
ilonatommy Nov 10, 2021
01f46d5
Extracting the check from the loop. One time check is enough.
ilonatommy Nov 10, 2021
d14367d
Simplifying multiple test cases into one call.
ilonatommy Nov 10, 2021
8a82380
Using local function as per review suggestion.
ilonatommy Nov 11, 2021
7f24d47
Added test that was skipped by mistake.
ilonatommy Nov 11, 2021
367c431
Added looking for the namespace in all assemblies because there is a …
ilonatommy Nov 11, 2021
55479c8
Extracting value based on the current frame, not the top of stack loc…
ilonatommy Nov 11, 2021
5f5cdf6
Test for classes evaluated from different frames.
ilonatommy Nov 11, 2021
7151177
Fixing indentation and spaces.
ilonatommy Nov 15, 2021
5fc759e
Applied review comments for values evaluation.
ilonatommy Nov 15, 2021
3661c0e
Compressed two tests into one with MemberData.
ilonatommy Nov 15, 2021
66ed5c2
Added test case of type without namespace (failing).
ilonatommy Nov 15, 2021
136f69a
Addressed Ankit advices from the review.
ilonatommy Nov 16, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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)
ilonatommy marked this conversation as resolved.
Show resolved Hide resolved
{
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)
ilonatommy marked this conversation as resolved.
Show resolved Hide resolved
{
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);
ilonatommy marked this conversation as resolved.
Show resolved Hide resolved
}
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 @@ -119,13 +119,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;
ilonatommy marked this conversation as resolved.
Show resolved Hide resolved
}
}
return null;
Expand Down Expand Up @@ -196,12 +218,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 @@ -695,6 +701,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")));
});
ilonatommy marked this conversation as resolved.
Show resolved Hide resolved

[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 @@ -403,6 +403,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 @@ -414,6 +422,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 @@ -454,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;
}
}
}