From 581c0b357f883185d60780718e053e600005dac4 Mon Sep 17 00:00:00 2001 From: toad <530901331qq@gmail.com> Date: Wed, 13 Dec 2023 10:17:58 +0800 Subject: [PATCH] gopls/internal/lsp/source: add receiver name to stubbed methods Fixes golang/go#64078 Change-Id: Ib551119b04a36d0be0929a3f949b052b598f57ad Reviewed-on: https://go-review.googlesource.com/c/tools/+/544916 LUCI-TryBot-Result: Go LUCI Reviewed-by: Dmitri Shuralyov Auto-Submit: Robert Findley Reviewed-by: Robert Findley --- gopls/internal/cmd/integration_test.go | 2 +- gopls/internal/lsp/source/stub.go | 31 ++++++++++++++- .../marker/testdata/stubmethods/basic.txt | 2 +- .../testdata/stubmethods/issue61693.txt | 2 +- .../testdata/stubmethods/issue61830.txt | 2 +- .../testdata/stubmethods/issue64078.txt | 36 ++++++++++++++++++ .../testdata/stubmethods/issue64114.txt | 4 +- .../marker/testdata/suggestedfix/stub.txt | 38 +++++++++---------- 8 files changed, 91 insertions(+), 26 deletions(-) create mode 100644 gopls/internal/test/marker/testdata/stubmethods/issue64078.txt diff --git a/gopls/internal/cmd/integration_test.go b/gopls/internal/cmd/integration_test.go index 80b4e34e8bf..4da649f5b4c 100644 --- a/gopls/internal/cmd/integration_test.go +++ b/gopls/internal/cmd/integration_test.go @@ -978,7 +978,7 @@ var _ io.Reader = C{} type C struct{} // Read implements io.Reader. -func (C) Read(p []byte) (n int, err error) { +func (c C) Read(p []byte) (n int, err error) { panic("unimplemented") } `[1:] diff --git a/gopls/internal/lsp/source/stub.go b/gopls/internal/lsp/source/stub.go index ac30aeca818..138b7acb5ea 100644 --- a/gopls/internal/lsp/source/stub.go +++ b/gopls/internal/lsp/source/stub.go @@ -190,17 +190,46 @@ func stubMethodsFixer(ctx context.Context, snapshot *cache.Snapshot, pkg *cache. star = "*" } + // If there are any that have named receiver, choose the first one. + // Otherwise, use lowercase for the first letter of the object. + rn := strings.ToLower(si.Concrete.Obj().Name()[0:1]) + for i := 0; i < si.Concrete.NumMethods(); i++ { + if recv, ok := si.Concrete.Method(i).Type().(*types.Signature); ok && recv.Recv().Name() != "" { + rn = recv.Recv().Name() + break + } + } + + // Check for receiver name conflicts + checkRecvName := func(tuple *types.Tuple) bool { + for i := 0; i < tuple.Len(); i++ { + if rn == tuple.At(i).Name() { + return true + } + } + return false + } + // Format the new methods. var newMethods bytes.Buffer + for index := range missing { + mrn := rn + " " + if sig, ok := missing[index].fn.Type().(*types.Signature); ok { + if checkRecvName(sig.Params()) || checkRecvName(sig.Results()) { + mrn = "" + } + } + fmt.Fprintf(&newMethods, `// %s implements %s. -%sfunc (%s%s%s) %s%s { +%sfunc (%s%s%s%s) %s%s { panic("unimplemented") } `, missing[index].fn.Name(), iface, missing[index].needSubtle, + mrn, star, si.Concrete.Obj().Name(), FormatTypeParams(si.Concrete.TypeParams()), diff --git a/gopls/internal/test/marker/testdata/stubmethods/basic.txt b/gopls/internal/test/marker/testdata/stubmethods/basic.txt index 5f87d13f5c7..95b515299a6 100644 --- a/gopls/internal/test/marker/testdata/stubmethods/basic.txt +++ b/gopls/internal/test/marker/testdata/stubmethods/basic.txt @@ -13,7 +13,7 @@ var _ error = C(0) //@suggestedfix(re"C.0.", re"missing method Error", stub) -- @stub/a/a.go -- @@ -5 +5,5 @@ +// Error implements error. -+func (C) Error() string { ++func (c C) Error() string { + panic("unimplemented") +} + diff --git a/gopls/internal/test/marker/testdata/stubmethods/issue61693.txt b/gopls/internal/test/marker/testdata/stubmethods/issue61693.txt index 40596da469b..387b494bc72 100644 --- a/gopls/internal/test/marker/testdata/stubmethods/issue61693.txt +++ b/gopls/internal/test/marker/testdata/stubmethods/issue61693.txt @@ -20,7 +20,7 @@ func _() { -- @stub/main.go -- @@ -5 +5,5 @@ +// Error implements error. -+func (C) Error() string { ++func (c C) Error() string { + panic("unimplemented") +} + diff --git a/gopls/internal/test/marker/testdata/stubmethods/issue61830.txt b/gopls/internal/test/marker/testdata/stubmethods/issue61830.txt index 0f23ffb39ee..bf5bcc5ca2e 100644 --- a/gopls/internal/test/marker/testdata/stubmethods/issue61830.txt +++ b/gopls/internal/test/marker/testdata/stubmethods/issue61830.txt @@ -18,7 +18,7 @@ var _ I = &A{} //@suggestedfix(re"&A..", re"missing method M", stub) -- @stub/p.go -- @@ -13 +13,5 @@ +// M implements I. -+func (*A) M(io.Reader, B) { ++func (a *A) M(io.Reader, B) { + panic("unimplemented") +} + diff --git a/gopls/internal/test/marker/testdata/stubmethods/issue64078.txt b/gopls/internal/test/marker/testdata/stubmethods/issue64078.txt new file mode 100644 index 00000000000..50db6f27cfd --- /dev/null +++ b/gopls/internal/test/marker/testdata/stubmethods/issue64078.txt @@ -0,0 +1,36 @@ +This test verifies that the named receiver is generated. + +-- p.go -- +package p + +type A struct{} + +func (aa *A) M1() { + panic("unimplemented") +} + +type I interface { + M1() + M2(aa string) + M3(bb string) + M4() (aa string) +} + +var _ I = &A{} //@suggestedfix(re"&A..", re"missing method M", stub) +-- @stub/p.go -- +@@ -5 +5,15 @@ ++// M2 implements I. ++func (*A) M2(aa string) { ++ panic("unimplemented") ++} ++ ++// M3 implements I. ++func (aa *A) M3(bb string) { ++ panic("unimplemented") ++} ++ ++// M4 implements I. ++func (*A) M4() (aa string) { ++ panic("unimplemented") ++} ++ diff --git a/gopls/internal/test/marker/testdata/stubmethods/issue64114.txt b/gopls/internal/test/marker/testdata/stubmethods/issue64114.txt index bf4d875aded..35f6db728bb 100644 --- a/gopls/internal/test/marker/testdata/stubmethods/issue64114.txt +++ b/gopls/internal/test/marker/testdata/stubmethods/issue64114.txt @@ -27,11 +27,11 @@ type WriteStruct struct { + +// RRRR implements WriteTest. +// Subtle: this method shadows the method (WriterTwoStruct).RRRR of WriteStruct.WriterTwoStruct. -+func (*WriteStruct) RRRR() { ++func (w *WriteStruct) RRRR() { + panic("unimplemented") +} + +// WWWW implements WriteTest. -+func (*WriteStruct) WWWW() { ++func (w *WriteStruct) WWWW() { + panic("unimplemented") +} diff --git a/gopls/internal/test/marker/testdata/suggestedfix/stub.txt b/gopls/internal/test/marker/testdata/suggestedfix/stub.txt index 514a293f602..e31494ae461 100644 --- a/gopls/internal/test/marker/testdata/suggestedfix/stub.txt +++ b/gopls/internal/test/marker/testdata/suggestedfix/stub.txt @@ -53,7 +53,7 @@ type byteWriter struct{} @@ -12 +12,5 @@ + +// WriteByte implements io.ByteWriter. -+func (*byteWriter) WriteByte(c byte) error { ++func (b *byteWriter) WriteByte(c byte) error { + panic("unimplemented") +} -- assign_multivars.go -- @@ -73,7 +73,7 @@ type multiByteWriter struct{} @@ -13 +13,5 @@ + +// WriteByte implements io.ByteWriter. -+func (*multiByteWriter) WriteByte(c byte) error { ++func (m *multiByteWriter) WriteByte(c byte) error { + panic("unimplemented") +} -- call_expr.go -- @@ -94,7 +94,7 @@ type callExpr struct{} @@ -14 +14,5 @@ + +// Error implements error. -+func (*callExpr) Error() string { ++func (c *callExpr) Error() string { + panic("unimplemented") +} -- embedded.go -- @@ -116,22 +116,22 @@ type embeddedInterface interface { -- @embedded/embedded.go -- @@ -12 +12,20 @@ +// Len implements embeddedInterface. -+func (*embeddedConcrete) Len() int { ++func (e *embeddedConcrete) Len() int { + panic("unimplemented") +} + +// Less implements embeddedInterface. -+func (*embeddedConcrete) Less(i int, j int) bool { ++func (e *embeddedConcrete) Less(i int, j int) bool { + panic("unimplemented") +} + +// Read implements embeddedInterface. -+func (*embeddedConcrete) Read(p []byte) (n int, err error) { ++func (e *embeddedConcrete) Read(p []byte) (n int, err error) { + panic("unimplemented") +} + +// Swap implements embeddedInterface. -+func (*embeddedConcrete) Swap(i int, j int) { ++func (e *embeddedConcrete) Swap(i int, j int) { + panic("unimplemented") +} + @@ -148,7 +148,7 @@ type customErr struct{} @@ -9 +9,5 @@ + +// Error implements error. -+func (*customErr) Error() string { ++func (c *customErr) Error() string { + panic("unimplemented") +} -- function_return.go -- @@ -167,7 +167,7 @@ type closer struct{} @@ -12 +12,5 @@ + +// Close implements io.Closer. -+func (closer) Close() error { ++func (c closer) Close() error { + panic("unimplemented") +} -- generic_receiver.go -- @@ -187,7 +187,7 @@ type genReader[T, Y any] struct { @@ -13 +13,5 @@ + +// ReadFrom implements io.ReaderFrom. -+func (*genReader[T, Y]) ReadFrom(r io.Reader) (n int64, err error) { ++func (g *genReader[T, Y]) ReadFrom(r io.Reader) (n int64, err error) { + panic("unimplemented") +} -- ignored_imports.go -- @@ -213,7 +213,7 @@ type ignoredResetter struct{} @@ -19 +19,5 @@ + +// Reset implements zlib.Resetter. -+func (*ignoredResetter) Reset(r Reader, dict []byte) error { ++func (i *ignoredResetter) Reset(r Reader, dict []byte) error { + panic("unimplemented") +} -- issue2606.go -- @@ -227,7 +227,7 @@ var _ I = C(0) //@suggestedfix("C", re"does not implement", issue2606) -- @issue2606/issue2606.go -- @@ -7 +7,5 @@ +// Error implements I. -+func (C) Error() string { ++func (c C) Error() string { + panic("unimplemented") +} + @@ -247,7 +247,7 @@ type multiVar struct{} @@ -12 +12,5 @@ + +// Read implements io.Reader. -+func (*multiVar) Read(p []byte) (n int, err error) { ++func (m *multiVar) Read(p []byte) (n int, err error) { + panic("unimplemented") +} -- pointer.go -- @@ -264,7 +264,7 @@ type pointerImpl struct{} @@ -10 +10,5 @@ + +// ReadFrom implements io.ReaderFrom. -+func (*pointerImpl) ReadFrom(r io.Reader) (n int64, err error) { ++func (p *pointerImpl) ReadFrom(r io.Reader) (n int64, err error) { + panic("unimplemented") +} -- renamed_import.go -- @@ -283,7 +283,7 @@ type myIO struct{} @@ -12 +12,5 @@ + +// Reset implements zlib.Resetter. -+func (*myIO) Reset(r myio.Reader, dict []byte) error { ++func (m *myIO) Reset(r myio.Reader, dict []byte) error { + panic("unimplemented") +} -- renamed_import_iface.go -- @@ -307,7 +307,7 @@ type otherInterfaceImpl struct{} @@ -14 +16,5 @@ + +// Get implements other.Interface. -+func (*otherInterfaceImpl) Get(context.Context) *bytes.Buffer { ++func (o *otherInterfaceImpl) Get(context.Context) *bytes.Buffer { + panic("unimplemented") +} -- stdlib.go -- @@ -324,7 +324,7 @@ type writer struct{} @@ -10 +10,5 @@ + +// Write implements io.Writer. -+func (writer) Write(p []byte) (n int, err error) { ++func (w writer) Write(p []byte) (n int, err error) { + panic("unimplemented") +} -- typedecl_group.go -- @@ -354,12 +354,12 @@ func _() { -- @typedecl_group/typedecl_group.go -- @@ -18 +18,10 @@ +// Close implements io.ReadCloser. -+func (rdcloser) Close() error { ++func (r rdcloser) Close() error { + panic("unimplemented") +} + +// Read implements io.ReadCloser. -+func (rdcloser) Read(p []byte) (n int, err error) { ++func (r rdcloser) Read(p []byte) (n int, err error) { + panic("unimplemented") +} +