Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

x/tools/gopls: code action "Implement" is not listed #64114

Closed
tttoad opened this issue Nov 14, 2023 · 6 comments
Closed

x/tools/gopls: code action "Implement" is not listed #64114

tttoad opened this issue Nov 14, 2023 · 6 comments
Labels
gopls Issues related to the Go language server, gopls. Tools This label describes issues relating to any tools in the x/tools repository.
Milestone

Comments

@tttoad
Copy link

tttoad commented Nov 14, 2023

gopls version

golang.org/x/tools/gopls v0.14.1
golang.org/x/tools/gopls@v0.14.1 h1:XaTETpi7Q67XO8nftquJitcx+9c2bPclO8Kz2sBVvec=
github.com/BurntSushi/toml@v1.2.1 h1:9F2/+DoOYIOksmaJFPw1tGFy1eDnIJXg+UHjuD8lTak=
github.com/google/go-cmp@v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/sergi/go-diff@v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
golang.org/x/exp/typeparams@v0.0.0-20221212164502-fae10dda9338 h1:2O2DON6y3XMJiQRAS1UWU+54aec2uopH3x7MAiqGW
6Y=
golang.org/x/mod@v0.13.0 h1:I/DsJXRlw/8l/0c24sM9yb0T4z9liZTduXvdAWYiysY=
golang.org/x/sync@v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ=
golang.org/x/sys@v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
golang.org/x/telemetry@v0.0.0-20231011160506-788d5629a052 h1:1baVNneD/IRxmu8JQdBuki78zUqBtZxq8smZXQj0X2Y=
golang.org/x/text@v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
golang.org/x/tools@v0.14.1-0.20231026192422-8b5abd452b28 h1:5YgdZAe2w0x3Xrjv0+GXrI0jvm7qCQK/ySGFfiEHMfU=
golang.org/x/vuln@v1.0.1 h1:KUas02EjQK5LTuIx1OylBQdKKZ9jeugs+HiqO5HormU=
honnef.co/go/tools@v0.4.5 h1:YGD4H+SuIOOqsyoLOpZDWcieM28W47/zRO7f+9V3nvo=
mvdan.cc/gofumpt@v0.4.0 h1:JVf4NN1mIpHogBj7ABpgOyZc65/UUOkKQFkoURsz4MM=
mvdan.cc/xurls/v2@v2.4.0 h1:tzxjVAj+wSBmDcF6zBB7/myTy3gX9xvi8Tyr28AuQgc=
go: go1.20.7

go env

GO111MODULE=""
GOARCH="arm64"
GOBIN=""
GOCACHE="/Users/toad/Library/Caches/go-build"
GOENV="/Users/toad/Library/Application Support/go/env"
GOEXE=""
GOEXPERIMENT=""
GOFLAGS=""
GOHOSTARCH="arm64"
GOHOSTOS="darwin"
GOINSECURE=""
GOMODCACHE="/Users/toad/work/pkg/mod"
GONOPROXY=""
GONOSUMDB=""
GOOS="darwin"
GOPATH="/Users/toad/work"
GOPRIVATE=""
GOPROXY="https://goproxy.io,direct/"
GOROOT="/Users/toad/go/go1.20.7"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/Users/toad/go/go1.20.7/pkg/tool/darwin_arm64"
GOVCS=""
GOVERSION="go1.20.7"
GCCGO="gccgo"
AR="ar"
CC="clang"
CXX="clang++"
CGO_ENABLED="1"
GOMOD="/Users/toad/work/demo5/go.mod"
GOWORK=""
CGO_CFLAGS="-O2 -g"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-O2 -g"
CGO_FFLAGS="-O2 -g"
CGO_LDFLAGS="-O2 -g"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -arch arm64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-pre
fix-map=/var/folders/g1/tgmnlrdn3vxgv08kdgh9vpkw0000gn/T/go-build1758453573=/tmp/go-build -gno-record-gcc-switc
hes -fno-common"

What did you do?

package test

import "io"

type IOPlus interface {
	io.ReadWriter
	RRRR() error
	WWWW() error
}

type ioPlus struct {
	*rrr
}

type rrr struct{}

func (r *rrr) RRRR(str string) error {
	return nil
}

var _ IOPlus = (*ioPlus)(nil)

