blob: 3129d0f14eda35bad4421afbeb89f570e275cce5 [file] [log] [blame]
// Copyright 2020 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package unusedvariable defines an analyzer that checks for unused variables.
package unusedvariable
import (
"fmt"
"go/ast"
"regexp"
"strings"
"golang.org/x/tools/go/analysis"
"golang.org/x/tools/go/analysis/passes/inspect"
"golang.org/x/tools/go/ast/inspector"
"golang.org/x/tools/internal/refactor"
)
const Doc = `check for unused variables and suggest fixes`
var Analyzer = &analysis.Analyzer{
Name: "unusedvariable",
Doc: Doc,
Requires: []*analysis.Analyzer{inspect.Analyzer},
Run: run,
RunDespiteErrors: true, // an unusedvariable diagnostic is a compile error
URL: "https://pkg.go.dev/golang.org/x/tools/gopls/internal/analysis/unusedvariable",
}
// The suffix for this error message changed in Go 1.20 and Go 1.23.
var unusedVariableRegexp = []*regexp.Regexp{
regexp.MustCompile("^(.*) declared and not used$"), // Go 1.20+
regexp.MustCompile("^declared and not used: (.*)$"), // Go 1.23+
}
func run(pass *analysis.Pass) (any, error) {
inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
for _, typeErr := range pass.TypeErrors {
for _, re := range unusedVariableRegexp {
match := re.FindStringSubmatch(typeErr.Msg)
if len(match) == 0 {
continue
}
// Since Go 1.23, go/types' error messages quote vars as `v'.
varName := strings.Trim(match[1], "`'")
curId, ok := inspect.Root().FindByPos(typeErr.Pos, typeErr.Pos)
if !ok {
continue // can't find error node
}
ident, ok := curId.Node().(*ast.Ident)
if !ok || ident.Name != varName {
continue // not the right identifier
}
tokFile := pass.Fset.File(ident.Pos())
edits := refactor.DeleteVar(tokFile, pass.TypesInfo, curId)
if len(edits) > 0 {
pass.Report(analysis.Diagnostic{
Pos: ident.Pos(),
End: ident.End(),
Message: typeErr.Msg,
SuggestedFixes: []analysis.SuggestedFix{{
Message: fmt.Sprintf("Remove variable %s", ident.Name),
TextEdits: edits,
}},
})
}
}
}
return nil, nil
}