Skip to content

Commit 18cdb55

Browse files
authored
Exported config (#565)
* working version * adds flag for replacing "stutters"
1 parent 406b1ce commit 18cdb55

File tree

8 files changed

+116
-5
lines changed

8 files changed

+116
-5
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -408,7 +408,7 @@ List of all available rules. The rules ported from `golint` are left unchanged a
408408
| [`error-return`](./RULES_DESCRIPTIONS.md#error-return) | n/a | The error return parameter should be last. | yes | no |
409409
| [`error-strings`](./RULES_DESCRIPTIONS.md#error-strings) | n/a | Conventions around error strings. | yes | no |
410410
| [`error-naming`](./RULES_DESCRIPTIONS.md#error-naming) | n/a | Naming of error variables. | yes | no |
411-
| [`exported`](./RULES_DESCRIPTIONS.md#exported) | n/a | Naming and commenting conventions on exported symbols. | yes | no |
411+
| [`exported`](./RULES_DESCRIPTIONS.md#exported) | []string | Naming and commenting conventions on exported symbols. | yes | no |
412412
| [`if-return`](./RULES_DESCRIPTIONS.md#if-return) | n/a | Redundant if when returning an error. | no | no |
413413
| [`increment-decrement`](./RULES_DESCRIPTIONS.md#increment-decrement) | n/a | Use `i++` and `i--` instead of `i += 1` and `i -= 1`. | yes | no |
414414
| [`var-naming`](./RULES_DESCRIPTIONS.md#var-naming) | whitelist & blacklist of initialisms | Naming rules. | yes | no |

RULES_DESCRIPTIONS.md

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -299,7 +299,20 @@ _Description_: Exported function and methods should have comments. This warns on
299299

300300
More information [here](https://github.com/golang/go/wiki/CodeReviewComments#doc-comments)
301301

302-
_Configuration_: N/A
302+
_Configuration_: ([]string) rule flags.
303+
Please notice that without configuration, the default behavior of the rule is that of its `golint` counterpart.
304+
Available flags are:
305+
306+
* _checkPrivateReceivers_ enables checking public methods of private types
307+
* _disableStutteringCheck_ disables checking for method names that stutter with the package name (i.e. avoid failure messages of the form _type name will be used as x.XY by other packages, and that stutters; consider calling this Y_)
308+
* _sayRepetitiveInsteadOfStutters_ replaces the use of the term _stutters_ by _repetitive_ in failure messages
309+
310+
Example:
311+
312+
```toml
313+
[rule.exported]
314+
arguments =["checkPrivateReceivers","disableStutteringCheck"]
315+
```
303316

304317
## file-header
305318

rule/exported.go

Lines changed: 46 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,20 @@ import (
1515
type ExportedRule struct{}
1616

1717
// Apply applies the rule to given file.
18-
func (r *ExportedRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
18+
func (r *ExportedRule) Apply(file *lint.File, args lint.Arguments) []lint.Failure {
1919
var failures []lint.Failure
2020

2121
if isTest(file) {
2222
return failures
2323
}
2424

25+
checkPrivateReceivers, disableStutteringCheck, sayRepetitiveInsteadOfStutters := r.getConf(args)
26+
27+
stuttersMsg := "stutters"
28+
if sayRepetitiveInsteadOfStutters {
29+
stuttersMsg = "is repetitive"
30+
}
31+
2532
fileAst := file.AST
2633
walker := lintExported{
2734
file: file,
@@ -30,6 +37,9 @@ func (r *ExportedRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
3037
failures = append(failures, failure)
3138
},
3239
genDeclMissingComments: make(map[*ast.GenDecl]bool),
40+
checkPrivateReceivers: checkPrivateReceivers,
41+
disableStutteringCheck: disableStutteringCheck,
42+
stuttersMsg: stuttersMsg,
3343
}
3444

3545
ast.Walk(&walker, fileAst)
@@ -42,12 +52,41 @@ func (r *ExportedRule) Name() string {
4252
return "exported"
4353
}
4454

55+
func (r *ExportedRule) getConf(args lint.Arguments) (checkPrivateReceivers bool, disableStutteringCheck bool, sayRepetitiveInsteadOfStutters bool) {
56+
// if any, we expect a slice of strings as configuration
57+
if len(args) < 1 {
58+
return
59+
}
60+
for _, flag := range args {
61+
flagStr, ok := flag.(string)
62+
if !ok {
63+
panic(fmt.Sprintf("Invalid argument for the %s rule: expecting a string, got %T", r.Name(), flag))
64+
}
65+
66+
switch flagStr {
67+
case "checkPrivateReceivers":
68+
checkPrivateReceivers = true
69+
case "disableStutteringCheck":
70+
disableStutteringCheck = true
71+
case "sayRepetitiveInsteadOfStutters":
72+
sayRepetitiveInsteadOfStutters = true
73+
default:
74+
panic(fmt.Sprintf("Unknown configuration flag %s for %s rule", flagStr, r.Name()))
75+
}
76+
}
77+
78+
return
79+
}
80+
4581
type lintExported struct {
4682
file *lint.File
4783
fileAst *ast.File
4884
lastGen *ast.GenDecl
4985
genDeclMissingComments map[*ast.GenDecl]bool
5086
onFailure func(lint.Failure)
87+
checkPrivateReceivers bool
88+
disableStutteringCheck bool
89+
stuttersMsg string
5190
}
5291

5392
func (w *lintExported) lintFuncDoc(fn *ast.FuncDecl) {
@@ -61,7 +100,7 @@ func (w *lintExported) lintFuncDoc(fn *ast.FuncDecl) {
61100
// method
62101
kind = "method"
63102
recv := receiverType(fn)
64-
if !ast.IsExported(recv) {
103+
if !ast.IsExported(recv) && !w.checkPrivateReceivers {
65104
// receiver is unexported
66105
return
67106
}
@@ -98,6 +137,10 @@ func (w *lintExported) lintFuncDoc(fn *ast.FuncDecl) {
98137
}
99138

100139
func (w *lintExported) checkStutter(id *ast.Ident, thing string) {
140+
if w.disableStutteringCheck {
141+
return
142+
}
143+
101144
pkg, name := w.fileAst.Name.Name, id.Name
102145
if !ast.IsExported(name) {
103146
// unexported name
@@ -122,7 +165,7 @@ func (w *lintExported) checkStutter(id *ast.Ident, thing string) {
122165
Node: id,
123166
Confidence: 0.8,
124167
Category: "naming",
125-
Failure: fmt.Sprintf("%s name will be used as %s.%s by other packages, and that stutters; consider calling this %s", thing, pkg, name, rem),
168+
Failure: fmt.Sprintf("%s name will be used as %s.%s by other packages, and that %s; consider calling this %s", thing, pkg, name, w.stuttersMsg, rem),
126169
})
127170
}
128171
}

test/exported_test.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package test
2+
3+
import (
4+
"testing"
5+
6+
"github.com/mgechev/revive/lint"
7+
"github.com/mgechev/revive/rule"
8+
)
9+
10+
func TestExportedWithDisableStutteringCheck(t *testing.T) {
11+
args := []interface{}{"disableStutteringCheck"}
12+
13+
testRule(t, "exported-issue-555", &rule.ExportedRule{}, &lint.RuleConfig{Arguments: args})
14+
}
15+
16+
func TestExportedWithChecksOnMethodsOfPrivateTypes(t *testing.T) {
17+
args := []interface{}{"checkPrivateReceivers"}
18+
19+
testRule(t, "exported-issue-552", &rule.ExportedRule{}, &lint.RuleConfig{Arguments: args})
20+
}
21+
22+
func TestExportedReplacingStuttersByRepetitive(t *testing.T) {
23+
args := []interface{}{"sayRepetitiveInsteadOfStutters"}
24+
25+
testRule(t, "exported-issue-519", &rule.ExportedRule{}, &lint.RuleConfig{Arguments: args})
26+
}

testdata/exported-issue-519.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// Package golint comment
2+
package golint
3+
4+
// Test case for the configuration option tp replace the word "stutters" by "repetitive" failure messages
5+
6+
// GolintRepetitive is a dummy function
7+
func GolintRepetitive() {} // MATCH /func name will be used as golint.GolintRepetitive by other packages, and that is repetitive; consider calling this Repetitive/

testdata/exported-issue-552.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// Package golint comment
2+
package golint
3+
4+
// Test cases for enabling checks of exported methods of private types in exported rule
5+
type private struct {
6+
}
7+
8+
// MATCH /comment on exported method private.Method should be of the form "Method ..."/
9+
func (p *private) Method() {
10+
}

testdata/exported-issue-555.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// Package golint comment
2+
package golint
3+
4+
// Test case for disabling stuttering check in exported rule
5+
6+
// GolintSomething is a dummy function
7+
func GolintSomething() {}

testdata/golint/exported.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ package golint
33

44
import "net/http"
55

6+
// GolintFoo is a dummy function
7+
func GolintFoo() {} // MATCH /func name will be used as golint.GolintFoo by other packages, and that stutters; consider calling this Foo/
8+
69
type (
710
// O is a shortcut (alias) for map[string]interface{}, e.g. a JSON object.
811
O = map[string]interface{}
@@ -53,3 +56,5 @@ func ServeHTTP(w http.ResponseWriter, r *http.Request) {} // MATC
5356
func Read(p []byte) (n int, err error) { return 0, nil } // MATCH /exported function Read should have comment or be unexported/
5457
func Write(p []byte) (n int, err error) { return 0, nil } // MATCH /exported function Write should have comment or be unexported/
5558
func Unwrap(err error) error { return nil } // MATCH /exported function Unwrap should have comment or be unexported/
59+
60+
// The following cases are tests for issue 555

0 commit comments

Comments
 (0)