Skip to content

Commit

Permalink
feat: option to exclude specific methods
Browse files Browse the repository at this point in the history
  • Loading branch information
ldez committed Nov 27, 2024
1 parent 02533ff commit 1d24ffa
Showing 1 changed file with 60 additions and 23 deletions.
83 changes: 60 additions & 23 deletions analyzer.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,21 +10,26 @@ import (

// NewAnalyzer returns a new analyzer to check for receiver type consistency.
func NewAnalyzer(s Settings) *analysis.Analyzer {
// Default excludes for Marshal/Encode methods https://github.com/raeperd/recvcheck/issues/7
excludedMethods := map[string]struct{}{
"MarshalText": {},
"MarshalJSON": {},
"MarshalYAML": {},
"MarshalXML": {},
"MarshalBinary": {},
"GobEncode": {},
a := &analyzer{
// Default excludes for Marshal/Encode methods https://github.com/raeperd/recvcheck/issues/7
excludedMethods: map[string]struct{}{
"MarshalText": {},
"MarshalJSON": {},
"MarshalYAML": {},
"MarshalXML": {},
"MarshalBinary": {},
"GobEncode": {},
},
excludedTuple: map[string]struct{}{},
}

if s.DisableBuiltin {
excludedMethods = map[string]struct{}{}
a.excludedMethods = map[string]struct{}{}
}

a := &analyzer{excludedMethods: excludedMethods}
for _, exclusion := range s.Exclusions {
a.excludedMethods[exclusion] = struct{}{}
}

return &analysis.Analyzer{
Name: "recvcheck",
Expand All @@ -45,10 +50,15 @@ type Settings struct {
// - "MarshalBinary"
// - "GobEncode"
DisableBuiltin bool

// Exclusions format is `struct_name.method_name` (ex: `Foo.MethodName`).
// A wildcard `*` can use as a struct name (ex: `*.MethodName`).
Exclusions []string
}

type analyzer struct {
excludedMethods map[string]struct{}
excludedTuple map[string]struct{}
}

func (r *analyzer) run(pass *analysis.Pass) (any, error) {
Expand All @@ -61,21 +71,16 @@ func (r *analyzer) run(pass *analysis.Pass) (any, error) {
return
}

if r.isExcluded(funcDecl) {
if r.isBuildInExcluded(funcDecl) {
return
}

recv, isStar := recvTypeIdent(funcDecl.Recv.List[0].Type)
if recv == nil {
return
}

var recv *ast.Ident
var isStar bool
switch recvType := funcDecl.Recv.List[0].Type.(type) {
case *ast.StarExpr:
isStar = true
if recv, ok = recvType.X.(*ast.Ident); !ok {
return
}
case *ast.Ident:
recv = recvType
default:
if r.isUserExcluded(recv, funcDecl) {
return
}

Expand All @@ -101,7 +106,25 @@ func (r *analyzer) run(pass *analysis.Pass) (any, error) {
return nil, nil
}

func (r *analyzer) isExcluded(f *ast.FuncDecl) bool {
func (r *analyzer) isUserExcluded(recv *ast.Ident, f *ast.FuncDecl) bool {
if f.Name == nil || f.Name.Name == "" {
return true
}

_, found := r.excludedTuple[recv.Name+"."+f.Name.Name]
if found {
return true
}

_, found = r.excludedTuple["*."+f.Name.Name]
if found {

Check failure on line 120 in analyzer.go

View workflow job for this annotation

GitHub Actions / lint

S1008: should use 'return found' instead of 'if found { return true }; return false' (gosimple)
return true
}

return false
}

func (r *analyzer) isBuildInExcluded(f *ast.FuncDecl) bool {
if f.Name == nil || f.Name.Name == "" {
return true
}
Expand All @@ -114,3 +137,17 @@ type structType struct {
starUsed bool
typeUsed bool
}

func recvTypeIdent(r ast.Expr) (*ast.Ident, bool) {
switch n := r.(type) {
case *ast.StarExpr:
if r, ok := n.X.(*ast.Ident); !ok {
return r, false
}

case *ast.Ident:
return n, false
}

return nil, false
}

0 comments on commit 1d24ffa

Please sign in to comment.