From 27e76fae2ee2d84dc7db63af1d9ed7358ba35b7a Mon Sep 17 00:00:00 2001 From: Taras Madan Date: Mon, 11 Nov 2024 11:41:38 +0100 Subject: vendor: update --- .../Antonboom/errname/pkg/analyzer/analyzer.go | 131 ++++++-------- .../Antonboom/errname/pkg/analyzer/facts.go | 199 ++------------------- 2 files changed, 63 insertions(+), 267 deletions(-) (limited to 'vendor/github.com/Antonboom/errname') 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 { -- cgit mrf-deployment