forked from OSchip/llvm-project
[lldb-vscode] Allow an empty 'breakpoints' field to clear breakpoints.
Per the DAP spec for SetBreakpoints [1], the way to clear breakpoints is: `To clear all breakpoint for a source, specify an empty array.` However, leaving the breakpoints field unset is also a well formed request (note the `breakpoints?:` in the `SetBreakpointsArguments` definition). If it's unset, we have a couple choices: 1. Crash (current behavior) 2. Clear breakpoints 3. Return an error response that the breakpoints field is missing. I propose we do (2) instead of (1), and treat an unset breakpoints field the same as an empty breakpoints field. [1] https://microsoft.github.io/debug-adapter-protocol/specification#Requests_SetBreakpoints Reviewed By: wallace, labath Differential Revision: https://reviews.llvm.org/D88513
This commit is contained in:
parent
655af658c9
commit
ad865d9d10
|
@ -728,24 +728,26 @@ class DebugCommunication(object):
|
|||
def request_setBreakpoints(self, file_path, line_array, condition=None,
|
||||
hitCondition=None):
|
||||
(dir, base) = os.path.split(file_path)
|
||||
breakpoints = []
|
||||
for line in line_array:
|
||||
bp = {'line': line}
|
||||
if condition is not None:
|
||||
bp['condition'] = condition
|
||||
if hitCondition is not None:
|
||||
bp['hitCondition'] = hitCondition
|
||||
breakpoints.append(bp)
|
||||
source_dict = {
|
||||
'name': base,
|
||||
'path': file_path
|
||||
}
|
||||
args_dict = {
|
||||
'source': source_dict,
|
||||
'breakpoints': breakpoints,
|
||||
'lines': '%s' % (line_array),
|
||||
'sourceModified': False,
|
||||
}
|
||||
if line_array is not None:
|
||||
args_dict['lines'] = '%s' % line_array
|
||||
breakpoints = []
|
||||
for line in line_array:
|
||||
bp = {'line': line}
|
||||
if condition is not None:
|
||||
bp['condition'] = condition
|
||||
if hitCondition is not None:
|
||||
bp['hitCondition'] = hitCondition
|
||||
breakpoints.append(bp)
|
||||
args_dict['breakpoints'] = breakpoints
|
||||
|
||||
command_dict = {
|
||||
'command': 'setBreakpoints',
|
||||
'type': 'request',
|
||||
|
|
|
@ -219,6 +219,48 @@ class TestVSCode_setBreakpoints(lldbvscode_testcase.VSCodeTestCaseBase):
|
|||
self.assertTrue(breakpoint['verified'],
|
||||
"expect breakpoint still verified")
|
||||
|
||||
@skipIfWindows
|
||||
@skipIfRemote
|
||||
def test_clear_breakpoints_unset_breakpoints(self):
|
||||
'''Test clearing breakpoints like test_set_and_clear, but clear
|
||||
breakpoints by omitting the breakpoints array instead of sending an
|
||||
empty one.'''
|
||||
lines = [line_number('main.cpp', 'break 12'),
|
||||
line_number('main.cpp', 'break 13')]
|
||||
|
||||
# Visual Studio Code Debug Adaptors have no way to specify the file
|
||||
# without launching or attaching to a process, so we must start a
|
||||
# process in order to be able to set breakpoints.
|
||||
program = self.getBuildArtifact("a.out")
|
||||
self.build_and_launch(program)
|
||||
|
||||
# Set one breakpoint and verify that it got set correctly.
|
||||
response = self.vscode.request_setBreakpoints(self.main_path, lines)
|
||||
line_to_id = {}
|
||||
breakpoints = response['body']['breakpoints']
|
||||
self.assertEquals(len(breakpoints), len(lines),
|
||||
"expect %u source breakpoints" % (len(lines)))
|
||||
for (breakpoint, index) in zip(breakpoints, range(len(lines))):
|
||||
line = breakpoint['line']
|
||||
self.assertTrue(line, lines[index])
|
||||
# Store the "id" of the breakpoint that was set for later
|
||||
line_to_id[line] = breakpoint['id']
|
||||
self.assertTrue(line in lines, "line expected in lines array")
|
||||
self.assertTrue(breakpoint['verified'],
|
||||
"expect breakpoint verified")
|
||||
|
||||
# Now clear all breakpoints for the source file by not setting the
|
||||
# lines array.
|
||||
lines = None
|
||||
response = self.vscode.request_setBreakpoints(self.main_path, lines)
|
||||
breakpoints = response['body']['breakpoints']
|
||||
self.assertEquals(len(breakpoints), 0, "expect no source breakpoints")
|
||||
|
||||
# Verify with the target that all breakpoints have been cleared.
|
||||
response = self.vscode.request_testGetTargetBreakpoints()
|
||||
breakpoints = response['body']['breakpoints']
|
||||
self.assertEquals(len(breakpoints), 0, "expect no source breakpoints")
|
||||
|
||||
@skipIfWindows
|
||||
@skipIfRemote
|
||||
def test_functionality(self):
|
||||
|
|
|
@ -1936,27 +1936,32 @@ void request_setBreakpoints(const llvm::json::Object &request) {
|
|||
|
||||
// Decode the source breakpoint infos for this "setBreakpoints" request
|
||||
SourceBreakpointMap request_bps;
|
||||
for (const auto &bp : *breakpoints) {
|
||||
auto bp_obj = bp.getAsObject();
|
||||
if (bp_obj) {
|
||||
SourceBreakpoint src_bp(*bp_obj);
|
||||
request_bps[src_bp.line] = src_bp;
|
||||
// "breakpoints" may be unset, in which case we treat it the same as being set
|
||||
// to an empty array.
|
||||
if (breakpoints) {
|
||||
for (const auto &bp : *breakpoints) {
|
||||
auto bp_obj = bp.getAsObject();
|
||||
if (bp_obj) {
|
||||
SourceBreakpoint src_bp(*bp_obj);
|
||||
request_bps[src_bp.line] = src_bp;
|
||||
|
||||
// We check if this breakpoint already exists to update it
|
||||
auto existing_source_bps = g_vsc.source_breakpoints.find(path);
|
||||
if (existing_source_bps != g_vsc.source_breakpoints.end()) {
|
||||
const auto &existing_bp = existing_source_bps->second.find(src_bp.line);
|
||||
if (existing_bp != existing_source_bps->second.end()) {
|
||||
existing_bp->second.UpdateBreakpoint(src_bp);
|
||||
AppendBreakpoint(existing_bp->second.bp, response_breakpoints, path,
|
||||
src_bp.line);
|
||||
continue;
|
||||
// We check if this breakpoint already exists to update it
|
||||
auto existing_source_bps = g_vsc.source_breakpoints.find(path);
|
||||
if (existing_source_bps != g_vsc.source_breakpoints.end()) {
|
||||
const auto &existing_bp =
|
||||
existing_source_bps->second.find(src_bp.line);
|
||||
if (existing_bp != existing_source_bps->second.end()) {
|
||||
existing_bp->second.UpdateBreakpoint(src_bp);
|
||||
AppendBreakpoint(existing_bp->second.bp, response_breakpoints, path,
|
||||
src_bp.line);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
// At this point the breakpoint is new
|
||||
src_bp.SetBreakpoint(path.data());
|
||||
AppendBreakpoint(src_bp.bp, response_breakpoints, path, src_bp.line);
|
||||
g_vsc.source_breakpoints[path][src_bp.line] = std::move(src_bp);
|
||||
}
|
||||
// At this point the breakpoint is new
|
||||
src_bp.SetBreakpoint(path.data());
|
||||
AppendBreakpoint(src_bp.bp, response_breakpoints, path, src_bp.line);
|
||||
g_vsc.source_breakpoints[path][src_bp.line] = std::move(src_bp);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue