Repository navigation
x/tools/gopls: "Remove variable" deletes the declaration but keeps an assignment to the variable #81809
Description
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. fatedier/frp at d20a232996007dfe6ab425abc0a39a3ae9a0889b, pkg/config/legacy/value.go, lines 65 to 74 (1-based); RenderContent(in []byte) (out []byte, err error) is defined in the same file:
func GetRenderedConfFromFile(path string) (out []byte, err error) {
var b []byte
b, err = os.ReadFile(path)
if err != nil {
return
}
out, err = RenderContent(b)
return
}- Open the file and delete the argument of
RenderContent(b)on line 72, so it readsout, err = RenderContent(). - gopls now reports
declared and not used: b(UnusedVar) at 66:6, besidesnot enough arguments in call to RenderContenton line 72. - Apply the quick fix "Remove variable b" offered for the UnusedVar diagnostic.
What did you see happen?
The fix deletes line 66 (var b []byte) and nothing else:
func GetRenderedConfFromFile(path string) (out []byte, err error) {
b, err = os.ReadFile(path)
if err != nil {
return
}
out, err = RenderContent()
return
}go build ./pkg/config/legacy before the fix (after step 1):
pkg/config/legacy/value.go:66:6: declared and not used: b
pkg/config/legacy/value.go:72:13: not enough arguments in call to RenderContent
have ()
want ([]byte)
after the fix:
pkg/config/legacy/value.go:66:2: undefined: b
pkg/config/legacy/value.go:71:13: not enough arguments in call to RenderContent
have ()
want ([]byte)
The not enough arguments error is the one I caused in step 1; declared and not used: b is replaced by undefined: b. gopls reports undefined: b right after the edit. Same in 3 of 3 runs.
What did you expect to see?
The fix removes b without leaving a use of it, for example by also turning the assignment into _, err = os.ReadFile(path), or it is not offered while b is still assigned.
#54373 (closed in January 2025) was about the same quick fix producing edits that were too large. Here the edit is too small: the assignment to the removed variable stays.
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
LSP trace
F stands for the URI of pkg/config/legacy/value.go; positions are 0-based.
--> textDocument/didChange {"textDocument":{"uri":F,"version":2},"contentChanges":[{"range":{"start":{"line":71,"character":26},"end":{"line":71,"character":27}},"text":""}]}
<-- textDocument/publishDiagnostics {"uri":F,"version":2,"diagnostics":[
{"range":{"start":{"line":65,"character":5},"end":{"line":65,"character":6}},"severity":1,"code":"UnusedVar","source":"compiler","message":"declared and not used: b","tags":[1]},
{"range":{"start":{"line":71,"character":26},...},"severity":1,"code":"WrongArgCount","source":"compiler","message":"not enough arguments in call to RenderContent\n\thave ()\n\twant ([]byte)"}]}
--> textDocument/codeAction {"textDocument":{"uri":F},"range":{"start":{"line":65,"character":5},"end":{"line":65,"character":6}},"context":{"diagnostics":[(the UnusedVar diagnostic)],"only":["quickfix"],"triggerKind":1}}
<-- [{"title":"Remove variable b","kind":"quickfix","diagnostics":[(the UnusedVar diagnostic)],
"edit":{"documentChanges":[{"textDocument":{"version":2,"uri":F},"edits":[{"range":{"start":{"line":65,"character":0},"end":{"line":66,"character":0}},"newText":""}]}]}}]
--> textDocument/didChange (the edit above, version 3)
<-- textDocument/publishDiagnostics {"uri":F,"version":3,"diagnostics":[
{"range":{"start":{"line":65,"character":1},"end":{"line":65,"character":2}},"severity":1,"code":"UndeclaredName","source":"compiler","message":"undefined: b"},
{"range":{"start":{"line":70,"character":26},...},"severity":1,"code":"WrongArgCount","source":"compiler","message":"not enough arguments in call to RenderContent\n\thave ()\n\twant ([]byte)"}]}
Activity
gabyhelp commentedon Sep 28, 2026
Related Issues
(Emoji vote if this was helpful or unhelpful; more detailed feedback welcome in this discussion.)
gopherbot commentedon Sep 29, 2026
Change https://go.dev/cl/841565 mentions this issue:
gopls/internal/analysis/unusedvariable: remove assignments to unused variablesgopls/internal/analysis/unusedvariable: remove assignments to unused …