1
0
mirror of https://github.com/mgechev/revive.git synced 2025-01-10 03:17:11 +02:00

Add receiver name

This commit is contained in:
mgechev 2018-01-25 11:12:27 -08:00
parent f9a08cd60f
commit d6a6d6290d
3 changed files with 134 additions and 0 deletions

View File

@ -0,0 +1,49 @@
// Test for bad receiver names.
// Package foo ...
package foo
type foo struct{}
func (this foo) f1() { // MATCH /receiver name should be a reflection of its identity; don't use generic names such as "this" or "self"/
}
func (self foo) f2() { // MATCH /receiver name should be a reflection of its identity; don't use generic names such as "this" or "self"/
}
func (f foo) f3() {
}
func (foo) f4() {
}
type bar struct{}
func (b bar) f1() {
}
func (b bar) f2() {
}
func (a bar) f3() { // MATCH /receiver name a should be consistent with previous receiver name b for bar/
}
func (a *bar) f4() { // MATCH /receiver name a should be consistent with previous receiver name b for bar/
}
func (b *bar) f5() {
}
func (bar) f6() {
}
func (_ *bar) f7() { // MATCH /receiver name should not be an underscore, omit the name if it is unused/
}
type multiError struct{}
func (me multiError) f8() {
}
// Regression test for a panic caused by ill-formed receiver type.
func (recv []*x.y) f()

84
rule/receiver-names.go Normal file
View File

@ -0,0 +1,84 @@
package rule
import (
"fmt"
"go/ast"
"github.com/mgechev/revive/lint"
)
// ReceiverNameRule lints given else constructs.
type ReceiverNameRule struct{}
// Apply applies the rule to given file.
func (r *ReceiverNameRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure {
var failures []lint.Failure
fileAst := file.AST
walker := lintReceiverName{
onFailure: func(failure lint.Failure) {
failures = append(failures, failure)
},
typeReceiver: map[string]string{},
}
ast.Walk(walker, fileAst)
return failures
}
// Name returns the rule name.
func (r *ReceiverNameRule) Name() string {
return "receiver-names"
}
type lintReceiverName struct {
onFailure func(lint.Failure)
typeReceiver map[string]string
}
func (w lintReceiverName) Visit(n ast.Node) ast.Visitor {
fn, ok := n.(*ast.FuncDecl)
if !ok || fn.Recv == nil || len(fn.Recv.List) == 0 {
return w
}
names := fn.Recv.List[0].Names
if len(names) < 1 {
return w
}
name := names[0].Name
const ref = styleGuideBase + "#receiver-names"
if name == "_" {
w.onFailure(lint.Failure{
Node: n,
Confidence: 1,
URL: ref,
Category: "naming",
Failure: "receiver name should not be an underscore, omit the name if it is unused",
})
return w
}
if name == "this" || name == "self" {
w.onFailure(lint.Failure{
Node: n,
Confidence: 1,
URL: ref,
Category: "naming",
Failure: `receiver name should be a reflection of its identity; don't use generic names such as "this" or "self"`,
})
return w
}
recv := receiverType(fn)
if prev, ok := w.typeReceiver[recv]; ok && prev != name {
w.onFailure(lint.Failure{
Node: n,
Confidence: 1,
URL: ref,
Category: "naming",
Failure: fmt.Sprintf("receiver name %s should be consistent with previous receiver name %s for %s", name, prev, recv),
})
return w
}
w.typeReceiver[recv] = name
return w
}

View File

@ -45,6 +45,7 @@ var rules = []lint.Rule{
&rule.ErrorfRule{},
&rule.ErrorsRule{},
&rule.ErrorStringsRule{},
&rule.ReceiverNameRule{},
}
func TestAll(t *testing.T) {