You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

78 lines
1.8 KiB

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