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  }