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  }