Skip to content

Commit bacb624

Browse files
committed
[lldb-dap] update gototargets to use the new protocol
1 parent af9b970 commit bacb624

File tree

9 files changed

+164
-186
lines changed

9 files changed

+164
-186
lines changed

lldb/test/API/tools/lldb-dap/gotoTargets/TestDAP_gotoTargets.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ def test_default(self):
6363
response = self.dap_server.request_goto(thread_id, target_id)
6464
self.assertEqual(response["success"], True, "goto request with targetId should be successful")
6565

66-
stopped_events = self.dap_server.wait_for_stopped()
66+
stopped_events = self.dap_server.wait_for_stopped(timeout=0.200)
6767
is_goto = lambda event: event["body"]["reason"] == "goto"
6868
has_goto_event = any(map(is_goto, stopped_events))
6969
self.assertEqual(has_goto_event, True, "expected a stopped event with reason `goto`")
@@ -126,7 +126,7 @@ def test_execute_again(self):
126126
response = self.dap_server.request_goto(thread_id, target_id)
127127
self.assertEqual(response["success"], True, "expects success to go to targetId")
128128

129-
stopped_events = self.dap_server.wait_for_stopped()
129+
stopped_events = self.dap_server.wait_for_stopped(timeout=0.200) # 200ms
130130
is_goto = lambda event: event["body"]["reason"] == "goto"
131131
has_goto_event = any(map(is_goto, stopped_events))
132132
self.assertEqual(has_goto_event, True, "expects stopped event with reason goto")

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

+21-73
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
#include "DAP.h"
1010
#include "EventHelper.h"
1111
#include "JSONUtils.h"
12+
#include "Protocol/ProtocolRequests.h"
13+
#include "RequestHandler.h"
1214

