71 lines
1.7 KiB
Go
71 lines
1.7 KiB
Go
package checkers
|
|
|
|
import (
|
|
"go/ast"
|
|
"go/types"
|
|
|
|
"github.com/go-lintpack/lintpack"
|
|
"github.com/go-lintpack/lintpack/astwalk"
|
|
)
|
|
|
|
func init() {
|
|
var info lintpack.CheckerInfo
|
|
info.Name = "ptrToRefParam"
|
|
info.Tags = []string{"style", "opinionated", "experimental"}
|
|
info.Summary = "Detects input and output parameters that have a type of pointer to referential type"
|
|
info.Before = `func f(m *map[string]int) (*chan *int)`
|
|
info.After = `func f(m map[string]int) (chan *int)`
|
|
|
|
collection.AddChecker(&info, func(ctx *lintpack.CheckerContext) lintpack.FileWalker {
|
|
return astwalk.WalkerForFuncDecl(&ptrToRefParamChecker{ctx: ctx})
|
|
})
|
|
}
|
|
|
|
type ptrToRefParamChecker struct {
|
|
astwalk.WalkHandler
|
|
ctx *lintpack.CheckerContext
|
|
}
|
|
|
|
func (c *ptrToRefParamChecker) VisitFuncDecl(fn *ast.FuncDecl) {
|
|
c.checkParams(fn.Type.Params.List)
|
|
if fn.Type.Results != nil {
|
|
c.checkParams(fn.Type.Results.List)
|
|
}
|
|
}
|
|
|
|
func (c *ptrToRefParamChecker) checkParams(params []*ast.Field) {
|
|
for _, param := range params {
|
|
ptr, ok := c.ctx.TypesInfo.TypeOf(param.Type).(*types.Pointer)
|
|
if !ok {
|
|
continue
|
|
}
|
|
|
|
if c.isRefType(ptr.Elem()) {
|
|
if len(param.Names) == 0 {
|
|
c.ctx.Warn(param, "consider to make non-pointer type for `%s`", param.Type)
|
|
} else {
|
|
for i := range param.Names {
|
|
c.warn(param.Names[i])
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func (c *ptrToRefParamChecker) isRefType(x types.Type) bool {
|
|
switch typ := x.(type) {
|
|
case *types.Map, *types.Chan, *types.Interface:
|
|
return true
|
|
case *types.Named:
|
|
// Handle underlying type only for interfaces.
|
|
if _, ok := typ.Underlying().(*types.Interface); ok {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func (c *ptrToRefParamChecker) warn(id *ast.Ident) {
|
|
c.ctx.Warn(id, "consider `%s' to be of non-pointer type", id)
|
|
}
|