src

Go monorepo.
git clone git://code.dwrz.net/src
Log | Files | Refs

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 }