mirror of
https://github.com/mgechev/revive.git
synced 2025-07-05 00:28:53 +02:00
Co-authored-by: SalvadorC <salvadorcavadini+github@gmail.com>
This commit is contained in:
@ -17,10 +17,25 @@ type ErrorStringsRule struct{}
|
|||||||
func (r *ErrorStringsRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
|
func (r *ErrorStringsRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
|
||||||
var failures []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
|
fileAst := file.AST
|
||||||
walker := lintErrorStrings{
|
walker := lintErrorStrings{
|
||||||
file: file,
|
file: file,
|
||||||
fileAst: fileAst,
|
fileAst: fileAst,
|
||||||
|
errorFunctions: errorFunctions,
|
||||||
onFailure: func(failure lint.Failure) {
|
onFailure: func(failure lint.Failure) {
|
||||||
failures = append(failures, failure)
|
failures = append(failures, failure)
|
||||||
},
|
},
|
||||||
@ -37,24 +52,31 @@ func (r *ErrorStringsRule) Name() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type lintErrorStrings struct {
|
type lintErrorStrings struct {
|
||||||
file *lint.File
|
file *lint.File
|
||||||
fileAst *ast.File
|
fileAst *ast.File
|
||||||
onFailure func(lint.Failure)
|
errorFunctions map[string]map[string]struct{}
|
||||||
|
onFailure func(lint.Failure)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Visit browses the AST
|
||||||
func (w lintErrorStrings) Visit(n ast.Node) ast.Visitor {
|
func (w lintErrorStrings) Visit(n ast.Node) ast.Visitor {
|
||||||
ce, ok := n.(*ast.CallExpr)
|
ce, ok := n.(*ast.CallExpr)
|
||||||
if !ok {
|
if !ok {
|
||||||
return w
|
return w
|
||||||
}
|
}
|
||||||
if !isPkgDot(ce.Fun, "errors", "New") && !isPkgDot(ce.Fun, "fmt", "Errorf") {
|
|
||||||
return w
|
|
||||||
}
|
|
||||||
if len(ce.Args) < 1 {
|
if len(ce.Args) < 1 {
|
||||||
return w
|
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
|
return w
|
||||||
}
|
}
|
||||||
s, _ := strconv.Unquote(str.Value) // can assume well-formed Go
|
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 {
|
if clean {
|
||||||
return w
|
return w
|
||||||
}
|
}
|
||||||
|
|
||||||
w.onFailure(lint.Failure{
|
w.onFailure(lint.Failure{
|
||||||
Node: str,
|
Node: str,
|
||||||
Confidence: conf,
|
Confidence: conf,
|
||||||
@ -75,6 +96,52 @@ func (w lintErrorStrings) Visit(n ast.Node) ast.Visitor {
|
|||||||
return w
|
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) {
|
func lintErrorString(s string) (isClean bool, conf float64) {
|
||||||
const basicConfidence = 0.8
|
const basicConfidence = 0.8
|
||||||
const capConfidence = basicConfidence - 0.2
|
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
|
||||||
|
}
|
Reference in New Issue
Block a user