mirror of
https://github.com/mgechev/revive.git
synced 2025-03-19 21:07:46 +02:00
rule.exported: add feature to disable checking on const,method,function, variable (#1047)
Co-authored-by: chavacava <salvadorcavadini+github@gmail.com>
This commit is contained in:
parent
ca2a32b087
commit
ff7b0adb4c
@ -475,12 +475,17 @@ Available flags are:
|
|||||||
* _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_)
|
* _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_)
|
||||||
* _sayRepetitiveInsteadOfStutters_ replaces the use of the term _stutters_ by _repetitive_ in failure messages
|
* _sayRepetitiveInsteadOfStutters_ replaces the use of the term _stutters_ by _repetitive_ in failure messages
|
||||||
* _checkPublicInterface_ enabled checking public method definitions in public interface types
|
* _checkPublicInterface_ enabled checking public method definitions in public interface types
|
||||||
|
* _disableChecksOnConstants_ disable all checks on constant declarations
|
||||||
|
* _disableChecksOnFunctions_ disable all checks on function declarations
|
||||||
|
* _disableChecksOnMethods_ disable all checks on method declarations
|
||||||
|
* _disableChecksOnTypes_ disable all checks on type declarations
|
||||||
|
* _disableChecksOnVariables_ disable all checks on variable declarations
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
[rule.exported]
|
[rule.exported]
|
||||||
arguments = ["checkPrivateReceivers", "disableStutteringCheck", "checkPublicInterface"]
|
arguments = ["checkPrivateReceivers", "disableStutteringCheck", "checkPublicInterface", "disableChecksOnFunctions"]
|
||||||
```
|
```
|
||||||
|
|
||||||
## file-header
|
## file-header
|
||||||
|
132
rule/exported.go
132
rule/exported.go
@ -13,40 +13,92 @@ import (
|
|||||||
"github.com/mgechev/revive/lint"
|
"github.com/mgechev/revive/lint"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// disabledChecks store ignored warnings types
|
||||||
|
type disabledChecks struct {
|
||||||
|
Const bool
|
||||||
|
Function bool
|
||||||
|
Method bool
|
||||||
|
PrivateReceivers bool
|
||||||
|
PublicInterfaces bool
|
||||||
|
Stuttering bool
|
||||||
|
Type bool
|
||||||
|
Var bool
|
||||||
|
}
|
||||||
|
|
||||||
|
const checkNamePrivateReceivers = "privateReceivers"
|
||||||
|
const checkNamePublicInterfaces = "publicInterfaces"
|
||||||
|
const checkNameStuttering = "stuttering"
|
||||||
|
|
||||||
|
// isDisabled returns true if the given check is disabled, false otherwise
|
||||||
|
func (dc *disabledChecks) isDisabled(checkName string) bool {
|
||||||
|
switch checkName {
|
||||||
|
case "var":
|
||||||
|
return dc.Var
|
||||||
|
case "const":
|
||||||
|
return dc.Const
|
||||||
|
case "function":
|
||||||
|
return dc.Function
|
||||||
|
case "method":
|
||||||
|
return dc.Method
|
||||||
|
case checkNamePrivateReceivers:
|
||||||
|
return dc.PrivateReceivers
|
||||||
|
case checkNamePublicInterfaces:
|
||||||
|
return dc.PublicInterfaces
|
||||||
|
case checkNameStuttering:
|
||||||
|
return dc.Stuttering
|
||||||
|
case "type":
|
||||||
|
return dc.Type
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ExportedRule lints given else constructs.
|
// ExportedRule lints given else constructs.
|
||||||
type ExportedRule struct {
|
type ExportedRule struct {
|
||||||
configured bool
|
configured bool
|
||||||
checkPrivateReceivers bool
|
stuttersMsg string
|
||||||
disableStutteringCheck bool
|
disabledChecks disabledChecks
|
||||||
checkPublicInterface bool
|
|
||||||
stuttersMsg string
|
|
||||||
sync.Mutex
|
sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *ExportedRule) configure(arguments lint.Arguments) {
|
func (r *ExportedRule) configure(arguments lint.Arguments) {
|
||||||
r.Lock()
|
r.Lock()
|
||||||
defer r.Unlock()
|
defer r.Unlock()
|
||||||
if !r.configured {
|
if r.configured {
|
||||||
r.stuttersMsg = "stutters"
|
return
|
||||||
for _, flag := range arguments {
|
}
|
||||||
flagStr, ok := flag.(string)
|
r.configured = true
|
||||||
if !ok {
|
|
||||||
panic(fmt.Sprintf("Invalid argument for the %s rule: expecting a string, got %T", r.Name(), flag))
|
r.disabledChecks = disabledChecks{PrivateReceivers: true, PublicInterfaces: true}
|
||||||
}
|
r.stuttersMsg = "stutters"
|
||||||
switch flagStr {
|
for _, flag := range arguments {
|
||||||
|
switch flag := flag.(type) {
|
||||||
|
case string:
|
||||||
|
switch flag {
|
||||||
case "checkPrivateReceivers":
|
case "checkPrivateReceivers":
|
||||||
r.checkPrivateReceivers = true
|
r.disabledChecks.PrivateReceivers = false
|
||||||
case "disableStutteringCheck":
|
case "disableStutteringCheck":
|
||||||
r.disableStutteringCheck = true
|
r.disabledChecks.Stuttering = true
|
||||||
case "sayRepetitiveInsteadOfStutters":
|
case "sayRepetitiveInsteadOfStutters":
|
||||||
r.stuttersMsg = "is repetitive"
|
r.stuttersMsg = "is repetitive"
|
||||||
case "checkPublicInterface":
|
case "checkPublicInterface":
|
||||||
r.checkPublicInterface = true
|
r.disabledChecks.PublicInterfaces = false
|
||||||
|
case "disableChecksOnConstants":
|
||||||
|
r.disabledChecks.Const = true
|
||||||
|
case "disableChecksOnFunctions":
|
||||||
|
r.disabledChecks.Function = true
|
||||||
|
case "disableChecksOnMethods":
|
||||||
|
r.disabledChecks.Method = true
|
||||||
|
case "disableChecksOnTypes":
|
||||||
|
r.disabledChecks.Type = true
|
||||||
|
case "disableChecksOnVariables":
|
||||||
|
r.disabledChecks.Var = true
|
||||||
default:
|
default:
|
||||||
panic(fmt.Sprintf("Unknown configuration flag %s for %s rule", flagStr, r.Name()))
|
panic(fmt.Sprintf("Unknown configuration flag %s for %s rule", flag, r.Name()))
|
||||||
}
|
}
|
||||||
|
default:
|
||||||
|
panic(fmt.Sprintf("Invalid argument for the %s rule: expecting a string, got %T", r.Name(), flag))
|
||||||
}
|
}
|
||||||
r.configured = true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -68,10 +120,8 @@ func (r *ExportedRule) Apply(file *lint.File, args lint.Arguments) []lint.Failur
|
|||||||
failures = append(failures, failure)
|
failures = append(failures, failure)
|
||||||
},
|
},
|
||||||
genDeclMissingComments: make(map[*ast.GenDecl]bool),
|
genDeclMissingComments: make(map[*ast.GenDecl]bool),
|
||||||
checkPrivateReceivers: r.checkPrivateReceivers,
|
|
||||||
disableStutteringCheck: r.disableStutteringCheck,
|
|
||||||
checkPublicInterface: r.checkPublicInterface,
|
|
||||||
stuttersMsg: r.stuttersMsg,
|
stuttersMsg: r.stuttersMsg,
|
||||||
|
disabledChecks: r.disabledChecks,
|
||||||
}
|
}
|
||||||
|
|
||||||
ast.Walk(&walker, fileAst)
|
ast.Walk(&walker, fileAst)
|
||||||
@ -90,30 +140,30 @@ type lintExported struct {
|
|||||||
lastGen *ast.GenDecl
|
lastGen *ast.GenDecl
|
||||||
genDeclMissingComments map[*ast.GenDecl]bool
|
genDeclMissingComments map[*ast.GenDecl]bool
|
||||||
onFailure func(lint.Failure)
|
onFailure func(lint.Failure)
|
||||||
checkPrivateReceivers bool
|
|
||||||
disableStutteringCheck bool
|
|
||||||
checkPublicInterface bool
|
|
||||||
stuttersMsg string
|
stuttersMsg string
|
||||||
|
disabledChecks disabledChecks
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *lintExported) lintFuncDoc(fn *ast.FuncDecl) {
|
func (w *lintExported) lintFuncDoc(fn *ast.FuncDecl) {
|
||||||
if !ast.IsExported(fn.Name.Name) {
|
if !ast.IsExported(fn.Name.Name) {
|
||||||
// func is unexported
|
return // func is unexported, nothing to do
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
kind := "function"
|
kind := "function"
|
||||||
name := fn.Name.Name
|
name := fn.Name.Name
|
||||||
if fn.Recv != nil && len(fn.Recv.List) > 0 {
|
isMethod := fn.Recv != nil && len(fn.Recv.List) > 0
|
||||||
// method
|
if isMethod {
|
||||||
kind = "method"
|
kind = "method"
|
||||||
recv := typeparams.ReceiverType(fn)
|
recv := typeparams.ReceiverType(fn)
|
||||||
if !w.checkPrivateReceivers && !ast.IsExported(recv) {
|
|
||||||
// receiver is unexported
|
if !ast.IsExported(recv) && w.disabledChecks.PrivateReceivers {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if commonMethods[name] {
|
if commonMethods[name] {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
switch name {
|
switch name {
|
||||||
case "Len", "Less", "Swap":
|
case "Len", "Less", "Swap":
|
||||||
sortables := w.file.Pkg.Sortable()
|
sortables := w.file.Pkg.Sortable()
|
||||||
@ -123,6 +173,11 @@ func (w *lintExported) lintFuncDoc(fn *ast.FuncDecl) {
|
|||||||
}
|
}
|
||||||
name = recv + "." + name
|
name = recv + "." + name
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if w.disabledChecks.isDisabled(kind) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if fn.Doc == nil {
|
if fn.Doc == nil {
|
||||||
w.onFailure(lint.Failure{
|
w.onFailure(lint.Failure{
|
||||||
Node: fn,
|
Node: fn,
|
||||||
@ -132,6 +187,7 @@ func (w *lintExported) lintFuncDoc(fn *ast.FuncDecl) {
|
|||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
s := normalizeText(fn.Doc.Text())
|
s := normalizeText(fn.Doc.Text())
|
||||||
prefix := fn.Name.Name + " "
|
prefix := fn.Name.Name + " "
|
||||||
if !strings.HasPrefix(s, prefix) {
|
if !strings.HasPrefix(s, prefix) {
|
||||||
@ -145,7 +201,7 @@ func (w *lintExported) lintFuncDoc(fn *ast.FuncDecl) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (w *lintExported) checkStutter(id *ast.Ident, thing string) {
|
func (w *lintExported) checkStutter(id *ast.Ident, thing string) {
|
||||||
if w.disableStutteringCheck {
|
if w.disabledChecks.Stuttering {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -179,9 +235,14 @@ func (w *lintExported) checkStutter(id *ast.Ident, thing string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (w *lintExported) lintTypeDoc(t *ast.TypeSpec, doc *ast.CommentGroup) {
|
func (w *lintExported) lintTypeDoc(t *ast.TypeSpec, doc *ast.CommentGroup) {
|
||||||
|
if w.disabledChecks.isDisabled("type") {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if !ast.IsExported(t.Name.Name) {
|
if !ast.IsExported(t.Name.Name) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if doc == nil {
|
if doc == nil {
|
||||||
w.onFailure(lint.Failure{
|
w.onFailure(lint.Failure{
|
||||||
Node: t,
|
Node: t,
|
||||||
@ -203,18 +264,19 @@ func (w *lintExported) lintTypeDoc(t *ast.TypeSpec, doc *ast.CommentGroup) {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// if comment starts with name of type and has some text after - it's ok
|
// if comment starts with name of type and has some text after - it's ok
|
||||||
expectedPrefix := t.Name.Name + " "
|
expectedPrefix := t.Name.Name + " "
|
||||||
if strings.HasPrefix(s, expectedPrefix) {
|
if strings.HasPrefix(s, expectedPrefix) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
w.onFailure(lint.Failure{
|
w.onFailure(lint.Failure{
|
||||||
Node: doc,
|
Node: doc,
|
||||||
Confidence: 1,
|
Confidence: 1,
|
||||||
Category: "comments",
|
Category: "comments",
|
||||||
Failure: fmt.Sprintf(`comment on exported type %v should be of the form "%s..." (with optional leading article)`, t.Name, expectedPrefix),
|
Failure: fmt.Sprintf(`comment on exported type %v should be of the form "%s..." (with optional leading article)`, t.Name, expectedPrefix),
|
||||||
})
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *lintExported) lintValueSpecDoc(vs *ast.ValueSpec, gd *ast.GenDecl, genDeclMissingComments map[*ast.GenDecl]bool) {
|
func (w *lintExported) lintValueSpecDoc(vs *ast.ValueSpec, gd *ast.GenDecl, genDeclMissingComments map[*ast.GenDecl]bool) {
|
||||||
@ -223,6 +285,10 @@ func (w *lintExported) lintValueSpecDoc(vs *ast.ValueSpec, gd *ast.GenDecl, genD
|
|||||||
kind = "const"
|
kind = "const"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if w.disabledChecks.isDisabled(kind) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if len(vs.Names) > 1 {
|
if len(vs.Names) > 1 {
|
||||||
// Check that none are exported except for the first.
|
// Check that none are exported except for the first.
|
||||||
for _, n := range vs.Names[1:] {
|
for _, n := range vs.Names[1:] {
|
||||||
@ -324,7 +390,7 @@ func (w *lintExported) Visit(n ast.Node) ast.Visitor {
|
|||||||
w.lintTypeDoc(v, doc)
|
w.lintTypeDoc(v, doc)
|
||||||
w.checkStutter(v.Name, "type")
|
w.checkStutter(v.Name, "type")
|
||||||
|
|
||||||
if w.checkPublicInterface {
|
if !w.disabledChecks.PublicInterfaces {
|
||||||
if iface, ok := v.Type.(*ast.InterfaceType); ok {
|
if iface, ok := v.Type.(*ast.InterfaceType); ok {
|
||||||
if ast.IsExported(v.Name.Name) {
|
if ast.IsExported(v.Name.Name) {
|
||||||
w.doCheckPublicInterface(v.Name.Name, iface)
|
w.doCheckPublicInterface(v.Name.Name, iface)
|
||||||
|
@ -30,3 +30,9 @@ func TestCheckPublicInterfaceOption(t *testing.T) {
|
|||||||
|
|
||||||
testRule(t, "exported-issue-1002", &rule.ExportedRule{}, &lint.RuleConfig{Arguments: args})
|
testRule(t, "exported-issue-1002", &rule.ExportedRule{}, &lint.RuleConfig{Arguments: args})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCheckDisablingOnDeclarationTypes(t *testing.T) {
|
||||||
|
args := []any{"disableChecksOnConstants", "disableChecksOnFunctions", "disableChecksOnMethods", "disableChecksOnTypes", "disableChecksOnVariables"}
|
||||||
|
|
||||||
|
testRule(t, "exported-issue-1045", &rule.ExportedRule{}, &lint.RuleConfig{Arguments: args})
|
||||||
|
}
|
||||||
|
25
testdata/exported-issue-1045.go
vendored
Normal file
25
testdata/exported-issue-1045.go
vendored
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
// Package golint comment
|
||||||
|
package golint
|
||||||
|
|
||||||
|
|
||||||
|
// path separator defined by os.Separator.
|
||||||
|
const FilePath = "xyz"
|
||||||
|
|
||||||
|
|
||||||
|
// Rewrite string to remove non-standard path characters
|
||||||
|
func UnicodeSanitize(s string) string {}
|
||||||
|
|
||||||
|
|
||||||
|
// Tags returns a slice of tags. The order is the original tag order unless it
|
||||||
|
// was changed.
|
||||||
|
func (t *Tags) Keys() []string {}
|
||||||
|
|
||||||
|
// A value which may be passed to the which parameter for Getitimer and
|
||||||
|
type ItimerWhich int
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
// PropertyBag
|
||||||
|
*/
|
||||||
|
// Rectangle An area within an image.
|
||||||
|
type Rectangle struct {}
|
Loading…
x
Reference in New Issue
Block a user