Skip to content

Commit 30bb0c4

Browse files
authored
[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.
1 parent ff21b50 commit 30bb0c4

File tree

7 files changed

+121
-12
lines changed

7 files changed

+121
-12
lines changed

lldb/tools/lldb-dap/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ add_lldb_tool(lldb-dap
1818
Breakpoint.cpp
1919
BreakpointBase.cpp
2020
DAP.cpp
21+
DAPError.cpp
2122
DAPLog.cpp
2223
EventHelper.cpp
2324
ExceptionBreakpoint.cpp

lldb/tools/lldb-dap/DAPError.cpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
//===-- DAPError.cpp ------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "DAPError.h"
10+
#include "llvm/Support/Error.h"
11+
#include <system_error>
12+
13+
namespace lldb_dap {
14+
15+
char DAPError::ID;
16+
17+
DAPError::DAPError(std::string message, std::error_code EC, bool show_user,
18+
std::optional<std::string> url,
19+
std::optional<std::string> url_label)
20+
: m_message(message), m_ec(EC), m_show_user(show_user), m_url(url),
21+
m_url_label(url_label) {}
22+
23+
void DAPError::log(llvm::raw_ostream &OS) const { OS << m_message; }
24+
25+
std::error_code DAPError::convertToErrorCode() const {
26+
return llvm::inconvertibleErrorCode();
27+
}
28+
29+
} // namespace lldb_dap

lldb/tools/lldb-dap/DAPError.h

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
//===-- DAPError.h --------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "llvm/Support/Error.h"
10+
#include <optional>
11+
#include <string>
12+
#include <system_error>
13+
14+
namespace lldb_dap {
15+
16+
/// An Error that is reported as a DAP Error Message, which may be presented to
17+
/// the user.
18+
class DAPError : public llvm::ErrorInfo<DAPError> {
19+
public:
20+
static char ID;
21+
22+
DAPError(std::string message,
23+
std::error_code EC = llvm::inconvertibleErrorCode(),
24+
bool show_user = true, std::optional<std::string> url = std::nullopt,
25+
std::optional<std::string> url_label = std::nullopt);
26+
27+
void log(llvm::raw_ostream &OS) const override;
28+
std::error_code convertToErrorCode() const override;
29+
30+
const std::string &getMessage() const { return m_message; }
31+
bool getShowUser() const { return m_show_user; }
32+
const std::optional<std::string> &getURL() const { return m_url; }
33+
const std::optional<std::string> &getURLLabel() const { return m_url; }
34+
35+
private:
36+
std::string m_message;
37+
std::error_code m_ec;
38+
bool m_show_user;
39+
std::optional<std::string> m_url;
40+
std::optional<std::string> m_url_label;
41+
};
42+
43+
} // namespace lldb_dap

lldb/tools/lldb-dap/Handler/RequestHandler.h

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,13 @@
1010
#define LLDB_TOOLS_LLDB_DAP_HANDLER_HANDLER_H
1111

1212
#include "DAP.h"
13+
#include "DAPError.h"
1314
#include "DAPLog.h"
1415
#include "Protocol/ProtocolBase.h"
1516
#include "Protocol/ProtocolRequests.h"
1617
#include "lldb/API/SBError.h"
1718
#include "llvm/ADT/StringRef.h"
19+
#include "llvm/Support/Error.h"
1820
#include "llvm/Support/JSON.h"
1921
#include <optional>
2022
#include <type_traits>
@@ -118,20 +120,38 @@ class RequestHandler : public BaseRequestHandler {
118120
std::string parse_failure;
119121
llvm::raw_string_ostream OS(parse_failure);
120122
root.printErrorContext(request.arguments, OS);
123+
124+
protocol::ErrorMessage error_message;
125+
error_message.format = parse_failure;
126+
127+
protocol::ErrorResponseBody body;
128+
body.error = error_message;
129+
121130
response.success = false;
122-
response.message = parse_failure;
131+
response.body = std::move(body);
132+
123133
dap.Send(response);
124134
return;
125135
}
126136

127-
auto body = Run(arguments);
128-
// FIXME: Add a dedicated DAPError for enhanced errors that are
129-
// user-visibile.
137+
llvm::Expected<Body> body = Run(arguments);
130138
if (auto Err = body.takeError()) {
139+
protocol::ErrorMessage error_message;
140+
error_message.sendTelemetry = false;
141+
if (llvm::Error unhandled = llvm::handleErrors(
142+
std::move(Err), [&](const DAPError &E) -> llvm::Error {
143+
error_message.format = E.getMessage();
144+
error_message.showUser = E.getShowUser();
145+
error_message.id = E.convertToErrorCode().value();
146+
error_message.url = E.getURL();
147+
error_message.urlLabel = E.getURLLabel();
148+
return llvm::Error::success();
149+
}))
150+
error_message.format = llvm::toString(std::move(unhandled));
151+
protocol::ErrorResponseBody body;
152+
body.error = error_message;
131153
response.success = false;
132-
// FIXME: Build ErrorMessage based on error details instead of using the
133-
// 'message' field.
134-
response.message = llvm::toString(std::move(Err));
154+
response.body = std::move(body);
135155
} else {
136156
response.success = true;
137157
if constexpr (!std::is_same_v<Body, std::monostate>)

lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ SourceRequestHandler::Run(const protocol::SourceArguments &args) const {
2929
args.source->sourceReference.value_or(args.sourceReference);
3030

3131
if (!source)
32-
return llvm::createStringError(
32+
return llvm::make_error<DAPError>(
3333
"invalid arguments, expected source.sourceReference to be set");
3434

3535
lldb::SBProcess process = dap.target.GetProcess();
@@ -39,7 +39,7 @@ SourceRequestHandler::Run(const protocol::SourceArguments &args) const {
3939
// Lower 32 bits is the frame index
4040
lldb::SBFrame frame = thread.GetFrameAtIndex(GetLLDBFrameID(source));
4141
if (!frame.IsValid())
42-
return llvm::createStringError("source not found");
42+
return llvm::make_error<DAPError>("source not found");
4343

4444
lldb::SBInstructionList insts = frame.GetSymbol().GetInstructions(dap.target);
4545
lldb::SBStream stream;

lldb/tools/lldb-dap/Protocol/ProtocolBase.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,4 +286,13 @@ json::Value toJSON(const Message &M) {
286286
return std::visit([](auto &M) { return toJSON(M); }, M);
287287
}
288288

289+
json::Value toJSON(const ErrorResponseBody &E) {
290+
json::Object result{};
291+
292+
if (E.error)
293+
result.insert({"error", *E.error});
294+
295+
return result;
296+
}
297+
289298
} // namespace lldb_dap::protocol

lldb/tools/lldb-dap/Protocol/ProtocolBase.h

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ struct ErrorMessage {
109109
/// requirement that every user visible error message needs a corresponding
110110
/// error number, so that users or customer support can find information about
111111
/// the specific error more easily.
112-
uint64_t id;
112+
uint64_t id = 0;
113113

114114
/// A format string for the message. Embedded variables have the form
115115
/// `{name}`. If variable name starts with an underscore character, the
@@ -122,10 +122,10 @@ struct ErrorMessage {
122122
std::optional<std::map<std::string, std::string>> variables;
123123

124124
/// If true send to telemetry.
125-
bool sendTelemetry;
125+
bool sendTelemetry = false;
126126

127127
/// If true show user.
128-
bool showUser;
128+
bool showUser = false;
129129

130130
/// A url where additional information about this message can be found.
131131
std::optional<std::string> url;
@@ -141,6 +141,13 @@ using Message = std::variant<Request, Response, Event>;
141141
bool fromJSON(const llvm::json::Value &, Message &, llvm::json::Path);
142142
llvm::json::Value toJSON(const Message &);
143143

144+
/// On error (whenever `success` is false), the body can provide more details.
145+
struct ErrorResponseBody {
146+
/// A structured error message.
147+
std::optional<ErrorMessage> error;
148+
};
149+
llvm::json::Value toJSON(const ErrorResponseBody &);
150+
144151
/// This is just an acknowledgement, so no body field is required.
145152
using VoidResponse = std::monostate;
146153

0 commit comments

Comments
 (0)