From e150c69d03898237a2d1d251b93d958016d70a44 Mon Sep 17 00:00:00 2001 From: Ilona Tomkowicz Date: Tue, 13 Sep 2022 11:59:43 +0200 Subject: [PATCH 1/3] Support for simple mathematical expressions + tests. --- .../MemberReferenceResolver.cs | 13 +++++- .../EvaluateOnCallFrameTests.cs | 43 +++++++++++++++++++ 2 files changed, 55 insertions(+), 1 deletion(-) diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/MemberReferenceResolver.cs b/src/mono/wasm/debugger/BrowserDebugProxy/MemberReferenceResolver.cs index 097452892fceae..9a72099fd32df0 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/MemberReferenceResolver.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/MemberReferenceResolver.cs @@ -8,6 +8,8 @@ using Microsoft.Extensions.Logging; using Newtonsoft.Json.Linq; using System.IO; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using System.Collections.Generic; using System.Net.WebSockets; @@ -409,7 +411,16 @@ public async Task Resolve(ElementAccessExpressionSyntax elementAccess, } elementIdxStr += indexObject["value"].ToString(); } - // FixMe: indexing with expressions, e.g. x[a + 1] + // indexing with expressions, e.g. x[a + 1] + else + { + SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(arg + @";", cancellationToken: token); + indexObject = await ExpressionEvaluator.EvaluateSimpleExpression(this, syntaxTree.ToString(), arg.ToString(), variableDefinitions, logger, token); + string type = indexObject["type"].Value(); + if (type != "number") + throw new InvalidOperationException($"Cannot index with an object of type '{type}'"); + elementIdxStr += indexObject["value"].ToString(); + } } } } diff --git a/src/mono/wasm/debugger/DebuggerTestSuite/EvaluateOnCallFrameTests.cs b/src/mono/wasm/debugger/DebuggerTestSuite/EvaluateOnCallFrameTests.cs index 0613570a45dc77..873f4fdb1858d4 100644 --- a/src/mono/wasm/debugger/DebuggerTestSuite/EvaluateOnCallFrameTests.cs +++ b/src/mono/wasm/debugger/DebuggerTestSuite/EvaluateOnCallFrameTests.cs @@ -627,6 +627,49 @@ await EvaluateOnCallFrameAndCheck(id, }); + [Fact] + public async Task EvaluateIndexingByExpression() => await CheckInspectLocalsAtBreakpointSite( + "DebuggerTests.EvaluateLocalsWithIndexingTests", "EvaluateLocals", 5, "DebuggerTests.EvaluateLocalsWithIndexingTests.EvaluateLocals", + "window.setTimeout(function() { invoke_static_method ('[debugger-test] DebuggerTests.EvaluateLocalsWithIndexingTests:EvaluateLocals'); })", + wait_for_event_fn: async (pause_location) => + { + var id = pause_location["callFrames"][0]["callFrameId"].Value(); + + await EvaluateOnCallFrameAndCheck(id, + ("f.numList[i + 1]", TNumber(2)), + ("f.textList[j - 1]", TString("1")), + ("f.numArray[f.numList[j - 1]]", TNumber(2)) + ); + }); + + [Fact] + public async Task EvaluateIndexingByExpressionMultidimensional() => await CheckInspectLocalsAtBreakpointSite( + "DebuggerTests.EvaluateLocalsWithMultidimensionalIndexingTests", "EvaluateLocals", 5, "DebuggerTests.EvaluateLocalsWithMultidimensionalIndexingTests.EvaluateLocals", + "window.setTimeout(function() { invoke_static_method ('[debugger-test] DebuggerTests.EvaluateLocalsWithMultidimensionalIndexingTests:EvaluateLocals'); })", + wait_for_event_fn: async (pause_location) => + { + var id = pause_location["callFrames"][0]["callFrameId"].Value(); + + await EvaluateOnCallFrameAndCheck(id, + ("f.numArray2D[0, j - 1]", TNumber(1)), // 0, 0 + ("f.numArray2D[f.idx1, i + j]", TNumber(4)), // 1, 1 + ("f.numArray2D[f.idx1 - j, i + j]", TNumber(2)), // 0, 1 + ("f.numArray2D[i + j, f.idx1 - 1]", TNumber(3)) // 1, 0 + ); + }); + + [ConditionalFact(nameof(RunningOnChrome))] + public async Task EvaluateIndexingByExpressionNegative() => await CheckInspectLocalsAtBreakpointSite( + "DebuggerTests.EvaluateLocalsWithIndexingTests", "EvaluateLocals", 5, "DebuggerTests.EvaluateLocalsWithIndexingTests.EvaluateLocals", + $"window.setTimeout(function() {{ invoke_static_method ('[debugger-test] DebuggerTests.EvaluateLocalsWithIndexingTests:EvaluateLocals'); 1 }})", + wait_for_event_fn: async (pause_location) => + { + // indexing with expression of a wrong type + var id = pause_location["callFrames"][0]["callFrameId"].Value(); + var (_, res) = await EvaluateOnCallFrame(id, "f.numList[\"a\" + 1]", expect_ok: false ); + Assert.Equal("Unable to evaluate element access 'f.numList[\"a\" + 1]': Cannot index with an object of type 'string'", res.Error["message"]?.Value()); + }); + [Fact] public async Task EvaluateIndexingByMemberVariables() => await CheckInspectLocalsAtBreakpointSite( "DebuggerTests.EvaluateLocalsWithIndexingTests", "EvaluateLocals", 5, "DebuggerTests.EvaluateLocalsWithIndexingTests.EvaluateLocals", From 30342fb56dac9bd2abe5f5936b508444c859e3bb Mon Sep 17 00:00:00 2001 From: Ilona Tomkowicz Date: Tue, 13 Sep 2022 12:06:29 +0200 Subject: [PATCH 2/3] A bit more complex expressions. --- .../debugger/DebuggerTestSuite/EvaluateOnCallFrameTests.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/mono/wasm/debugger/DebuggerTestSuite/EvaluateOnCallFrameTests.cs b/src/mono/wasm/debugger/DebuggerTestSuite/EvaluateOnCallFrameTests.cs index 873f4fdb1858d4..1580ce3c043fc3 100644 --- a/src/mono/wasm/debugger/DebuggerTestSuite/EvaluateOnCallFrameTests.cs +++ b/src/mono/wasm/debugger/DebuggerTestSuite/EvaluateOnCallFrameTests.cs @@ -637,6 +637,7 @@ public async Task EvaluateIndexingByExpression() => await CheckInspectLocalsAtBr await EvaluateOnCallFrameAndCheck(id, ("f.numList[i + 1]", TNumber(2)), + ("f.textList[(2 * j) - 1]", TString("2")), ("f.textList[j - 1]", TString("1")), ("f.numArray[f.numList[j - 1]]", TNumber(2)) ); @@ -653,7 +654,7 @@ public async Task EvaluateIndexingByExpressionMultidimensional() => await CheckI await EvaluateOnCallFrameAndCheck(id, ("f.numArray2D[0, j - 1]", TNumber(1)), // 0, 0 ("f.numArray2D[f.idx1, i + j]", TNumber(4)), // 1, 1 - ("f.numArray2D[f.idx1 - j, i + j]", TNumber(2)), // 0, 1 + ("f.numArray2D[(f.idx1 - j) * 5, i + j]", TNumber(2)), // 0, 1 ("f.numArray2D[i + j, f.idx1 - 1]", TNumber(3)) // 1, 0 ); }); From d73905af65af2081f84ac9f9f3750ae479f86f44 Mon Sep 17 00:00:00 2001 From: Ilona Tomkowicz Date: Tue, 13 Sep 2022 21:19:55 +0200 Subject: [PATCH 3/3] Applied @radical's suggestions. --- .../MemberReferenceResolver.cs | 4 +-- .../EvaluateOnCallFrameTests.cs | 36 +++++++++---------- 2 files changed, 19 insertions(+), 21 deletions(-) diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/MemberReferenceResolver.cs b/src/mono/wasm/debugger/BrowserDebugProxy/MemberReferenceResolver.cs index 9a72099fd32df0..aca71e664673cf 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/MemberReferenceResolver.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/MemberReferenceResolver.cs @@ -414,8 +414,8 @@ public async Task Resolve(ElementAccessExpressionSyntax elementAccess, // indexing with expressions, e.g. x[a + 1] else { - SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(arg + @";", cancellationToken: token); - indexObject = await ExpressionEvaluator.EvaluateSimpleExpression(this, syntaxTree.ToString(), arg.ToString(), variableDefinitions, logger, token); + string expression = arg.ToString(); + indexObject = await ExpressionEvaluator.EvaluateSimpleExpression(this, expression, expression, variableDefinitions, logger, token); string type = indexObject["type"].Value(); if (type != "number") throw new InvalidOperationException($"Cannot index with an object of type '{type}'"); diff --git a/src/mono/wasm/debugger/DebuggerTestSuite/EvaluateOnCallFrameTests.cs b/src/mono/wasm/debugger/DebuggerTestSuite/EvaluateOnCallFrameTests.cs index 1580ce3c043fc3..2790e8f131ebae 100644 --- a/src/mono/wasm/debugger/DebuggerTestSuite/EvaluateOnCallFrameTests.cs +++ b/src/mono/wasm/debugger/DebuggerTestSuite/EvaluateOnCallFrameTests.cs @@ -632,32 +632,30 @@ public async Task EvaluateIndexingByExpression() => await CheckInspectLocalsAtBr "DebuggerTests.EvaluateLocalsWithIndexingTests", "EvaluateLocals", 5, "DebuggerTests.EvaluateLocalsWithIndexingTests.EvaluateLocals", "window.setTimeout(function() { invoke_static_method ('[debugger-test] DebuggerTests.EvaluateLocalsWithIndexingTests:EvaluateLocals'); })", wait_for_event_fn: async (pause_location) => - { - var id = pause_location["callFrames"][0]["callFrameId"].Value(); - - await EvaluateOnCallFrameAndCheck(id, - ("f.numList[i + 1]", TNumber(2)), - ("f.textList[(2 * j) - 1]", TString("2")), - ("f.textList[j - 1]", TString("1")), - ("f.numArray[f.numList[j - 1]]", TNumber(2)) + { + var id = pause_location["callFrames"][0]["callFrameId"].Value(); + await EvaluateOnCallFrameAndCheck(id, + ("f.numList[i + 1]", TNumber(2)), + ("f.textList[(2 * j) - 1]", TString("2")), + ("f.textList[j - 1]", TString("1")), + ("f.numArray[f.numList[j - 1]]", TNumber(2)) ); - }); + }); [Fact] public async Task EvaluateIndexingByExpressionMultidimensional() => await CheckInspectLocalsAtBreakpointSite( "DebuggerTests.EvaluateLocalsWithMultidimensionalIndexingTests", "EvaluateLocals", 5, "DebuggerTests.EvaluateLocalsWithMultidimensionalIndexingTests.EvaluateLocals", "window.setTimeout(function() { invoke_static_method ('[debugger-test] DebuggerTests.EvaluateLocalsWithMultidimensionalIndexingTests:EvaluateLocals'); })", wait_for_event_fn: async (pause_location) => - { - var id = pause_location["callFrames"][0]["callFrameId"].Value(); - - await EvaluateOnCallFrameAndCheck(id, - ("f.numArray2D[0, j - 1]", TNumber(1)), // 0, 0 - ("f.numArray2D[f.idx1, i + j]", TNumber(4)), // 1, 1 - ("f.numArray2D[(f.idx1 - j) * 5, i + j]", TNumber(2)), // 0, 1 - ("f.numArray2D[i + j, f.idx1 - 1]", TNumber(3)) // 1, 0 + { + var id = pause_location["callFrames"][0]["callFrameId"].Value(); + await EvaluateOnCallFrameAndCheck(id, + ("f.numArray2D[0, j - 1]", TNumber(1)), // 0, 0 + ("f.numArray2D[f.idx1, i + j]", TNumber(4)), // 1, 1 + ("f.numArray2D[(f.idx1 - j) * 5, i + j]", TNumber(2)), // 0, 1 + ("f.numArray2D[i + j, f.idx1 - 1]", TNumber(3)) // 1, 0 ); - }); + }); [ConditionalFact(nameof(RunningOnChrome))] public async Task EvaluateIndexingByExpressionNegative() => await CheckInspectLocalsAtBreakpointSite( @@ -669,7 +667,7 @@ public async Task EvaluateIndexingByExpressionNegative() => await CheckInspectLo var id = pause_location["callFrames"][0]["callFrameId"].Value(); var (_, res) = await EvaluateOnCallFrame(id, "f.numList[\"a\" + 1]", expect_ok: false ); Assert.Equal("Unable to evaluate element access 'f.numList[\"a\" + 1]': Cannot index with an object of type 'string'", res.Error["message"]?.Value()); - }); + }); [Fact] public async Task EvaluateIndexingByMemberVariables() => await CheckInspectLocalsAtBreakpointSite(