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  }