Skip to content

Commit

Permalink
[wasm][debugger] Indexing with expression (dotnet#75524)
Browse files Browse the repository at this point in the history
* Support for simple mathematical expressions + tests.

* A bit more complex expressions.

* Applied @radical's suggestions.

* [wasm][debugger] Add another test for EvaluateIndexingByExpressionContainingUnknownIdentifier

* [wasm][debugger] Add a broken case of indexing with string accessor

Co-authored-by: Ankit Jain <radical@gmail.com>
  • Loading branch information
ilonatommy and radical authored Sep 14, 2022
1 parent 7993e51 commit 5c6cb20
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -406,7 +408,16 @@ public async Task<JObject> Resolve(ElementAccessExpressionSyntax elementAccess,
indexObject ??= await Resolve(argParm.Identifier.Text, token);
elementIdxStr += indexObject["value"].ToString();
}
// FixMe: indexing with expressions, e.g. x[a + 1]
// indexing with expressions, e.g. x[a + 1]
else
{
string expression = arg.ToString();
indexObject = await ExpressionEvaluator.EvaluateSimpleExpression(this, expression, expression, variableDefinitions, logger, token);
string type = indexObject["type"].Value<string>();
if (type != "number")
throw new InvalidOperationException($"Cannot index with an object of type '{type}'");
elementIdxStr += indexObject["value"].ToString();
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -627,6 +627,61 @@ 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<string>();
await EvaluateOnCallFrameAndCheck(id,
("f.numList[i + 1]", TNumber(2)),
("f.textList[(2 * j) - 1]", TString("2")),
("f.textList[j - 1]", TString("1")),
//("f[\"longstring\"]", TBool(true)), FIXME: Broken case
("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<string>();
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(
"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<string>();
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<string>());
});

[ConditionalFact(nameof(RunningOnChrome))]
public async Task EvaluateIndexingByExpressionContainingUnknownIdentifier() => 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<string>();
var (_, res) = await EvaluateOnCallFrame(id, "f.numList[\"a\" + x]", expect_ok: false);
Assert.Equal("The name x does not exist in the current context", res.Error["result"]?["description"]?.Value<string>());
});

[Fact]
public async Task EvaluateIndexingByMemberVariables() => await CheckInspectLocalsAtBreakpointSite(
"DebuggerTests.EvaluateLocalsWithIndexingTests", "EvaluateLocals", 5, "DebuggerTests.EvaluateLocalsWithIndexingTests.EvaluateLocals",
Expand All @@ -642,7 +697,6 @@ await EvaluateOnCallFrameAndCheck(id,
("f.textList[f.idx1]", TString("2")),
("f.numArray[f.idx1]", TNumber(2)),
("f.textArray[f.idx0]", TString("1")));

});

[Fact]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -519,6 +519,8 @@ public class TestEvaluate
public int idx0;
public int idx1;

public bool this[string key] => key.Length > 3;

public void run()
{
numList = new List<int> { 1, 2 };
Expand Down

0 comments on commit 5c6cb20

Please sign in to comment.