github.com/amarpal/go-tools@v0.0.0-20240422043104-40142f59f616/staticcheck/sa4024/sa4024.go (about) 1 package sa4024 2 3 import ( 4 "fmt" 5 "go/ast" 6 7 "github.com/amarpal/go-tools/analysis/code" 8 "github.com/amarpal/go-tools/analysis/lint" 9 "github.com/amarpal/go-tools/analysis/report" 10 "github.com/amarpal/go-tools/pattern" 11 12 "golang.org/x/tools/go/analysis" 13 "golang.org/x/tools/go/analysis/passes/inspect" 14 ) 15 16 var SCAnalyzer = lint.InitializeAnalyzer(&lint.Analyzer{ 17 Analyzer: &analysis.Analyzer{ 18 Name: "SA4024", 19 Run: run, 20 Requires: []*analysis.Analyzer{inspect.Analyzer}, 21 }, 22 Doc: &lint.Documentation{ 23 Title: `Checking for impossible return value from a builtin function`, 24 Text: `Return values of the \'len\' and \'cap\' builtins cannot be negative. 25 26 See https://golang.org/pkg/builtin/#len and https://golang.org/pkg/builtin/#cap. 27 28 Example: 29 30 if len(slice) < 0 { 31 fmt.Println("unreachable code") 32 }`, 33 Since: "2021.1", 34 Severity: lint.SeverityWarning, 35 MergeIf: lint.MergeIfAny, 36 }, 37 }) 38 39 var Analyzer = SCAnalyzer.Analyzer 40 41 var builtinLessThanZeroQ = pattern.MustParse(` 42 (Or 43 (BinaryExpr 44 (IntegerLiteral "0") 45 ">" 46 (CallExpr builtin@(Builtin (Or "len" "cap")) _)) 47 (BinaryExpr 48 (CallExpr builtin@(Builtin (Or "len" "cap")) _) 49 "<" 50 (IntegerLiteral "0"))) 51 `) 52 53 func run(pass *analysis.Pass) (interface{}, error) { 54 fn := func(node ast.Node) { 55 matcher, ok := code.Match(pass, builtinLessThanZeroQ, node) 56 if !ok { 57 return 58 } 59 60 builtin := matcher.State["builtin"].(*ast.Ident) 61 report.Report(pass, node, fmt.Sprintf("builtin function %s does not return negative values", builtin.Name)) 62 } 63 code.Preorder(pass, fn, (*ast.BinaryExpr)(nil)) 64 65 return nil, nil 66 }