s1036.go raw
1 package s1036
2
3 import (
4 "go/ast"
5
6 "honnef.co/go/tools/analysis/code"
7 "honnef.co/go/tools/analysis/edit"
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: "S1036",
19 Run: run,
20 Requires: []*analysis.Analyzer{inspect.Analyzer},
21 },
22 Doc: &lint.RawDocumentation{
23 Title: `Unnecessary guard around map access`,
24
25 Text: `
26 When accessing a map key that doesn't exist yet, one receives a zero
27 value. Often, the zero value is a suitable value, for example when
28 using append or doing integer math.
29
30 The following
31
32 if _, ok := m["foo"]; ok {
33 m["foo"] = append(m["foo"], "bar")
34 } else {
35 m["foo"] = []string{"bar"}
36 }
37
38 can be simplified to
39
40 m["foo"] = append(m["foo"], "bar")
41
42 and
43
44 if _, ok := m2["k"]; ok {
45 m2["k"] += 4
46 } else {
47 m2["k"] = 4
48 }
49
50 can be simplified to
51
52 m["k"] += 4
53 `,
54 Since: "2020.1",
55 MergeIf: lint.MergeIfAny,
56 },
57 })
58
59 var Analyzer = SCAnalyzer.Analyzer
60
61 var checkUnnecessaryGuardQ = pattern.MustParse(`
62 (Or
63 (IfStmt
64 (AssignStmt [(Ident "_") ok@(Ident _)] ":=" indexexpr@(IndexExpr _ _))
65 ok
66 set@(AssignStmt indexexpr "=" (CallExpr (Builtin "append") indexexpr:values))
67 (AssignStmt indexexpr "=" (CompositeLit _ values)))
68 (IfStmt
69 (AssignStmt [(Ident "_") ok] ":=" indexexpr@(IndexExpr _ _))
70 ok
71 set@(AssignStmt indexexpr "+=" value)
72 (AssignStmt indexexpr "=" value))
73 (IfStmt
74 (AssignStmt [(Ident "_") ok] ":=" indexexpr@(IndexExpr _ _))
75 ok
76 set@(IncDecStmt indexexpr "++")
77 (AssignStmt indexexpr "=" (IntegerLiteral "1"))))`)
78
79 func run(pass *analysis.Pass) (interface{}, error) {
80 fn := func(node ast.Node) {
81 if m, ok := code.Match(pass, checkUnnecessaryGuardQ, node); ok {
82 if code.MayHaveSideEffects(pass, m.State["indexexpr"].(ast.Expr), nil) {
83 return
84 }
85 report.Report(pass, node, "unnecessary guard around map access",
86 report.ShortRange(),
87 report.Fixes(edit.Fix("simplify map access", edit.ReplaceWithNode(pass.Fset, node, m.State["set"].(ast.Node)))))
88 }
89 }
90 code.Preorder(pass, fn, (*ast.IfStmt)(nil))
91 return nil, nil
92 }
93