when code action is called at (*ioPlus)(nil), Implement IOPlus is not listed.
Maybe caused by anonymous objects having functions with the same name but different arguments.

What did you expect to see?

ackage test

import "io"

type IOPlus interface {
	io.ReadWriter
	RRRR() error
	WWWW() error
}

type ioPlus struct {
	*rrr
}

// RRRR implements IOPlus.
func (*ioPlus) RRRR() error {
	panic("unimplemented")
}

// Read implements IOPlus.
func (*ioPlus) Read(p []byte) (n int, err error) {
	panic("unimplemented")
}

// WWWW implements IOPlus.
func (*ioPlus) WWWW() error {
	panic("unimplemented")
}

// Write implements IOPlus.
func (*ioPlus) Write(p []byte) (n int, err error) {
	panic("unimplemented")
}

type rrr struct{}

func (r *rrr) RRRR(str string) error {
	return nil
}

var _ IOPlus = (*ioPlus)(nil)
@tttoad tttoad added gopls Issues related to the Go language server, gopls. Tools This label describes issues relating to any tools in the x/tools repository. labels Nov 14, 2023
@gopherbot gopherbot added this to the Unreleased milestone Nov 14, 2023
@suzmue suzmue modified the milestones: Unreleased, gopls/backlog Nov 16, 2023
@adonovan
Copy link
Member

Yes, it looks like the presence of a method of the same name but a different signature defeats the code action, spuriously in this case because the method is promoted for an embedded field. In this case it would be safe for the code action to proceed, though it is potentially a little confusing that the new method would shadow another one. It might be worth emitting a comment into the code in this case, something like:

// RRRR implements IOPlus.
// Subtle: this method shadows the method (*rrr).RRRR of ioPlus.rrr.
func (*ioPlus) RRRR() error {
	panic("unimplemented")
}

I would accept a CL that implemented it, if you're willing to have a go at it.

@gopherbot
Copy link

Change https://go.dev/cl/544915 mentions this issue: gopls/Stub: support for method generation with same name but different receiver

@tttoad
Copy link
Author

tttoad commented Nov 24, 2023

@adonovan I need some help. I'm adding stub's CodeAction for testing. But the code below can't get the code... Is there any examples or documentation for this?

func TestImplement_Issuse64114(t *testing.T) {
	const basic = `
-- go.mod --
module stub.com

go 1.19
-- main.go --
package main

type TestStructOne struct{}

type WriteTest interface {
	Write(s string)
}

var _ WriteTest = (*TestStructTwo)(nil) // want "Implement WriteTest"

type TestStructTwo struct {
	*TestStructOne
}
`
	Run(t, basic, func(t *testing.T, env *Env) {
		env.OpenFile("main.go")
		code, err := env.Editor.CodeAction(env.Ctx, env.RegexpSearch("main.go", "(nil)"), nil)
		if err != nil {
			t.Fatal(err)
		}
		fmt.Println(code)
		err = env.Editor.ApplyCodeAction(env.Ctx, code[0])
		if err != nil {
			t.Fatal(err)
		}
		want := `package main

type TestStructOne struct{}

type WriteTest interface {
	Write(s string)
}

var _ WriteTest = (*TestStructTwo)(nil) // want "Implement WriteTest"

type TestStructTwo struct {
	*TestStructOne
}

// Write implements WriteTest.
func (t *TestStructTwo) Write(s string) {
	panic("unimplemented")
}
`
		if got := env.BufferText("main.go"); got != want {
			t.Fatalf("TestFStub failed:\n%s", compare.Text(want, got))
		}
	})
}

@adonovan
Copy link
Member

Is there any examples or documentation for this?

The easiest way to test stubmethods is using the marker test framework, documented here. You can see an example test using this approach here.

@gopherbot
Copy link

Change https://go.dev/cl/545675 mentions this issue: gopls/internal/lsp/source: allow iface stubs to shadow definitions

@tttoad
Copy link
Author

tttoad commented Nov 30, 2023

@adonovan Others have also committed code that fixes... I don't understand the workflow, can you tell me what I should do now?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
gopls Issues related to the Go language server, gopls. Tools This label describes issues relating to any tools in the x/tools repository.
Projects
None yet
Development

No branches or pull requests

4 participants