github.com/Johnny2210/revive@v1.0.8-0.20210625134200-febf37ccd0f5/rule/context-keys-type.go (about) 1 package rule 2 3 import ( 4 "fmt" 5 "go/ast" 6 "go/types" 7 8 "github.com/mgechev/revive/lint" 9 ) 10 11 // ContextKeysType lints given else constructs. 12 type ContextKeysType struct{} 13 14 // Apply applies the rule to given file. 15 func (r *ContextKeysType) Apply(file *lint.File, _ lint.Arguments) []lint.Failure { 16 var failures []lint.Failure 17 18 fileAst := file.AST 19 walker := lintContextKeyTypes{ 20 file: file, 21 fileAst: fileAst, 22 onFailure: func(failure lint.Failure) { 23 failures = append(failures, failure) 24 }, 25 } 26 27 file.Pkg.TypeCheck() 28 ast.Walk(walker, fileAst) 29 30 return failures 31 } 32 33 // Name returns the rule name. 34 func (r *ContextKeysType) Name() string { 35 return "context-keys-type" 36 } 37 38 type lintContextKeyTypes struct { 39 file *lint.File 40 fileAst *ast.File 41 onFailure func(lint.Failure) 42 } 43 44 func (w lintContextKeyTypes) Visit(n ast.Node) ast.Visitor { 45 switch n := n.(type) { 46 case *ast.CallExpr: 47 checkContextKeyType(w, n) 48 } 49 50 return w 51 } 52 53 func checkContextKeyType(w lintContextKeyTypes, x *ast.CallExpr) { 54 f := w.file 55 sel, ok := x.Fun.(*ast.SelectorExpr) 56 if !ok { 57 return 58 } 59 pkg, ok := sel.X.(*ast.Ident) 60 if !ok || pkg.Name != "context" { 61 return 62 } 63 if sel.Sel.Name != "WithValue" { 64 return 65 } 66 67 // key is second argument to context.WithValue 68 if len(x.Args) != 3 { 69 return 70 } 71 key := f.Pkg.TypesInfo.Types[x.Args[1]] 72 73 if ktyp, ok := key.Type.(*types.Basic); ok && ktyp.Kind() != types.Invalid { 74 w.onFailure(lint.Failure{ 75 Confidence: 1, 76 Node: x, 77 Category: "content", 78 Failure: fmt.Sprintf("should not use basic type %s as key in context.WithValue", key.Type), 79 }) 80 } 81 }