Adjusting `VariableReferenceStorage` to only need to track permanent vs temporary storage by making `VariableStore` the common base class. Moved the subclasses of `VariableStore` into the Variables.cpp file, since they're no long referenced externally. Expanding on the tests by adding an updated core dump with variables in the argument scope we can use to validate variable storage.
97 lines
3.4 KiB
C++
97 lines
3.4 KiB
C++
//===-- SetVariableRequestHandler.cpp -------------------------------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "DAP.h"
|
|
#include "EventHelper.h"
|
|
#include "JSONUtils.h"
|
|
#include "Protocol/DAPTypes.h"
|
|
#include "Protocol/ProtocolEvents.h"
|
|
#include "Protocol/ProtocolTypes.h"
|
|
#include "RequestHandler.h"
|
|
|
|
using namespace lldb_dap::protocol;
|
|
|
|
namespace lldb_dap {
|
|
|
|
/// Set the variable with the given name in the variable container to a new
|
|
/// value. Clients should only call this request if the corresponding capability
|
|
/// `supportsSetVariable` is true.
|
|
///
|
|
/// If a debug adapter implements both `setVariable` and `setExpression`,
|
|
/// a client will only use `setExpression` if the variable has an evaluateName
|
|
/// property.
|
|
llvm::Expected<SetVariableResponseBody>
|
|
SetVariableRequestHandler::Run(const SetVariableArguments &args) const {
|
|
const auto args_name = llvm::StringRef(args.name);
|
|
|
|
if (args.variablesReference.Kind() == eReferenceKindInvalid) {
|
|
return llvm::make_error<DAPError>(
|
|
llvm::formatv("invalid reference {}",
|
|
args.variablesReference.AsUInt32())
|
|
.str(),
|
|
llvm::inconvertibleErrorCode(),
|
|
/*show_user=*/false);
|
|
}
|
|
|
|
constexpr llvm::StringRef return_value_name = "(Return Value)";
|
|
if (args_name == return_value_name)
|
|
return llvm::make_error<DAPError>(
|
|
"cannot change the value of the return value");
|
|
|
|
lldb::SBValue variable =
|
|
dap.reference_storage.FindVariable(args.variablesReference, args_name);
|
|
|
|
if (!variable.IsValid())
|
|
return llvm::make_error<DAPError>("could not find variable in scope");
|
|
|
|
lldb::SBError error;
|
|
const bool success = variable.SetValueFromCString(args.value.c_str(), error);
|
|
if (!success)
|
|
return llvm::make_error<DAPError>(error.GetCString());
|
|
|
|
const bool hex = args.format ? args.format->hex : false;
|
|
VariableDescription desc(variable,
|
|
dap.configuration.enableAutoVariableSummaries, hex);
|
|
|
|
SetVariableResponseBody body;
|
|
body.value = desc.display_value;
|
|
body.type = desc.display_type_name;
|
|
|
|
// We don't know the index of the variable in our dap.variables
|
|
// so always insert a new one to get its variablesReference.
|
|
// is_permanent is false because debug console does not support
|
|
// setVariable request.
|
|
const var_ref_t new_var_ref =
|
|
dap.reference_storage.Insert(variable, /*is_permanent=*/false);
|
|
if (variable.MightHaveChildren()) {
|
|
body.variablesReference = new_var_ref;
|
|
if (desc.type_obj.IsArrayType())
|
|
body.indexedVariables = variable.GetNumChildren();
|
|
else
|
|
body.namedVariables = variable.GetNumChildren();
|
|
}
|
|
|
|
if (const lldb::addr_t addr = variable.GetLoadAddress();
|
|
addr != LLDB_INVALID_ADDRESS)
|
|
body.memoryReference = addr;
|
|
|
|
if (ValuePointsToCode(variable))
|
|
body.valueLocationReference = new_var_ref.AsUInt32();
|
|
|
|
// Also send invalidated event to signal client that some variables
|
|
// (e.g. references) can be changed.
|
|
SendInvalidatedEvent(dap, {InvalidatedEventBody::eAreaVariables});
|
|
|
|
// Also send memory event to signal client that variable memory was changed.
|
|
SendMemoryEvent(dap, variable);
|
|
|
|
return body;
|
|
}
|
|
|
|
} // namespace lldb_dap
|