sa1018.go raw
1 package sa1018
2
3 import (
4 "fmt"
5 "go/constant"
6
7 "honnef.co/go/tools/analysis/callcheck"
8 "honnef.co/go/tools/analysis/lint"
9 "honnef.co/go/tools/go/ir"
10 "honnef.co/go/tools/internal/passes/buildir"
11
12 "golang.org/x/tools/go/analysis"
13 )
14
15 var SCAnalyzer = lint.InitializeAnalyzer(&lint.Analyzer{
16 Analyzer: &analysis.Analyzer{
17 Name: "SA1018",
18 Requires: []*analysis.Analyzer{buildir.Analyzer},
19 Run: callcheck.Analyzer(rules),
20 },
21 Doc: &lint.RawDocumentation{
22 Title: `\'strings.Replace\' called with \'n == 0\', which does nothing`,
23 Text: `With \'n == 0\', zero instances will be replaced. To replace all
24 instances, use a negative number, or use \'strings.ReplaceAll\'.`,
25 Since: "2017.1",
26 Severity: lint.SeverityWarning,
27 MergeIf: lint.MergeIfAny, // MergeIfAny if we only flag literals, not named constants
28 },
29 })
30
31 var Analyzer = SCAnalyzer.Analyzer
32
33 var rules = map[string]callcheck.Check{
34 "strings.Replace": check("strings.Replace", 3),
35 "bytes.Replace": check("bytes.Replace", 3),
36 }
37
38 func check(name string, arg int) callcheck.Check {
39 return func(call *callcheck.Call) {
40 arg := call.Args[arg]
41 if k, ok := arg.Value.Value.(*ir.Const); ok && k.Value.Kind() == constant.Int {
42 if v, ok := constant.Int64Val(k.Value); ok && v == 0 {
43 arg.Invalid(fmt.Sprintf("calling %s with n == 0 will return no results, did you mean -1?", name))
44 }
45 }
46 }
47 }
48