1315
namespace lldb_dap {
1416

@@ -26,89 +28,35 @@ static void SendThreadGotoEvent(DAP &dap, lldb::tid_t thread_id) {
2628
dap.SendJSON(llvm::json::Value(std::move(event)));
2729
}
2830

29-
// "GotoRequest": {
30-
// "allOf": [ { "$ref": "#/definitions/Request" }, {
31-
// "type": "object",
32-
// "description": "The request sets the location where the debuggee will
33-
// continue to run.\nThis makes it possible to skip the execution of code or
34-
// to execute code again.\nThe code between the current location and the
35-
// goto target is not executed but skipped.\nThe debug adapter first sends
36-
// the response and then a `stopped` event with reason `goto`.\nClients
37-
// should only call this request if the corresponding capability
38-
// `supportsGotoTargetsRequest` is true (because only then goto targets
39-
// exist that can be passed as arguments).",
40-
//. "properties": {
41-
// "command": {
42-
// "type": "string",
43-
// "enum": [ "goto" ]
44-
// },
45-
// "arguments": {
46-
// "$ref": "#/definitions/GotoArguments"
47-
// }
48-
// },
49-
// "required": [ "command", "arguments" ]
50-
// }]
51-
// }
52-
// "GotoArguments": {
53-
// "type": "object",
54-
// "description": "Arguments for `goto` request.",
55-
// "properties": {
56-
// "threadId": {
57-
// "type": "integer",
58-
// "description": "Set the goto target for this thread."
59-
// },
60-
// "targetId": {
61-
// "type": "integer",
62-
// "description": "The location where the debuggee will continue to run."
63-
// }
64-
// },
65-
// "required": [ "threadId", "targetId" ]
66-
// }
67-
// "GotoResponse": {
68-
// "allOf": [ { "$ref": "#/definitions/Response" }, {
69-
// "type": "object",
70-
// "description": "Response to `goto` request. This is just an
71-
// acknowledgement, so no body field is required."
72-
// }]
73-
// }
74-
void GoToRequestHandler::operator()(const llvm::json::Object &request) const {
75-
llvm::json::Object response;
76-
FillResponse(request, response);
31+
llvm::Expected<protocol::GotoResponseBody>
32+
GotoRequestHandler::Run(const protocol::GotoArguments &args) const {
33+
const lldb::tid_t thread_id = args.threadId;
34+
lldb::SBThread current_thread =
35+
dap.target.GetProcess().GetThreadByID(thread_id);
7736

78-
auto SendError = [&](auto &&message) {
79-
response["success"] = false;
80-
response["message"] = message;
81-
dap.SendJSON(llvm::json::Value(std::move(response)));
82-
};
83-
84-
const auto *goto_arguments = request.getObject("arguments");
85-
if (goto_arguments == nullptr) {
86-
return SendError("Arguments is empty");
87-
}
88-
89-
lldb::SBThread current_thread = dap.GetLLDBThread(*goto_arguments);
9037
if (!current_thread.IsValid()) {
91-
return SendError(llvm::formatv("Thread id `{0}` is not valid",
92-
current_thread.GetThreadID()));
38+
return llvm::createStringError(llvm::formatv("Thread id `{0}` is not valid",
39+
current_thread.GetThreadID()));
9340
}
9441

95-
const auto target_id = GetInteger<uint64_t>(goto_arguments, "targetId");
96-
const auto line_entry = dap.gotos.GetLineEntry(target_id.value());
97-
if (!target_id || !line_entry) {
98-
return SendError(llvm::formatv("Target id `{0}` is not valid",
99-
current_thread.GetThreadID()));
42+
const uint64_t target_id = args.targetId;
43+
const std::optional<lldb::SBLineEntry> line_entry =
44+
dap.gotos.GetLineEntry(target_id);
45+
if (!line_entry) {
46+
return llvm::createStringError(
47+
llvm::formatv("Target id `{0}` is not valid", thread_id));
10048
}
10149

102-
auto file_spec = line_entry->GetFileSpec();
103-
const auto error =
50+
lldb::SBFileSpec file_spec = line_entry->GetFileSpec();
51+
const lldb::SBError error =
10452
current_thread.JumpToLine(file_spec, line_entry->GetLine());
53+
10554
if (error.Fail()) {
106-
return SendError(error.GetCString());
55+
return llvm::createStringError(error.GetCString());
10756
}
10857

109-
dap.SendJSON(llvm::json::Value(std::move(response)));
110-
111-
SendThreadGotoEvent(dap, current_thread.GetThreadID());
58+
SendThreadGotoEvent(dap, thread_id);
59+
return protocol::GotoResponseBody();
11260
}
11361

11462
} // namespace lldb_dap

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

+27-101
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
#include "DAP.h"
1010

1111
#include "JSONUtils.h"
12+
#include "Protocol/ProtocolRequests.h"
13+
#include "RequestHandler.h"
1214

1315
#include <lldb/API/SBBreakpointLocation.h>
1416
#include <lldb/API/SBListener.h>
@@ -20,7 +22,7 @@ static llvm::SmallVector<lldb::SBLineEntry>
2022
GetLineValidEntry(DAP &dap, const lldb::SBFileSpec &file_spec, uint32_t line) {
2123
// Disable breakpoint listeners so they do not send events to the DAP client.
2224
lldb::SBListener listener = dap.debugger.GetListener();
23-
lldb::SBBroadcaster broadcaster = dap.target.GetBroadcaster();
25+
const lldb::SBBroadcaster broadcaster = dap.target.GetBroadcaster();
2426
constexpr auto event_mask = lldb::SBTarget::eBroadcastBitBreakpointChanged;
2527
listener.StopListeningForEvents(broadcaster, event_mask);
2628

@@ -55,111 +57,35 @@ GetLineValidEntry(DAP &dap, const lldb::SBFileSpec &file_spec, uint32_t line) {
5557
return entry_locations;
5658
}
5759

58-
// "GotoTargetsRequest": {
59-
// "allOf": [ { "$ref": "#/definitions/Request" }, {
60-
// "type": "object",
61-
// "description": "This request retrieves the possible goto targets for the
62-
// specified source location.\nThese targets can be used in the `goto`
63-
// request.\nClients should only call this request if the corresponding
64-
// capability `supportsGotoTargetsRequest` is true.",
65-
//. "properties": {
66-
// "command": {
67-
// "type": "string",
68-
// "enum": [ "gotoTargets" ]
69-
// },
70-
// "arguments": {
71-
// "$ref": "#/definitions/GotoTargetsArguments"
72-
// }
73-
// },
74-
// "required": [ "command", "arguments" ]
75-
// }]
76-
// },
77-
// "GotoTargetsArguments": {
78-
// "type": "object",
79-
// "description": "Arguments for `gotoTargets` request.",
80-
// "properties": {
81-
// "source": {
82-
// "$ref": "#/definitions/Source",
83-
// "description": "The source location for which the goto targets are
84-
// determined."
85-
// },
86-
// "line": {
87-
// "type": "integer",
88-
// "description": "The line location for which the goto targets are
89-
// determined."
90-
// },
91-
// "column": {
92-
// "type": "integer",
93-
// "description": "The position within `line` for which the goto targets
94-
// are determined. It is measured in UTF-16 code units and the client
95-
// capability `columnsStartAt1` determines whether it is 0- or 1-based."
96-
// }
97-
// },
98-
// "required": [ "source", "line" ]
99-
// },
100-
// "GotoTargetsResponse": {
101-
// "allOf": [ { "$ref": "#/definitions/Response" }, {
102-
// "type": "object",
103-
// "description": "Response to `gotoTargets` request.",
104-
// "properties": {
105-
// "body": {
106-
// "type": "object",
107-
// "properties": {
108-
// "targets": {
109-
// "type": "array",
110-
// "items": {
111-
// "$ref": "#/definitions/GotoTarget"
112-
// },
113-
// "description": "The possible goto targets of the specified
114-
// location."
115-
// }
116-
// },
117-
// "required": [ "targets" ]
118-
// }
119-
// },
120-
// "required": [ "body" ]
121-
// }]
122-
// },
123-
void GoToTargetsRequestHandler::operator()(
124-
const llvm::json::Object &request) const {
125-
llvm::json::Object response;
126-
FillResponse(request, response);
127-
128-
const llvm::json::Object *arguments = request.getObject("arguments");
129-
const llvm::json::Object *source = arguments->getObject("source");
130-
const std::string path = GetString(source, "path").str();
131-
const lldb::SBFileSpec file_spec(path.c_str(), true);
132-
const uint64_t goto_line =
133-
GetInteger<uint64_t>(arguments, "line").value_or(1U);
134-
135-
llvm::json::Object body;
60+
/// GotoTargets request; value of command field is 'gotoTargets'.
61+
llvm::Expected<protocol::GotoTargetsResponseBody>
62+
GotoTargetsRequestHandler::Run(
63+
const protocol::GotoTargetsArguments &args) const {
64+
const lldb::SBFileSpec file_spec(args.source.path.value_or("").c_str(), true);
65+
const uint64_t goto_line = args.line;
13666

13767
llvm::SmallVector<lldb::SBLineEntry> goto_locations =
13868
GetLineValidEntry(dap, file_spec, goto_line);
139-
if (goto_locations.empty()) {
140-
response["success"] = false;
141-
response["message"] = "Invalid jump location";
142-
} else {
143-
llvm::json::Array response_targets;
144-
for (lldb::SBLineEntry &line_entry : goto_locations) {
145-
const uint64_t target_id = dap.gotos.InsertLineEntry(line_entry);
146-
const uint32_t target_line = line_entry.GetLine();
147-
auto target = llvm::json::Object();
148-
target.try_emplace("id", target_id);
149-
150-
lldb::SBStream stream;
151-
line_entry.GetDescription(stream);
152-
target.try_emplace("label",
153-
llvm::StringRef(stream.GetData(), stream.GetSize()));
154-
target.try_emplace("line", target_line);
155-
response_targets.push_back(std::move(target));
156-
}
157-
158-
body.try_emplace("targets", std::move(response_targets));
69+
70+
if (goto_locations.empty())
71+
return llvm::createStringError("Invalid jump location");
72+
73+
protocol::GotoTargetsResponseBody body{};
74+
75+
for (lldb::SBLineEntry &line_entry : goto_locations) {
76+
const uint64_t target_id = dap.gotos.InsertLineEntry(line_entry);
77+
const uint32_t target_line = line_entry.GetLine();
78+
protocol::GotoTarget target{};
79+
target.id = target_id;
80+
81+
lldb::SBStream stream;
82+
line_entry.GetDescription(stream);
83+
target.label = std::string(stream.GetData(), stream.GetSize());
84+
target.line = target_line;
85+
body.targets.emplace_back(target);
15986
}
16087

161-
response.try_emplace("body", std::move(body));
162-
dap.SendJSON(llvm::json::Value(std::move(response)));
88+
return body;
16389
}
16490

16591
} // namespace lldb_dap

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

+16-8
Original file line numberDiff line numberDiff line change
@@ -215,18 +215,26 @@ class ExceptionInfoRequestHandler : public LegacyRequestHandler {
215215
void operator()(const llvm::json::Object &request) const override;
216216
};
217217

218-
class GoToRequestHandler : public LegacyRequestHandler {
218+
class GotoRequestHandler final
219+
: public RequestHandler<protocol::GotoArguments,
220+
protocol::GotoResponseBody> {
219221
public:
220-
using LegacyRequestHandler::LegacyRequestHandler;
221-
static llvm::StringLiteral getCommand() { return "goto"; }
222-
void operator()(const llvm::json::Object &request) const override;
222+
using RequestHandler::RequestHandler;
223+
static llvm::StringLiteral GetCommand() { return "goto"; }
224+
225+
llvm::Expected<protocol::GotoResponseBody>
226+
Run(const protocol::GotoArguments &args) const override;
223227
};
224228

225-
class GoToTargetsRequestHandler : public LegacyRequestHandler {
229+
class GotoTargetsRequestHandler final
230+
: public RequestHandler<protocol::GotoTargetsArguments,
231+
protocol::GotoTargetsResponseBody> {
226232
public:
227-
using LegacyRequestHandler::LegacyRequestHandler;
228-
static llvm::StringLiteral getCommand() { return "gotoTargets"; }
229-
void operator()(const llvm::json::Object &request) const override;
233+
using RequestHandler::RequestHandler;
234+
static llvm::StringLiteral GetCommand() { return "gotoTargets"; }
235+
236+
llvm::Expected<protocol::GotoTargetsResponseBody>
237+
Run(const protocol::GotoTargetsArguments &args) const override;
230238
};
231239

232240
class InitializeRequestHandler : public LegacyRequestHandler {

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

+20
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,26 @@ bool fromJSON(const json::Value &Params, DisconnectArguments &DA,
2222
O.mapOptional("terminateDebuggee", DA.terminateDebuggee) &&
2323
O.mapOptional("suspendDebuggee", DA.suspendDebuggee);
2424
}
25+
bool fromJSON(const llvm::json::Value &Params, GotoArguments &GA,
26+
llvm::json::Path P) {
27+
json::ObjectMapper O(Params, P);
28+
return O && O.map("targetId", GA.targetId) && O.map("threadId", GA.threadId);
29+
}
30+
31+
bool fromJSON(const llvm::json::Value &Params, GotoTargetsArguments &GTA,
32+
llvm::json::Path P) {
33+
json::ObjectMapper O(Params, P);
34+
return O && O.map("source", GTA.source) && O.map("line", GTA.line) &&
35+
O.mapOptional("column", GTA.column);
36+
}
37+
38+
llvm::json::Value toJSON(const GotoTargetsResponseBody &GTA) {
39+
json::Array targets;
40+
for (const auto &target : GTA.targets) {
41+
targets.emplace_back(target);
42+
}
43+
return json::Object{{"targets", std::move(targets)}};
44+
}
2545

2646
bool fromJSON(const json::Value &Params, SourceArguments &SA, json::Path P) {
2747
json::ObjectMapper O(Params, P);

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

+37
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,43 @@ bool fromJSON(const llvm::json::Value &, DisconnectArguments &,
5454
/// body field is required.
5555
using DisconnectResponse = VoidResponse;
5656

57+
/// Arguments for `goto` request.
58+
struct GotoArguments {
59+
/// Set the goto target for this thread.
60+
uint64_t threadId;
61+
62+
/// The location where the debuggee will continue to run.
63+
uint64_t targetId;
64+
};
65+
bool fromJSON(const llvm::json::Value &, GotoArguments &, llvm::json::Path);
66+
67+
/// Response to goto request. This is just an acknowledgement, so no
68+
/// body field is required.
69+
using GotoResponseBody = VoidResponse;
70+
71+
/// Arguments for `gotoTargets` request.
72+
struct GotoTargetsArguments {
73+
/// The source location for which the goto targets are determined.
74+
Source source;
75+
76+
/// The line location for which the goto targets are determined.
77+
uint64_t line;
78+
79+
/// The position within `line` for which the goto targets are determined. It
80+
/// is
81+
/// measured in UTF-16 code units and the client capability `columnsStartAt1`
82+
/// determines whether it is 0- or 1-based.
83+
std::optional<uint64_t> column;
84+
};
85+
bool fromJSON(const llvm::json::Value &, GotoTargetsArguments &,
86+
llvm::json::Path);
87+
88+
struct GotoTargetsResponseBody {
89+
/// The possible goto targets of the specified location.
90+
llvm::SmallVector<GotoTarget> targets;
91+
};
92+
llvm::json::Value toJSON(const GotoTargetsResponseBody &);
93+
5794
/// Arguments for `source` request.
5895
struct SourceArguments {
5996
/// Specifies the source content to load. Either `source.path` or

0 commit comments

Comments
 (0)