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 }