aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorViktor Blomqvist <veblomqvist@gmail.com>2023-02-06 21:16:06 +0100
committerGopher Robot <gobot@golang.org>2023-02-22 16:48:32 +0000
commit25d2519c869614b0d15632ad5d03f656e267eef1 (patch)
treeb164005da267b7347d693ab139b06e739d020bad
parente85b5336ed5c729c983d08d5f581b5034e8f1a9b (diff)
downloadgolang-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.go53
-rw-r--r--gopls/internal/regtest/misc/definition_test.go39
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