mirror of
https://github.com/mgechev/revive.git
synced 2024-11-30 08:57:07 +02:00
82 lines
1.6 KiB
Go
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),
|
|
})
|
|
}
|
|
}
|