blob: 5a01afe240044d539aa2ce901810dfdef3354d4e [file] [log] [blame]
// Copyright 2020 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package misc
import (
"testing"
"golang.org/x/tools/gopls/internal/settings"
"golang.org/x/tools/gopls/internal/test/compare"
. "golang.org/x/tools/gopls/internal/test/integration"
"golang.org/x/tools/gopls/internal/protocol"
)
// A basic test for fillstruct, now that it uses a command and supports resolve edits.
func TestFillStruct(t *testing.T) {
tc := []struct {
name string
capabilities string
wantCommand bool
}{
{"default", "{}", true},
{"no data", `{ "textDocument": {"codeAction": { "resolveSupport": { "properties": ["edit"] } } } }`, true},
{"resolve support", `{ "textDocument": {"codeAction": { "dataSupport": true, "resolveSupport": { "properties": ["edit"] } } } }`, false},
}
const basic = `
-- go.mod --
module mod.com
go 1.14
-- main.go --
package main
type Info struct {
WordCounts map[string]int
Words []string
}
func Foo() {
_ = Info{}
}
`
for _, tt := range tc {
t.Run(tt.name, func(t *testing.T) {
runner := WithOptions(CapabilitiesJSON([]byte(tt.capabilities)))
runner.Run(t, basic, func(t *testing.T, env *Env) {
env.OpenFile("main.go")
fixes, err := env.Editor.CodeActions(env.Ctx, env.RegexpSearch("main.go", "Info{}"), nil, settings.RefactorRewriteFillStruct)
if err != nil {
t.Fatal(err)
}
if len(fixes) != 1 {
t.Fatalf("expected 1 code action, got %v", len(fixes))
}
if tt.wantCommand {
if fixes[0].Command == nil || fixes[0].Data != nil {
t.Errorf("expected code action to have command not data, got %v", fixes[0])
}
} else {
if fixes[0].Command != nil || fixes[0].Data == nil {
t.Errorf("expected code action to have command not data, got %v", fixes[0])
}
}
// Apply the code action (handles resolving the code action), and check that the result is correct.
if err := env.Editor.RefactorRewrite(env.Ctx, env.RegexpSearch("main.go", "Info{}")); err != nil {
t.Fatal(err)
}
want := `package main
type Info struct {
WordCounts map[string]int
Words []string
}
func Foo() {
_ = Info{
WordCounts: map[string]int{},
Words: []string{},
}
}
`
if got := env.BufferText("main.go"); got != want {
t.Fatalf("TestFillStruct failed:\n%s", compare.Text(want, got))
}
})
})
}
}
func TestFillReturns(t *testing.T) {
const files = `
-- go.mod --
module mod.com
go 1.12
-- main.go --
package main
func Foo() error {
return
}
`
Run(t, files, func(t *testing.T, env *Env) {
env.OpenFile("main.go")
var d protocol.PublishDiagnosticsParams
env.AfterChange(
// The error message here changed in 1.18; "return values" covers both forms.
Diagnostics(env.AtRegexp("main.go", `return`), WithMessage("return values")),
ReadDiagnostics("main.go", &d),
)
var quickFixes []*protocol.CodeAction
for _, act := range env.CodeActionForFile("main.go", d.Diagnostics) {
if act.Kind == protocol.QuickFix {
act := act // remove in go1.22
quickFixes = append(quickFixes, &act)
}
}
if len(quickFixes) != 1 {
t.Fatalf("expected 1 quick fix, got %d:\n%v", len(quickFixes), quickFixes)
}
env.ApplyQuickFixes("main.go", d.Diagnostics)
env.AfterChange(NoDiagnostics(ForFile("main.go")))
})
}
func TestUnusedParameter_Issue63755(t *testing.T) {
// This test verifies the fix for #63755, where codeActions panicked on parameters
// of functions with no function body.
// We should not detect parameters as unused for external functions.
const files = `
-- go.mod --
module unused.mod
go 1.18
-- external.go --
package external
func External(z int)
func _() {
External(1)
}
`
Run(t, files, func(t *testing.T, env *Env) {
env.OpenFile("external.go")
_, err := env.Editor.CodeAction(env.Ctx, env.RegexpSearch("external.go", "z"), nil, protocol.CodeActionUnknownTrigger)
if err != nil {
t.Fatal(err)
}
// yay, no panic
})
}