diff --git a/Source/cmDebuggerAdapter.cxx b/Source/cmDebuggerAdapter.cxx index 0eacd0c121..c3587a1055 100644 --- a/Source/cmDebuggerAdapter.cxx +++ b/Source/cmDebuggerAdapter.cxx @@ -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 lock(Mutex); cm::optional response = - ThreadManager->GetThreadStackTraceResponse(request.threadId); + ThreadManager->GetThreadStackTraceResponse(request); if (response.has_value()) { return response.value(); } diff --git a/Source/cmDebuggerStackFrame.cxx b/Source/cmDebuggerStackFrame.cxx index 789b0a5939..89cdbc6a02 100644 --- a/Source/cmDebuggerStackFrame.cxx +++ b/Source/cmDebuggerStackFrame.cxx @@ -25,4 +25,10 @@ int64_t cmDebuggerStackFrame::GetLine() const noexcept return this->Function.Line(); } +std::vector const& cmDebuggerStackFrame::GetArguments() + const noexcept +{ + return this->Function.Arguments(); +} + } // namespace cmDebugger diff --git a/Source/cmDebuggerStackFrame.h b/Source/cmDebuggerStackFrame.h index f4e6612e9c..2133bcdf40 100644 --- a/Source/cmDebuggerStackFrame.h +++ b/Source/cmDebuggerStackFrame.h @@ -7,8 +7,10 @@ #include #include #include +#include class cmListFileFunction; +struct cmListFileArgument; class cmMakefile; namespace cmDebugger { @@ -32,6 +34,7 @@ public: { return this->Function; } + std::vector const& GetArguments() const noexcept; }; } // namespace cmDebugger diff --git a/Source/cmDebuggerThread.cxx b/Source/cmDebuggerThread.cxx index f7a17781d4..047dd2d203 100644 --- a/Source/cmDebuggerThread.cxx +++ b/Source/cmDebuggerThread.cxx @@ -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 const& thread) + std::shared_ptr const& thread, + dap::optional 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 lock(thread->Mutex); for (int i = static_cast(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(stackFrame.line)); + } + + stackFrame.name = stackName; response.stackFrames.push_back(stackFrame); } diff --git a/Source/cmDebuggerThread.h b/Source/cmDebuggerThread.h index 65ee2cf15b..81664b50c7 100644 --- a/Source/cmDebuggerThread.h +++ b/Source/cmDebuggerThread.h @@ -23,6 +23,11 @@ class cmDebuggerVariables; class cmDebuggerVariablesManager; } +namespace dap { +template +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 const& thread); + std::shared_ptr const& thread, + dap::optional format); }; } // namespace cmDebugger diff --git a/Source/cmDebuggerThreadManager.cxx b/Source/cmDebuggerThreadManager.cxx index 0eb443bd8f..0f15b6b281 100644 --- a/Source/cmDebuggerThreadManager.cxx +++ b/Source/cmDebuggerThreadManager.cxx @@ -6,6 +6,7 @@ #include #include +#include #include "cmDebuggerThread.h" @@ -30,18 +31,19 @@ void cmDebuggerThreadManager::EndThread( } cm::optional -cmDebuggerThreadManager::GetThreadStackTraceResponse(int64_t id) +cmDebuggerThreadManager::GetThreadStackTraceResponse( + const dap::StackTraceRequest& request) { auto it = find_if(Threads.begin(), Threads.end(), [&](const std::shared_ptr& 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 diff --git a/Source/cmDebuggerThreadManager.h b/Source/cmDebuggerThreadManager.h index 934cf8590e..6d27a5c339 100644 --- a/Source/cmDebuggerThreadManager.h +++ b/Source/cmDebuggerThreadManager.h @@ -17,6 +17,7 @@ class cmDebuggerThread; } namespace dap { +struct StackTraceRequest; struct StackTraceResponse; } @@ -32,7 +33,7 @@ public: std::shared_ptr StartThread(std::string const& name); void EndThread(std::shared_ptr const& thread); cm::optional GetThreadStackTraceResponse( - std::int64_t id); + const dap::StackTraceRequest& request); }; } // namespace cmDebugger diff --git a/Tests/CMakeLib/testDebuggerAdapter.cxx b/Tests/CMakeLib/testDebuggerAdapter.cxx index a055cb7c6e..b2c9458881 100644 --- a/Tests/CMakeLib/testDebuggerAdapter.cxx +++ b/Tests/CMakeLib/testDebuggerAdapter.cxx @@ -132,6 +132,7 @@ bool runTest(std::function 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(); diff --git a/Tests/CMakeLib/testDebuggerThread.cxx b/Tests/CMakeLib/testDebuggerThread.cxx index 3b7fe6e2fa..4eed247aef 100644 --- a/Tests/CMakeLib/testDebuggerThread.cxx +++ b/Tests/CMakeLib/testDebuggerThread.cxx @@ -2,6 +2,7 @@ #include #include +#include #include #include @@ -10,21 +11,52 @@ #include "testCommon.h" -static bool testStackFrameFunctionName() +static bool testStackFrameFunctionName( + dap::optional format, const char* expectedName) { auto thread = std::make_shared(0, "name"); const auto* functionName = "function_name"; - auto arguments = std::vector{}; + auto arguments = std::vector{ 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 }); }