github.com/amarpal/go-tools@v0.0.0-20240422043104-40142f59f616/simple/s1005/s1005.go (about) 1 package s1005 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/facts/generated" 9 "github.com/amarpal/go-tools/analysis/lint" 10 "github.com/amarpal/go-tools/analysis/report" 11 "github.com/amarpal/go-tools/go/ast/astutil" 12 "github.com/amarpal/go-tools/pattern" 13 14 "golang.org/x/tools/go/analysis" 15 "golang.org/x/tools/go/analysis/passes/inspect" 16 ) 17 18 var SCAnalyzer = lint.InitializeAnalyzer(&lint.Analyzer{ 19 Analyzer: &analysis.Analyzer{ 20 Name: "S1005", 21 Run: run, 22 Requires: []*analysis.Analyzer{inspect.Analyzer, generated.Analyzer}, 23 }, 24 Doc: &lint.Documentation{ 25 Title: `Drop unnecessary use of the blank identifier`, 26 Text: `In many cases, assigning to the blank identifier is unnecessary.`, 27 Before: ` 28 for _ = range s {} 29 x, _ = someMap[key] 30 _ = <-ch`, 31 After: ` 32 for range s{} 33 x = someMap[key] 34 <-ch`, 35 Since: "2017.1", 36 MergeIf: lint.MergeIfAny, 37 }, 38 }) 39 40 var Analyzer = SCAnalyzer.Analyzer 41 42 var ( 43 checkUnnecessaryBlankQ1 = pattern.MustParse(` 44 (AssignStmt 45 [_ (Ident "_")] 46 _ 47 (Or 48 (IndexExpr _ _) 49 (UnaryExpr "<-" _))) `) 50 checkUnnecessaryBlankQ2 = pattern.MustParse(` 51 (AssignStmt 52 (Ident "_") _ recv@(UnaryExpr "<-" _))`) 53 ) 54 55 func run(pass *analysis.Pass) (interface{}, error) { 56 fn1 := func(node ast.Node) { 57 if _, ok := code.Match(pass, checkUnnecessaryBlankQ1, node); ok { 58 r := *node.(*ast.AssignStmt) 59 r.Lhs = r.Lhs[0:1] 60 report.Report(pass, node, "unnecessary assignment to the blank identifier", 61 report.FilterGenerated(), 62 report.Fixes(edit.Fix("remove assignment to blank identifier", edit.ReplaceWithNode(pass.Fset, node, &r)))) 63 } else if m, ok := code.Match(pass, checkUnnecessaryBlankQ2, node); ok { 64 report.Report(pass, node, "unnecessary assignment to the blank identifier", 65 report.FilterGenerated(), 66 report.Fixes(edit.Fix("simplify channel receive operation", edit.ReplaceWithNode(pass.Fset, node, m.State["recv"].(ast.Node))))) 67 } 68 } 69 70 fn3 := func(node ast.Node) { 71 rs := node.(*ast.RangeStmt) 72 73 // for _ 74 if rs.Value == nil && astutil.IsBlank(rs.Key) { 75 report.Report(pass, rs.Key, "unnecessary assignment to the blank identifier", 76 report.FilterGenerated(), 77 report.MinimumLanguageVersion(4), 78 report.Fixes(edit.Fix("remove assignment to blank identifier", edit.Delete(edit.Range{rs.Key.Pos(), rs.TokPos + 1})))) 79 } 80 81 // for _, _ 82 if astutil.IsBlank(rs.Key) && astutil.IsBlank(rs.Value) { 83 // FIXME we should mark both key and value 84 report.Report(pass, rs.Key, "unnecessary assignment to the blank identifier", 85 report.FilterGenerated(), 86 report.MinimumLanguageVersion(4), 87 report.Fixes(edit.Fix("remove assignment to blank identifier", edit.Delete(edit.Range{rs.Key.Pos(), rs.TokPos + 1})))) 88 } 89 90 // for x, _ 91 if !astutil.IsBlank(rs.Key) && astutil.IsBlank(rs.Value) { 92 report.Report(pass, rs.Value, "unnecessary assignment to the blank identifier", 93 report.FilterGenerated(), 94 report.MinimumLanguageVersion(4), 95 report.Fixes(edit.Fix("remove assignment to blank identifier", edit.Delete(edit.Range{rs.Key.End(), rs.Value.End()})))) 96 } 97 } 98 99 code.Preorder(pass, fn1, (*ast.AssignStmt)(nil)) 100 code.Preorder(pass, fn3, (*ast.RangeStmt)(nil)) 101 return nil, nil 102 }