[tools] gopls/internal/golang: pre-filter identifiers by name in localReferences

0 views
Skip to first unread message

Robert Findley (Gerrit)

unread,
Apr 8, 2026, 9:40:21 PM (3 hours ago) Apr 8
to goph...@pubsubhelper.golang.org, golang-co...@googlegroups.com

Robert Findley has uploaded the change for review

Commit message

gopls/internal/golang: pre-filter identifiers by name in localReferences

Build a set of target object names and skip identifiers whose name is
not in the set before consulting TypesInfo.Uses. Also add a fast path
to containsOrigin: check for an exact match first, and return false
immediately when origin(obj) == obj (the non-generic case) since the
exact-match check is then exhaustive.

Benchstat on x/tools, incremental over the parent CL (Xeon 8488C):

│ parent │ this CL │
│ sec/op │ sec/op vs base │
References/tools-64 3.765m ± 2% 2.221m ± 3% -41.02% (p=0.000 n=10)

│ cpu_seconds/op │ cpu_seconds/op vs base │
References/tools-64 4.023m ± 7% 1.550m ± 35% -61.46% (p=0.000 n=10)

Updates golang/go#69523
Change-Id: I58d32eebeb3fce5072af666d99999c9fc978aaa6

Change diff

diff --git a/gopls/internal/golang/origin.go b/gopls/internal/golang/origin.go
index aa77a9b..cdaec01 100644
--- a/gopls/internal/golang/origin.go
+++ b/gopls/internal/golang/origin.go
@@ -10,7 +10,13 @@
// with the same origin as the provided obj (which may be a synthetic object
// created during instantiation).
func containsOrigin(objSet map[types.Object]bool, obj types.Object) bool {
+ if objSet[obj] {
+ return true // fast path: exact match (common for non-generic code)
+ }
objOrigin := origin(obj)
+ if objOrigin == obj {
+ return false // non-generic: origin is identity, so no match
+ }
for target := range objSet {
if origin(target) == objOrigin {
return true
diff --git a/gopls/internal/golang/references.go b/gopls/internal/golang/references.go
index ed89c33..91e992a 100644
--- a/gopls/internal/golang/references.go
+++ b/gopls/internal/golang/references.go
@@ -599,10 +599,20 @@
return false
}

+ // Collect target names for fast pre-filtering:
+ // skip identifiers whose name can't match any target.
+ targetNames := make(map[string]struct{}, len(targets))
+ for obj := range targets {
+ targetNames[obj.Name()] = struct{}{}
+ }
+
// Scan through syntax looking for uses of one of the target objects.
for _, pgf := range pkg.CompiledGoFiles() {
for curId := range pgf.Cursor().Preorder((*ast.Ident)(nil)) {
id := curId.Node().(*ast.Ident)
+ if _, ok := targetNames[id.Name]; !ok {
+ continue
+ }
if obj, ok := pkg.TypesInfo().Uses[id]; ok && matches(obj) {
report(mustLocation(pgf, id), false)
}

Change information

Files:
  • M gopls/internal/golang/origin.go
  • M gopls/internal/golang/references.go
Change size: S
Delta: 2 files changed, 16 insertions(+), 0 deletions(-)
Open in Gerrit

Related details

Attention set is empty
Submit Requirements:
  • requirement is not satisfiedCode-Review
  • requirement satisfiedNo-Unresolved-Comments
  • requirement is not satisfiedReview-Enforcement
  • requirement is not satisfiedTryBots-Pass
Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
Gerrit-MessageType: newchange
Gerrit-Project: tools
Gerrit-Branch: master
Gerrit-Change-Id: I58d32eebeb3fce5072af666d99999c9fc978aaa6
Gerrit-Change-Number: 763742
Gerrit-PatchSet: 1
Gerrit-Owner: Robert Findley <rfin...@golang.org>
unsatisfied_requirement
satisfied_requirement
open
diffy
Reply all
Reply to author
Forward
0 new messages