From 6ef9d1acec34b6dcfc3389e43e6117b9441383b7 Mon Sep 17 00:00:00 2001 From: luoliwoshang <2643523683@qq.com> Date: Wed, 24 Apr 2024 00:33:56 +0800 Subject: [PATCH 1/9] fix:correct anonymous overloaded function definition location --- gopls/internal/lsp/source/definition_gox.go | 26 ++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/gopls/internal/lsp/source/definition_gox.go b/gopls/internal/lsp/source/definition_gox.go index b14c77438ef..b008f093f38 100644 --- a/gopls/internal/lsp/source/definition_gox.go +++ b/gopls/internal/lsp/source/definition_gox.go @@ -79,14 +79,29 @@ func GopDefinition(ctx context.Context, snapshot Snapshot, fh FileHandle, positi } // The general case: the cursor is on an identifier. - _, obj, _ := gopReferencedObject(pkg, pgf, pos) + ident, obj, _ := gopReferencedObject(pkg, pgf, pos) + if obj == nil { return nil, nil } + + anonyOvId := false + if fun, ok := obj.(*types.Func); ok { + overload := pkg.GopTypesInfo().Overloads[ident] + for _, ov := range overload { + if v, ok := ov.(*types.Func); ok { + if n := len(v.Name()); v.Pos() == fun.Pos() && n > 3 && v.Name()[n-3:n-1] == "__" { + anonyOvId = true + break + } + } + } + } + if goxls.DbgDefinition { log.Println("gopReferencedObject ret:", obj, "pos:", obj.Pos()) } - + // Handle objects with no position: builtin, unsafe. if !obj.Pos().IsValid() { var pgf *ParsedGoFile @@ -136,7 +151,12 @@ func GopDefinition(ctx context.Context, snapshot Snapshot, fh FileHandle, positi } // Finally, map the object position. - loc, err := mapPosition(ctx, pkg.FileSet(), snapshot, obj.Pos(), adjustedObjEnd(obj)) + typeEnd := adjustedObjEnd(obj) + if anonyOvId { + // goxls: anonymous overload function identifier range + typeEnd = obj.Pos() + token.Pos(len("func")) + } + loc, err := mapPosition(ctx, pkg.FileSet(), snapshot, obj.Pos(), typeEnd) if goxls.DbgDefinition { log.Println("gopReferencedObject mapPosition:", obj, "err:", err, "loc:", loc) } From 7233be97b9c3b795348df063e27f56b57bc7edc2 Mon Sep 17 00:00:00 2001 From: luoliwoshang <2643523683@qq.com> Date: Thu, 25 Apr 2024 14:41:35 +0800 Subject: [PATCH 2/9] update:get the anonymous overload function by info.Implicits --- gopls/internal/lsp/source/definition_gox.go | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/gopls/internal/lsp/source/definition_gox.go b/gopls/internal/lsp/source/definition_gox.go index b008f093f38..ace53e6c7a1 100644 --- a/gopls/internal/lsp/source/definition_gox.go +++ b/gopls/internal/lsp/source/definition_gox.go @@ -79,7 +79,7 @@ func GopDefinition(ctx context.Context, snapshot Snapshot, fh FileHandle, positi } // The general case: the cursor is on an identifier. - ident, obj, _ := gopReferencedObject(pkg, pgf, pos) + _, obj, _ := gopReferencedObject(pkg, pgf, pos) if obj == nil { return nil, nil @@ -87,10 +87,9 @@ func GopDefinition(ctx context.Context, snapshot Snapshot, fh FileHandle, positi anonyOvId := false if fun, ok := obj.(*types.Func); ok { - overload := pkg.GopTypesInfo().Overloads[ident] - for _, ov := range overload { - if v, ok := ov.(*types.Func); ok { - if n := len(v.Name()); v.Pos() == fun.Pos() && n > 3 && v.Name()[n-3:n-1] == "__" { + for _, ov := range pkg.GopTypesInfo().Implicits { + if v, ok := ov.(*types.Func); ok { + if v.Pos() == fun.Pos() { anonyOvId = true break } @@ -101,7 +100,7 @@ func GopDefinition(ctx context.Context, snapshot Snapshot, fh FileHandle, positi if goxls.DbgDefinition { log.Println("gopReferencedObject ret:", obj, "pos:", obj.Pos()) } - + // Handle objects with no position: builtin, unsafe. if !obj.Pos().IsValid() { var pgf *ParsedGoFile @@ -150,12 +149,12 @@ func GopDefinition(ctx context.Context, snapshot Snapshot, fh FileHandle, positi return []protocol.Location{loc}, nil } - // Finally, map the object position. typeEnd := adjustedObjEnd(obj) if anonyOvId { // goxls: anonymous overload function identifier range typeEnd = obj.Pos() + token.Pos(len("func")) } + // Finally, map the object position. loc, err := mapPosition(ctx, pkg.FileSet(), snapshot, obj.Pos(), typeEnd) if goxls.DbgDefinition { log.Println("gopReferencedObject mapPosition:", obj, "err:", err, "loc:", loc) From dd666e8b9afe4a0017d34975cb20cf3bc9933e2d Mon Sep 17 00:00:00 2001 From: luoliwoshang <2643523683@qq.com> Date: Thu, 25 Apr 2024 14:42:44 +0800 Subject: [PATCH 3/9] test:add test of overload function definition --- gopls/internal/lsp/source/definition_gox.go | 5 +- .../regtest/misc/definition_gox_test.go | 150 ++++++++++++++++++ 2 files changed, 152 insertions(+), 3 deletions(-) create mode 100644 gopls/internal/regtest/misc/definition_gox_test.go diff --git a/gopls/internal/lsp/source/definition_gox.go b/gopls/internal/lsp/source/definition_gox.go index ace53e6c7a1..ad92a2a4674 100644 --- a/gopls/internal/lsp/source/definition_gox.go +++ b/gopls/internal/lsp/source/definition_gox.go @@ -80,15 +80,14 @@ func GopDefinition(ctx context.Context, snapshot Snapshot, fh FileHandle, positi // The general case: the cursor is on an identifier. _, obj, _ := gopReferencedObject(pkg, pgf, pos) - if obj == nil { return nil, nil } anonyOvId := false if fun, ok := obj.(*types.Func); ok { - for _, ov := range pkg.GopTypesInfo().Implicits { - if v, ok := ov.(*types.Func); ok { + for ov := range pkg.GopTypesInfo().Implicits { + if v, ok := ov.(*ast.FuncLit); ok { if v.Pos() == fun.Pos() { anonyOvId = true break diff --git a/gopls/internal/regtest/misc/definition_gox_test.go b/gopls/internal/regtest/misc/definition_gox_test.go new file mode 100644 index 00000000000..04b06126d1c --- /dev/null +++ b/gopls/internal/regtest/misc/definition_gox_test.go @@ -0,0 +1,150 @@ +package misc + +import ( + "testing" + + . "golang.org/x/tools/gopls/internal/lsp/regtest" +) + +const overloadDefinition1 = ` +-- go.mod -- +module mod.com + +go 1.21.4 +-- def.gop -- +func add = ( + func(a, b int) int { + return a + b + } + func(a, b string) string { + return a + b + } +) +-- test.gop -- +println add(100, 7) +` + +func TestOverloadDefinition1(t *testing.T) { + Run(t, overloadDefinition1, func(t *testing.T, env *Env) { + env.OpenFile("test.gop") + loc := env.GoToDefinition(env.RegexpSearch("test.gop", "add")) + name := env.Sandbox.Workdir.URIToPath(loc.URI) + if want := "def.gop"; name != want { + t.Errorf("GoToDefinition: got file %q, want %q", name, want) + } + // goxls : match the 'func' position of the corresponding overloaded function + if want := env.RegexpSearch("def.gop", `(func)\(a, b int\) int`); loc != want { + t.Errorf("GoToDefinition: got location %v, want %v", loc, want) + } + }) +} + +const overloadDefinition2 = ` +-- go.mod -- +module mod.com + +go 1.21.4 +-- def.gop -- +func mulInt(a, b int) int { + return a * b +} + +func mulFloat(a, b float64) float64 { + return a * b +} + +func mul = ( + mulInt + mulFloat +) +-- test.gop -- +println mul(100, 7) +` + +func TestOverloadDefinition2(t *testing.T) { + Run(t, overloadDefinition2, func(t *testing.T, env *Env) { + env.OpenFile("test.gop") + loc := env.GoToDefinition(env.RegexpSearch("test.gop", `println (mul)\(100, 7\)`)) + name := env.Sandbox.Workdir.URIToPath(loc.URI) + if want := "def.gop"; name != want { + t.Errorf("GoToDefinition: got file %q, want %q", name, want) + } + // goxls: match mulInt + if want := env.RegexpSearch("def.gop", `func (mulInt)\(a, b int\) int`); loc != want { + t.Errorf("GoToDefinition: got location %v, want %v", loc, want) + } + }) +} + +const overloadDefinition3 = ` +-- go.mod -- +module mod.com + +go 1.21.4 +-- def.gop -- +type foo struct { +} + +func (a *foo) mulInt(b int) *foo { + return a +} + +func (a *foo) mulFoo(b *foo) *foo { + return a +} + +func (foo).mul = ( + (foo).mulInt + (foo).mulFoo +) +-- test.gop -- +var a *foo +var c = a.mul(100) +` + +func TestOverloadDefinition3(t *testing.T) { + Run(t, overloadDefinition3, func(t *testing.T, env *Env) { + env.OpenFile("test.gop") + loc := env.GoToDefinition(env.RegexpSearch("test.gop", "mul")) + name := env.Sandbox.Workdir.URIToPath(loc.URI) + if want := "def.gop"; name != want { + t.Errorf("GoToDefinition: got file %q, want %q", name, want) + } + // goxls: match mulInt + if want := env.RegexpSearch("def.gop", `func \(a \*foo\) (mulInt)\(b int\) \*foo`); loc != want { + t.Errorf("GoToDefinition: got location %v, want %v", loc, want) + } + }) +} + +const overloadDefinition4 = ` +-- go.mod -- +module mod.com + +go 1.21.4 +-- def.go -- +package main +type foo struct { +} + +func (f *foo) Broadcast__0(msg string) bool { + return true +} +-- test.gop -- +var a *foo +a.Broadcast("hhh") +` + +func TestOverloadDefinition4(t *testing.T) { + Run(t, overloadDefinition4, func(t *testing.T, env *Env) { + env.OpenFile("test.gop") + loc := env.GoToDefinition(env.RegexpSearch("test.gop", "Broadcast")) + name := env.Sandbox.Workdir.URIToPath(loc.URI) + if want := "def.go"; name != want { + t.Errorf("GoToDefinition: got file %q, want %q", name, want) + } + if want := env.RegexpSearch("def.go", `Broadcast__0`); loc != want { + t.Errorf("GoToDefinition: got location %v, want %v", loc, want) + } + }) +} From c710788a9cd8659ad374822835d6641bee8968ae Mon Sep 17 00:00:00 2001 From: luoliwoshang <2643523683@qq.com> Date: Thu, 9 May 2024 16:03:15 +0800 Subject: [PATCH 4/9] update:anonymous function definition range --- gopls/internal/lsp/source/definition_gox.go | 9 ++++----- gopls/internal/regtest/misc/definition_gox_test.go | 2 +- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/gopls/internal/lsp/source/definition_gox.go b/gopls/internal/lsp/source/definition_gox.go index ad92a2a4674..a9e0b796b73 100644 --- a/gopls/internal/lsp/source/definition_gox.go +++ b/gopls/internal/lsp/source/definition_gox.go @@ -84,12 +84,12 @@ func GopDefinition(ctx context.Context, snapshot Snapshot, fh FileHandle, positi return nil, nil } - anonyOvId := false + var anonyOvFunc *ast.FuncLit if fun, ok := obj.(*types.Func); ok { for ov := range pkg.GopTypesInfo().Implicits { if v, ok := ov.(*ast.FuncLit); ok { if v.Pos() == fun.Pos() { - anonyOvId = true + anonyOvFunc = v break } } @@ -149,9 +149,8 @@ func GopDefinition(ctx context.Context, snapshot Snapshot, fh FileHandle, positi } typeEnd := adjustedObjEnd(obj) - if anonyOvId { - // goxls: anonymous overload function identifier range - typeEnd = obj.Pos() + token.Pos(len("func")) + if anonyOvFunc != nil { // goxls: anonymous overload function + typeEnd = anonyOvFunc.Type.End() } // Finally, map the object position. loc, err := mapPosition(ctx, pkg.FileSet(), snapshot, obj.Pos(), typeEnd) diff --git a/gopls/internal/regtest/misc/definition_gox_test.go b/gopls/internal/regtest/misc/definition_gox_test.go index 04b06126d1c..63a45fc7c0a 100644 --- a/gopls/internal/regtest/misc/definition_gox_test.go +++ b/gopls/internal/regtest/misc/definition_gox_test.go @@ -33,7 +33,7 @@ func TestOverloadDefinition1(t *testing.T) { t.Errorf("GoToDefinition: got file %q, want %q", name, want) } // goxls : match the 'func' position of the corresponding overloaded function - if want := env.RegexpSearch("def.gop", `(func)\(a, b int\) int`); loc != want { + if want := env.RegexpSearch("def.gop", `func\(a, b int\) int`); loc != want { t.Errorf("GoToDefinition: got location %v, want %v", loc, want) } }) From eeadb4fa6a721479a67b1455c9690ba786fa386d Mon Sep 17 00:00:00 2001 From: luoliwoshang <2643523683@qq.com> Date: Sun, 12 May 2024 23:03:45 +0800 Subject: [PATCH 5/9] update:find overload definition cross package --- gopls/internal/lsp/source/definition_gox.go | 65 +++++++++++++++++---- 1 file changed, 55 insertions(+), 10 deletions(-) diff --git a/gopls/internal/lsp/source/definition_gox.go b/gopls/internal/lsp/source/definition_gox.go index a9e0b796b73..fb422233eeb 100644 --- a/gopls/internal/lsp/source/definition_gox.go +++ b/gopls/internal/lsp/source/definition_gox.go @@ -9,6 +9,7 @@ import ( "fmt" "go/types" "log" + "strings" "github.com/goplus/gop/ast" "github.com/goplus/gop/token" @@ -16,6 +17,8 @@ import ( "golang.org/x/tools/gopls/internal/goxls" "golang.org/x/tools/gopls/internal/goxls/parserutil" "golang.org/x/tools/gopls/internal/lsp/protocol" + "golang.org/x/tools/gopls/internal/lsp/safetoken" + "golang.org/x/tools/gopls/internal/span" "golang.org/x/tools/internal/event" ) @@ -84,16 +87,11 @@ func GopDefinition(ctx context.Context, snapshot Snapshot, fh FileHandle, positi return nil, nil } - var anonyOvFunc *ast.FuncLit - if fun, ok := obj.(*types.Func); ok { - for ov := range pkg.GopTypesInfo().Implicits { - if v, ok := ov.(*ast.FuncLit); ok { - if v.Pos() == fun.Pos() { - anonyOvFunc = v - break - } - } - } + var anonyOvFunc *ast.FuncLit //goxls:overload anonymous member + if ovPkg, ovFuncLit, ovObj, ok := IsOverloadAnonymousMember(ctx, snapshot, pkg, obj); ok { + pkg = ovPkg + obj = ovObj + anonyOvFunc = ovFuncLit } if goxls.DbgDefinition { @@ -299,3 +297,50 @@ func gopImportDefinition(ctx context.Context, s Snapshot, pkg Package, pgf *Pars return locs, nil } + +// goxls:match in current package & variants +func IsOverloadAnonymousMember(ctx context.Context, snapshot Snapshot, pkg Package, obj types.Object) (Package, *ast.FuncLit, types.Object, bool) { + if _, ok := obj.(*types.Func); !ok { + return nil, nil, nil, false + } + + declPosn := safetoken.StartPosition(pkg.FileSet(), obj.Pos()) + declURI := span.URIFromPath(declPosn.Filename) + + inPkg := func(searchPkg Package) (*ast.FuncLit, types.Object, bool) { + fset := searchPkg.FileSet() + for ov, om := range searchPkg.GopTypesInfo().Implicits { + if anonyOvFunc, ok := ov.(*ast.FuncLit); ok { + funPos := safetoken.StartPosition(fset, anonyOvFunc.Pos()) + if declPosn.Offset == funPos.Offset { + return anonyOvFunc, om, true + } + } + } + return nil, nil, false + } + + // goxls:match in current package + if funcLit, ovObj, ok := inPkg(pkg); ok { + return pkg, funcLit, ovObj, true + } + + // goxls:match in variants package + if strings.HasSuffix(string(declURI), ".gop") { + variants, err := snapshot.MetadataForFile(ctx, declURI) + if err != nil { + return nil, nil, nil, false + } + for _, m := range variants { + varPkgs, err := snapshot.TypeCheck(ctx, m.ID) + if err != nil { + return nil, nil, nil, false + } + varPkg := varPkgs[0] + if funcLit, ovObj, ok := inPkg(varPkg); ok { + return varPkg, funcLit, ovObj, true + } + } + } + return nil, nil, nil, false +} From 36344fae6a887fbeb48bf720871108301003a4f0 Mon Sep 17 00:00:00 2001 From: luoliwoshang <2643523683@qq.com> Date: Mon, 27 May 2024 11:48:21 +0800 Subject: [PATCH 6/9] test:add gop_autogen for package data --- .../regtest/misc/definition_gox_test.go | 106 ++++++++++++++++-- 1 file changed, 95 insertions(+), 11 deletions(-) diff --git a/gopls/internal/regtest/misc/definition_gox_test.go b/gopls/internal/regtest/misc/definition_gox_test.go index 63a45fc7c0a..00f58323266 100644 --- a/gopls/internal/regtest/misc/definition_gox_test.go +++ b/gopls/internal/regtest/misc/definition_gox_test.go @@ -10,7 +10,7 @@ const overloadDefinition1 = ` -- go.mod -- module mod.com -go 1.21.4 +go 1.19 -- def.gop -- func add = ( func(a, b int) int { @@ -22,6 +22,21 @@ func add = ( ) -- test.gop -- println add(100, 7) +-- gop_autogen.go -- +package main + +import "fmt" + +const _ = true +func add__0(a int, b int) int { + return a + b +} +func add__1(a string, b string) string { + return a + b +} +func main() { + fmt.Println(add__0(100, 7)) +} ` func TestOverloadDefinition1(t *testing.T) { @@ -43,7 +58,7 @@ const overloadDefinition2 = ` -- go.mod -- module mod.com -go 1.21.4 +go 1.19 -- def.gop -- func mulInt(a, b int) int { return a * b @@ -55,10 +70,32 @@ func mulFloat(a, b float64) float64 { func mul = ( mulInt + func(a, b string) string { + return a + b + } mulFloat ) -- test.gop -- println mul(100, 7) +-- gop_autogen.go -- +package main + +import "fmt" + +const _ = true +const Gopo_mul = "mulInt,,mulFloat" +func mulInt(a int, b int) int { + return a * b +} +func mul__1(a string, b string) string { + return a + b +} +func mulFloat(a float64, b float64) float64 { + return a * b +} +func main() { + fmt.Println(mulInt(100, 7)) +} ` func TestOverloadDefinition2(t *testing.T) { @@ -80,7 +117,7 @@ const overloadDefinition3 = ` -- go.mod -- module mod.com -go 1.21.4 +go 1.19 -- def.gop -- type foo struct { } @@ -100,6 +137,27 @@ func (foo).mul = ( -- test.gop -- var a *foo var c = a.mul(100) +-- gop_autogen.go -- +package main + +const _ = true + +type foo struct { +} + +const Gopo_foo_mul = ".mulInt,.mulFoo" +func (a *foo) mulInt(b int) *foo { + return a +} +func (a *foo) mulFoo(b *foo) *foo { + return a +} + +var a *foo +var c = a.mulInt(100) + +func main() { +} ` func TestOverloadDefinition3(t *testing.T) { @@ -121,29 +179,55 @@ const overloadDefinition4 = ` -- go.mod -- module mod.com -go 1.21.4 +go 1.19 -- def.go -- package main -type foo struct { + +const GopPackage = true + +type N struct { } -func (f *foo) Broadcast__0(msg string) bool { - return true +func (m *N) OnKey__0(a string, fn func()) { + fn() +} + +func (m *N) OnKey__1(a string, fn func(key string)) { + fn(a) +} + +func (m *N) OnKey__2(a []string, fn func()) { + fn() } -- test.gop -- -var a *foo -a.Broadcast("hhh") +n := &N{} + +n.onKey("hello", func() { + println("hello world") +}) +-- gop_autogen.go -- +package main + +import "fmt" + +const _ = true +func main() { + n := &N{} + n.OnKey__0("hello", func() { + fmt.Println("hello world") + }) +} ` func TestOverloadDefinition4(t *testing.T) { Run(t, overloadDefinition4, func(t *testing.T, env *Env) { env.OpenFile("test.gop") - loc := env.GoToDefinition(env.RegexpSearch("test.gop", "Broadcast")) + loc := env.GoToDefinition(env.RegexpSearch("test.gop", "onKey")) name := env.Sandbox.Workdir.URIToPath(loc.URI) if want := "def.go"; name != want { t.Errorf("GoToDefinition: got file %q, want %q", name, want) } - if want := env.RegexpSearch("def.go", `Broadcast__0`); loc != want { + if want := env.RegexpSearch("def.go", `OnKey__0`); loc != want { t.Errorf("GoToDefinition: got location %v, want %v", loc, want) } }) From d40032c3933d1ea5bcc6879d502b9b678ccd8787 Mon Sep 17 00:00:00 2001 From: luoliwoshang <2643523683@qq.com> Date: Fri, 4 Apr 2025 15:46:42 +0800 Subject: [PATCH 7/9] chore:refine before misunderstand varaint pkg --- gopls/internal/lsp/source/definition_gox.go | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/gopls/internal/lsp/source/definition_gox.go b/gopls/internal/lsp/source/definition_gox.go index fb422233eeb..2cee9077715 100644 --- a/gopls/internal/lsp/source/definition_gox.go +++ b/gopls/internal/lsp/source/definition_gox.go @@ -147,7 +147,9 @@ func GopDefinition(ctx context.Context, snapshot Snapshot, fh FileHandle, positi } typeEnd := adjustedObjEnd(obj) - if anonyOvFunc != nil { // goxls: anonymous overload function + if anonyOvFunc != nil { + // goxls:if the object is an anonymous overload function + // use the end of the overload function typeEnd = anonyOvFunc.Type.End() } // Finally, map the object position. @@ -325,18 +327,18 @@ func IsOverloadAnonymousMember(ctx context.Context, snapshot Snapshot, pkg Packa return pkg, funcLit, ovObj, true } - // goxls:match in variants package + // goxls:match in local package if strings.HasSuffix(string(declURI), ".gop") { - variants, err := snapshot.MetadataForFile(ctx, declURI) + metas, err := snapshot.MetadataForFile(ctx, declURI) if err != nil { return nil, nil, nil, false } - for _, m := range variants { - varPkgs, err := snapshot.TypeCheck(ctx, m.ID) + for _, m := range metas { + pkgs, err := snapshot.TypeCheck(ctx, m.ID) if err != nil { return nil, nil, nil, false } - varPkg := varPkgs[0] + varPkg := pkgs[0] if funcLit, ovObj, ok := inPkg(varPkg); ok { return varPkg, funcLit, ovObj, true } From 473c47f2d8858c01331ace05bdd86a959c2db86d Mon Sep 17 00:00:00 2001 From: luoliwoshang <2643523683@qq.com> Date: Fri, 4 Apr 2025 16:56:41 +0800 Subject: [PATCH 8/9] test cross package 's overload definition --- .../regtest/misc/definition_gox_test.go | 159 ++++++++++++------ 1 file changed, 106 insertions(+), 53 deletions(-) diff --git a/gopls/internal/regtest/misc/definition_gox_test.go b/gopls/internal/regtest/misc/definition_gox_test.go index 00f58323266..e0428609925 100644 --- a/gopls/internal/regtest/misc/definition_gox_test.go +++ b/gopls/internal/regtest/misc/definition_gox_test.go @@ -6,7 +6,7 @@ import ( . "golang.org/x/tools/gopls/internal/lsp/regtest" ) -const overloadDefinition1 = ` +const anonyOverload = ` -- go.mod -- module mod.com @@ -39,22 +39,14 @@ func main() { } ` -func TestOverloadDefinition1(t *testing.T) { - Run(t, overloadDefinition1, func(t *testing.T, env *Env) { - env.OpenFile("test.gop") - loc := env.GoToDefinition(env.RegexpSearch("test.gop", "add")) - name := env.Sandbox.Workdir.URIToPath(loc.URI) - if want := "def.gop"; name != want { - t.Errorf("GoToDefinition: got file %q, want %q", name, want) - } - // goxls : match the 'func' position of the corresponding overloaded function - if want := env.RegexpSearch("def.gop", `func\(a, b int\) int`); loc != want { - t.Errorf("GoToDefinition: got location %v, want %v", loc, want) - } - }) +func TestAnonyOverload(t *testing.T) { + testCases := []match{ + {`test.gop`, `println (add)\(100, 7\)`, "def.gop", `func\(a, b int\) int`}, + } + runGoToDefinitionTest(t, anonyOverload, testCases) } -const overloadDefinition2 = ` +const overloadMixAnonyAndNamed = ` -- go.mod -- module mod.com @@ -98,22 +90,14 @@ func main() { } ` -func TestOverloadDefinition2(t *testing.T) { - Run(t, overloadDefinition2, func(t *testing.T, env *Env) { - env.OpenFile("test.gop") - loc := env.GoToDefinition(env.RegexpSearch("test.gop", `println (mul)\(100, 7\)`)) - name := env.Sandbox.Workdir.URIToPath(loc.URI) - if want := "def.gop"; name != want { - t.Errorf("GoToDefinition: got file %q, want %q", name, want) - } - // goxls: match mulInt - if want := env.RegexpSearch("def.gop", `func (mulInt)\(a, b int\) int`); loc != want { - t.Errorf("GoToDefinition: got location %v, want %v", loc, want) - } - }) +func TestOverloadMixAnonyAndNamed(t *testing.T) { + testCases := []match{ + {`test.gop`, `println (mul)\(100, 7\)`, "def.gop", `func (mulInt)\(a, b int\) int`}, + } + runGoToDefinitionTest(t, overloadMixAnonyAndNamed, testCases) } -const overloadDefinition3 = ` +const overloadMethod = ` -- go.mod -- module mod.com @@ -160,22 +144,14 @@ func main() { } ` -func TestOverloadDefinition3(t *testing.T) { - Run(t, overloadDefinition3, func(t *testing.T, env *Env) { - env.OpenFile("test.gop") - loc := env.GoToDefinition(env.RegexpSearch("test.gop", "mul")) - name := env.Sandbox.Workdir.URIToPath(loc.URI) - if want := "def.gop"; name != want { - t.Errorf("GoToDefinition: got file %q, want %q", name, want) - } - // goxls: match mulInt - if want := env.RegexpSearch("def.gop", `func \(a \*foo\) (mulInt)\(b int\) \*foo`); loc != want { - t.Errorf("GoToDefinition: got location %v, want %v", loc, want) - } - }) +func TestOverloadMethod(t *testing.T) { + testCases := []match{ + {`test.gop`, `var c = a.(mul)\(100\)`, "def.gop", `func \(a \*foo\) (mulInt)\(b int\) \*foo`}, + } + runGoToDefinitionTest(t, overloadMethod, testCases) } -const overloadDefinition4 = ` +const overloadFromGo = ` -- go.mod -- module mod.com @@ -219,16 +195,93 @@ func main() { } ` -func TestOverloadDefinition4(t *testing.T) { - Run(t, overloadDefinition4, func(t *testing.T, env *Env) { - env.OpenFile("test.gop") - loc := env.GoToDefinition(env.RegexpSearch("test.gop", "onKey")) - name := env.Sandbox.Workdir.URIToPath(loc.URI) - if want := "def.go"; name != want { - t.Errorf("GoToDefinition: got file %q, want %q", name, want) - } - if want := env.RegexpSearch("def.go", `OnKey__0`); loc != want { - t.Errorf("GoToDefinition: got location %v, want %v", loc, want) +func TestOverloadFromGo(t *testing.T) { + testCases := []match{ + {`test.gop`, `onKey`, "def.go", `OnKey__0`}, + } + runGoToDefinitionTest(t, overloadFromGo, testCases) +} + +const overloadCrossPkg = ` +-- go.mod -- +module mod.com + +go 1.19 +-- lib/lib.gop -- +package lib + +func Add = ( + func(a, b int) int { + return a + b + } + func(a, b string) string { + return a + b + } +) + +-- lib/gop_autogen.go -- +package lib + +const GopPackage = true +const _ = true +func Add__0(a int, b int) int { + return a + b +} +func Add__1(a string, b string) string { + return a + b +} + +-- main.gop -- +import ( + "mod.com/lib" +) + +println lib.Add(100, 7) +println lib.Add("Hello", "World") + +-- gop_autogen.go -- +package main + +import ( + "fmt" + "mod.com/lib" +) + +const _ = true +func main() { + fmt.Println(lib.Add__0(100, 7)) + fmt.Println(lib.Add__1("Hello", "World")) +} +` + +// Test cross package 's overload definition +func TestOverloadCrossPkg(t *testing.T) { + testCases := []match{ + {`main.gop`, `println lib.(Add)\(100, 7\)`, "lib/lib.gop", `func\(a, b int\) int`}, + {`main.gop`, `println lib.(Add)\("Hello", "World"\)`, "lib/lib.gop", `func\(a, b string\) string`}, + } + runGoToDefinitionTest(t, overloadCrossPkg, testCases) +} + +type match struct { + findLocFile string + findLocReg string + wantFile string + wantLocReg string +} + +func runGoToDefinitionTest(t *testing.T, files string, testCases []match) { + Run(t, files, func(t *testing.T, env *Env) { + for _, test := range testCases { + env.OpenFile(test.findLocFile) + loc := env.GoToDefinition(env.RegexpSearch(test.findLocFile, test.findLocReg)) + name := env.Sandbox.Workdir.URIToPath(loc.URI) + if name != test.wantFile { + t.Errorf("GoToDefinition: got file %q, want %q", name, test.wantFile) + } + if want := env.RegexpSearch(test.wantFile, test.wantLocReg); loc != want { + t.Errorf("GoToDefinition: got location %v, want %v", loc, want) + } } }) } From e20447def9edad21589aaabc21b7dfea0b2c844d Mon Sep 17 00:00:00 2001 From: luoliwoshang <2643523683@qq.com> Date: Fri, 4 Apr 2025 23:23:28 +0800 Subject: [PATCH 9/9] test:patch more overload define test --- gopls/internal/lsp/source/definition_gox.go | 6 +- .../regtest/misc/definition_gox_test.go | 181 +++++++++++++++++- 2 files changed, 174 insertions(+), 13 deletions(-) diff --git a/gopls/internal/lsp/source/definition_gox.go b/gopls/internal/lsp/source/definition_gox.go index 2cee9077715..51e9a79239c 100644 --- a/gopls/internal/lsp/source/definition_gox.go +++ b/gopls/internal/lsp/source/definition_gox.go @@ -338,9 +338,9 @@ func IsOverloadAnonymousMember(ctx context.Context, snapshot Snapshot, pkg Packa if err != nil { return nil, nil, nil, false } - varPkg := pkgs[0] - if funcLit, ovObj, ok := inPkg(varPkg); ok { - return varPkg, funcLit, ovObj, true + localPkg := pkgs[0] + if funcLit, ovObj, ok := inPkg(localPkg); ok { + return localPkg, funcLit, ovObj, true } } } diff --git a/gopls/internal/regtest/misc/definition_gox_test.go b/gopls/internal/regtest/misc/definition_gox_test.go index e0428609925..08c746054e2 100644 --- a/gopls/internal/regtest/misc/definition_gox_test.go +++ b/gopls/internal/regtest/misc/definition_gox_test.go @@ -22,6 +22,7 @@ func add = ( ) -- test.gop -- println add(100, 7) +println add("Hello", "World") -- gop_autogen.go -- package main @@ -36,12 +37,14 @@ func add__1(a string, b string) string { } func main() { fmt.Println(add__0(100, 7)) + fmt.Println(add__1("Hello", "World")) } ` func TestAnonyOverload(t *testing.T) { - testCases := []match{ + testCases := []defTest{ {`test.gop`, `println (add)\(100, 7\)`, "def.gop", `func\(a, b int\) int`}, + {`test.gop`, `println (add)\("Hello", "World"\)`, "def.gop", `func\(a, b string\) string`}, } runGoToDefinitionTest(t, anonyOverload, testCases) } @@ -69,6 +72,8 @@ func mul = ( ) -- test.gop -- println mul(100, 7) +println mul("Hello", "World") +println mul(200.5, 2.3) -- gop_autogen.go -- package main @@ -87,12 +92,16 @@ func mulFloat(a float64, b float64) float64 { } func main() { fmt.Println(mulInt(100, 7)) + fmt.Println(mul__1("Hello", "World")) + fmt.Println(mulFloat(200.5, 2.3)) } ` func TestOverloadMixAnonyAndNamed(t *testing.T) { - testCases := []match{ + testCases := []defTest{ {`test.gop`, `println (mul)\(100, 7\)`, "def.gop", `func (mulInt)\(a, b int\) int`}, + {`test.gop`, `println (mul)\("Hello", "World"\)`, "def.gop", `func\(a, b string\) string`}, + {`test.gop`, `println (mul)\(200.5, 2.3\)`, "def.gop", `func (mulFloat)\(a, b float64\) float64`}, } runGoToDefinitionTest(t, overloadMixAnonyAndNamed, testCases) } @@ -121,6 +130,7 @@ func (foo).mul = ( -- test.gop -- var a *foo var c = a.mul(100) +var d = a.mul(&foo{}) -- gop_autogen.go -- package main @@ -139,14 +149,20 @@ func (a *foo) mulFoo(b *foo) *foo { var a *foo var c = a.mulInt(100) +var d = a.mulFoo(&foo{}) func main() { } ` func TestOverloadMethod(t *testing.T) { - testCases := []match{ - {`test.gop`, `var c = a.(mul)\(100\)`, "def.gop", `func \(a \*foo\) (mulInt)\(b int\) \*foo`}, + mulIntLocReg := `func \(a \*foo\) (mulInt)\(b int\) \*foo` + mulFooLocReg := `func \(a \*foo\) (mulFoo)\(b \*foo\) \*foo` + testCases := []defTest{ + {`test.gop`, `var c = a.(mul)\(100\)`, "def.gop", mulIntLocReg}, + {`test.gop`, `var d = a.(mul)\(&foo\{\}\)`, "def.gop", mulFooLocReg}, + {`def.gop`, `\(foo\)\.(mulInt)`, "def.gop", mulIntLocReg}, + {`def.gop`, `\(foo\)\.(mulFoo)`, "def.gop", mulFooLocReg}, } runGoToDefinitionTest(t, overloadMethod, testCases) } @@ -181,6 +197,14 @@ n := &N{} n.onKey("hello", func() { println("hello world") }) + +n.onKey("hello", func(key string) { + println("hello world", key) +}) + +n.onKey([]string{"hello", "world"}, func() { + println("hello world") +}) -- gop_autogen.go -- package main @@ -192,12 +216,20 @@ func main() { n.OnKey__0("hello", func() { fmt.Println("hello world") }) + n.OnKey__1("hello", func(key string) { + fmt.Println("hello world", key) + }) + n.OnKey__2([]string{"hello", "world"}, func() { + fmt.Println("hello world") + }) } ` func TestOverloadFromGo(t *testing.T) { - testCases := []match{ - {`test.gop`, `onKey`, "def.go", `OnKey__0`}, + testCases := []defTest{ + {`test.gop`, `n.(onKey)\("hello", func\(\)`, "def.go", `OnKey__0`}, + {`test.gop`, `n.(onKey)\("hello", func\(key string\)`, "def.go", `OnKey__1`}, + {`test.gop`, `n.(onKey)\(\[\]string\{"hello", "world"\}, func\(\)`, "def.go", `OnKey__2`}, } runGoToDefinitionTest(t, overloadFromGo, testCases) } @@ -219,58 +251,187 @@ func Add = ( } ) +func MulInt(a, b int) int { + return a * b +} + +func MulFloat(a, b float64) float64 { + return a * b +} + +func Mul = ( + MulInt + func(x, y string) string { + return x + y + } + MulFloat +) + +type Foo struct { +} + +func (a *Foo) MulInt(b int) *Foo { + return a +} + +func (a *Foo) MulFoo(b *Foo) *Foo { + return a +} + +func (Foo).Mul = ( + (Foo).MulInt + (Foo).MulFoo +) -- lib/gop_autogen.go -- package lib const GopPackage = true const _ = true +const Gopo_Mul = "MulInt,,MulFloat" + +type Foo struct { +} + +const Gopo_Foo_Mul = ".MulInt,.MulFoo" func Add__0(a int, b int) int { return a + b } func Add__1(a string, b string) string { return a + b } +func MulInt(a int, b int) int { + return a * b +} +func Mul__1(x string, y string) string { + return x + y +} +func MulFloat(a float64, b float64) float64 { + return a * b +} +func (a *Foo) MulInt(b int) *Foo { + return a +} +func (a *Foo) MulFoo(b *Foo) *Foo { + return a +} +-- lib2/lib2.go -- +package lib2 + +const GopPackage = true + +type N struct { +} + +func (m *N) OnKey__0(a string, fn func()) { + fn() +} +func (m *N) OnKey__1(a string, fn func(key string)) { + fn(a) +} + +func (m *N) OnKey__2(a []string, fn func()) { + fn() +} -- main.gop -- import ( "mod.com/lib" + "mod.com/lib2" ) println lib.Add(100, 7) println lib.Add("Hello", "World") +println lib.Mul(100, 7) +println lib.Mul("Hello", "World") +println lib.Mul(200.5, 2.3) + +var a *lib.Foo +var c = a.Mul(100) +var d = a.Mul(&lib.Foo{}) + +_ = c +_ = d + +n := &lib2.N{} + +n.OnKey("hello", func() { + println("hello world") +}) + +n.OnKey("hello", func(key string) { + println("hello world", key) +}) + +n.OnKey([]string{"hello", "world"}, func() { + println("hello world") +}) -- gop_autogen.go -- package main import ( "fmt" "mod.com/lib" + "mod.com/lib2" ) const _ = true func main() { fmt.Println(lib.Add__0(100, 7)) fmt.Println(lib.Add__1("Hello", "World")) + fmt.Println(lib.MulInt(100, 7)) + fmt.Println(lib.Mul__1("Hello", "World")) + fmt.Println(lib.MulFloat(200.5, 2.3)) + var a *lib.Foo + var c = a.MulInt(100) + var d = a.MulFoo(&lib.Foo{}) + _ = c + _ = d + n := &lib2.N{} + n.OnKey__0("hello", func() { + fmt.Println("hello world") + }) + n.OnKey__1("hello", func(key string) { + fmt.Println("hello world", key) + }) + n.OnKey__2([]string{"hello", "world"}, func() { + fmt.Println("hello world") + }) } ` // Test cross package 's overload definition func TestOverloadCrossPkg(t *testing.T) { - testCases := []match{ + testCases := []defTest{ + // anony overload {`main.gop`, `println lib.(Add)\(100, 7\)`, "lib/lib.gop", `func\(a, b int\) int`}, {`main.gop`, `println lib.(Add)\("Hello", "World"\)`, "lib/lib.gop", `func\(a, b string\) string`}, + + // named & anony overload + {`main.gop`, `println lib.(Mul)\(100, 7\)`, "lib/lib.gop", `func (MulInt)\(a, b int\) int`}, + {`main.gop`, `println lib.(Mul)\("Hello", "World"\)`, "lib/lib.gop", `func\(x, y string\) string`}, + {`main.gop`, `println lib.(Mul)\(200.5, 2.3\)`, "lib/lib.gop", `func (MulFloat)\(a, b float64\) float64`}, + + // method + {`main.gop`, `var c = a.(Mul)\(100\)`, "lib/lib.gop", `func \(a \*Foo\) (MulInt)\(b int\) \*Foo`}, + {`main.gop`, `var d = a.(Mul)\(&lib\.Foo\{\}\)`, "lib/lib.gop", `func \(a \*Foo\) (MulFoo)\(b \*Foo\) \*Foo`}, + + // from go + {`main.gop`, `n.(OnKey)\("hello", func\(\)`, "lib2/lib2.go", `OnKey__0`}, + {`main.gop`, `n.(OnKey)\("hello", func\(key string\)`, "lib2/lib2.go", `OnKey__1`}, + {`main.gop`, `n.(OnKey)\(\[\]string\{"hello", "world"\}, func\(\)`, "lib2/lib2.go", `OnKey__2`}, } runGoToDefinitionTest(t, overloadCrossPkg, testCases) } -type match struct { +type defTest struct { findLocFile string findLocReg string wantFile string wantLocReg string } -func runGoToDefinitionTest(t *testing.T, files string, testCases []match) { +func runGoToDefinitionTest(t *testing.T, files string, testCases []defTest) { Run(t, files, func(t *testing.T, env *Env) { for _, test := range testCases { env.OpenFile(test.findLocFile) @@ -280,7 +441,7 @@ func runGoToDefinitionTest(t *testing.T, files string, testCases []match) { t.Errorf("GoToDefinition: got file %q, want %q", name, test.wantFile) } if want := env.RegexpSearch(test.wantFile, test.wantLocReg); loc != want { - t.Errorf("GoToDefinition: got location %v, want %v", loc, want) + t.Errorf("GoToDefinition:%v got location %v, want %v", test.findLocReg, loc, want) } } })