s1005.go (3491B)
1 package s1005 2 3 import ( 4 "go/ast" 5 "go/types" 6 7 "honnef.co/go/tools/analysis/code" 8 "honnef.co/go/tools/analysis/edit" 9 "honnef.co/go/tools/analysis/facts/generated" 10 "honnef.co/go/tools/analysis/lint" 11 "honnef.co/go/tools/analysis/report" 12 "honnef.co/go/tools/go/ast/astutil" 13 "honnef.co/go/tools/pattern" 14 15 "golang.org/x/tools/go/analysis" 16 "golang.org/x/tools/go/analysis/passes/inspect" 17 ) 18 19 var SCAnalyzer = lint.InitializeAnalyzer(&lint.Analyzer{ 20 Analyzer: &analysis.Analyzer{ 21 Name: "S1005", 22 Run: run, 23 Requires: []*analysis.Analyzer{inspect.Analyzer, generated.Analyzer}, 24 }, 25 Doc: &lint.RawDocumentation{ 26 Title: `Drop unnecessary use of the blank identifier`, 27 Text: `In many cases, assigning to the blank identifier is unnecessary.`, 28 Before: ` 29 for _ = range s {} 30 _ = <-ch`, 31 After: ` 32 for range s{} 33 <-ch`, 34 Since: "2017.1", 35 MergeIf: lint.MergeIfAny, 36 }, 37 }) 38 39 var Analyzer = SCAnalyzer.Analyzer 40 41 var ( 42 checkUnnecessaryBlankQ1 = pattern.MustParse(` 43 (AssignStmt 44 [_ (Ident "_")] 45 _ 46 (UnaryExpr "<-" _)) `) 47 checkUnnecessaryBlankQ2 = pattern.MustParse(` 48 (AssignStmt 49 (Ident "_") _ recv@(UnaryExpr "<-" _))`) 50 ) 51 52 func run(pass *analysis.Pass) (any, error) { 53 fn1 := func(node ast.Node) { 54 // We don't check for 'x, _ = m[k]', which might be used to indicate 55 // that one knows that there might be no entry and that one doesn't 56 // care. 57 58 if _, ok := code.Match(pass, checkUnnecessaryBlankQ1, node); ok { 59 r := *node.(*ast.AssignStmt) 60 r.Lhs = r.Lhs[0:1] 61 report.Report(pass, node, "unnecessary assignment to the blank identifier", 62 report.FilterGenerated(), 63 report.Fixes(edit.Fix("Remove assignment to blank identifier", edit.ReplaceWithNode(pass.Fset, node, &r)))) 64 } else if m, ok := code.Match(pass, checkUnnecessaryBlankQ2, node); ok { 65 report.Report(pass, node, "unnecessary assignment to the blank identifier", 66 report.FilterGenerated(), 67 report.Fixes(edit.Fix("Simplify channel receive operation", edit.ReplaceWithNode(pass.Fset, node, m.State["recv"].(ast.Node))))) 68 } 69 } 70 71 fn3 := func(node ast.Node) { 72 rs := node.(*ast.RangeStmt) 73 74 if _, ok := pass.TypesInfo.TypeOf(rs.X).Underlying().(*types.Signature); ok { 75 // iteration variables are not optional with rangefunc 76 return 77 } 78 79 // for _ 80 if rs.Value == nil && astutil.IsBlank(rs.Key) { 81 report.Report(pass, rs.Key, "unnecessary assignment to the blank identifier", 82 report.FilterGenerated(), 83 report.MinimumLanguageVersion("go1.4"), 84 report.Fixes(edit.Fix("Remove assignment to blank identifier", edit.Delete(edit.Range{rs.Key.Pos(), rs.TokPos + 1})))) 85 } 86 87 // for _, _ 88 if astutil.IsBlank(rs.Key) && astutil.IsBlank(rs.Value) { 89 // FIXME we should mark both key and value 90 report.Report(pass, rs.Key, "unnecessary assignment to the blank identifier", 91 report.FilterGenerated(), 92 report.MinimumLanguageVersion("go1.4"), 93 report.Fixes(edit.Fix("Remove assignment to blank identifier", edit.Delete(edit.Range{rs.Key.Pos(), rs.TokPos + 1})))) 94 } 95 96 // for x, _ 97 if !astutil.IsBlank(rs.Key) && astutil.IsBlank(rs.Value) { 98 report.Report(pass, rs.Value, "unnecessary assignment to the blank identifier", 99 report.FilterGenerated(), 100 report.MinimumLanguageVersion("go1.4"), 101 report.Fixes(edit.Fix("Remove assignment to blank identifier", edit.Delete(edit.Range{rs.Key.End(), rs.Value.End()})))) 102 } 103 } 104 105 code.Preorder(pass, fn1, (*ast.AssignStmt)(nil)) 106 code.Preorder(pass, fn3, (*ast.RangeStmt)(nil)) 107 return nil, nil 108 }