internal async Task <JToken> TryGetVariableValue(MessageId msg_id, int scope_id, string expression, bool only_search_on_this, CancellationToken token) { JToken thisValue = null; var context = GetContext(msg_id); if (context.CallStack == null) { return(null); } if (TryFindVariableValueInCache(context, expression, only_search_on_this, out JToken obj)) { return(obj); } var scope = context.CallStack.FirstOrDefault(s => s.Id == scope_id); var live_vars = scope.Method.GetLiveVarsAt(scope.Location.CliLocation.Offset); //get_this var res = await SendMonoCommand(msg_id, MonoCommands.GetScopeVariables(scope.Id, live_vars.Select(lv => lv.Index).ToArray()), token); var scope_values = res.Value? ["result"]? ["value"]?.Values <JObject> ()?.ToArray(); thisValue = scope_values?.FirstOrDefault(v => v ["name"]?.Value <string> () == "this"); if (!only_search_on_this) { if (thisValue != null && expression == "this") { return(thisValue); } var value = scope_values.SingleOrDefault(sv => sv ["name"]?.Value <string> () == expression); if (value != null) { return(value); } } //search in scope if (thisValue != null) { if (!DotnetObjectId.TryParse(thisValue ["value"] ["objectId"], out var objectId)) { return(null); } res = await SendMonoCommand(msg_id, MonoCommands.GetDetails(objectId), token); scope_values = res.Value? ["result"]? ["value"]?.Values <JObject> ().ToArray(); var foundValue = scope_values.FirstOrDefault(v => v ["name"].Value <string> () == expression); if (foundValue != null) { foundValue["fromThis"] = true; context.LocalsCache[foundValue ["name"].Value <string> ()] = foundValue; return(foundValue); } } return(null); }
async Task <Result> GetScopeProperties(MessageId msg_id, int scope_id, CancellationToken token) { try { var ctx = GetContext(msg_id); var scope = ctx.CallStack.FirstOrDefault(s => s.Id == scope_id); if (scope == null) { return(Result.Err(JObject.FromObject(new { message = $"Could not find scope with id #{scope_id}" }))); } var vars = scope.Method.GetLiveVarsAt(scope.Location.CliLocation.Offset); var var_ids = vars.Select(v => v.Index).ToArray(); var res = await SendMonoCommand(msg_id, MonoCommands.GetScopeVariables(scope.Id, var_ids), token); //if we fail we just buble that to the IDE (and let it panic over it) if (res.IsErr) { return(res); } var values = res.Value? ["result"]? ["value"]?.Values <JObject> ().ToArray(); if (values == null) { return(Result.OkFromObject(new { result = Array.Empty <object> () })); } var var_list = new List <object> (); int i = 0; for (; i < vars.Length && i < values.Length; i++) { // For async methods, we get locals with names, unlike non-async methods // and the order may not match the var_ids, so, use the names that they // come with if (values [i]["name"] != null) { continue; } ctx.LocalsCache[vars [i].Name] = values [i]; var_list.Add(new { name = vars [i].Name, value = values [i]["value"] }); } for (; i < values.Length; i++) { ctx.LocalsCache[values [i]["name"].ToString()] = values [i]; var_list.Add(values [i]); } return(Result.OkFromObject(new { result = var_list })); } catch (Exception exception) { Log("verbose", $"Error resolving scope properties {exception.Message}"); return(Result.Exception(exception)); } }
async Task <Result> GetScopeProperties(MessageId msg_id, int scope_id, CancellationToken token) { try { var ctx = GetContext(msg_id); var scope = ctx.CallStack.FirstOrDefault(s => s.Id == scope_id); if (scope == null) { return(Result.Err(JObject.FromObject(new { message = $"Could not find scope with id #{scope_id}" }))); } var var_ids = scope.Method.GetLiveVarsAt(scope.Location.CliLocation.Offset); var res = await SendMonoCommand(msg_id, MonoCommands.GetScopeVariables(scope.Id, var_ids), token); //if we fail we just buble that to the IDE (and let it panic over it) if (res.IsErr) { return(res); } var values = res.Value? ["result"]? ["value"]?.Values <JObject> ().ToArray(); if (values == null || values.Length == 0) { return(Result.OkFromObject(new { result = Array.Empty <object> () })); } foreach (var value in values) { ctx.LocalsCache [value ["name"]?.Value <string> ()] = value; } return(Result.OkFromObject(new { result = values })); } catch (Exception exception) { Log("verbose", $"Error resolving scope properties {exception.Message}"); return(Result.Exception(exception)); } }
internal async Task <JToken> TryGetVariableValue(MessageId msg_id, int scope_id, string expression, bool only_search_on_this, CancellationToken token) { JToken thisValue = null; var context = GetContext(msg_id); if (context.CallStack == null) { return(null); } if (TryFindVariableValueInCache(context, expression, only_search_on_this, out JToken obj)) { return(obj); } var scope = context.CallStack.FirstOrDefault(s => s.Id == scope_id); var vars = scope.Method.GetLiveVarsAt(scope.Location.CliLocation.Offset); //get_this int [] var_ids = { }; var res = await SendMonoCommand(msg_id, MonoCommands.GetScopeVariables(scope.Id, var_ids), token); var values = res.Value? ["result"]? ["value"]?.Values <JObject> ().ToArray(); thisValue = values.FirstOrDefault(v => v ["name"].Value <string> () == "this"); if (!only_search_on_this) { if (thisValue != null && expression == "this") { return(thisValue); } //search in locals var var_id = vars.SingleOrDefault(v => v.Name == expression); if (var_id != null) { res = await SendMonoCommand(msg_id, MonoCommands.GetScopeVariables(scope.Id, new int [] { var_id.Index }), token); values = res.Value? ["result"]? ["value"]?.Values <JObject> ().ToArray(); return(values [0]); } } //search in scope if (thisValue != null) { var objectId = thisValue ["value"] ["objectId"].Value <string> (); var parts = objectId.Split(new char [] { ':' }); res = await SendMonoCommand(msg_id, MonoCommands.GetObjectProperties(int.Parse(parts [2]), expandValueTypes: false), token); values = res.Value? ["result"]? ["value"]?.Values <JObject> ().ToArray(); var foundValue = values.FirstOrDefault(v => v ["name"].Value <string> () == expression); if (foundValue != null) { foundValue["fromThis"] = true; context.LocalsCache[foundValue ["name"].Value <string> ()] = foundValue; return(foundValue); } } return(null); }
async Task GetScopeProperties(MessageId msg_id, int scope_id, CancellationToken token) { try { var scope = GetContext(msg_id).CallStack.FirstOrDefault(s => s.Id == scope_id); var vars = scope.Method.GetLiveVarsAt(scope.Location.CliLocation.Offset); var var_ids = vars.Select(v => v.Index).ToArray(); var res = await SendMonoCommand(msg_id, MonoCommands.GetScopeVariables(scope.Id, var_ids), token); //if we fail we just buble that to the IDE (and let it panic over it) if (res.IsErr) { SendResponse(msg_id, res, token); return; } var values = res.Value? ["result"]? ["value"]?.Values <JObject> ().ToArray(); if (values == null) { SendResponse(msg_id, Result.OkFromObject(new { result = Array.Empty <object> () }), token); return; } var var_list = new List <object> (); int i = 0; // Trying to inspect the stack frame for DotNetDispatcher::InvokeSynchronously // results in a "Memory access out of bounds", causing 'values' to be null, // so skip returning variable values in that case. while (i < vars.Length && i < values.Length) { var value = values [i] ["value"]; if (((string)value ["description"]) == null) { value ["description"] = value ["value"]?.ToString(); } var_list.Add(new { name = vars [i].Name, value }); i++; } //Async methods are special in the way that local variables can be lifted to generated class fields //value of "this" comes here either while (i < values.Length) { String name = values [i] ["name"].ToString(); if (name.IndexOf(">", StringComparison.Ordinal) > 0) { name = name.Substring(1, name.IndexOf(">", StringComparison.Ordinal) - 1); } var value = values [i + 1] ["value"]; if (((string)value ["description"]) == null) { value ["description"] = value ["value"]?.ToString(); } var_list.Add(new { name, value }); i = i + 2; } SendResponse(msg_id, Result.OkFromObject(new { result = var_list }), token); } catch (Exception exception) { Log("verbose", $"Error resolving scope properties {exception.Message}"); SendResponse(msg_id, Result.Exception(exception), token); } }