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 --