Skip to content

Commit 53a111d

Browse files
chavacavachavacavaytnsym
authored
adds check for receiver names length (#1048)
Co-authored-by: chavacava <[email protected]> Co-authored-by: yuta nishiyama <[email protected]>
1 parent a65fb8d commit 53a111d

File tree

5 files changed

+80
-7
lines changed

5 files changed

+80
-7
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -480,7 +480,7 @@ List of all available rules. The rules ported from `golint` are left unchanged a
480480
| [`var-naming`](./RULES_DESCRIPTIONS.md#var-naming) | allowlist & blocklist of initialisms | Naming rules. | yes | no |
481481
| [`package-comments`](./RULES_DESCRIPTIONS.md#package-comments) | n/a | Package commenting conventions. | yes | no |
482482
| [`range`](./RULES_DESCRIPTIONS.md#range) | n/a | Prevents redundant variables when iterating over a collection. | yes | no |
483-
| [`receiver-naming`](./RULES_DESCRIPTIONS.md#receiver-naming) | n/a | Conventions around the naming of receivers. | yes | no |
483+
| [`receiver-naming`](./RULES_DESCRIPTIONS.md#receiver-naming) | map (optional) | Conventions around the naming of receivers. | yes | no |
484484
| [`indent-error-flow`](./RULES_DESCRIPTIONS.md#indent-error-flow) | []string | Prevents redundant else statements. | yes | no |
485485
| [`argument-limit`](./RULES_DESCRIPTIONS.md#argument-limit) | int (defaults to 8) | Specifies the maximum number of arguments a function can receive | no | no |
486486
| [`cyclomatic`](./RULES_DESCRIPTIONS.md#cyclomatic) | int (defaults to 10) | Sets restriction for maximum Cyclomatic complexity. | no | no |

RULES_DESCRIPTIONS.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -737,7 +737,14 @@ _Configuration_: N/A
737737
738738
_Description_: By convention, receiver names in a method should reflect their identity. For example, if the receiver is of type `Parts`, `p` is an adequate name for it. Contrary to other languages, it is not idiomatic to name receivers as `this` or `self`.
739739
740-
_Configuration_: N/A
740+
_Configuration_: (optional) list of key-value-pair-map (`[]map[string]any`).
741+
742+
- `maxLength` : (int) max length of receiver name
743+
744+
```toml
745+
[rule.receiver-naming]
746+
arguments = [{maxLength=2}]
747+
```
741748
742749
## redefines-builtin-id
743750

rule/receiver-naming.go

Lines changed: 57 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,24 +3,64 @@ package rule
33
import (
44
"fmt"
55
"go/ast"
6+
"sync"
67

78
"github.com/mgechev/revive/internal/typeparams"
89
"github.com/mgechev/revive/lint"
910
)
1011

1112
// ReceiverNamingRule lints given else constructs.
12-
type ReceiverNamingRule struct{}
13+
type ReceiverNamingRule struct {
14+
receiverNameMaxLength int
15+
sync.Mutex
16+
}
17+
18+
const defaultReceiverNameMaxLength = -1 // thus will not check
19+
20+
func (r *ReceiverNamingRule) configure(arguments lint.Arguments) {
21+
r.Lock()
22+
defer r.Unlock()
23+
if r.receiverNameMaxLength != 0 {
24+
return
25+
}
26+
27+
r.receiverNameMaxLength = defaultReceiverNameMaxLength
28+
if len(arguments) < 1 {
29+
return
30+
}
31+
32+
args, ok := arguments[0].(map[string]any)
33+
if !ok {
34+
panic(fmt.Sprintf("Unable to get arguments for rule %s. Expected object of key-value-pairs.", r.Name()))
35+
}
36+
37+
for k, v := range args {
38+
switch k {
39+
case "maxLength":
40+
value, ok := v.(int64)
41+
if !ok {
42+
panic(fmt.Sprintf("Invalid value %v for argument %s of rule %s, expected integer value got %T", v, k, r.Name(), v))
43+
}
44+
r.receiverNameMaxLength = int(value)
45+
default:
46+
panic(fmt.Sprintf("Unknown argument %s for %s rule.", k, r.Name()))
47+
}
48+
}
49+
}
1350

1451
// Apply applies the rule to given file.
15-
func (*ReceiverNamingRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
52+
func (r *ReceiverNamingRule) Apply(file *lint.File, args lint.Arguments) []lint.Failure {
53+
r.configure(args)
54+
1655
var failures []lint.Failure
1756

1857
fileAst := file.AST
1958
walker := lintReceiverName{
2059
onFailure: func(failure lint.Failure) {
2160
failures = append(failures, failure)
2261
},
23-
typeReceiver: map[string]string{},
62+
typeReceiver: map[string]string{},
63+
receiverNameMaxLength: r.receiverNameMaxLength,
2464
}
2565

2666
ast.Walk(walker, fileAst)
@@ -34,8 +74,9 @@ func (*ReceiverNamingRule) Name() string {
3474
}
3575

3676
type lintReceiverName struct {
37-
onFailure func(lint.Failure)
38-
typeReceiver map[string]string
77+
onFailure func(lint.Failure)
78+
typeReceiver map[string]string
79+
receiverNameMaxLength int
3980
}
4081

4182
func (w lintReceiverName) Visit(n ast.Node) ast.Visitor {
@@ -66,6 +107,17 @@ func (w lintReceiverName) Visit(n ast.Node) ast.Visitor {
66107
})
67108
return w
68109
}
110+
111+
if w.receiverNameMaxLength > 0 && len([]rune(name)) > w.receiverNameMaxLength {
112+
w.onFailure(lint.Failure{
113+
Node: n,
114+
Confidence: 1,
115+
Category: "naming",
116+
Failure: fmt.Sprintf("receiver name %s is longer than %d characters", name, w.receiverNameMaxLength),
117+
})
118+
return w
119+
}
120+
69121
recv := typeparams.ReceiverType(fn)
70122
if prev, ok := w.typeReceiver[recv]; ok && prev != name {
71123
w.onFailure(lint.Failure{

test/receiver-naming_test.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"testing"
55

66
"github.com/mgechev/revive/internal/typeparams"
7+
"github.com/mgechev/revive/lint"
78
"github.com/mgechev/revive/rule"
89
)
910

@@ -13,3 +14,11 @@ func TestReceiverNamingTypeParams(t *testing.T) {
1314
}
1415
testRule(t, "receiver-naming-issue-669", &rule.ReceiverNamingRule{})
1516
}
17+
18+
func TestReceiverNamingMaxLength(t *testing.T) {
19+
args := []any{map[string]any{
20+
"maxLength": int64(2),
21+
}}
22+
testRule(t, "receiver-naming-issue-1040", &rule.ReceiverNamingRule{},
23+
&lint.RuleConfig{Arguments: args})
24+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package fixtures
2+
3+
func (o *o) f1() {}
4+
func (tw *tw) f2() {}
5+
func (thr *thr) f3() {} // MATCH /receiver name thr is longer than 2 characters/

0 commit comments

Comments
 (0)