From 776b86ffc2259ca76cfa95a4dd891e5aad0f0616 Mon Sep 17 00:00:00 2001 From: Suzy Mueller Date: Tue, 20 Jul 2021 10:51:08 -0500 Subject: [PATCH] service/dap: send continued event before step response (#2594) * service/dap: send continued event before step response Send the continued event before the step response to make sure that there is no time where the client believes that only a single thread is running. Updates golang/vscode-go#1617 * move to helper --- service/dap/daptest/gen/main.go | 14 +++++++------- service/dap/daptest/resp.go | 30 +++++++++++++++--------------- service/dap/server.go | 28 ++++++++++++++++------------ 3 files changed, 38 insertions(+), 34 deletions(-) diff --git a/service/dap/daptest/gen/main.go b/service/dap/daptest/gen/main.go index b7801cef..13010d4f 100644 --- a/service/dap/daptest/gen/main.go +++ b/service/dap/daptest/gen/main.go @@ -39,16 +39,16 @@ func (c *Client) Expect{{.}}(t *testing.T) *dap.{{.}} { // Check{{.}} fails the test if m is not *{{.}}. func (c *Client) Check{{.}}(t *testing.T, m dap.Message) *dap.{{.}} { - t.Helper() + t.Helper(){{if or (or (eq . "StepInResponse") (eq . "StepOutResponse")) (eq . "NextResponse") }} + _, ok := m.(*dap.ContinuedEvent) + if !ok { + t.Fatalf("got %#v, want *dap.ContinuedEvent", m) + } + m = c.ExpectMessage(t){{end}} r, ok := m.(*dap.{{.}}) if !ok { t.Fatalf("got %#v, want *dap.{{.}}", m) - }{{if or (or (eq . "StepInResponse") (eq . "StepOutResponse")) (eq . "NextResponse") }} - m = c.ExpectMessage(t) - _, ok = m.(*dap.ContinuedEvent) - if !ok { - t.Fatalf("got %#v, want *dap.ContinuedEvent", m) - }{{end}} + } return r }{{end}} `)) diff --git a/service/dap/daptest/resp.go b/service/dap/daptest/resp.go index dfac8636..6501a51b 100644 --- a/service/dap/daptest/resp.go +++ b/service/dap/daptest/resp.go @@ -488,15 +488,15 @@ func (c *Client) ExpectNextResponse(t *testing.T) *dap.NextResponse { // CheckNextResponse fails the test if m is not *NextResponse. func (c *Client) CheckNextResponse(t *testing.T, m dap.Message) *dap.NextResponse { t.Helper() + _, ok := m.(*dap.ContinuedEvent) + if !ok { + t.Fatalf("got %#v, want *dap.ContinuedEvent", m) + } + m = c.ExpectMessage(t) r, ok := m.(*dap.NextResponse) if !ok { t.Fatalf("got %#v, want *dap.NextResponse", m) } - m = c.ExpectMessage(t) - _, ok = m.(*dap.ContinuedEvent) - if !ok { - t.Fatalf("got %#v, want *dap.ContinuedEvent", m) - } return r } @@ -907,15 +907,15 @@ func (c *Client) ExpectStepInResponse(t *testing.T) *dap.StepInResponse { // CheckStepInResponse fails the test if m is not *StepInResponse. func (c *Client) CheckStepInResponse(t *testing.T, m dap.Message) *dap.StepInResponse { t.Helper() + _, ok := m.(*dap.ContinuedEvent) + if !ok { + t.Fatalf("got %#v, want *dap.ContinuedEvent", m) + } + m = c.ExpectMessage(t) r, ok := m.(*dap.StepInResponse) if !ok { t.Fatalf("got %#v, want *dap.StepInResponse", m) } - m = c.ExpectMessage(t) - _, ok = m.(*dap.ContinuedEvent) - if !ok { - t.Fatalf("got %#v, want *dap.ContinuedEvent", m) - } return r } @@ -948,15 +948,15 @@ func (c *Client) ExpectStepOutResponse(t *testing.T) *dap.StepOutResponse { // CheckStepOutResponse fails the test if m is not *StepOutResponse. func (c *Client) CheckStepOutResponse(t *testing.T, m dap.Message) *dap.StepOutResponse { t.Helper() + _, ok := m.(*dap.ContinuedEvent) + if !ok { + t.Fatalf("got %#v, want *dap.ContinuedEvent", m) + } + m = c.ExpectMessage(t) r, ok := m.(*dap.StepOutResponse) if !ok { t.Fatalf("got %#v, want *dap.StepOutResponse", m) } - m = c.ExpectMessage(t) - _, ok = m.(*dap.ContinuedEvent) - if !ok { - t.Fatalf("got %#v, want *dap.ContinuedEvent", m) - } return r } diff --git a/service/dap/server.go b/service/dap/server.go index 25e50e03..1bb02e62 100644 --- a/service/dap/server.go +++ b/service/dap/server.go @@ -1510,24 +1510,37 @@ func (s *Server) onAttachRequest(request *dap.AttachRequest) { // onNextRequest handles 'next' request. // This is a mandatory request to support. func (s *Server) onNextRequest(request *dap.NextRequest, asyncSetupDone chan struct{}) { - s.send(&dap.NextResponse{Response: *newResponse(request.Request)}) + s.sendStepResponse(request.Arguments.ThreadId, &dap.NextResponse{Response: *newResponse(request.Request)}) s.doStepCommand(api.Next, request.Arguments.ThreadId, asyncSetupDone) } // onStepInRequest handles 'stepIn' request // This is a mandatory request to support. func (s *Server) onStepInRequest(request *dap.StepInRequest, asyncSetupDone chan struct{}) { - s.send(&dap.StepInResponse{Response: *newResponse(request.Request)}) + s.sendStepResponse(request.Arguments.ThreadId, &dap.StepInResponse{Response: *newResponse(request.Request)}) s.doStepCommand(api.Step, request.Arguments.ThreadId, asyncSetupDone) } // onStepOutRequest handles 'stepOut' request // This is a mandatory request to support. func (s *Server) onStepOutRequest(request *dap.StepOutRequest, asyncSetupDone chan struct{}) { - s.send(&dap.StepOutResponse{Response: *newResponse(request.Request)}) + s.sendStepResponse(request.Arguments.ThreadId, &dap.StepOutResponse{Response: *newResponse(request.Request)}) s.doStepCommand(api.StepOut, request.Arguments.ThreadId, asyncSetupDone) } +func (s *Server) sendStepResponse(threadId int, message dap.Message) { + // All of the threads will be continued by this request, so we need to send + // a continued event so the UI can properly reflect the current state. + s.send(&dap.ContinuedEvent{ + Event: *newEvent("continued"), + Body: dap.ContinuedEventBody{ + ThreadId: threadId, + AllThreadsContinued: true, + }, + }) + s.send(message) +} + func stoppedGoroutineID(state *api.DebuggerState) (id int) { if state.SelectedGoroutine != nil { id = state.SelectedGoroutine.ID @@ -1544,15 +1557,6 @@ func stoppedGoroutineID(state *api.DebuggerState) (id int) { // due to an error, so the server is ready to receive new requests. func (s *Server) doStepCommand(command string, threadId int, asyncSetupDone chan struct{}) { defer s.asyncCommandDone(asyncSetupDone) - // All of the threads will be continued by this request, so we need to send - // a continued event so the UI can properly reflect the current state. - s.send(&dap.ContinuedEvent{ - Event: *newEvent("continued"), - Body: dap.ContinuedEventBody{ - ThreadId: threadId, - AllThreadsContinued: true, - }, - }) _, err := s.debugger.Command(&api.DebuggerCommand{Name: api.SwitchGoroutine, GoroutineID: threadId}, nil) if err != nil { s.log.Errorf("Error switching goroutines while stepping: %v", err)