sa4024.go raw
1 package sa4024
2
3 import (
4 "fmt"
5 "go/ast"
6
7 "honnef.co/go/tools/analysis/code"
8 "honnef.co/go/tools/analysis/lint"
9 "honnef.co/go/tools/analysis/report"
10 "honnef.co/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.RawDocumentation{
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 }
67