Skip to content

Commit 9818120

Browse files
authored
[lldb-dap] Migrating breakpointLocations request to use typed RequestHandler (#137426)
* Migrating breakpointLocations request to use typed RequestHandle * Preliminary step in order to implement assembly source breakpoints
1 parent 7aed77e commit 9818120

File tree

7 files changed

+125
-139
lines changed

7 files changed

+125
-139
lines changed

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

Lines changed: 20 additions & 136 deletions
Original file line numberDiff line numberDiff line change
@@ -9,136 +9,22 @@
99
#include "DAP.h"
1010
#include "JSONUtils.h"
1111
#include "RequestHandler.h"
12+
#include <vector>
1213

1314
namespace lldb_dap {
1415

15-
// "BreakpointLocationsRequest": {
16-
// "allOf": [ { "$ref": "#/definitions/Request" }, {
17-
// "type": "object",
18-
// "description": "The `breakpointLocations` request returns all possible
19-
// locations for source breakpoints in a given range.\nClients should only
20-
// call this request if the corresponding capability
21-
// `supportsBreakpointLocationsRequest` is true.",
22-
// "properties": {
23-
// "command": {
24-
// "type": "string",
25-
// "enum": [ "breakpointLocations" ]
26-
// },
27-
// "arguments": {
28-
// "$ref": "#/definitions/BreakpointLocationsArguments"
29-
// }
30-
// },
31-
// "required": [ "command" ]
32-
// }]
33-
// },
34-
// "BreakpointLocationsArguments": {
35-
// "type": "object",
36-
// "description": "Arguments for `breakpointLocations` request.",
37-
// "properties": {
38-
// "source": {
39-
// "$ref": "#/definitions/Source",
40-
// "description": "The source location of the breakpoints; either
41-
// `source.path` or `source.sourceReference` must be specified."
42-
// },
43-
// "line": {
44-
// "type": "integer",
45-
// "description": "Start line of range to search possible breakpoint
46-
// locations in. If only the line is specified, the request returns all
47-
// possible locations in that line."
48-
// },
49-
// "column": {
50-
// "type": "integer",
51-
// "description": "Start position within `line` to search possible
52-
// breakpoint locations in. It is measured in UTF-16 code units and the
53-
// client capability `columnsStartAt1` determines whether it is 0- or
54-
// 1-based. If no column is given, the first position in the start line is
55-
// assumed."
56-
// },
57-
// "endLine": {
58-
// "type": "integer",
59-
// "description": "End line of range to search possible breakpoint
60-
// locations in. If no end line is given, then the end line is assumed to
61-
// be the start line."
62-
// },
63-
// "endColumn": {
64-
// "type": "integer",
65-
// "description": "End position within `endLine` to search possible
66-
// breakpoint locations in. It is measured in UTF-16 code units and the
67-
// client capability `columnsStartAt1` determines whether it is 0- or
68-
// 1-based. If no end column is given, the last position in the end line
69-
// is assumed."
70-
// }
71-
// },
72-
// "required": [ "source", "line" ]
73-
// },
74-
// "BreakpointLocationsResponse": {
75-
// "allOf": [ { "$ref": "#/definitions/Response" }, {
76-
// "type": "object",
77-
// "description": "Response to `breakpointLocations` request.\nContains
78-
// possible locations for source breakpoints.",
79-
// "properties": {
80-
// "body": {
81-
// "type": "object",
82-
// "properties": {
83-
// "breakpoints": {
84-
// "type": "array",
85-
// "items": {
86-
// "$ref": "#/definitions/BreakpointLocation"
87-
// },
88-
// "description": "Sorted set of possible breakpoint locations."
89-
// }
90-
// },
91-
// "required": [ "breakpoints" ]
92-
// }
93-
// },
94-
// "required": [ "body" ]
95-
// }]
96-
// },
97-
// "BreakpointLocation": {
98-
// "type": "object",
99-
// "description": "Properties of a breakpoint location returned from the
100-
// `breakpointLocations` request.",
101-
// "properties": {
102-
// "line": {
103-
// "type": "integer",
104-
// "description": "Start line of breakpoint location."
105-
// },
106-
// "column": {
107-
// "type": "integer",
108-
// "description": "The start position of a breakpoint location. Position
109-
// is measured in UTF-16 code units and the client capability
110-
// `columnsStartAt1` determines whether it is 0- or 1-based."
111-
// },
112-
// "endLine": {
113-
// "type": "integer",
114-
// "description": "The end line of breakpoint location if the location
115-
// covers a range."
116-
// },
117-
// "endColumn": {
118-
// "type": "integer",
119-
// "description": "The end position of a breakpoint location (if the
120-
// location covers a range). Position is measured in UTF-16 code units and
121-
// the client capability `columnsStartAt1` determines whether it is 0- or
122-
// 1-based."
123-
// }
124-
// },
125-
// "required": [ "line" ]
126-
// },
127-
void BreakpointLocationsRequestHandler::operator()(
128-
const llvm::json::Object &request) const {
129-
llvm::json::Object response;
130-
FillResponse(request, response);
131-
auto *arguments = request.getObject("arguments");
132-
auto *source = arguments->getObject("source");
133-
std::string path = GetString(source, "path").value_or("").str();
134-
const auto start_line = GetInteger<uint64_t>(arguments, "line")
135-
.value_or(LLDB_INVALID_LINE_NUMBER);
136-
const auto start_column = GetInteger<uint64_t>(arguments, "column")
137-
.value_or(LLDB_INVALID_COLUMN_NUMBER);
138-
const auto end_line =
139-
GetInteger<uint64_t>(arguments, "endLine").value_or(start_line);
140-
const auto end_column = GetInteger<uint64_t>(arguments, "endColumn")
141-
.value_or(std::numeric_limits<uint64_t>::max());
16+
/// The `breakpointLocations` request returns all possible locations for source
17+
/// breakpoints in a given range. Clients should only call this request if the
18+
/// corresponding capability `supportsBreakpointLocationsRequest` is true.
19+
llvm::Expected<protocol::BreakpointLocationsResponseBody>
20+
BreakpointLocationsRequestHandler::Run(
21+
const protocol::BreakpointLocationsArguments &args) const {
22+
std::string path = args.source.path.value_or("");
23+
uint32_t start_line = args.line;
24+
uint32_t start_column = args.column.value_or(LLDB_INVALID_COLUMN_NUMBER);
25+
uint32_t end_line = args.endLine.value_or(start_line);
26+
uint32_t end_column =
27+
args.endColumn.value_or(std::numeric_limits<uint32_t>::max());
14228

14329
lldb::SBFileSpec file_spec(path.c_str(), true);
14430
lldb::SBSymbolContextList compile_units =
@@ -191,18 +77,16 @@ void BreakpointLocationsRequestHandler::operator()(
19177
std::sort(locations.begin(), locations.end());
19278
locations.erase(llvm::unique(locations), locations.end());
19379

194-
llvm::json::Array locations_json;
80+
std::vector<protocol::BreakpointLocation> breakpoint_locations;
19581
for (auto &l : locations) {
196-
llvm::json::Object location;
197-
location.try_emplace("line", l.first);
198-
location.try_emplace("column", l.second);
199-
locations_json.emplace_back(std::move(location));
82+
protocol::BreakpointLocation lc;
83+
lc.line = l.first;
84+
lc.column = l.second;
85+
breakpoint_locations.push_back(std::move(lc));
20086
}
20187

202-
llvm::json::Object body;
203-
body.try_emplace("breakpoints", std::move(locations_json));
204-
response.try_emplace("body", std::move(body));
205-
dap.SendJSON(llvm::json::Value(std::move(response)));
88+
return protocol::BreakpointLocationsResponseBody{
89+
/*breakpoints=*/std::move(breakpoint_locations)};
20690
}
20791

20892
} // namespace lldb_dap

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

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -206,14 +206,18 @@ class AttachRequestHandler
206206
void PostRun() const override;
207207
};
208208

209-
class BreakpointLocationsRequestHandler : public LegacyRequestHandler {
209+
class BreakpointLocationsRequestHandler
210+
: public RequestHandler<
211+
protocol::BreakpointLocationsArguments,
212+
llvm::Expected<protocol::BreakpointLocationsResponseBody>> {
210213
public:
211-
using LegacyRequestHandler::LegacyRequestHandler;
214+
using RequestHandler::RequestHandler;
212215
static llvm::StringLiteral GetCommand() { return "breakpointLocations"; }
213216
FeatureSet GetSupportedFeatures() const override {
214217
return {protocol::eAdapterFeatureBreakpointLocationsRequest};
215218
}
216-
void operator()(const llvm::json::Object &request) const override;
219+
llvm::Expected<protocol::BreakpointLocationsResponseBody>
220+
Run(const protocol::BreakpointLocationsArguments &args) const override;
217221
};
218222

219223
class CompletionsRequestHandler : public LegacyRequestHandler {

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

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,23 @@ bool fromJSON(const json::Value &Params, Configuration &C, json::Path P) {
248248
parseTimeout(Params, C.timeout, P);
249249
}
250250

251+
bool fromJSON(const json::Value &Params, BreakpointLocationsArguments &BLA,
252+
json::Path P) {
253+
json::ObjectMapper O(Params, P);
254+
return O && O.map("source", BLA.source) && O.map("line", BLA.line) &&
255+
O.mapOptional("column", BLA.column) &&
256+
O.mapOptional("endLine", BLA.endLine) &&
257+
O.mapOptional("endColumn", BLA.endColumn);
258+
}
259+
260+
llvm::json::Value toJSON(const BreakpointLocationsResponseBody &BLRB) {
261+
llvm::json::Array breakpoints_json;
262+
for (const auto &breakpoint : BLRB.breakpoints) {
263+
breakpoints_json.push_back(toJSON(breakpoint));
264+
}
265+
return llvm::json::Object{{"breakpoints", std::move(breakpoints_json)}};
266+
}
267+
251268
bool fromJSON(const json::Value &Params, LaunchRequestArguments &LRA,
252269
json::Path P) {
253270
json::ObjectMapper O(Params, P);

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

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#include <cstdint>
3232
#include <optional>
3333
#include <string>
34+
#include <vector>
3435

3536
namespace lldb_dap::protocol {
3637

@@ -521,6 +522,43 @@ bool fromJSON(const llvm::json::Value &, StepOutArguments &, llvm::json::Path);
521522
/// body field is required.
522523
using StepOutResponse = VoidResponse;
523524

525+
/// Arguments for `breakpointLocations` request.
526+
struct BreakpointLocationsArguments {
527+
/// The source location of the breakpoints; either `source.path` or
528+
/// `source.sourceReference` must be specified.
529+
Source source;
530+
531+
/// Start line of range to search possible breakpoint locations in. If only
532+
/// the line is specified, the request returns all possible locations in that
533+
/// line.
534+
uint32_t line;
535+
536+
/// Start position within `line` to search possible breakpoint locations in.
537+
/// It is measured in UTF-16 code units and the client capability
538+
/// `columnsStartAt1` determines whether it is 0- or 1-based. If no column is
539+
/// given, the first position in the start line is assumed.
540+
std::optional<uint32_t> column;
541+
542+
/// End line of range to search possible breakpoint locations in. If no end
543+
/// line is given, then the end line is assumed to be the start line.
544+
std::optional<uint32_t> endLine;
545+
546+
/// End position within `endLine` to search possible breakpoint locations in.
547+
/// It is measured in UTF-16 code units and the client capability
548+
/// `columnsStartAt1` determines whether it is 0- or 1-based. If no end column
549+
/// is given, the last position in the end line is assumed.
550+
std::optional<uint32_t> endColumn;
551+
};
552+
bool fromJSON(const llvm::json::Value &, BreakpointLocationsArguments &,
553+
llvm::json::Path);
554+
555+
/// Response to `breakpointLocations` request.
556+
struct BreakpointLocationsResponseBody {
557+
/// Content of the source reference.
558+
std::vector<BreakpointLocation> breakpoints;
559+
};
560+
llvm::json::Value toJSON(const BreakpointLocationsResponseBody &);
561+
524562
} // namespace lldb_dap::protocol
525563

526564
#endif

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

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,4 +260,18 @@ bool fromJSON(const llvm::json::Value &Params, ValueFormat &VF,
260260
return O && O.mapOptional("hex", VF.hex);
261261
}
262262

263+
json::Value toJSON(const BreakpointLocation &B) {
264+
json::Object result;
265+
266+
result.insert({"line", B.line});
267+
if (B.column)
268+
result.insert({"column", *B.column});
269+
if (B.endLine)
270+
result.insert({"endLine", *B.endLine});
271+
if (B.endColumn)
272+
result.insert({"endColumn", *B.endColumn});
273+
274+
return result;
275+
}
276+
263277
} // namespace lldb_dap::protocol

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

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,27 @@ struct ValueFormat {
329329
};
330330
bool fromJSON(const llvm::json::Value &, ValueFormat &, llvm::json::Path);
331331

332+
/// Properties of a breakpoint location returned from the `breakpointLocations`
333+
/// request.
334+
struct BreakpointLocation {
335+
/// Start line of breakpoint location.
336+
uint32_t line;
337+
338+
/// The start position of a breakpoint location. Position is measured in
339+
/// UTF-16 code units and the client capability `columnsStartAt1` determines
340+
/// whether it is 0- or 1-based.
341+
std::optional<uint32_t> column;
342+
343+
/// The end line of breakpoint location if the location covers a range.
344+
std::optional<uint32_t> endLine;
345+
346+
/// The end position of a breakpoint location (if the location covers a
347+
/// range). Position is measured in UTF-16 code units and the client
348+
/// capability `columnsStartAt1` determines whether it is 0- or 1-based.
349+
std::optional<uint32_t> endColumn;
350+
};
351+
llvm::json::Value toJSON(const BreakpointLocation &);
352+
332353
} // namespace lldb_dap::protocol
333354

334355
#endif

llvm/include/llvm/Support/JSON.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -776,6 +776,14 @@ inline bool fromJSON(const Value &E, bool &Out, Path P) {
776776
P.report("expected boolean");
777777
return false;
778778
}
779+
inline bool fromJSON(const Value &E, unsigned int &Out, Path P) {
780+
if (auto S = E.getAsInteger()) {
781+
Out = *S;
782+
return true;
783+
}
784+
P.report("expected integer");
785+
return false;
786+
}
779787
inline bool fromJSON(const Value &E, uint64_t &Out, Path P) {
780788
if (auto S = E.getAsUINT64()) {
781789
Out = *S;

0 commit comments

Comments
 (0)