honnef.co/go/tools@v0.5.0-0.dev.0.20240520180541-dcae280a5e87/stylecheck/st1012/st1012.go (about)

     1  package st1012
     2  
     3  import (
     4  	"fmt"
     5  	"go/ast"
     6  	"go/token"
     7  	"strings"
     8  
     9  	"honnef.co/go/tools/analysis/code"
    10  	"honnef.co/go/tools/analysis/lint"
    11  	"honnef.co/go/tools/analysis/report"
    12  
    13  	"golang.org/x/tools/go/analysis"
    14  )
    15  
    16  var SCAnalyzer = lint.InitializeAnalyzer(&lint.Analyzer{
    17  	Analyzer: &analysis.Analyzer{
    18  		Name: "ST1012",
    19  		Run:  run,
    20  	},
    21  	Doc: &lint.Documentation{
    22  		Title: `Poorly chosen name for error variable`,
    23  		Text: `Error variables that are part of an API should be called \'errFoo\' or
    24  \'ErrFoo\'.`,
    25  		Since:   "2019.1",
    26  		MergeIf: lint.MergeIfAny,
    27  	},
    28  })
    29  
    30  var Analyzer = SCAnalyzer.Analyzer
    31  
    32  func run(pass *analysis.Pass) (interface{}, error) {
    33  	for _, f := range pass.Files {
    34  		for _, decl := range f.Decls {
    35  			gen, ok := decl.(*ast.GenDecl)
    36  			if !ok || gen.Tok != token.VAR {
    37  				continue
    38  			}
    39  			for _, spec := range gen.Specs {
    40  				spec := spec.(*ast.ValueSpec)
    41  				if len(spec.Names) != len(spec.Values) {
    42  					continue
    43  				}
    44  
    45  				for i, name := range spec.Names {
    46  					val := spec.Values[i]
    47  					if !code.IsCallToAny(pass, val, "errors.New", "fmt.Errorf") {
    48  						continue
    49  					}
    50  
    51  					if pass.Pkg.Path() == "net/http" && strings.HasPrefix(name.Name, "http2err") {
    52  						// special case for internal variable names of
    53  						// bundled HTTP 2 code in net/http
    54  						continue
    55  					}
    56  					prefix := "err"
    57  					if name.IsExported() {
    58  						prefix = "Err"
    59  					}
    60  					if !strings.HasPrefix(name.Name, prefix) {
    61  						report.Report(pass, name, fmt.Sprintf("error var %s should have name of the form %sFoo", name.Name, prefix))
    62  					}
    63  				}
    64  			}
    65  		}
    66  	}
    67  	return nil, nil
    68  }