aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/github.com/tomarrell
diff options
context:
space:
mode:
authorTaras Madan <tarasmadan@google.com>2025-01-22 16:07:17 +0100
committerTaras Madan <tarasmadan@google.com>2025-01-23 10:42:36 +0000
commit7b4377ad9d8a7205416df8d6217ef2b010f89481 (patch)
treee6fec4fd12ff807a16d847923f501075bf71d16c /vendor/github.com/tomarrell
parent475a4c203afb8b7d3af51c4fd32bb170ff32a45e (diff)
vendor: delete
Diffstat (limited to 'vendor/github.com/tomarrell')
-rw-r--r--vendor/github.com/tomarrell/wrapcheck/v2/LICENSE21
-rw-r--r--vendor/github.com/tomarrell/wrapcheck/v2/wrapcheck/wrapcheck.go463
2 files changed, 0 insertions, 484 deletions
diff --git a/vendor/github.com/tomarrell/wrapcheck/v2/LICENSE b/vendor/github.com/tomarrell/wrapcheck/v2/LICENSE
deleted file mode 100644
index b5d9d30d3..000000000
--- a/vendor/github.com/tomarrell/wrapcheck/v2/LICENSE
+++ /dev/null
@@ -1,21 +0,0 @@
-MIT License
-
-Copyright (c) 2020 Tom Arrell
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
diff --git a/vendor/github.com/tomarrell/wrapcheck/v2/wrapcheck/wrapcheck.go b/vendor/github.com/tomarrell/wrapcheck/v2/wrapcheck/wrapcheck.go
deleted file mode 100644
index 2c1b2d20b..000000000
--- a/vendor/github.com/tomarrell/wrapcheck/v2/wrapcheck/wrapcheck.go
+++ /dev/null
@@ -1,463 +0,0 @@
-package wrapcheck
-
-import (
- "fmt"
- "go/ast"
- "go/token"
- "go/types"
- "regexp"
- "strings"
-
- "github.com/gobwas/glob"
- "golang.org/x/tools/go/analysis"
-)
-
-var DefaultIgnoreSigs = []string{
- ".Errorf(",
- "errors.New(",
- "errors.Unwrap(",
- "errors.Join(",
- ".Wrap(",
- ".Wrapf(",
- ".WithMessage(",
- ".WithMessagef(",
- ".WithStack(",
-}
-
-// WrapcheckConfig is the set of configuration values which configure the
-// behaviour of the linter.
-type WrapcheckConfig struct {
- // IgnoreSigs defines a list of substrings which if contained within the
- // signature of the function call returning the error, will be ignored. This
- // allows you to specify functions that wrapcheck will not report as
- // unwrapped.
- //
- // For example, an ignoreSig of `[]string{"errors.New("}` will ignore errors
- // returned from the stdlib package error's function:
- //
- // `func errors.New(message string) error`
- //
- // Due to the signature containing the substring `errors.New(`.
- //
- // Note: Setting this value will intentionally override the default ignored
- // sigs. To achieve the same behaviour as default, you should add the default
- // list to your config.
- IgnoreSigs []string `mapstructure:"ignoreSigs" yaml:"ignoreSigs"`
-
- // IgnoreSigRegexps defines a list of regular expressions which if matched
- // to the signature of the function call returning the error, will be ignored. This
- // allows you to specify functions that wrapcheck will not report as
- // unwrapped.
- //
- // For example, an ignoreSigRegexp of `[]string{"\.New.*Err\("}`` will ignore errors
- // returned from any signature whose method name starts with "New" and ends with "Err"
- // due to the signature matching the regular expression `\.New.*Err\(`.
- //
- // Note that this is similar to the ignoreSigs configuration, but provides
- // slightly more flexibility in defining rules by which signatures will be
- // ignored.
- IgnoreSigRegexps []string `mapstructure:"ignoreSigRegexps" yaml:"ignoreSigRegexps"`
-
- // IgnorePackageGlobs defines a list of globs which, if matching the package
- // of the function returning the error, will ignore the error when doing
- // wrapcheck analysis.
- //
- // This is useful for broadly ignoring packages and subpackages from wrapcheck
- // analysis. For example, to ignore all errors from all packages and
- // subpackages of "encoding" you may include the configuration:
- //
- // -- .wrapcheck.yaml
- // ignorePackageGlobs:
- // - encoding/*
- IgnorePackageGlobs []string `mapstructure:"ignorePackageGlobs" yaml:"ignorePackageGlobs"`
-
- // IgnoreInterfaceRegexps defines a list of regular expressions which, if matched
- // to a underlying interface name, will ignore unwrapped errors returned from a
- // function whose call is defined on the given interface.
- //
- // For example, an ignoreInterfaceRegexps of `[]string{"Transac(tor|tion)"}` will ignore errors
- // returned from any function whose call is defined on a interface named 'Transactor'
- // or 'Transaction' due to the name matching the regular expression `Transac(tor|tion)`.
- IgnoreInterfaceRegexps []string `mapstructure:"ignoreInterfaceRegexps" yaml:"ignoreInterfaceRegexps"`
-}
-
-func NewDefaultConfig() WrapcheckConfig {
- return WrapcheckConfig{
- IgnoreSigs: DefaultIgnoreSigs,
- IgnoreSigRegexps: []string{},
- IgnorePackageGlobs: []string{},
- IgnoreInterfaceRegexps: []string{},
- }
-}
-
-func NewAnalyzer(cfg WrapcheckConfig) *analysis.Analyzer {
- return &analysis.Analyzer{
- Name: "wrapcheck",
- Doc: "Checks that errors returned from external packages are wrapped",
- Run: run(cfg),
- }
-}
-
-func run(cfg WrapcheckConfig) func(*analysis.Pass) (interface{}, error) {
- // Precompile the regexps, report the error
- var (
- ignoreSigRegexp []*regexp.Regexp
- ignoreInterfaceRegexps []*regexp.Regexp
- ignorePackageGlobs []glob.Glob
- err error
- )
-
- ignoreSigRegexp, err = compileRegexps(cfg.IgnoreSigRegexps)
- if err == nil {
- ignoreInterfaceRegexps, err = compileRegexps(cfg.IgnoreInterfaceRegexps)
- }
- if err == nil {
- ignorePackageGlobs, err = compileGlobs(cfg.IgnorePackageGlobs)
- }
-
- return func(pass *analysis.Pass) (interface{}, error) {
- if err != nil {
- return nil, err
- }
-
- for _, file := range pass.Files {
- // Keep track of parents so that can can traverse upwards to check for
- // FuncDecls and FuncLits.
- var parents []ast.Node
-
- ast.Inspect(file, func(n ast.Node) bool {
- if n == nil {
- // Pop, since we're done with this node and its children.
- parents = parents[:len(parents)-1]
- } else {
- // Push this node on the stack, since its children will be visited
- // next.
- parents = append(parents, n)
- }
-
- ret, ok := n.(*ast.ReturnStmt)
- if !ok {
- return true
- }
-
- if len(ret.Results) < 1 {
- return true
- }
-
- // Iterate over the values to be returned looking for errors
- for _, expr := range ret.Results {
- // Check if the return expression is a function call, if it is, we need
- // to handle it by checking the return params of the function.
- retFn, ok := expr.(*ast.CallExpr)
- if ok {
- // If you go up, and the parent is a FuncLit, then don't report an
- // error as you are in an anonymous function. If you are inside a
- // FuncDecl, then continue as normal.
- for i := len(parents) - 1; i > 0; i-- {
- if _, ok := parents[i].(*ast.FuncLit); ok {
- return true
- } else if _, ok := parents[i].(*ast.FuncDecl); ok {
- break
- }
- }
-
- // If the return type of the function is a single error. This will not
- // match an error within multiple return values, for that, the below
- // tuple check is required.
-
- if isError(pass.TypesInfo.TypeOf(expr)) {
- reportUnwrapped(pass, retFn, retFn.Pos(), cfg, ignoreSigRegexp, ignoreInterfaceRegexps, ignorePackageGlobs)
- return true
- }
-
- // Check if one of the return values from the function is an error
- tup, ok := pass.TypesInfo.TypeOf(expr).(*types.Tuple)
- if !ok {
- return true
- }
-
- // Iterate over the return values of the function looking for error
- // types
- for i := 0; i < tup.Len(); i++ {
- v := tup.At(i)
- if v == nil {
- return true
- }
- if isError(v.Type()) {
- reportUnwrapped(pass, retFn, expr.Pos(), cfg, ignoreSigRegexp, ignoreInterfaceRegexps, ignorePackageGlobs)
- return true
- }
- }
- }
-
- if !isError(pass.TypesInfo.TypeOf(expr)) {
- continue
- }
-
- ident, ok := expr.(*ast.Ident)
- if !ok {
- return true
- }
-
- var call *ast.CallExpr
-
- // Attempt to find the most recent short assign
- if shortAss := prevErrAssign(pass, file, ident); shortAss != nil {
- call, ok = shortAss.Rhs[0].(*ast.CallExpr)
- if !ok {
- return true
- }
- } else if isUnresolved(file, ident) {
- // TODO Check if the identifier is unresolved, and try to resolve it in
- // another file.
- return true
- } else {
- // Check for ValueSpec nodes in order to locate a possible var
- // declaration.
- if ident.Obj == nil {
- return true
- }
-
- vSpec, ok := ident.Obj.Decl.(*ast.ValueSpec)
- if !ok {
- // We couldn't find a short or var assign for this error return.
- // This is an error. Where did this identifier come from? Possibly a
- // function param.
- //
- // TODO decide how to handle this case, whether to follow function
- // param back, or assert wrapping at call site.
-
- return true
- }
-
- if len(vSpec.Values) < 1 {
- return true
- }
-
- call, ok = vSpec.Values[0].(*ast.CallExpr)
- if !ok {
- return true
- }
- }
-
- // Make sure there is a call identified as producing the error being
- // returned, otherwise just bail
- if call == nil {
- return true
- }
-
- reportUnwrapped(pass, call, ident.NamePos, cfg, ignoreSigRegexp, ignoreInterfaceRegexps, ignorePackageGlobs)
- }
-
- return true
- })
- }
-
- return nil, nil
- }
-}
-
-// Report unwrapped takes a call expression and an identifier and reports
-// if the call is unwrapped.
-func reportUnwrapped(
- pass *analysis.Pass,
- call *ast.CallExpr,
- tokenPos token.Pos,
- cfg WrapcheckConfig,
- regexpsSig []*regexp.Regexp,
- regexpsInter []*regexp.Regexp,
- pkgGlobs []glob.Glob,
-) {
-
- sel, ok := call.Fun.(*ast.SelectorExpr)
- if !ok {
- return
- }
-
- // Check for ignored signatures
- fnSig := pass.TypesInfo.ObjectOf(sel.Sel).String()
- if contains(cfg.IgnoreSigs, fnSig) {
- return
- } else if containsMatch(regexpsSig, fnSig) {
- return
- }
-
- // Check if the underlying type of the "x" in x.y.z is an interface, as
- // errors returned from exported interface types should be wrapped, unless
- // ignored as per `ignoreInterfaceRegexps`
- if sel.Sel.IsExported() && isInterface(pass, sel) {
- pkgPath := pass.TypesInfo.ObjectOf(sel.Sel).Pkg().Path()
- name := types.TypeString(pass.TypesInfo.TypeOf(sel.X), func(p *types.Package) string { return p.Name() })
- if !containsMatch(regexpsInter, name) && !containsMatchGlob(pkgGlobs, pkgPath) {
- pass.Reportf(tokenPos, "error returned from interface method should be wrapped: sig: %s", fnSig)
- return
- }
- }
-
- // Check whether the function being called comes from another package,
- // as functions called across package boundaries which returns errors
- // should be wrapped
- if isFromOtherPkg(pass, sel, pkgGlobs) {
- pass.Reportf(tokenPos, "error returned from external package is unwrapped: sig: %s", fnSig)
- return
- }
-}
-
-// isInterface returns whether the function call is one defined on an interface.
-func isInterface(pass *analysis.Pass, sel *ast.SelectorExpr) bool {
- _, ok := pass.TypesInfo.TypeOf(sel.X).Underlying().(*types.Interface)
-
- return ok
-}
-
-// isFromotherPkg returns whether the function is defined in the package
-// currently under analysis or is considered external. It will ignore packages
-// defined in config.IgnorePackageGlobs.
-func isFromOtherPkg(pass *analysis.Pass, sel *ast.SelectorExpr, pkgGlobs []glob.Glob) bool {
- // The package of the function that we are calling which returns the error
- fn := pass.TypesInfo.ObjectOf(sel.Sel)
- if containsMatchGlob(pkgGlobs, fn.Pkg().Path()) {
- return false
- }
-
- // If it's not a package name, then we should check the selector to make sure
- // that it's an identifier from the same package
- if pass.Pkg.Path() == fn.Pkg().Path() {
- return false
- }
-
- return true
-}
-
-// prevErrAssign traverses the AST of a file looking for the most recent
-// assignment to an error declaration which is specified by the returnIdent
-// identifier.
-//
-// This only returns short form assignments and reassignments, e.g. `:=` and
-// `=`. This does not include `var` statements. This function will return nil if
-// the only declaration is a `var` (aka ValueSpec) declaration.
-func prevErrAssign(pass *analysis.Pass, file *ast.File, returnIdent *ast.Ident) *ast.AssignStmt {
- // A slice containing all the assignments which contain an identifier
- // referring to the source declaration of the error. This is to catch
- // cases where err is defined once, and then reassigned multiple times
- // within the same block. In these cases, we should check the method of
- // the most recent call.
- var assigns []*ast.AssignStmt
-
- // Find all assignments which have the same declaration
- ast.Inspect(file, func(n ast.Node) bool {
- if ass, ok := n.(*ast.AssignStmt); ok {
- for _, expr := range ass.Lhs {
- if !isError(pass.TypesInfo.TypeOf(expr)) {
- continue
- }
-
- if assIdent, ok := expr.(*ast.Ident); ok {
- if assIdent.Obj == nil || returnIdent.Obj == nil {
- // If we can't find the Obj for one of the identifiers, just skip
- // it.
- return true
- } else if assIdent.Obj.Decl == returnIdent.Obj.Decl {
- assigns = append(assigns, ass)
- }
- }
- }
- }
-
- return true
- })
-
- // Iterate through the assignments, comparing the token positions to
- // find the assignment that directly precedes the return position
- var mostRecentAssign *ast.AssignStmt
-
- for _, ass := range assigns {
- if ass.Pos() > returnIdent.Pos() {
- break
- }
-
- mostRecentAssign = ass
- }
-
- return mostRecentAssign
-}
-
-func contains(slice []string, el string) bool {
- for _, s := range slice {
- if strings.Contains(el, s) {
- return true
- }
- }
-
- return false
-}
-
-func containsMatch(regexps []*regexp.Regexp, el string) bool {
- for _, re := range regexps {
- if re.MatchString(el) {
- return true
- }
- }
-
- return false
-}
-
-func containsMatchGlob(globs []glob.Glob, el string) bool {
- for _, g := range globs {
- if g.Match(el) {
- return true
- }
- }
-
- return false
-}
-
-// isError returns whether or not the provided type interface is an error
-func isError(typ types.Type) bool {
- if typ == nil {
- return false
- }
-
- return typ.String() == "error"
-}
-
-func isUnresolved(file *ast.File, ident *ast.Ident) bool {
- for _, unresolvedIdent := range file.Unresolved {
- if unresolvedIdent.Pos() == ident.Pos() {
- return true
- }
- }
-
- return false
-}
-
-// compileRegexps compiles a set of regular expressions returning them for use,
-// or the first encountered error due to an invalid expression.
-func compileRegexps(regexps []string) ([]*regexp.Regexp, error) {
- compiledRegexps := make([]*regexp.Regexp, len(regexps))
- for idx, reg := range regexps {
- re, err := regexp.Compile(reg)
- if err != nil {
- return nil, fmt.Errorf("unable to compile regexp %s: %v\n", reg, err)
- }
-
- compiledRegexps[idx] = re
- }
-
- return compiledRegexps, nil
-}
-
-// compileGlobs compiles a set of globs, returning them for use,
-// or the first encountered error due to an invalid expression.
-func compileGlobs(globs []string) ([]glob.Glob, error) {
- compiledGlobs := make([]glob.Glob, len(globs))
- for idx, globString := range globs {
- glob, err := glob.Compile(globString)
- if err != nil {
- return nil, fmt.Errorf("unable to compile globs %s: %v\n", glob, err)
- }
-
- compiledGlobs[idx] = glob
- }
- return compiledGlobs, nil
-}