github.com/Johnny2210/revive@v1.0.8-0.20210625134200-febf37ccd0f5/rule/unused-receiver.go (about) 1 package rule 2 3 import ( 4 "fmt" 5 "go/ast" 6 7 "github.com/mgechev/revive/lint" 8 ) 9 10 // UnusedReceiverRule lints unused params in functions. 11 type UnusedReceiverRule struct{} 12 13 // Apply applies the rule to given file. 14 func (*UnusedReceiverRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure { 15 var failures []lint.Failure 16 17 onFailure := func(failure lint.Failure) { 18 failures = append(failures, failure) 19 } 20 21 w := lintUnusedReceiverRule{onFailure: onFailure} 22 23 ast.Walk(w, file.AST) 24 25 return failures 26 } 27 28 // Name returns the rule name. 29 func (*UnusedReceiverRule) Name() string { 30 return "unused-receiver" 31 } 32 33 type lintUnusedReceiverRule struct { 34 onFailure func(lint.Failure) 35 } 36 37 func (w lintUnusedReceiverRule) Visit(node ast.Node) ast.Visitor { 38 switch n := node.(type) { 39 case *ast.FuncDecl: 40 if n.Recv == nil { 41 return nil // skip this func decl, not a method 42 } 43 44 rec := n.Recv.List[0] // safe to access only the first (unique) element of the list 45 if len(rec.Names) < 1 { 46 return nil // the receiver is anonymous: func (aType) Foo(...) ... 47 } 48 49 recID := rec.Names[0] 50 if recID.Name == "_" { 51 return nil // the receiver is already named _ 52 } 53 54 // inspect the func body looking for references to the receiver id 55 fselect := func(n ast.Node) bool { 56 ident, isAnID := n.(*ast.Ident) 57 58 return isAnID && ident.Obj == recID.Obj 59 } 60 refs2recID := pick(n.Body, fselect, nil) 61 62 if len(refs2recID) > 0 { 63 return nil // the receiver is referenced in the func body 64 } 65 66 w.onFailure(lint.Failure{ 67 Confidence: 1, 68 Node: recID, 69 Category: "bad practice", 70 Failure: fmt.Sprintf("method receiver '%s' is not referenced in method's body, consider removing or renaming it as _", recID.Name), 71 }) 72 73 return nil // full method body already inspected 74 } 75 76 return w 77 }