github.com/Johnny2210/revive@v1.0.8-0.20210625134200-febf37ccd0f5/rule/context-as-argument.go (about) 1 package rule 2 3 import ( 4 "go/ast" 5 6 "github.com/mgechev/revive/lint" 7 ) 8 9 // ContextAsArgumentRule lints given else constructs. 10 type ContextAsArgumentRule struct{} 11 12 // Apply applies the rule to given file. 13 func (r *ContextAsArgumentRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure { 14 var failures []lint.Failure 15 16 fileAst := file.AST 17 walker := lintContextArguments{ 18 file: file, 19 fileAst: fileAst, 20 onFailure: func(failure lint.Failure) { 21 failures = append(failures, failure) 22 }, 23 } 24 25 ast.Walk(walker, fileAst) 26 27 return failures 28 } 29 30 // Name returns the rule name. 31 func (r *ContextAsArgumentRule) Name() string { 32 return "context-as-argument" 33 } 34 35 type lintContextArguments struct { 36 file *lint.File 37 fileAst *ast.File 38 onFailure func(lint.Failure) 39 } 40 41 func (w lintContextArguments) Visit(n ast.Node) ast.Visitor { 42 fn, ok := n.(*ast.FuncDecl) 43 if !ok || len(fn.Type.Params.List) <= 1 { 44 return w 45 } 46 // A context.Context should be the first parameter of a function. 47 // Flag any that show up after the first. 48 previousArgIsCtx := isPkgDot(fn.Type.Params.List[0].Type, "context", "Context") 49 for _, arg := range fn.Type.Params.List[1:] { 50 argIsCtx := isPkgDot(arg.Type, "context", "Context") 51 if argIsCtx && !previousArgIsCtx { 52 w.onFailure(lint.Failure{ 53 Node: arg, 54 Category: "arg-order", 55 Failure: "context.Context should be the first parameter of a function", 56 Confidence: 0.9, 57 }) 58 break // only flag one 59 } 60 previousArgIsCtx = argIsCtx 61 } 62 return w 63 }