From c534554607c4a35ed63ad1cef428ada20f378502 Mon Sep 17 00:00:00 2001 From: Suzy Mueller Date: Fri, 16 Jul 2021 12:09:07 -0400 Subject: [PATCH] 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 --- service/dap/daptest/gen/main.go | 14 ++++++------- service/dap/daptest/resp.go | 24 +++++++++++----------- service/dap/server.go | 36 ++++++++++++++++++++++++--------- 3 files changed, 46 insertions(+), 28 deletions(-) diff --git a/service/dap/daptest/gen/main.go b/service/dap/daptest/gen/main.go index b7801cef74..13010d4fc7 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 dfac863612..6501a51b30 100644 --- a/service/dap/daptest/resp.go +++ b/service/dap/daptest/resp.go @@ -488,14 +488,14 @@ 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() - r, ok := m.(*dap.NextResponse) + _, ok := m.(*dap.ContinuedEvent) if !ok { - t.Fatalf("got %#v, want *dap.NextResponse", m) + t.Fatalf("got %#v, want *dap.ContinuedEvent", m) } m = c.ExpectMessage(t) - _, ok = m.(*dap.ContinuedEvent) + r, ok := m.(*dap.NextResponse) if !ok { - t.Fatalf("got %#v, want *dap.ContinuedEvent", m) + t.Fatalf("got %#v, want *dap.NextResponse", m) } return r } @@ -907,14 +907,14 @@ 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() - r, ok := m.(*dap.StepInResponse) + _, ok := m.(*dap.ContinuedEvent) if !ok { - t.Fatalf("got %#v, want *dap.StepInResponse", m) + t.Fatalf("got %#v, want *dap.ContinuedEvent", m) } m = c.ExpectMessage(t) - _, ok = m.(*dap.ContinuedEvent) + r, ok := m.(*dap.StepInResponse) if !ok { - t.Fatalf("got %#v, want *dap.ContinuedEvent", m) + t.Fatalf("got %#v, want *dap.StepInResponse", m) } return r } @@ -948,14 +948,14 @@ 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() - r, ok := m.(*dap.StepOutResponse) + _, ok := m.(*dap.ContinuedEvent) if !ok { - t.Fatalf("got %#v, want *dap.StepOutResponse", m) + t.Fatalf("got %#v, want *dap.ContinuedEvent", m) } m = c.ExpectMessage(t) - _, ok = m.(*dap.ContinuedEvent) + r, ok := m.(*dap.StepOutResponse) if !ok { - t.Fatalf("got %#v, want *dap.ContinuedEvent", m) + t.Fatalf("got %#v, want *dap.StepOutResponse", m) } return r } diff --git a/service/dap/server.go b/service/dap/server.go index cec104ad14..a425969a21 100644 --- a/service/dap/server.go +++ b/service/dap/server.go @@ -1458,6 +1458,15 @@ 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{}) { + // 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: request.Arguments.ThreadId, + AllThreadsContinued: true, + }, + }) s.send(&dap.NextResponse{Response: *newResponse(request.Request)}) s.doStepCommand(api.Next, request.Arguments.ThreadId, asyncSetupDone) } @@ -1465,6 +1474,15 @@ func (s *Server) onNextRequest(request *dap.NextRequest, asyncSetupDone chan str // onStepInRequest handles 'stepIn' request // This is a mandatory request to support. func (s *Server) onStepInRequest(request *dap.StepInRequest, asyncSetupDone chan struct{}) { + // 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: request.Arguments.ThreadId, + AllThreadsContinued: true, + }, + }) s.send(&dap.StepInResponse{Response: *newResponse(request.Request)}) s.doStepCommand(api.Step, request.Arguments.ThreadId, asyncSetupDone) } @@ -1472,6 +1490,15 @@ func (s *Server) onStepInRequest(request *dap.StepInRequest, asyncSetupDone chan // onStepOutRequest handles 'stepOut' request // This is a mandatory request to support. func (s *Server) onStepOutRequest(request *dap.StepOutRequest, asyncSetupDone chan struct{}) { + // 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: request.Arguments.ThreadId, + AllThreadsContinued: true, + }, + }) s.send(&dap.StepOutResponse{Response: *newResponse(request.Request)}) s.doStepCommand(api.StepOut, request.Arguments.ThreadId, asyncSetupDone) } @@ -1492,15 +1519,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)