Skip to content

x/tools/gopls: references miss uses in a package's _test.go files until a file of the package is edited #81811

Open

Description

@wangzhihao-lab

gopls version

golang.org/x/tools/gopls v0.23.0 (h1:Dn6mf9WXu9iLnTftDDMb9wV0c6Se7PjzEMqP0LEe08Y=), built with go1.27.1.
v0.23.0 is still the newest gopls release (checked 2026-09-28); reproduces on it again in 3 of 3 runs.
Same result with gopls v0.20.0.

go env

GOARCH=arm64
GOOS=darwin
GOVERSION=go1.27.1
GOFLAGS=-modcacherw
GOTOOLCHAIN=local

(macOS 27 on Apple silicon; path variables left out.)

What did you do?

I drive gopls over LSP from a small script. charmbracelet/bubbletea at 657aaae216e3f87df09b60959a9fe5de7b2ca419. The repository root is module charm.land/bubbletea/v2 (package tea); examples/ is a separate module (module examples) with replace charm.land/bubbletea/v2 => ../. There is no go.work. gopls is started at the repository root and creates two views, one for the root and one for examples.

The request is textDocument/references on Model in examples/http/main.go line 38, column 43 (1-based; LSP {line: 37, character: 42}):

func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {

Two runs, each with a newly started gopls, the same files on disk, and the same three files open at the end (examples/http/main.go, examples/set-window-title/main.go, mouse.go):

  • A: open examples/http/main.go, examples/set-window-title/main.go and mouse.go (a file of package tea), wait until gopls is idle, send the request.
  • B: open examples/http/main.go and termios_unix.go; in termios_unix.go type ( after the ) that closes the import block (line 9, column 2; LSP {line: 8, character: 1}); close termios_unix.go without saving. The steps were sent about 200 ms apart. Then open examples/set-window-title/main.go and mouse.go, wait until gopls is idle, send the request.

What did you see happen?

A returns 80 locations: 70 in examples/, 9 in tea.go, 1 in options.go, none in a _test.go file.

B returns 87: the same 80 plus these 7 in package tea's test files (1-based):

cursed_renderer_test.go:20:43   func (m *mouseRaceModel) Update(msg Msg) (Model, Cmd) {
exec_test.go:32:42              func (m *testExecModel) Update(msg Msg) (Model, Cmd) {
options_test.go:39:42           p := NewProgram(nil, WithFilter(func(_ Model, msg Msg) Msg { return msg }))
screen_test.go:37:42            func (m *testViewModel) Update(msg Msg) (Model, Cmd) {
tea_test.go:37:38               func (m *testModel) Update(msg Msg) (Model, Cmd) {
tea_test.go:244:20              p.filter = func(_ Model, msg Msg) Msg {
tea_test.go:623:38              func (m benchModel) Update(msg Msg) (Model, Cmd) {

These files have package tea, go list -test . lists them in TestGoFiles, none declares its own Model, and go vet . passes, so all 7 refer to tea.Model.

Opening and closing termios_unix.go without typing gives 80, and so does leaving it out. The edit has to be there, even though it is discarded. Waiting 60 s before the request does not change either answer. I repeated each variant 3 times with the same results.

What did you expect to see?

The same answer in both runs. Since the answer already includes the uses in tea.go and options.go, I expected the uses in the package's _test.go files as well.

#43144 (fixed in 2022, now locked) described find-references missing test files "unless you've opened the test's package". Here a file of the package (mouse.go) is open in both runs and opening termios_unix.go is not enough; only an edit to one of its files makes the test files appear. The request also comes from another module that reaches the package through a replace directive, which may matter. #73781 is about references across modules in general and does not cover this.

Editor and settings

No editor; a script over stdio (gopls serve). Settings returned for workspace/configuration: {"semanticTokens": true, "hints": {"assignVariableTypes": true, "compositeLiteralFields": true, "compositeLiteralTypes": true, "constantValues": true, "functionTypeParameters": true, "parameterNames": true, "rangeVariableTypes": true}}.

Logs

In the recorded run B below, after termios_unix.go is closed, gopls logs an extra go/packages.Load for the examples view whose query names charm.land/bubbletea/v2 and the example packages. In run A the examples view is only loaded once, with the pattern examples/....

LSP trace

URIs shortened to file:///repo/..., file texts elided; <ws> in log messages is the repository root. The recorded run B also opened examples/set-window-title/main.go early and closed and reopened it before closing termios_unix.go; that is not needed to reproduce, the steps above are enough.

Run B:

--> textDocument/didOpen {"textDocument":{"uri":"file:///repo/examples/http/main.go","languageId":"go","version":1,"text":"..."}}
<-- window/logMessage go/packages.Load #1  view_id="1" snapshot=0 query=[<ws>/... builtin] packages=4
--> textDocument/didOpen {"textDocument":{"uri":"file:///repo/examples/set-window-title/main.go","languageId":"go","version":1,"text":"..."}}
<-- window/logMessage go/packages.Load #2  view_id="2" snapshot=0 query=[<ws>/examples/... builtin] packages=66
--> textDocument/didOpen {"textDocument":{"uri":"file:///repo/termios_unix.go","languageId":"go","version":1,"text":"..."}}
--> textDocument/didChange {"textDocument":{"uri":"file:///repo/termios_unix.go","version":2},"contentChanges":[{"range":{"start":{"line":8,"character":1},"end":{"line":8,"character":1}},"text":"("}]}
--> textDocument/didClose {"textDocument":{"uri":"file:///repo/examples/set-window-title/main.go"}}
--> textDocument/didOpen {"textDocument":{"uri":"file:///repo/examples/set-window-title/main.go","languageId":"go","version":1,"text":"..."}}
--> textDocument/didClose {"textDocument":{"uri":"file:///repo/termios_unix.go"}}
--> textDocument/didOpen {"textDocument":{"uri":"file:///repo/mouse.go","languageId":"go","version":1,"text":"..."}}
<-- window/logMessage go/packages.Load #3  view_id="1" snapshot=8 query=[file=<ws>/mouse.go] packages=2
<-- window/logMessage go/packages.Load #4  view_id="2" snapshot=8 query=[charm.land/bubbles/v2/cursor ... charm.land/bubbletea/v2 examples/altscreen-toggle ... examples/split-editors ...]
--> textDocument/references {"textDocument":{"uri":"file:///repo/examples/http/main.go"},"position":{"line":37,"character":42},"context":{"includeDeclaration":true}}
<-- [87 locations, including
     {"uri":"file:///repo/cursed_renderer_test.go","range":{"start":{"line":19,"character":42},"end":{"line":19,"character":47}}},
     {"uri":"file:///repo/exec_test.go","range":{"start":{"line":31,"character":41},"end":{"line":31,"character":46}}},
     {"uri":"file:///repo/options_test.go","range":{"start":{"line":38,"character":41},"end":{"line":38,"character":46}}},
     {"uri":"file:///repo/screen_test.go","range":{"start":{"line":36,"character":41},"end":{"line":36,"character":46}}},
     {"uri":"file:///repo/tea_test.go","range":{"start":{"line":36,"character":37},"end":{"line":36,"character":42}}},
     {"uri":"file:///repo/tea_test.go","range":{"start":{"line":243,"character":19},"end":{"line":243,"character":24}}},
     {"uri":"file:///repo/tea_test.go","range":{"start":{"line":622,"character":37},"end":{"line":622,"character":42}}}]

Run A (the same textDocument/references request):

<-- window/logMessage go/packages.Load #1  view_id="1" snapshot=0 query=[<ws>/... builtin] packages=4
<-- window/logMessage go/packages.Load #2  view_id="2" snapshot=0 query=[<ws>/examples/... builtin] packages=66
--> textDocument/references {"textDocument":{"uri":"file:///repo/examples/http/main.go"},"position":{"line":37,"character":42},"context":{"includeDeclaration":true}}
<-- [80 locations: 70 under examples/, tea.go lines 53, 60, 480, 489, 603, 751 (twice), 894, 999, options.go line 133; no _test.go file]

Activity

  1. added
    ToolsThis label describes issues relating to any tools in the x/tools repository.
    goplsIssues related to the Go language server, gopls.
    on Sep 28, 2026
  2. added this to the Unreleased milestone on Sep 28, 2026
  3. added
    NeedsInvestigationSomeone must examine and confirm this is a valid issue and not a duplicate of an existing one.
    on Oct 1, 2026
  4. self-assigned this
    on Oct 1, 2026
  5. h9jiang commented on Oct 1, 2026

    @h9jiang
    Member

    +Needs Investigation

    I think I previously investigated in #73781 so I will take another action item and reply later to this issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

NeedsInvestigationSomeone must examine and confirm this is a valid issue and not a duplicate of an existing one.ToolsThis label describes issues relating to any tools in the x/tools repository.goplsIssues related to the Go language server, gopls.

Type

No type

Projects

No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions