Skip to content

Commit 0322e45

Browse files
committed
internal/lsp: add a test for gc annotation details code lens
This change adds a test to check the functionality of the GC details code lens, including the behavior of toggling it on and off. This exposed a Windows bug that was mentioned on Slack, which can be fixed by adjusting the URI. I also refactored a bit of the code to use a JSON decoder, which simplifies things a little bit. Change-Id: I7737107cf020fa35bca245485a3b1a1416920fd2 Reviewed-on: https://go-review.googlesource.com/c/tools/+/256940 Trust: Rebecca Stambler <[email protected]> Run-TryBot: Rebecca Stambler <[email protected]> gopls-CI: kokoro <[email protected]> TryBot-Result: Go Bot <[email protected]> Reviewed-by: Peter Weinberger <[email protected]> (cherry picked from commit 0eae6ac) Reviewed-on: https://go-review.googlesource.com/c/tools/+/257598
1 parent 90d1b4e commit 0322e45

File tree

5 files changed

+183
-115
lines changed

5 files changed

+183
-115
lines changed

gopls/internal/regtest/codelens_test.go

Lines changed: 57 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
package regtest
66

77
import (
8+
"runtime"
9+
"strings"
810
"testing"
911

1012
"golang.org/x/tools/internal/lsp/protocol"
@@ -177,24 +179,7 @@ func main() {
177179
`
178180
runner.Run(t, shouldRemoveDep, func(t *testing.T, env *Env) {
179181
env.OpenFile("go.mod")
180-
lenses := env.CodeLens("go.mod")
181-
want := "Tidy module"
182-
var found protocol.CodeLens
183-
for _, lens := range lenses {
184-
if lens.Command.Title == want {
185-
found = lens
186-
break
187-
}
188-
}
189-
if found.Command.Command == "" {
190-
t.Fatalf("did not find lens %q, got %v", want, found.Command)
191-
}
192-
if _, err := env.Editor.Server.ExecuteCommand(env.Ctx, &protocol.ExecuteCommandParams{
193-
Command: found.Command.Command,
194-
Arguments: found.Command.Arguments,
195-
}); err != nil {
196-
t.Fatal(err)
197-
}
182+
env.ExecuteCodeLensCommand("go.mod", source.CommandTidy)
198183
env.Await(NoOutstandingWork())
199184
got := env.ReadWorkspaceFile("go.mod")
200185
const wantGoMod = `module mod.com
@@ -239,19 +224,62 @@ func Foo() {
239224
env.Await(env.DiagnosticAtRegexp("cgo.go", `C\.(fortytwo)`))
240225

241226
// Regenerate cgo, fixing the diagnostic.
242-
lenses := env.CodeLens("cgo.go")
243-
var lens protocol.CodeLens
244-
for _, l := range lenses {
245-
if l.Command.Command == source.CommandRegenerateCgo.Name {
246-
lens = l
227+
env.ExecuteCodeLensCommand("cgo.go", source.CommandRegenerateCgo)
228+
env.Await(EmptyDiagnostics("cgo.go"))
229+
})
230+
}
231+
232+
func TestGCDetails(t *testing.T) {
233+
testenv.NeedsGo1Point(t, 15)
234+
if runtime.GOOS == "android" {
235+
t.Skipf("the gc details code lens doesn't work on Android")
236+
}
237+
238+
const mod = `
239+
-- go.mod --
240+
module mod.com
241+
242+
go 1.15
243+
-- main.go --
244+
package main
245+
246+
import "fmt"
247+
248+
func main() {
249+
var x string
250+
fmt.Println(x)
251+
}
252+
`
253+
withOptions(
254+
EditorConfig{CodeLens: map[string]bool{"gc_details": true}},
255+
).run(t, mod, func(t *testing.T, env *Env) {
256+
env.Await(InitialWorkspaceLoad)
257+
env.OpenFile("main.go")
258+
env.ExecuteCodeLensCommand("main.go", source.CommandToggleDetails)
259+
d := &protocol.PublishDiagnosticsParams{}
260+
env.Await(
261+
OnceMet(
262+
DiagnosticAt("main.go", 6, 12),
263+
ReadDiagnostics("main.go", d),
264+
),
265+
)
266+
// Confirm that the diagnostics come from the gc details code lens.
267+
var found bool
268+
for _, d := range d.Diagnostics {
269+
if d.Severity != protocol.SeverityInformation {
270+
t.Fatalf("unexpected diagnostic severity %v, wanted Information", d.Severity)
271+
}
272+
if strings.Contains(d.Message, "x escapes") {
273+
found = true
247274
}
248275
}
249-
if _, err := env.Editor.Server.ExecuteCommand(env.Ctx, &protocol.ExecuteCommandParams{
250-
Command: lens.Command.Command,
251-
Arguments: lens.Command.Arguments,
252-
}); err != nil {
253-
t.Fatal(err)
276+
if !found {
277+
t.Fatalf(`expected to find diagnostic with message "escape(x escapes to heap)", found none`)
254278
}
255-
env.Await(EmptyDiagnostics("cgo.go"))
279+
// Toggle the GC details code lens again so now it should be off.
280+
env.ExecuteCodeLensCommand("main.go", source.CommandToggleDetails)
281+
env.Await(
282+
EmptyDiagnostics("main.go"),
283+
)
256284
})
257285
}

gopls/internal/regtest/wrappers.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010

1111
"golang.org/x/tools/internal/lsp/fake"
1212
"golang.org/x/tools/internal/lsp/protocol"
13+
"golang.org/x/tools/internal/lsp/source"
1314
errors "golang.org/x/xerrors"
1415
)
1516

@@ -259,6 +260,29 @@ func (e *Env) CodeLens(path string) []protocol.CodeLens {
259260
return lens
260261
}
261262

263+
// ExecuteCodeLensCommand executes the command for the code lens matching the
264+
// given command name.
265+
func (e *Env) ExecuteCodeLensCommand(path string, cmd *source.Command) {
266+
lenses := e.CodeLens(path)
267+
var lens protocol.CodeLens
268+
var found bool
269+
for _, l := range lenses {
270+
if l.Command.Command == cmd.Name {
271+
lens = l
272+
found = true
273+
}
274+
}
275+
if !found {
276+
e.T.Fatalf("found no command with the title %s", cmd.Name)
277+
}
278+
if _, err := e.Editor.Server.ExecuteCommand(e.Ctx, &protocol.ExecuteCommandParams{
279+
Command: lens.Command.Command,
280+
Arguments: lens.Command.Arguments,
281+
}); err != nil {
282+
e.T.Fatal(err)
283+
}
284+
}
285+
262286
// References calls textDocument/references for the given path at the given
263287
// position.
264288
func (e *Env) References(path string, pos fake.Pos) []protocol.Location {

internal/lsp/command.go

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,6 @@ import (
1111
"fmt"
1212
"io"
1313
"io/ioutil"
14-
"log"
15-
"path"
1614
"path/filepath"
1715

1816
"golang.org/x/tools/internal/event"
@@ -203,16 +201,14 @@ func (s *Server) runCommand(ctx context.Context, work *workDone, command *source
203201
if err := source.UnmarshalArgs(args, &fileURI); err != nil {
204202
return err
205203
}
206-
pkgDir := span.URIFromPath(path.Dir(fileURI.Filename()))
204+
pkgDir := span.URIFromPath(filepath.Dir(fileURI.Filename()))
207205
s.gcOptimizationDetailsMu.Lock()
208206
if _, ok := s.gcOptimizatonDetails[pkgDir]; ok {
209207
delete(s.gcOptimizatonDetails, pkgDir)
210208
} else {
211209
s.gcOptimizatonDetails[pkgDir] = struct{}{}
212210
}
213211
s.gcOptimizationDetailsMu.Unlock()
214-
event.Log(ctx, fmt.Sprintf("gc_details %s now %v %v", pkgDir, s.gcOptimizatonDetails[pkgDir],
215-
s.gcOptimizatonDetails))
216212
// need to recompute diagnostics.
217213
// so find the snapshot
218214
sv, err := s.session.ViewOf(fileURI)
@@ -290,7 +286,6 @@ func (s *Server) runTests(ctx context.Context, snapshot source.Snapshot, uri pro
290286
var failedTests int
291287
for _, funcName := range tests {
292288
args := []string{pkgPath, "-v", "-count=1", "-run", fmt.Sprintf("^%s$", funcName)}
293-
log.Printf("running with these args: %v", args)
294289
if err := snapshot.RunGoCommandPiped(ctx, "test", args, out, out); err != nil {
295290
if errors.Is(err, context.Canceled) {
296291
return err

internal/lsp/source/code_lens.go

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -242,14 +242,12 @@ func toggleDetailsCodeLens(ctx context.Context, snapshot Snapshot, fh FileHandle
242242
if err != nil {
243243
return nil, err
244244
}
245-
return []protocol.CodeLens{
246-
{
247-
Range: rng,
248-
Command: protocol.Command{
249-
Title: "Toggle gc annotation details",
250-
Command: CommandToggleDetails.Name,
251-
Arguments: jsonArgs,
252-
},
245+
return []protocol.CodeLens{{
246+
Range: rng,
247+
Command: protocol.Command{
248+
Title: "Toggle gc annotation details",
249+
Command: CommandToggleDetails.Name,
250+
Arguments: jsonArgs,
253251
},
254-
}, nil
252+
}}, nil
255253
}

0 commit comments

Comments
 (0)