Author: John Harrison Date: 2025-03-20T15:33:05-07:00 New Revision: 30bb0c443e163b244d663c88821524b6e747747b
URL: https://github.com/llvm/llvm-project/commit/30bb0c443e163b244d663c88821524b6e747747b DIFF: https://github.com/llvm/llvm-project/commit/30bb0c443e163b244d663c88821524b6e747747b.diff LOG: [lldb-dap] Adding a DAPError for showing users error messages. (#132255) The `DAPError` can be used to craft an error message that is displayed to a user (with showUser=true). Any request handler implementation using subclassing `RequestHandler<>` should be able to use this. I updated SourceRequestHandler to report DAPError's specifically. Added: lldb/tools/lldb-dap/DAPError.cpp lldb/tools/lldb-dap/DAPError.h Modified: lldb/tools/lldb-dap/CMakeLists.txt lldb/tools/lldb-dap/Handler/RequestHandler.h lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp lldb/tools/lldb-dap/Protocol/ProtocolBase.cpp lldb/tools/lldb-dap/Protocol/ProtocolBase.h Removed: ################################################################################ diff --git a/lldb/tools/lldb-dap/CMakeLists.txt b/lldb/tools/lldb-dap/CMakeLists.txt index 93c5ee4426783..e9773db7586e6 100644 --- a/lldb/tools/lldb-dap/CMakeLists.txt +++ b/lldb/tools/lldb-dap/CMakeLists.txt @@ -18,6 +18,7 @@ add_lldb_tool(lldb-dap Breakpoint.cpp BreakpointBase.cpp DAP.cpp + DAPError.cpp DAPLog.cpp EventHelper.cpp ExceptionBreakpoint.cpp diff --git a/lldb/tools/lldb-dap/DAPError.cpp b/lldb/tools/lldb-dap/DAPError.cpp new file mode 100644 index 0000000000000..dcb955af0345f --- /dev/null +++ b/lldb/tools/lldb-dap/DAPError.cpp @@ -0,0 +1,29 @@ +//===-- DAPError.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 "DAPError.h" +#include "llvm/Support/Error.h" +#include <system_error> + +namespace lldb_dap { + +char DAPError::ID; + +DAPError::DAPError(std::string message, std::error_code EC, bool show_user, + std::optional<std::string> url, + std::optional<std::string> url_label) + : m_message(message), m_ec(EC), m_show_user(show_user), m_url(url), + m_url_label(url_label) {} + +void DAPError::log(llvm::raw_ostream &OS) const { OS << m_message; } + +std::error_code DAPError::convertToErrorCode() const { + return llvm::inconvertibleErrorCode(); +} + +} // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/DAPError.h b/lldb/tools/lldb-dap/DAPError.h new file mode 100644 index 0000000000000..564651b1f587d --- /dev/null +++ b/lldb/tools/lldb-dap/DAPError.h @@ -0,0 +1,43 @@ +//===-- DAPError.h --------------------------------------------------------===// +// +// 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 "llvm/Support/Error.h" +#include <optional> +#include <string> +#include <system_error> + +namespace lldb_dap { + +/// An Error that is reported as a DAP Error Message, which may be presented to +/// the user. +class DAPError : public llvm::ErrorInfo<DAPError> { +public: + static char ID; + + DAPError(std::string message, + std::error_code EC = llvm::inconvertibleErrorCode(), + bool show_user = true, std::optional<std::string> url = std::nullopt, + std::optional<std::string> url_label = std::nullopt); + + void log(llvm::raw_ostream &OS) const override; + std::error_code convertToErrorCode() const override; + + const std::string &getMessage() const { return m_message; } + bool getShowUser() const { return m_show_user; } + const std::optional<std::string> &getURL() const { return m_url; } + const std::optional<std::string> &getURLLabel() const { return m_url; } + +private: + std::string m_message; + std::error_code m_ec; + bool m_show_user; + std::optional<std::string> m_url; + std::optional<std::string> m_url_label; +}; + +} // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.h b/lldb/tools/lldb-dap/Handler/RequestHandler.h index d327820224a30..8971b02fcb92e 100644 --- a/lldb/tools/lldb-dap/Handler/RequestHandler.h +++ b/lldb/tools/lldb-dap/Handler/RequestHandler.h @@ -10,11 +10,13 @@ #define LLDB_TOOLS_LLDB_DAP_HANDLER_HANDLER_H #include "DAP.h" +#include "DAPError.h" #include "DAPLog.h" #include "Protocol/ProtocolBase.h" #include "Protocol/ProtocolRequests.h" #include "lldb/API/SBError.h" #include "llvm/ADT/StringRef.h" +#include "llvm/Support/Error.h" #include "llvm/Support/JSON.h" #include <optional> #include <type_traits> @@ -118,20 +120,38 @@ class RequestHandler : public BaseRequestHandler { std::string parse_failure; llvm::raw_string_ostream OS(parse_failure); root.printErrorContext(request.arguments, OS); + + protocol::ErrorMessage error_message; + error_message.format = parse_failure; + + protocol::ErrorResponseBody body; + body.error = error_message; + response.success = false; - response.message = parse_failure; + response.body = std::move(body); + dap.Send(response); return; } - auto body = Run(arguments); - // FIXME: Add a dedicated DAPError for enhanced errors that are - // user-visibile. + llvm::Expected<Body> body = Run(arguments); if (auto Err = body.takeError()) { + protocol::ErrorMessage error_message; + error_message.sendTelemetry = false; + if (llvm::Error unhandled = llvm::handleErrors( + std::move(Err), [&](const DAPError &E) -> llvm::Error { + error_message.format = E.getMessage(); + error_message.showUser = E.getShowUser(); + error_message.id = E.convertToErrorCode().value(); + error_message.url = E.getURL(); + error_message.urlLabel = E.getURLLabel(); + return llvm::Error::success(); + })) + error_message.format = llvm::toString(std::move(unhandled)); + protocol::ErrorResponseBody body; + body.error = error_message; response.success = false; - // FIXME: Build ErrorMessage based on error details instead of using the - // 'message' field. - response.message = llvm::toString(std::move(Err)); + response.body = std::move(body); } else { response.success = true; if constexpr (!std::is_same_v<Body, std::monostate>) diff --git a/lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp index 57cfb09692990..1a7a13d9f267a 100644 --- a/lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp @@ -29,7 +29,7 @@ SourceRequestHandler::Run(const protocol::SourceArguments &args) const { args.source->sourceReference.value_or(args.sourceReference); if (!source) - return llvm::createStringError( + return llvm::make_error<DAPError>( "invalid arguments, expected source.sourceReference to be set"); lldb::SBProcess process = dap.target.GetProcess(); @@ -39,7 +39,7 @@ SourceRequestHandler::Run(const protocol::SourceArguments &args) const { // Lower 32 bits is the frame index lldb::SBFrame frame = thread.GetFrameAtIndex(GetLLDBFrameID(source)); if (!frame.IsValid()) - return llvm::createStringError("source not found"); + return llvm::make_error<DAPError>("source not found"); lldb::SBInstructionList insts = frame.GetSymbol().GetInstructions(dap.target); lldb::SBStream stream; diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolBase.cpp b/lldb/tools/lldb-dap/Protocol/ProtocolBase.cpp index f30517715194f..0ef90eb7d76bd 100644 --- a/lldb/tools/lldb-dap/Protocol/ProtocolBase.cpp +++ b/lldb/tools/lldb-dap/Protocol/ProtocolBase.cpp @@ -286,4 +286,13 @@ json::Value toJSON(const Message &M) { return std::visit([](auto &M) { return toJSON(M); }, M); } +json::Value toJSON(const ErrorResponseBody &E) { + json::Object result{}; + + if (E.error) + result.insert({"error", *E.error}); + + return result; +} + } // namespace lldb_dap::protocol diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolBase.h b/lldb/tools/lldb-dap/Protocol/ProtocolBase.h index e10a903b80aaa..baf5f8f165183 100644 --- a/lldb/tools/lldb-dap/Protocol/ProtocolBase.h +++ b/lldb/tools/lldb-dap/Protocol/ProtocolBase.h @@ -109,7 +109,7 @@ struct ErrorMessage { /// requirement that every user visible error message needs a corresponding /// error number, so that users or customer support can find information about /// the specific error more easily. - uint64_t id; + uint64_t id = 0; /// A format string for the message. Embedded variables have the form /// `{name}`. If variable name starts with an underscore character, the @@ -122,10 +122,10 @@ struct ErrorMessage { std::optional<std::map<std::string, std::string>> variables; /// If true send to telemetry. - bool sendTelemetry; + bool sendTelemetry = false; /// If true show user. - bool showUser; + bool showUser = false; /// A url where additional information about this message can be found. std::optional<std::string> url; @@ -141,6 +141,13 @@ using Message = std::variant<Request, Response, Event>; bool fromJSON(const llvm::json::Value &, Message &, llvm::json::Path); llvm::json::Value toJSON(const Message &); +/// On error (whenever `success` is false), the body can provide more details. +struct ErrorResponseBody { + /// A structured error message. + std::optional<ErrorMessage> error; +}; +llvm::json::Value toJSON(const ErrorResponseBody &); + /// This is just an acknowledgement, so no body field is required. using VoidResponse = std::monostate; _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits