gopls/internal/lsp/source/xrefs: allow Lookup of a set
This change generalizes xrefs.Lookup to allow lookup of
a set of (package path, object path) targets in a single
call, amortizing decoding. It will be used to support
exported methods in implementsV2.
Change-Id: If10c21db97df7a9e8088b3a98e81018d12c52fb2
Reviewed-on: https://go-review.googlesource.com/c/tools/+/463140
Reviewed-by: Robert Findley <rfindley@google.com>
Run-TryBot: Alan Donovan <adonovan@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
diff --git a/gopls/internal/lsp/cache/pkg.go b/gopls/internal/lsp/cache/pkg.go
index 0a986de..37aae50 100644
--- a/gopls/internal/lsp/cache/pkg.go
+++ b/gopls/internal/lsp/cache/pkg.go
@@ -178,13 +178,15 @@
return res
}
-func (p *pkg) ReferencesTo(pkgPath PackagePath, objPath objectpath.Path) []protocol.Location {
+// ReferencesTo returns the location of each reference within package p
+// to one of the target objects denoted by the pair (package path, object path).
+func (p *pkg) ReferencesTo(targets map[PackagePath]map[objectpath.Path]struct{}) []protocol.Location {
// TODO(adonovan): In future, p.xrefs will be retrieved from a
// section of the cache file produced by type checking.
// (Other sections will include the package's export data,
// "implements" relations, exported symbols, etc.)
// For now we just hang it off the pkg.
- return xrefs.Lookup(p.m, p.xrefs, pkgPath, objPath)
+ return xrefs.Lookup(p.m, p.xrefs, targets)
}
func (p *pkg) MethodSetsIndex() *methodsets.Index {
diff --git a/gopls/internal/lsp/source/references2.go b/gopls/internal/lsp/source/references2.go
index 1fc01dc..538639a 100644
--- a/gopls/internal/lsp/source/references2.go
+++ b/gopls/internal/lsp/source/references2.go
@@ -290,9 +290,9 @@
// Is the object exported?
// (objectpath succeeds for lowercase names, arguably a bug.)
- var exportedObjectPath objectpath.Path
+ var exportedObjectPaths map[objectpath.Path]unit
if path, err := objectpath.For(obj); err == nil && obj.Exported() {
- exportedObjectPath = path
+ exportedObjectPaths = map[objectpath.Path]unit{path: unit{}}
// If the object is an exported method, we need to search for
// all matching implementations (using the incremental
@@ -342,10 +342,12 @@
return localReferences(ctx, snapshot, declURI, declPosn.Offset, m, report)
})
- if exportedObjectPath == "" {
+ if exportedObjectPaths == nil {
continue // non-exported
}
+ targets := map[PackagePath]map[objectpath.Path]struct{}{m.PkgPath: exportedObjectPaths}
+
// global
group.Go(func() error {
// Compute the global-scope query for every variant
@@ -358,7 +360,7 @@
for _, rdep := range rdeps {
rdep := rdep
group.Go(func() error {
- return globalReferences(ctx, snapshot, rdep, m.PkgPath, exportedObjectPath, report)
+ return globalReferences(ctx, snapshot, rdep, targets, report)
})
}
return nil
@@ -504,9 +506,9 @@
return targets, nil
}
-// globalReferences reports each cross-package
-// reference to the object identified by (pkgPath, objectPath).
-func globalReferences(ctx context.Context, snapshot Snapshot, m *Metadata, pkgPath PackagePath, objectPath objectpath.Path, report func(loc protocol.Location, isDecl bool)) error {
+// globalReferences reports each cross-package reference to one of the
+// target objects denoted by (package path, object path).
+func globalReferences(ctx context.Context, snapshot Snapshot, m *Metadata, targets map[PackagePath]map[objectpath.Path]unit, report func(loc protocol.Location, isDecl bool)) error {
// TODO(adonovan): opt: don't actually type-check here,
// since we quite intentionally don't look at type information.
// Instead, access the reference index computed during
@@ -515,7 +517,7 @@
if err != nil {
return err
}
- for _, loc := range pkgs[0].ReferencesTo(pkgPath, objectPath) {
+ for _, loc := range pkgs[0].ReferencesTo(targets) {
report(loc, false)
}
return nil
diff --git a/gopls/internal/lsp/source/view.go b/gopls/internal/lsp/source/view.go
index 640a32e..81a91cc 100644
--- a/gopls/internal/lsp/source/view.go
+++ b/gopls/internal/lsp/source/view.go
@@ -773,11 +773,13 @@
ResolveImportPath(path ImportPath) (Package, error)
Imports() []Package // new slice of all direct dependencies, unordered
HasTypeErrors() bool
- DiagnosticsForFile(uri span.URI) []*Diagnostic // new array of list/parse/type errors
- ReferencesTo(PackagePath, objectpath.Path) []protocol.Location // new sorted array of xrefs
+ DiagnosticsForFile(uri span.URI) []*Diagnostic // new array of list/parse/type errors
+ ReferencesTo(map[PackagePath]map[objectpath.Path]unit) []protocol.Location // new sorted array of xrefs
MethodSetsIndex() *methodsets.Index
}
+type unit = struct{}
+
// A CriticalError is a workspace-wide error that generally prevents gopls from
// functioning correctly. In the presence of critical errors, other diagnostics
// in the workspace may not make sense.
diff --git a/gopls/internal/lsp/source/xrefs/xrefs.go b/gopls/internal/lsp/source/xrefs/xrefs.go
index db9bab1..b0d2207 100644
--- a/gopls/internal/lsp/source/xrefs/xrefs.go
+++ b/gopls/internal/lsp/source/xrefs/xrefs.go
@@ -134,8 +134,9 @@
// Lookup searches a serialized index produced by an indexPackage
// operation on m, and returns the locations of all references from m
-// to the object denoted by (pkgPath, objectPath).
-func Lookup(m *source.Metadata, data []byte, pkgPath source.PackagePath, objPath objectpath.Path) []protocol.Location {
+// to any object in the target set. Each object is denoted by a pair
+// of (package path, object path).
+func Lookup(m *source.Metadata, data []byte, targets map[source.PackagePath]map[objectpath.Path]struct{}) (locs []protocol.Location) {
// TODO(adonovan): opt: evaluate whether it would be faster to decode
// in two passes, first with struct { PkgPath string; Objects BLOB }
@@ -146,10 +147,9 @@
mustDecode(data, &packages)
for _, gp := range packages {
- if gp.PkgPath == pkgPath {
- var locs []protocol.Location
+ if objectSet, ok := targets[gp.PkgPath]; ok {
for _, gobObj := range gp.Objects {
- if gobObj.Path == objPath {
+ if _, ok := objectSet[gobObj.Path]; ok {
for _, ref := range gobObj.Refs {
uri := m.CompiledGoFiles[ref.FileIndex]
locs = append(locs, protocol.Location{
@@ -159,10 +159,10 @@
}
}
}
- return locs
}
}
- return nil // this package does not reference that one
+
+ return locs
}
// -- serialized representation --