Skip to content

x/tools/gopls: "Remove variable" deletes the declaration but keeps an assignment to the variable #81809

Closed

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. 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
}
  1. Open the file and delete the argument of RenderContent(b) on line 72, so it reads out, err = RenderContent().
  2. gopls now reports declared and not used: b (UnusedVar) at 66:6, besides not enough arguments in call to RenderContent on line 72.
  3. 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

  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. self-assigned this
    on Sep 29, 2026
  4. gopherbot commented on Sep 29, 2026

    @gopherbot
    Contributor

    Change https://go.dev/cl/841565 mentions this issue: gopls/internal/analysis/unusedvariable: remove assignments to unused variables

  5. added a commit that references this issue on Oct 12, 2026
    291f247
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

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

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions