github.com/amarpal/go-tools@v0.0.0-20240422043104-40142f59f616/simple/s1036/s1036.go (about) 1 package s1036 2 3 import ( 4 "go/ast" 5 6 "github.com/amarpal/go-tools/analysis/code" 7 "github.com/amarpal/go-tools/analysis/edit" 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: "S1036", 19 Run: run, 20 Requires: []*analysis.Analyzer{inspect.Analyzer}, 21 }, 22 Doc: &lint.Documentation{ 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 }