diff options
author | Viktor Blomqvist <veblomqvist@gmail.com> | 2023-02-06 21:16:06 +0100 |
---|---|---|
committer | Gopher Robot <gobot@golang.org> | 2023-02-22 16:48:32 +0000 |
commit | 25d2519c869614b0d15632ad5d03f656e267eef1 (patch) | |
tree | b164005da267b7347d693ab139b06e739d020bad | |
parent | e85b5336ed5c729c983d08d5f581b5034e8f1a9b (diff) | |
download | golang-x-tools-25d2519c869614b0d15632ad5d03f656e267eef1.tar.gz |
gopls/internal/lsp: support more cases of definition on linkname directive.
Handle the case where //go:linkname localname importpath.name
is used in a package with no transitive dependency, forwards or
reverse, to importpath.
Updates golang/go#57312
Change-Id: I0033b166558275931a371a967caa6044a1b089f3
Reviewed-on: https://go-review.googlesource.com/c/tools/+/469695
Run-TryBot: Alan Donovan <adonovan@google.com>
gopls-CI: kokoro <noreply+kokoro@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Auto-Submit: Alan Donovan <adonovan@google.com>
Reviewed-by: Than McIntosh <thanm@google.com>
Reviewed-by: Alan Donovan <adonovan@google.com>
-rw-r--r-- | gopls/internal/lsp/source/linkname.go | 53 | ||||
-rw-r--r-- | gopls/internal/regtest/misc/definition_test.go | 39 |
2 files changed, 51 insertions, 41 deletions
diff --git a/gopls/internal/lsp/source/linkname.go b/gopls/internal/lsp/source/linkname.go index 4fb667e68..9017d14ea 100644 --- a/gopls/internal/lsp/source/linkname.go +++ b/gopls/internal/lsp/source/linkname.go @@ -92,31 +92,23 @@ func findLinknameOnLine(pgf *ParsedGoFile, line int) (string, int) { // findLinkname searches dependencies of packages containing fh for an object // with linker name matching the given package path and name. func findLinkname(ctx context.Context, snapshot Snapshot, fh FileHandle, pos protocol.Position, pkgPath PackagePath, name string) ([]protocol.Location, error) { - metas, err := snapshot.MetadataForFile(ctx, fh.URI()) + // Typically the linkname refers to a forward dependency + // or a reverse dependency, but in general it may refer + // to any package in the workspace. + var pkgMeta *Metadata + metas, err := snapshot.AllMetadata(ctx) if err != nil { return nil, err } - if len(metas) == 0 { - return nil, fmt.Errorf("no package found for file %q", fh.URI()) + metas = RemoveIntermediateTestVariants(metas) + for _, meta := range metas { + if meta.PkgPath == pkgPath { + pkgMeta = meta + break + } } - - // Find package starting from narrowest package metadata. - pkgMeta := findPackageInDeps(snapshot, metas[0], pkgPath) if pkgMeta == nil { - // Fall back to searching reverse dependencies. - reverse, err := snapshot.ReverseDependencies(ctx, metas[0].ID, true /* transitive */) - if err != nil { - return nil, err - } - for _, dep := range reverse { - if dep.PkgPath == pkgPath { - pkgMeta = dep - break - } - } - if pkgMeta == nil { - return nil, fmt.Errorf("cannot find package %q", pkgPath) - } + return nil, fmt.Errorf("cannot find package %q", pkgPath) } // When found, type check the desired package (snapshot.TypeCheck in TypecheckFull mode), @@ -142,24 +134,3 @@ func findLinkname(ctx context.Context, snapshot Snapshot, fh FileHandle, pos pro } return []protocol.Location{loc}, nil } - -// findPackageInDeps returns the dependency of meta of the specified package path, if any. -func findPackageInDeps(snapshot Snapshot, meta *Metadata, pkgPath PackagePath) *Metadata { - seen := make(map[*Metadata]bool) - var visit func(*Metadata) *Metadata - visit = func(meta *Metadata) *Metadata { - if !seen[meta] { - seen[meta] = true - if meta.PkgPath == pkgPath { - return meta - } - for _, id := range meta.DepsByPkgPath { - if m := visit(snapshot.Metadata(id)); m != nil { - return m - } - } - } - return nil - } - return visit(meta) -} diff --git a/gopls/internal/regtest/misc/definition_test.go b/gopls/internal/regtest/misc/definition_test.go index 7767ac5aa..c2dd67fc3 100644 --- a/gopls/internal/regtest/misc/definition_test.go +++ b/gopls/internal/regtest/misc/definition_test.go @@ -147,6 +147,45 @@ func TestGoToLinknameDefinitionInReverseDep(t *testing.T) { }) } +// The linkname directive connects two packages not related in the import graph. +const linknameDefinitionDisconnected = ` +-- go.mod -- +module mod.com + +-- a/a.go -- +package a + +import ( + _ "unsafe" +) + +//go:linkname foo mod.com/b.bar +func foo() string + +-- b/b.go -- +package b + +func bar() string { + return "bar as foo" +}` + +func TestGoToLinknameDefinitionDisconnected(t *testing.T) { + Run(t, linknameDefinitionDisconnected, func(t *testing.T, env *Env) { + env.OpenFile("a/a.go") + + // Jump from directives 2nd arg. + start := env.RegexpSearch("a/a.go", `b.bar`) + loc := env.GoToDefinition(start) + name := env.Sandbox.Workdir.URIToPath(loc.URI) + if want := "b/b.go"; name != want { + t.Errorf("GoToDefinition: got file %q, want %q", name, want) + } + if want := env.RegexpSearch("b/b.go", `bar`); loc != want { + t.Errorf("GoToDefinition: got position %v, want %v", loc, want) + } + }) +} + const stdlibDefinition = ` -- go.mod -- module mod.com |