sa1032.go (2056B)
1 package sa1032 2 3 import ( 4 "honnef.co/go/tools/analysis/callcheck" 5 "honnef.co/go/tools/analysis/lint" 6 "honnef.co/go/tools/go/ir" 7 "honnef.co/go/tools/internal/passes/buildir" 8 9 "golang.org/x/tools/go/analysis" 10 ) 11 12 var SCAnalyzer = lint.InitializeAnalyzer(&lint.Analyzer{ 13 Analyzer: &analysis.Analyzer{ 14 Name: "SA1032", 15 Requires: []*analysis.Analyzer{buildir.Analyzer}, 16 Run: callcheck.Analyzer(rules), 17 }, 18 Doc: &lint.RawDocumentation{ 19 Title: `Wrong order of arguments to \'errors.Is\'`, 20 Text: ` 21 The first argument of the function \'errors.Is\' is the error 22 that we have and the second argument is the error we're trying to match against. 23 For example: 24 25 if errors.Is(err, io.EOF) { ... } 26 27 This check detects some cases where the two arguments have been swapped. It 28 flags any calls where the first argument is referring to a package-level error 29 variable, such as 30 31 if errors.Is(io.EOF, err) { /* this is wrong */ }`, 32 Since: "2024.1", 33 Severity: lint.SeverityError, 34 MergeIf: lint.MergeIfAny, 35 }, 36 }) 37 38 var Analyzer = SCAnalyzer.Analyzer 39 40 var rules = map[string]callcheck.Check{ 41 "errors.Is": validateIs, 42 } 43 44 func validateIs(call *callcheck.Call) { 45 if len(call.Args) != 2 { 46 return 47 } 48 49 global := func(arg *callcheck.Argument) *ir.Global { 50 v, ok := arg.Value.Value.(*ir.Load) 51 if !ok { 52 return nil 53 } 54 g, _ := v.X.(*ir.Global) 55 return g 56 } 57 58 x, y := call.Args[0], call.Args[1] 59 gx := global(x) 60 if gx == nil { 61 return 62 } 63 64 if pkgx := gx.Package().Pkg; pkgx != nil && pkgx.Path() != call.Pass.Pkg.Path() { 65 // x is a global that's not in this package 66 67 if gy := global(y); gy != nil { 68 if pkgy := gy.Package().Pkg; pkgy != nil && pkgy.Path() != call.Pass.Pkg.Path() { 69 // Both arguments refer to globals that aren't in this package. This can 70 // genuinely happen for external tests that check that one error "is" 71 // another one. net/http's external tests, for example, do 72 // `errors.Is(http.ErrNotSupported, errors.ErrUnsupported)`. 73 return 74 } 75 } 76 77 call.Invalid("arguments have the wrong order") 78 } 79 }