Skip to content

Commit 9eb5e3e

Browse files
committed
Disable canceled step/next/finish
When `next` command canceled with other breaks, for example, stop at a breakpoint while executing `next` command, the `next` command should be canceled and it should not stop on the next line. However, the current implementation left the TracePoint object for step commands, so it should be disabled.
1 parent eeb5bb6 commit 9eb5e3e

File tree

3 files changed

+66
-5
lines changed

3 files changed

+66
-5
lines changed

lib/debug/session.rb

+11-3
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ module DEBUGGER__
8989
class PostmortemError < RuntimeError; end
9090

9191
class Session
92-
attr_reader :intercepted_sigint_cmd, :process_group
92+
attr_reader :intercepted_sigint_cmd, :process_group, :subsession_id
9393

9494
include Color
9595

@@ -116,6 +116,7 @@ def initialize
116116
@intercepted_sigint_cmd = 'DEFAULT'
117117
@process_group = ProcessGroup.new
118118
@subsession_stack = []
119+
@subsession_id = 0
119120

120121
@frame_map = {} # for DAP: {id => [threadId, frame_depth]} and CDP: {id => frame_depth}
121122
@var_map = {1 => [:globals], } # {id => ...} for DAP
@@ -138,8 +139,14 @@ def active?
138139
!@q_evt.closed?
139140
end
140141

141-
def break_at? file, line
142-
@bps.has_key? [file, line]
142+
def stop_stepping? file, line, subsession_id
143+
if @bps.has_key? [file, line]
144+
true
145+
elsif @subsession_id != subsession_id
146+
true
147+
else
148+
false
149+
end
143150
end
144151

145152
def activate ui = nil, on_fork: false
@@ -1571,6 +1578,7 @@ def get_thread_client th = Thread.current
15711578
end
15721579

15731580
private def enter_subsession
1581+
@subsession_id += 1
15741582
if !@subsession_stack.empty?
15751583
DEBUGGER__.info "Enter subsession (nested #{@subsession_stack.size})"
15761584
else

lib/debug/thread_client.rb

+9-2
Original file line numberDiff line numberDiff line change
@@ -328,10 +328,14 @@ def step_tp iter, events = [:line, :b_return, :return]
328328
@step_tp.disable if @step_tp
329329

330330
thread = Thread.current
331+
subsession_id = SESSION.subsession_id
331332

332333
if SUPPORT_TARGET_THREAD
333334
@step_tp = TracePoint.new(*events){|tp|
334-
next if SESSION.break_at? tp.path, tp.lineno
335+
if SESSION.stop_stepping? tp.path, tp.lineno, subsession_id
336+
tp.disable
337+
next
338+
end
335339
next if !yield(tp.event)
336340
next if tp.path.start_with?(__dir__)
337341
next if tp.path.start_with?('<internal:trace_point>')
@@ -347,7 +351,10 @@ def step_tp iter, events = [:line, :b_return, :return]
347351
else
348352
@step_tp = TracePoint.new(*events){|tp|
349353
next if thread != Thread.current
350-
next if SESSION.break_at? tp.path, tp.lineno
354+
if SESSION.stop_stepping? tp.path, tp.lineno, subsession_id
355+
tp.disable
356+
next
357+
end
351358
next if !yield(tp.event)
352359
next if tp.path.start_with?(__dir__)
353360
next if tp.path.start_with?('<internal:trace_point>')

test/console/control_flow_commands_test.rb

+46
Original file line numberDiff line numberDiff line change
@@ -358,4 +358,50 @@ def test_next_steps_over_rescue_when_raising_from_method
358358
end
359359
end
360360
end
361+
362+
class CancelStepTest < ConsoleTestCase
363+
def program
364+
<<~RUBY
365+
1| def foo m
366+
2| __send__ m
367+
3| end
368+
4| def bar
369+
5| a = :bar1
370+
6| b = :bar2
371+
7| c = :bar3
372+
8| end
373+
9|
374+
10| def baz
375+
11| :baz
376+
12| end
377+
13| foo :bar
378+
14| foo :baz
379+
15| foo :baz
380+
RUBY
381+
end
382+
383+
def test_next_should_be_canceled
384+
debug_code program do
385+
type 'b 13'
386+
type 'b Object#bar'
387+
type 'c'
388+
assert_line_num 13
389+
type 'n'
390+
assert_line_num 5
391+
type 'c'
392+
end
393+
end
394+
395+
def test_finish_should_be_canceled
396+
debug_code program do
397+
type 'b 5'
398+
type 'b 6'
399+
type 'c'
400+
assert_line_num 5
401+
type 'finish'
402+
assert_line_num 6
403+
type 'c'
404+
end
405+
end
406+
end
361407
end

0 commit comments

Comments
 (0)