Skip to content

Commit

Permalink
gopls/internal/lsp/source: add receiver name to stubbed methods
Browse files Browse the repository at this point in the history
Fixes golang/go#64078

Change-Id: Ib551119b04a36d0be0929a3f949b052b598f57ad
Reviewed-on: https://go-review.googlesource.com/c/tools/+/544916
LUCI-TryBot-Result: Go LUCI <[email protected]>
Reviewed-by: Dmitri Shuralyov <[email protected]>
Auto-Submit: Robert Findley <[email protected]>
Reviewed-by: Robert Findley <[email protected]>
  • Loading branch information
tttoad authored and gopherbot committed Jan 9, 2024
1 parent c95fa0f commit 581c0b3
Show file tree
Hide file tree
Showing 8 changed files with 91 additions and 26 deletions.
2 changes: 1 addition & 1 deletion gopls/internal/cmd/integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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:]
Expand Down
31 changes: 30 additions & 1 deletion gopls/internal/lsp/source/stub.go
Original file line number Diff line number Diff line change
Expand Up @@ -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()),
Expand Down
2 changes: 1 addition & 1 deletion gopls/internal/test/marker/testdata/stubmethods/basic.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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")
+}
+
Original file line number Diff line number Diff line change
Expand Up @@ -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")
+}
+
Original file line number Diff line number Diff line change
Expand Up @@ -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")
+}
+
36 changes: 36 additions & 0 deletions gopls/internal/test/marker/testdata/stubmethods/issue64078.txt
Original file line number Diff line number Diff line change
@@ -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")
+}
+
Original file line number Diff line number Diff line change
Expand Up @@ -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")
+}
38 changes: 19 additions & 19 deletions gopls/internal/test/marker/testdata/suggestedfix/stub.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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 --
Expand All @@ -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 --
Expand All @@ -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 --
Expand All @@ -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")
+}
+
Expand All @@ -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 --
Expand All @@ -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 --
Expand All @@ -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 --
Expand All @@ -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 --
Expand All @@ -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")
+}
+
Expand All @@ -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 --
Expand All @@ -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 --
Expand All @@ -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 --
Expand All @@ -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 --
Expand All @@ -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 --
Expand Down Expand Up @@ -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")
+}
+

0 comments on commit 581c0b3

Please sign in to comment.