aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/github.com/Antonboom/errname
diff options
context:
space:
mode:
authorTaras Madan <tarasmadan@google.com>2024-11-11 11:41:38 +0100
committerTaras Madan <tarasmadan@google.com>2024-11-11 11:10:48 +0000
commit27e76fae2ee2d84dc7db63af1d9ed7358ba35b7a (patch)
treeed19c0e35e272b3c4cc5a2f2c595e035b2428337 /vendor/github.com/Antonboom/errname
parent621e84e063b0e15b23e17780338627c509e1b9e8 (diff)
vendor: update
Diffstat (limited to 'vendor/github.com/Antonboom/errname')
-rw-r--r--vendor/github.com/Antonboom/errname/pkg/analyzer/analyzer.go131
-rw-r--r--vendor/github.com/Antonboom/errname/pkg/analyzer/facts.go199
2 files changed, 63 insertions, 267 deletions
diff --git a/vendor/github.com/Antonboom/errname/pkg/analyzer/analyzer.go b/vendor/github.com/Antonboom/errname/pkg/analyzer/analyzer.go
index aa8522510..2b8794dc2 100644
--- a/vendor/github.com/Antonboom/errname/pkg/analyzer/analyzer.go
+++ b/vendor/github.com/Antonboom/errname/pkg/analyzer/analyzer.go
@@ -1,11 +1,9 @@
package analyzer
import (
- "fmt"
"go/ast"
"go/token"
- "strconv"
- "strings"
+ "go/types"
"unicode"
"golang.org/x/tools/go/analysis"
@@ -23,86 +21,61 @@ func New() *analysis.Analyzer {
}
}
-type stringSet = map[string]struct{}
-
-var (
- importNodes = []ast.Node{(*ast.ImportSpec)(nil)}
- typeNodes = []ast.Node{(*ast.TypeSpec)(nil)}
- funcNodes = []ast.Node{(*ast.FuncDecl)(nil)}
-)
-
func run(pass *analysis.Pass) (interface{}, error) {
insp := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
- pkgAliases := map[string]string{}
- insp.Preorder(importNodes, func(node ast.Node) {
- i := node.(*ast.ImportSpec)
- if n := i.Name; n != nil && i.Path != nil {
- if path, err := strconv.Unquote(i.Path.Value); err == nil {
- pkgAliases[n.Name] = getPkgFromPath(path)
- }
- }
- })
-
- allTypes := stringSet{}
- typesSpecs := map[string]*ast.TypeSpec{}
- insp.Preorder(typeNodes, func(node ast.Node) {
- t := node.(*ast.TypeSpec)
- allTypes[t.Name.Name] = struct{}{}
- typesSpecs[t.Name.Name] = t
- })
-
- errorTypes := stringSet{}
- insp.Preorder(funcNodes, func(node ast.Node) {
- f := node.(*ast.FuncDecl)
- t, ok := isMethodError(f)
- if !ok {
- return
- }
- errorTypes[t] = struct{}{}
-
- tSpec, ok := typesSpecs[t]
- if !ok {
- panic(fmt.Sprintf("no specification for type %q", t))
- }
-
- if _, ok := tSpec.Type.(*ast.ArrayType); ok {
- if !isValidErrorArrayTypeName(t) {
- reportAboutErrorType(pass, tSpec.Pos(), t, true)
- }
- } else if !isValidErrorTypeName(t) {
- reportAboutErrorType(pass, tSpec.Pos(), t, false)
- }
- })
-
- errorFuncs := stringSet{}
- insp.Preorder(funcNodes, func(node ast.Node) {
- f := node.(*ast.FuncDecl)
- if isFuncReturningErr(f.Type, allTypes, errorTypes) {
- errorFuncs[f.Name.Name] = struct{}{}
+ insp.Nodes([]ast.Node{
+ (*ast.TypeSpec)(nil),
+ (*ast.ValueSpec)(nil),
+ (*ast.FuncDecl)(nil),
+ }, func(node ast.Node, push bool) bool {
+ if !push {
+ return false
}
- })
- inspectPkgLevelVarsOnly := func(node ast.Node) bool {
switch v := node.(type) {
case *ast.FuncDecl:
return false
case *ast.ValueSpec:
- if name, ok := isSentinelError(v, pkgAliases, allTypes, errorTypes, errorFuncs); ok && !isValidErrorVarName(name) {
- reportAboutErrorVar(pass, v.Pos(), name)
+ if len(v.Names) != 1 {
+ return false
+ }
+ ident := v.Names[0]
+
+ if exprImplementsError(pass, ident) && !isValidErrorVarName(ident.Name) {
+ reportAboutSentinelError(pass, v.Pos(), ident.Name)
+ }
+ return false
+
+ case *ast.TypeSpec:
+ tt := pass.TypesInfo.TypeOf(v.Name)
+ if tt == nil {
+ return false
+ }
+ // NOTE(a.telyshev): Pointer is the hack against Error() method with pointer receiver.
+ if !typeImplementsError(types.NewPointer(tt)) {
+ return false
}
+
+ name := v.Name.Name
+ if _, ok := v.Type.(*ast.ArrayType); ok {
+ if !isValidErrorArrayTypeName(name) {
+ reportAboutArrayErrorType(pass, v.Pos(), name)
+ }
+ } else if !isValidErrorTypeName(name) {
+ reportAboutErrorType(pass, v.Pos(), name)
+ }
+ return false
}
+
return true
- }
- for _, f := range pass.Files {
- ast.Inspect(f, inspectPkgLevelVarsOnly)
- }
+ })
return nil, nil //nolint:nilnil
}
-func reportAboutErrorType(pass *analysis.Pass, typePos token.Pos, typeName string, isArrayType bool) {
+func reportAboutErrorType(pass *analysis.Pass, typePos token.Pos, typeName string) {
var form string
if unicode.IsLower([]rune(typeName)[0]) {
form = "xxxError"
@@ -110,26 +83,26 @@ func reportAboutErrorType(pass *analysis.Pass, typePos token.Pos, typeName strin
form = "XxxError"
}
- if isArrayType {
- form += "s"
+ pass.Reportf(typePos, "the error type name `%s` should conform to the `%s` format", typeName, form)
+}
+
+func reportAboutArrayErrorType(pass *analysis.Pass, typePos token.Pos, typeName string) {
+ var forms string
+ if unicode.IsLower([]rune(typeName)[0]) {
+ forms = "`xxxErrors` or `xxxError`"
+ } else {
+ forms = "`XxxErrors` or `XxxError`"
}
- pass.Reportf(typePos, "the type name `%s` should conform to the `%s` format", typeName, form)
+
+ pass.Reportf(typePos, "the error type name `%s` should conform to the %s format", typeName, forms)
}
-func reportAboutErrorVar(pass *analysis.Pass, pos token.Pos, varName string) {
+func reportAboutSentinelError(pass *analysis.Pass, pos token.Pos, varName string) {
var form string
if unicode.IsLower([]rune(varName)[0]) {
form = "errXxx"
} else {
form = "ErrXxx"
}
- pass.Reportf(pos, "the variable name `%s` should conform to the `%s` format", varName, form)
-}
-
-func getPkgFromPath(p string) string {
- idx := strings.LastIndex(p, "/")
- if idx == -1 {
- return p
- }
- return p[idx+1:]
+ pass.Reportf(pos, "the sentinel error name `%s` should conform to the `%s` format", varName, form)
}
diff --git a/vendor/github.com/Antonboom/errname/pkg/analyzer/facts.go b/vendor/github.com/Antonboom/errname/pkg/analyzer/facts.go
index 06f8d61d8..04e14fb68 100644
--- a/vendor/github.com/Antonboom/errname/pkg/analyzer/facts.go
+++ b/vendor/github.com/Antonboom/errname/pkg/analyzer/facts.go
@@ -1,58 +1,22 @@
package analyzer
import (
- "fmt"
"go/ast"
- "go/token"
"go/types"
"strings"
"unicode"
-)
-
-func isMethodError(f *ast.FuncDecl) (typeName string, ok bool) {
- if f.Recv == nil || len(f.Recv.List) != 1 {
- return "", false
- }
- if f.Name == nil || f.Name.Name != "Error" {
- return "", false
- }
- if f.Type == nil || f.Type.Results == nil || len(f.Type.Results.List) != 1 {
- return "", false
- }
-
- returnType, ok := f.Type.Results.List[0].Type.(*ast.Ident)
- if !ok {
- return "", false
- }
-
- var receiverType string
-
- unwrapIdentName := func(e ast.Expr) string {
- switch v := e.(type) {
- case *ast.Ident:
- return v.Name
- case *ast.IndexExpr:
- if i, ok := v.X.(*ast.Ident); ok {
- return i.Name
- }
- case *ast.IndexListExpr:
- if i, ok := v.X.(*ast.Ident); ok {
- return i.Name
- }
- }
- panic(fmt.Errorf("unsupported Error() receiver type %q", types.ExprString(e)))
- }
+ "golang.org/x/tools/go/analysis"
+)
- switch rt := f.Recv.List[0].Type; v := rt.(type) {
- case *ast.Ident, *ast.IndexExpr, *ast.IndexListExpr: // SomeError, SomeError[T], SomeError[T1, T2, ...]
- receiverType = unwrapIdentName(rt)
+var errorIface = types.Universe.Lookup("error").Type().Underlying().(*types.Interface)
- case *ast.StarExpr: // *SomeError, *SomeError[T], *SomeError[T1, T2, ...]
- receiverType = unwrapIdentName(v.X)
- }
+func exprImplementsError(pass *analysis.Pass, e ast.Expr) bool {
+ return typeImplementsError(pass.TypesInfo.TypeOf(e))
+}
- return receiverType, returnType.Name == "string"
+func typeImplementsError(t types.Type) bool {
+ return t != nil && types.Implements(t, errorIface)
}
func isValidErrorTypeName(s string) bool {
@@ -77,153 +41,12 @@ func isValidErrorArrayTypeName(s string) bool {
words := split(s)
wordsCnt := wordsCount(words)
- if wordsCnt["errors"] != 1 {
- return false
- }
- return words[len(words)-1] == "errors"
-}
-
-func isFuncReturningErr(fType *ast.FuncType, allTypes, errorTypes stringSet) bool {
- if fType == nil || fType.Results == nil || len(fType.Results.List) != 1 {
+ if wordsCnt["errors"] != 1 && wordsCnt["error"] != 1 {
return false
}
- var returnTypeName string
- switch rt := fType.Results.List[0].Type.(type) {
- case *ast.Ident:
- returnTypeName = rt.Name
- case *ast.StarExpr:
- if i, ok := rt.X.(*ast.Ident); ok {
- returnTypeName = i.Name
- }
- }
-
- return isErrorType(returnTypeName, allTypes, errorTypes)
-}
-
-func isErrorType(tName string, allTypes, errorTypes stringSet) bool {
- _, isUserType := allTypes[tName]
- _, isErrType := errorTypes[tName]
- return isErrType || (tName == "error" && !isUserType)
-}
-
-var knownErrConstructors = stringSet{
- "fmt.Errorf": {},
- "errors.Errorf": {},
- "errors.New": {},
- "errors.Newf": {},
- "errors.NewWithDepth": {},
- "errors.NewWithDepthf": {},
- "errors.NewAssertionErrorWithWrappedErrf": {},
-}
-
-func isSentinelError( //nolint:gocognit,gocyclo
- v *ast.ValueSpec,
- pkgAliases map[string]string,
- allTypes, errorTypes, errorFuncs stringSet,
-) (varName string, ok bool) {
- if len(v.Names) != 1 {
- return "", false
- }
- varName = v.Names[0].Name
-
- switch vv := v.Type.(type) {
- // var ErrEndOfFile error
- // var ErrEndOfFile SomeErrType
- case *ast.Ident:
- if isErrorType(vv.Name, allTypes, errorTypes) {
- return varName, true
- }
-
- // var ErrEndOfFile *SomeErrType
- case *ast.StarExpr:
- if i, ok := vv.X.(*ast.Ident); ok && isErrorType(i.Name, allTypes, errorTypes) {
- return varName, true
- }
- }
-
- if len(v.Values) != 1 {
- return "", false
- }
-
- switch vv := v.Values[0].(type) {
- case *ast.CallExpr:
- switch fun := vv.Fun.(type) {
- // var ErrEndOfFile = errors.New("end of file")
- case *ast.SelectorExpr:
- pkg, ok := fun.X.(*ast.Ident)
- if !ok {
- return "", false
- }
- pkgFun := fun.Sel
-
- pkgName := pkg.Name
- if a, ok := pkgAliases[pkgName]; ok {
- pkgName = a
- }
-
- _, ok = knownErrConstructors[pkgName+"."+pkgFun.Name]
- return varName, ok
-
- // var ErrEndOfFile = newErrEndOfFile()
- // var ErrEndOfFile = new(EndOfFileError)
- // const ErrEndOfFile = constError("end of file")
- // var statusCodeError = new(SomePtrError[string])
- case *ast.Ident:
- if isErrorType(fun.Name, allTypes, errorTypes) {
- return varName, true
- }
-
- if _, ok := errorFuncs[fun.Name]; ok {
- return varName, true
- }
-
- if fun.Name == "new" && len(vv.Args) == 1 {
- switch i := vv.Args[0].(type) {
- case *ast.Ident:
- return varName, isErrorType(i.Name, allTypes, errorTypes)
- case *ast.IndexExpr:
- if ii, ok := i.X.(*ast.Ident); ok {
- return varName, isErrorType(ii.Name, allTypes, errorTypes)
- }
- }
- }
-
- // var ErrEndOfFile = func() error { ... }
- case *ast.FuncLit:
- return varName, isFuncReturningErr(fun.Type, allTypes, errorTypes)
- }
-
- // var ErrEndOfFile = &EndOfFileError{}
- // var ErrOK = &SomePtrError[string]{Code: "200 OK"}
- case *ast.UnaryExpr:
- if vv.Op == token.AND { // &
- if lit, ok := vv.X.(*ast.CompositeLit); ok {
- switch i := lit.Type.(type) {
- case *ast.Ident:
- return varName, isErrorType(i.Name, allTypes, errorTypes)
- case *ast.IndexExpr:
- if ii, ok := i.X.(*ast.Ident); ok {
- return varName, isErrorType(ii.Name, allTypes, errorTypes)
- }
- }
- }
- }
-
- // var ErrEndOfFile = EndOfFileError{}
- // var ErrNotFound = SomeError[string]{Code: "Not Found"}
- case *ast.CompositeLit:
- switch i := vv.Type.(type) {
- case *ast.Ident:
- return varName, isErrorType(i.Name, allTypes, errorTypes)
- case *ast.IndexExpr:
- if ii, ok := i.X.(*ast.Ident); ok {
- return varName, isErrorType(ii.Name, allTypes, errorTypes)
- }
- }
- }
-
- return "", false
+ lastWord := words[len(words)-1]
+ return lastWord == "errors" || lastWord == "error"
}
func isValidErrorVarName(s string) bool {