mirror of
https://github.com/mgechev/revive.git
synced 2025-01-22 03:38:47 +02:00
Co-authored-by: SalvadorC <salvadorcavadini+github@gmail.com>
This commit is contained in:
parent
2c895fb33f
commit
0fada9d76c
@ -17,10 +17,25 @@ type ErrorStringsRule struct{}
|
||||
func (r *ErrorStringsRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
|
||||
var failures []lint.Failure
|
||||
|
||||
var errorFunctions = map[string]map[string]struct{}{
|
||||
"fmt": {
|
||||
"Errorf": {},
|
||||
},
|
||||
"errors": {
|
||||
"Errorf": {},
|
||||
"WithMessage": {},
|
||||
"Wrap": {},
|
||||
"New": {},
|
||||
"WithMessagef": {},
|
||||
"Wrapf": {},
|
||||
},
|
||||
}
|
||||
|
||||
fileAst := file.AST
|
||||
walker := lintErrorStrings{
|
||||
file: file,
|
||||
fileAst: fileAst,
|
||||
file: file,
|
||||
fileAst: fileAst,
|
||||
errorFunctions: errorFunctions,
|
||||
onFailure: func(failure lint.Failure) {
|
||||
failures = append(failures, failure)
|
||||
},
|
||||
@ -37,24 +52,31 @@ func (r *ErrorStringsRule) Name() string {
|
||||
}
|
||||
|
||||
type lintErrorStrings struct {
|
||||
file *lint.File
|
||||
fileAst *ast.File
|
||||
onFailure func(lint.Failure)
|
||||
file *lint.File
|
||||
fileAst *ast.File
|
||||
errorFunctions map[string]map[string]struct{}
|
||||
onFailure func(lint.Failure)
|
||||
}
|
||||
|
||||
// Visit browses the AST
|
||||
func (w lintErrorStrings) Visit(n ast.Node) ast.Visitor {
|
||||
ce, ok := n.(*ast.CallExpr)
|
||||
if !ok {
|
||||
return w
|
||||
}
|
||||
if !isPkgDot(ce.Fun, "errors", "New") && !isPkgDot(ce.Fun, "fmt", "Errorf") {
|
||||
return w
|
||||
}
|
||||
|
||||
if len(ce.Args) < 1 {
|
||||
return w
|
||||
}
|
||||
str, ok := ce.Args[0].(*ast.BasicLit)
|
||||
if !ok || str.Kind != token.STRING {
|
||||
|
||||
// expression matches the known pkg.function
|
||||
ok = w.match(ce)
|
||||
if !ok {
|
||||
return w
|
||||
}
|
||||
|
||||
str, ok := w.getMessage(ce)
|
||||
if !ok {
|
||||
return w
|
||||
}
|
||||
s, _ := strconv.Unquote(str.Value) // can assume well-formed Go
|
||||
@ -65,7 +87,6 @@ func (w lintErrorStrings) Visit(n ast.Node) ast.Visitor {
|
||||
if clean {
|
||||
return w
|
||||
}
|
||||
|
||||
w.onFailure(lint.Failure{
|
||||
Node: str,
|
||||
Confidence: conf,
|
||||
@ -75,6 +96,52 @@ func (w lintErrorStrings) Visit(n ast.Node) ast.Visitor {
|
||||
return w
|
||||
}
|
||||
|
||||
// match returns true if the expression corresponds to the known pkg.function
|
||||
// i.e.: errors.Wrap
|
||||
func (w lintErrorStrings) match(expr *ast.CallExpr) bool {
|
||||
sel, ok := expr.Fun.(*ast.SelectorExpr)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
// retrieve the package
|
||||
id, ok := sel.X.(*ast.Ident)
|
||||
functions, ok := w.errorFunctions[id.Name]
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
// retrieve the function
|
||||
_, ok = functions[sel.Sel.Name]
|
||||
return ok
|
||||
}
|
||||
|
||||
// getMessage returns the message depending on its position
|
||||
// returns false if the cast is unsuccessful
|
||||
func (w lintErrorStrings) getMessage(expr *ast.CallExpr) (s *ast.BasicLit, success bool) {
|
||||
str, ok := w.checkArg(expr, 0)
|
||||
if ok {
|
||||
return str, true
|
||||
}
|
||||
if len(expr.Args) < 2 {
|
||||
return s, false
|
||||
}
|
||||
str, ok = w.checkArg(expr, 1)
|
||||
if !ok {
|
||||
return s, false
|
||||
}
|
||||
return str, true
|
||||
}
|
||||
|
||||
func (lintErrorStrings) checkArg(expr *ast.CallExpr, arg int) (s *ast.BasicLit, success bool) {
|
||||
str, ok := expr.Args[arg].(*ast.BasicLit)
|
||||
if !ok {
|
||||
return s, false
|
||||
}
|
||||
if str.Kind != token.STRING {
|
||||
return s, false
|
||||
}
|
||||
return str, true
|
||||
}
|
||||
|
||||
func lintErrorString(s string) (isClean bool, conf float64) {
|
||||
const basicConfidence = 0.8
|
||||
const capConfidence = basicConfidence - 0.2
|
||||
|
18
testdata/golint/error-strings-pkg-errors.go
vendored
Normal file
18
testdata/golint/error-strings-pkg-errors.go
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
// Package foo ...
|
||||
package foo
|
||||
|
||||
import (
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// Check for the error strings themselves.
|
||||
|
||||
func errorsStrings(x int) error {
|
||||
var err error
|
||||
err = errors.Wrap(err, "This %d is too low") // MATCH /error strings should not be capitalized or end with punctuation or a newline/
|
||||
err = errors.New("This %d is too low") // MATCH /error strings should not be capitalized or end with punctuation or a newline/
|
||||
err = errors.Wrapf(err, "This %d is too low", x) // MATCH /error strings should not be capitalized or end with punctuation or a newline/
|
||||
err = errors.WithMessage(err, "This %d is too low") // MATCH /error strings should not be capitalized or end with punctuation or a newline/
|
||||
err = errors.WithMessagef(err, "This %d is too low", x) // MATCH /error strings should not be capitalized or end with punctuation or a newline/
|
||||
return err
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user