github.com/amarpal/go-tools@v0.0.0-20240422043104-40142f59f616/staticcheck/sa1013/sa1013.go (about)

     1  package sa1013
     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/knowledge"
    11  	"github.com/amarpal/go-tools/pattern"
    12  
    13  	"golang.org/x/tools/go/analysis"
    14  	"golang.org/x/tools/go/analysis/passes/inspect"
    15  )
    16  
    17  var SCAnalyzer = lint.InitializeAnalyzer(&lint.Analyzer{
    18  	Analyzer: &analysis.Analyzer{
    19  		Name:     "SA1013",
    20  		Run:      run,
    21  		Requires: []*analysis.Analyzer{inspect.Analyzer},
    22  	},
    23  	Doc: &lint.Documentation{
    24  		Title:    `\'io.Seeker.Seek\' is being called with the whence constant as the first argument, but it should be the second`,
    25  		Since:    "2017.1",
    26  		Severity: lint.SeverityWarning,
    27  		MergeIf:  lint.MergeIfAny,
    28  	},
    29  })
    30  
    31  var Analyzer = SCAnalyzer.Analyzer
    32  
    33  var (
    34  	checkSeekerQ = pattern.MustParse(`(CallExpr fun@(SelectorExpr _ (Ident "Seek")) [arg1@(SelectorExpr _ (Symbol (Or "io.SeekStart" "io.SeekCurrent" "io.SeekEnd"))) arg2])`)
    35  	checkSeekerR = pattern.MustParse(`(CallExpr fun [arg2 arg1])`)
    36  )
    37  
    38  func run(pass *analysis.Pass) (interface{}, error) {
    39  	fn := func(node ast.Node) {
    40  		if m, edits, ok := code.MatchAndEdit(pass, checkSeekerQ, checkSeekerR, node); ok {
    41  			if !code.IsMethod(pass, m.State["fun"].(*ast.SelectorExpr), "Seek", knowledge.Signatures["(io.Seeker).Seek"]) {
    42  				return
    43  			}
    44  			report.Report(pass, node, "the first argument of io.Seeker is the offset, but an io.Seek* constant is being used instead",
    45  				report.Fixes(edit.Fix("swap arguments", edits...)))
    46  		}
    47  	}
    48  	code.Preorder(pass, fn, (*ast.CallExpr)(nil))
    49  	return nil, nil
    50  }