mirror of
https://github.com/Kitware/CMake.git
synced 2026-01-11 08:20:18 -06:00
Debugger: Add Value Formatting support for StackTrace request
Add support for the "format" property of the Debug Adapter Protocol StackTrace request to fulfill the host's request to format the resulting StackFrame name differently.
This commit is contained in:
@@ -148,6 +148,7 @@ cmDebuggerAdapter::cmDebuggerAdapter(
|
||||
SupportsVariableType = req.supportsVariableType.value(false);
|
||||
dap::CMakeInitializeResponse response;
|
||||
response.supportsConfigurationDoneRequest = true;
|
||||
response.supportsValueFormattingOptions = true;
|
||||
response.cmakeVersion.major = CMake_VERSION_MAJOR;
|
||||
response.cmakeVersion.minor = CMake_VERSION_MINOR;
|
||||
response.cmakeVersion.patch = CMake_VERSION_PATCH;
|
||||
@@ -186,7 +187,7 @@ cmDebuggerAdapter::cmDebuggerAdapter(
|
||||
std::unique_lock<std::mutex> lock(Mutex);
|
||||
|
||||
cm::optional<dap::StackTraceResponse> response =
|
||||
ThreadManager->GetThreadStackTraceResponse(request.threadId);
|
||||
ThreadManager->GetThreadStackTraceResponse(request);
|
||||
if (response.has_value()) {
|
||||
return response.value();
|
||||
}
|
||||
|
||||
@@ -25,4 +25,10 @@ int64_t cmDebuggerStackFrame::GetLine() const noexcept
|
||||
return this->Function.Line();
|
||||
}
|
||||
|
||||
std::vector<cmListFileArgument> const& cmDebuggerStackFrame::GetArguments()
|
||||
const noexcept
|
||||
{
|
||||
return this->Function.Arguments();
|
||||
}
|
||||
|
||||
} // namespace cmDebugger
|
||||
|
||||
@@ -7,8 +7,10 @@
|
||||
#include <atomic>
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class cmListFileFunction;
|
||||
struct cmListFileArgument;
|
||||
class cmMakefile;
|
||||
|
||||
namespace cmDebugger {
|
||||
@@ -32,6 +34,7 @@ public:
|
||||
{
|
||||
return this->Function;
|
||||
}
|
||||
std::vector<cmListFileArgument> const& GetArguments() const noexcept;
|
||||
};
|
||||
|
||||
} // namespace cmDebugger
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include "cmDebuggerVariablesHelper.h"
|
||||
#include "cmDebuggerVariablesManager.h"
|
||||
#include "cmListFileCache.h"
|
||||
#include "cmStringAlgorithms.h"
|
||||
|
||||
namespace cmDebugger {
|
||||
|
||||
@@ -117,8 +118,27 @@ dap::VariablesResponse cmDebuggerThread::GetVariablesResponse(
|
||||
}
|
||||
|
||||
dap::StackTraceResponse GetStackTraceResponse(
|
||||
std::shared_ptr<cmDebuggerThread> const& thread)
|
||||
std::shared_ptr<cmDebuggerThread> const& thread,
|
||||
dap::optional<dap::StackFrameFormat> format)
|
||||
{
|
||||
dap::boolean showParameters = false;
|
||||
dap::boolean showParameterValues = false;
|
||||
dap::boolean showLine = false;
|
||||
if (format.has_value()) {
|
||||
auto formatValue = format.value();
|
||||
if (formatValue.parameters.has_value()) {
|
||||
showParameters = formatValue.parameters.value();
|
||||
}
|
||||
|
||||
if (formatValue.parameterValues.has_value()) {
|
||||
showParameterValues = formatValue.parameterValues.value();
|
||||
}
|
||||
|
||||
if (formatValue.line.has_value()) {
|
||||
showLine = formatValue.line.value();
|
||||
}
|
||||
}
|
||||
|
||||
dap::StackTraceResponse response;
|
||||
std::unique_lock<std::mutex> lock(thread->Mutex);
|
||||
for (int i = static_cast<int>(thread->Frames.size()) - 1; i >= 0; --i) {
|
||||
@@ -136,10 +156,29 @@ dap::StackTraceResponse GetStackTraceResponse(
|
||||
#endif
|
||||
stackFrame.line = thread->Frames[i]->GetLine();
|
||||
stackFrame.column = 1;
|
||||
stackFrame.name = thread->Frames[i]->GetFunction().OriginalName();
|
||||
stackFrame.id = thread->Frames[i]->GetId();
|
||||
stackFrame.source = source;
|
||||
|
||||
auto stackName = thread->Frames[i]->GetFunction().OriginalName();
|
||||
if (showParameters) {
|
||||
stackName.push_back('(');
|
||||
if (showParameterValues && !thread->Frames[i]->GetArguments().empty()) {
|
||||
for (auto const& arg : thread->Frames[i]->GetArguments()) {
|
||||
stackName = cmStrCat(stackName, arg.Value, ", ");
|
||||
}
|
||||
|
||||
stackName.erase(stackName.end() - 2, stackName.end());
|
||||
}
|
||||
|
||||
stackName.push_back(')');
|
||||
}
|
||||
|
||||
if (showLine) {
|
||||
stackName =
|
||||
cmStrCat(stackName, " Line: ", static_cast<int64_t>(stackFrame.line));
|
||||
}
|
||||
|
||||
stackFrame.name = stackName;
|
||||
response.stackFrames.push_back(stackFrame);
|
||||
}
|
||||
|
||||
|
||||
@@ -23,6 +23,11 @@ class cmDebuggerVariables;
|
||||
class cmDebuggerVariablesManager;
|
||||
}
|
||||
|
||||
namespace dap {
|
||||
template <typename T>
|
||||
class optional;
|
||||
}
|
||||
|
||||
namespace cmDebugger {
|
||||
|
||||
class cmDebuggerThread
|
||||
@@ -53,7 +58,8 @@ public:
|
||||
dap::VariablesResponse GetVariablesResponse(
|
||||
dap::VariablesRequest const& request);
|
||||
friend dap::StackTraceResponse GetStackTraceResponse(
|
||||
std::shared_ptr<cmDebuggerThread> const& thread);
|
||||
std::shared_ptr<cmDebuggerThread> const& thread,
|
||||
dap::optional<dap::StackFrameFormat> format);
|
||||
};
|
||||
|
||||
} // namespace cmDebugger
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <algorithm>
|
||||
|
||||
#include <cm3p/cppdap/protocol.h>
|
||||
#include <cm3p/cppdap/types.h>
|
||||
|
||||
#include "cmDebuggerThread.h"
|
||||
|
||||
@@ -30,18 +31,19 @@ void cmDebuggerThreadManager::EndThread(
|
||||
}
|
||||
|
||||
cm::optional<dap::StackTraceResponse>
|
||||
cmDebuggerThreadManager::GetThreadStackTraceResponse(int64_t id)
|
||||
cmDebuggerThreadManager::GetThreadStackTraceResponse(
|
||||
const dap::StackTraceRequest& request)
|
||||
{
|
||||
auto it = find_if(Threads.begin(), Threads.end(),
|
||||
[&](const std::shared_ptr<cmDebuggerThread>& t) {
|
||||
return t->GetId() == id;
|
||||
return t->GetId() == request.threadId;
|
||||
});
|
||||
|
||||
if (it == Threads.end()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
return GetStackTraceResponse(*it);
|
||||
return GetStackTraceResponse(*it, request.format);
|
||||
}
|
||||
|
||||
} // namespace cmDebugger
|
||||
|
||||
@@ -17,6 +17,7 @@ class cmDebuggerThread;
|
||||
}
|
||||
|
||||
namespace dap {
|
||||
struct StackTraceRequest;
|
||||
struct StackTraceResponse;
|
||||
}
|
||||
|
||||
@@ -32,7 +33,7 @@ public:
|
||||
std::shared_ptr<cmDebuggerThread> StartThread(std::string const& name);
|
||||
void EndThread(std::shared_ptr<cmDebuggerThread> const& thread);
|
||||
cm::optional<dap::StackTraceResponse> GetThreadStackTraceResponse(
|
||||
std::int64_t id);
|
||||
const dap::StackTraceRequest& request);
|
||||
};
|
||||
|
||||
} // namespace cmDebugger
|
||||
|
||||
@@ -132,6 +132,7 @@ bool runTest(std::function<bool(dap::Session&)> onThreadExitedEvent)
|
||||
ASSERT_TRUE(initializeResponse.response.supportsExceptionInfoRequest);
|
||||
ASSERT_TRUE(
|
||||
initializeResponse.response.exceptionBreakpointFilters.has_value());
|
||||
ASSERT_TRUE(initializeResponse.response.supportsValueFormattingOptions);
|
||||
|
||||
dap::LaunchRequest launchRequest;
|
||||
auto launchResponse = client->send(launchRequest).get();
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <cm3p/cppdap/optional.h>
|
||||
#include <cm3p/cppdap/protocol.h>
|
||||
#include <cm3p/cppdap/types.h>
|
||||
|
||||
@@ -10,21 +11,52 @@
|
||||
|
||||
#include "testCommon.h"
|
||||
|
||||
static bool testStackFrameFunctionName()
|
||||
static bool testStackFrameFunctionName(
|
||||
dap::optional<dap::StackFrameFormat> format, const char* expectedName)
|
||||
{
|
||||
auto thread = std::make_shared<cmDebugger::cmDebuggerThread>(0, "name");
|
||||
const auto* functionName = "function_name";
|
||||
auto arguments = std::vector<cmListFileArgument>{};
|
||||
auto arguments = std::vector<cmListFileArgument>{ cmListFileArgument(
|
||||
"arg", cmListFileArgument::Delimiter::Unquoted, 0) };
|
||||
cmListFileFunction func(functionName, 10, 20, arguments);
|
||||
thread->PushStackFrame(nullptr, "CMakeLists.txt", func);
|
||||
|
||||
auto stackTrace = GetStackTraceResponse(thread);
|
||||
auto stackTrace = GetStackTraceResponse(thread, format);
|
||||
|
||||
ASSERT_TRUE(stackTrace.stackFrames[0].name == functionName);
|
||||
ASSERT_TRUE(stackTrace.stackFrames[0].name == expectedName);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool testStackFrameNoFormatting()
|
||||
{
|
||||
return testStackFrameFunctionName({}, "function_name");
|
||||
}
|
||||
|
||||
bool testStackFrameFormatParameters()
|
||||
{
|
||||
dap::StackFrameFormat format;
|
||||
format.parameters = true;
|
||||
return testStackFrameFunctionName(format, "function_name()");
|
||||
}
|
||||
|
||||
bool testStackFrameFormatParameterValues()
|
||||
{
|
||||
dap::StackFrameFormat format;
|
||||
format.parameters = true;
|
||||
format.parameterValues = true;
|
||||
return testStackFrameFunctionName(format, "function_name(arg)");
|
||||
}
|
||||
|
||||
bool testStackFrameFormatLine()
|
||||
{
|
||||
dap::StackFrameFormat format;
|
||||
format.line = true;
|
||||
return testStackFrameFunctionName(format, "function_name Line: 10");
|
||||
}
|
||||
|
||||
int testDebuggerThread(int, char*[])
|
||||
{
|
||||
return runTests({ testStackFrameFunctionName });
|
||||
return runTests({ testStackFrameNoFormatting, testStackFrameFormatParameters,
|
||||
testStackFrameFormatParameterValues,
|
||||
testStackFrameFormatLine });
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user