1
0
mirror of https://github.com/mgechev/revive.git synced 2024-11-30 08:57:07 +02:00
revive/rule/context-keys-type.go
2022-04-10 11:55:13 +02:00

82 lines
1.6 KiB
Go

package rule
import (
"fmt"
"go/ast"
"go/types"
"github.com/mgechev/revive/lint"
)
// ContextKeysType lints given else constructs.
type ContextKeysType struct{}
// Apply applies the rule to given file.
func (*ContextKeysType) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
var failures []lint.Failure
fileAst := file.AST
walker := lintContextKeyTypes{
file: file,
fileAst: fileAst,
onFailure: func(failure lint.Failure) {
failures = append(failures, failure)
},
}
file.Pkg.TypeCheck()
ast.Walk(walker, fileAst)
return failures
}
// Name returns the rule name.
func (*ContextKeysType) Name() string {
return "context-keys-type"
}
type lintContextKeyTypes struct {
file *lint.File
fileAst *ast.File
onFailure func(lint.Failure)
}
func (w lintContextKeyTypes) Visit(n ast.Node) ast.Visitor {
switch n := n.(type) {
case *ast.CallExpr:
checkContextKeyType(w, n)
}
return w
}
func checkContextKeyType(w lintContextKeyTypes, x *ast.CallExpr) {
f := w.file
sel, ok := x.Fun.(*ast.SelectorExpr)
if !ok {
return
}
pkg, ok := sel.X.(*ast.Ident)
if !ok || pkg.Name != "context" {
return
}
if sel.Sel.Name != "WithValue" {
return
}
// key is second argument to context.WithValue
if len(x.Args) != 3 {
return
}
key := f.Pkg.TypesInfo().Types[x.Args[1]]
if ktyp, ok := key.Type.(*types.Basic); ok && ktyp.Kind() != types.Invalid {
w.onFailure(lint.Failure{
Confidence: 1,
Node: x,
Category: "content",
Failure: fmt.Sprintf("should not use basic type %s as key in context.WithValue", key.Type),
})
}
}