diff --git a/go/ast/inspector/cursor.go b/go/ast/inspector/cursor.go
index fc9bbc7..75f0983 100644
--- a/go/ast/inspector/cursor.go
+++ b/go/ast/inspector/cursor.go
@@ -449,10 +449,13 @@
return Cursor{}, false
}
-// FindByPos returns the cursor for the innermost node n in the tree
+// FindByPos returns the cursor for the first innermost node n in the tree
// rooted at c such that n.Pos() <= start && end <= n.End().
// (For an *ast.File, it uses the bounds n.FileStart-n.FileEnd.)
//
+// The "first" is specified because if the input is a position, the cursor may
+// be wholly contained by two nodes (e.g. at the boundary "foo|()").
+//
// It returns zero if none is found.
// Precondition: start <= end.
//
@@ -469,10 +472,14 @@
// best is the push-index of the latest (=innermost) node containing range.
// (Beware: latest is not always innermost because FuncDecl.{Name,Type} overlap.)
- best := int32(-1)
+ best, bestLimit := int32(-1), int32(-1)
for i, limit := c.indices(); i < limit; i++ {
ev := events[i]
if ev.index > i { // push?
+ if bestLimit != -1 && i >= bestLimit {
+ break
+ }
+
n := ev.node
var nodeEnd token.Pos
if file, ok := n.(*ast.File); ok {
@@ -501,10 +508,12 @@
break // disjoint, after; stop
}
}
+
// Inv: node.{Pos,FileStart} <= start
if end <= nodeEnd {
// node fully contains target range
best = i
+ bestLimit = ev.index
} else if nodeEnd < start {
i = ev.index // disjoint, before; skip forward
}
diff --git a/gopls/internal/test/marker/testdata/references/issue76872.txt b/gopls/internal/test/marker/testdata/references/issue76872.txt
new file mode 100644
index 0000000..77f1457
--- /dev/null
+++ b/gopls/internal/test/marker/testdata/references/issue76872.txt
@@ -0,0 +1,14 @@
+This test exercises a references query at a position where the cursor belongs to
+two syntax nodes: the node before and the node after. It ensures that we find
+the reference of the syntax node before the cursor.
+
+See https://github.com/golang/go/issues/76872.
+
+-- main.go --
+package main
+
+func foo() {} //@ loc(decl, "foo"), refs(re"foo()", decl, call)
+
+func _() {
+ foo() //@ loc(call, "foo")
+}