aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/github.com/polyfloyd/go-errorlint
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/polyfloyd/go-errorlint
parent475a4c203afb8b7d3af51c4fd32bb170ff32a45e (diff)
vendor: delete
Diffstat (limited to 'vendor/github.com/polyfloyd/go-errorlint')
-rw-r--r--vendor/github.com/polyfloyd/go-errorlint/LICENSE21
-rw-r--r--vendor/github.com/polyfloyd/go-errorlint/errorlint/allowed.go253
-rw-r--r--vendor/github.com/polyfloyd/go-errorlint/errorlint/analysis.go116
-rw-r--r--vendor/github.com/polyfloyd/go-errorlint/errorlint/lint.go385
-rw-r--r--vendor/github.com/polyfloyd/go-errorlint/errorlint/options.go15
-rw-r--r--vendor/github.com/polyfloyd/go-errorlint/errorlint/printf.go122
6 files changed, 0 insertions, 912 deletions
diff --git a/vendor/github.com/polyfloyd/go-errorlint/LICENSE b/vendor/github.com/polyfloyd/go-errorlint/LICENSE
deleted file mode 100644
index b7f88cf1c..000000000
--- a/vendor/github.com/polyfloyd/go-errorlint/LICENSE
+++ /dev/null
@@ -1,21 +0,0 @@
-The MIT License (MIT)
-
-Copyright (c) 2019 polyfloyd
-
-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/polyfloyd/go-errorlint/errorlint/allowed.go b/vendor/github.com/polyfloyd/go-errorlint/errorlint/allowed.go
deleted file mode 100644
index c639af6f3..000000000
--- a/vendor/github.com/polyfloyd/go-errorlint/errorlint/allowed.go
+++ /dev/null
@@ -1,253 +0,0 @@
-package errorlint
-
-import (
- "fmt"
- "go/ast"
- "go/types"
- "strings"
-)
-
-type AllowPair struct {
- Err string
- Fun string
-}
-
-var allowedErrorsMap = make(map[string]map[string]struct{})
-
-func setDefaultAllowedErrors() {
- allowedMapAppend([]AllowPair{
- // pkg/archive/tar
- {Err: "io.EOF", Fun: "(*archive/tar.Reader).Next"},
- {Err: "io.EOF", Fun: "(*archive/tar.Reader).Read"},
- // pkg/bufio
- {Err: "io.EOF", Fun: "(*bufio.Reader).Discard"},
- {Err: "io.EOF", Fun: "(*bufio.Reader).Peek"},
- {Err: "io.EOF", Fun: "(*bufio.Reader).Read"},
- {Err: "io.EOF", Fun: "(*bufio.Reader).ReadByte"},
- {Err: "io.EOF", Fun: "(*bufio.Reader).ReadBytes"},
- {Err: "io.EOF", Fun: "(*bufio.Reader).ReadLine"},
- {Err: "io.EOF", Fun: "(*bufio.Reader).ReadSlice"},
- {Err: "io.EOF", Fun: "(*bufio.Reader).ReadString"},
- {Err: "io.EOF", Fun: "(*bufio.Scanner).Scan"},
- // pkg/bytes
- {Err: "io.EOF", Fun: "(*bytes.Buffer).Read"},
- {Err: "io.EOF", Fun: "(*bytes.Buffer).ReadByte"},
- {Err: "io.EOF", Fun: "(*bytes.Buffer).ReadBytes"},
- {Err: "io.EOF", Fun: "(*bytes.Buffer).ReadRune"},
- {Err: "io.EOF", Fun: "(*bytes.Buffer).ReadString"},
- {Err: "io.EOF", Fun: "(*bytes.Reader).Read"},
- {Err: "io.EOF", Fun: "(*bytes.Reader).ReadAt"},
- {Err: "io.EOF", Fun: "(*bytes.Reader).ReadByte"},
- {Err: "io.EOF", Fun: "(*bytes.Reader).ReadRune"},
- {Err: "io.EOF", Fun: "(*bytes.Reader).ReadString"},
- // pkg/database/sql
- {Err: "database/sql.ErrNoRows", Fun: "(*database/sql.Row).Scan"},
- // pkg/debug/elf
- {Err: "io.EOF", Fun: "debug/elf.Open"},
- {Err: "io.EOF", Fun: "debug/elf.NewFile"},
- // pkg/io
- {Err: "io.EOF", Fun: "(io.ReadCloser).Read"},
- {Err: "io.EOF", Fun: "(io.Reader).Read"},
- {Err: "io.EOF", Fun: "(io.ReaderAt).ReadAt"},
- {Err: "io.EOF", Fun: "(*io.LimitedReader).Read"},
- {Err: "io.EOF", Fun: "(*io.SectionReader).Read"},
- {Err: "io.EOF", Fun: "(*io.SectionReader).ReadAt"},
- {Err: "io.ErrClosedPipe", Fun: "(*io.PipeWriter).Write"},
- {Err: "io.EOF", Fun: "io.ReadAtLeast"},
- {Err: "io.ErrShortBuffer", Fun: "io.ReadAtLeast"},
- {Err: "io.ErrUnexpectedEOF", Fun: "io.ReadAtLeast"},
- {Err: "io.EOF", Fun: "io.ReadFull"},
- {Err: "io.ErrUnexpectedEOF", Fun: "io.ReadFull"},
- // pkg/mime
- {Err: "mime.ErrInvalidMediaParameter", Fun: "mime.ParseMediaType"},
- // pkg/net/http
- {Err: "net/http.ErrServerClosed", Fun: "(*net/http.Server).ListenAndServe"},
- {Err: "net/http.ErrServerClosed", Fun: "(*net/http.Server).ListenAndServeTLS"},
- {Err: "net/http.ErrServerClosed", Fun: "(*net/http.Server).Serve"},
- {Err: "net/http.ErrServerClosed", Fun: "(*net/http.Server).ServeTLS"},
- {Err: "net/http.ErrServerClosed", Fun: "net/http.ListenAndServe"},
- {Err: "net/http.ErrServerClosed", Fun: "net/http.ListenAndServeTLS"},
- {Err: "net/http.ErrServerClosed", Fun: "net/http.Serve"},
- {Err: "net/http.ErrServerClosed", Fun: "net/http.ServeTLS"},
- // pkg/os
- {Err: "io.EOF", Fun: "(*os.File).Read"},
- {Err: "io.EOF", Fun: "(*os.File).ReadAt"},
- {Err: "io.EOF", Fun: "(*os.File).ReadDir"},
- {Err: "io.EOF", Fun: "(*os.File).Readdir"},
- {Err: "io.EOF", Fun: "(*os.File).Readdirnames"},
- // pkg/strings
- {Err: "io.EOF", Fun: "(*strings.Reader).Read"},
- {Err: "io.EOF", Fun: "(*strings.Reader).ReadAt"},
- {Err: "io.EOF", Fun: "(*strings.Reader).ReadByte"},
- {Err: "io.EOF", Fun: "(*strings.Reader).ReadRune"},
- // pkg/context
- {Err: "context.DeadlineExceeded", Fun: "(context.Context).Err"},
- {Err: "context.Canceled", Fun: "(context.Context).Err"},
- // pkg/encoding/json
- {Err: "io.EOF", Fun: "(*encoding/json.Decoder).Decode"},
- {Err: "io.EOF", Fun: "(*encoding/json.Decoder).Token"},
- // pkg/encoding/csv
- {Err: "io.EOF", Fun: "(*encoding/csv.Reader).Read"},
- // pkg/mime/multipart
- {Err: "io.EOF", Fun: "(*mime/multipart.Reader).NextPart"},
- {Err: "io.EOF", Fun: "(*mime/multipart.Reader).NextRawPart"},
- {Err: "mime/multipart.ErrMessageTooLarge", Fun: "(*mime/multipart.Reader).ReadForm"},
- })
-}
-
-func allowedMapAppend(ap []AllowPair) {
- for _, pair := range ap {
- if _, ok := allowedErrorsMap[pair.Err]; !ok {
- allowedErrorsMap[pair.Err] = make(map[string]struct{})
- }
- allowedErrorsMap[pair.Err][pair.Fun] = struct{}{}
- }
-}
-
-var allowedErrorWildcards = []AllowPair{
- // pkg/syscall
- {Err: "syscall.E", Fun: "syscall."},
- // golang.org/x/sys/unix
- {Err: "golang.org/x/sys/unix.E", Fun: "golang.org/x/sys/unix."},
-}
-
-func allowedWildcardAppend(ap []AllowPair) {
- allowedErrorWildcards = append(allowedErrorWildcards, ap...)
-}
-
-func isAllowedErrAndFunc(err, fun string) bool {
- if allowedFuncs, allowErr := allowedErrorsMap[err]; allowErr {
- if _, allow := allowedFuncs[fun]; allow {
- return true
- }
- }
-
- for _, allow := range allowedErrorWildcards {
- if strings.HasPrefix(fun, allow.Fun) && strings.HasPrefix(err, allow.Err) {
- return true
- }
- }
-
- return false
-}
-
-func isAllowedErrorComparison(pass *TypesInfoExt, a, b ast.Expr) bool {
- var errName string // `<package>.<name>`, e.g. `io.EOF`
- var callExprs []*ast.CallExpr
-
- // Figure out which half of the expression is the returned error and which
- // half is the presumed error declaration.
- for _, expr := range []ast.Expr{a, b} {
- switch t := expr.(type) {
- case *ast.SelectorExpr:
- // A selector which we assume refers to a staticaly declared error
- // in a package.
- errName = selectorToString(pass, t)
- case *ast.Ident:
- // Identifier, most likely to be the `err` variable or whatever
- // produces it.
- callExprs = assigningCallExprs(pass, t, map[types.Object]bool{})
- case *ast.CallExpr:
- callExprs = append(callExprs, t)
- }
- }
-
- // Unimplemented or not sure, disallow the expression.
- if errName == "" || len(callExprs) == 0 {
- return false
- }
-
- // Map call expressions to the function name format of the allow list.
- functionNames := make([]string, len(callExprs))
- for i, callExpr := range callExprs {
- functionSelector, ok := callExpr.Fun.(*ast.SelectorExpr)
- if !ok {
- // If the function is not a selector it is not an Std function that is
- // allowed.
- return false
- }
- if sel, ok := pass.TypesInfo.Selections[functionSelector]; ok {
- functionNames[i] = fmt.Sprintf("(%s).%s", sel.Recv(), sel.Obj().Name())
- } else {
- // If there is no selection, assume it is a package.
- functionNames[i] = selectorToString(pass, callExpr.Fun.(*ast.SelectorExpr))
- }
- }
-
- // All assignments done must be allowed.
- for _, funcName := range functionNames {
- if !isAllowedErrAndFunc(errName, funcName) {
- return false
- }
- }
- return true
-}
-
-// assigningCallExprs finds all *ast.CallExpr nodes that are part of an
-// *ast.AssignStmt that assign to the subject identifier.
-func assigningCallExprs(pass *TypesInfoExt, subject *ast.Ident, visitedObjects map[types.Object]bool) []*ast.CallExpr {
- if subject.Obj == nil {
- return nil
- }
-
- // Find other identifiers that reference this same object.
- sobj := pass.TypesInfo.ObjectOf(subject)
-
- if visitedObjects[sobj] {
- return nil
- }
- visitedObjects[sobj] = true
-
- // Make sure to exclude the subject identifier as it will cause an infinite recursion and is
- // being used in a read operation anyway.
- identifiers := []*ast.Ident{}
- for _, ident := range pass.IdentifiersForObject[sobj] {
- if subject.Pos() != ident.Pos() {
- identifiers = append(identifiers, ident)
- }
- }
-
- // Find out whether the identifiers are part of an assignment statement.
- var callExprs []*ast.CallExpr
- for _, ident := range identifiers {
- parent := pass.NodeParent[ident]
- switch declT := parent.(type) {
- case *ast.AssignStmt:
- // The identifier is LHS of an assignment.
- assignment := declT
-
- assigningExpr := assignment.Rhs[0]
- // If the assignment is comprised of multiple expressions, find out
- // which RHS expression we should use by finding its index in the LHS.
- if len(assignment.Lhs) == len(assignment.Rhs) {
- for i, lhs := range assignment.Lhs {
- if ident, ok := lhs.(*ast.Ident); ok && subject.Name == ident.Name {
- assigningExpr = assignment.Rhs[i]
- break
- }
- }
- }
-
- switch assignT := assigningExpr.(type) {
- case *ast.CallExpr:
- // Found the function call.
- callExprs = append(callExprs, assignT)
- case *ast.Ident:
- // Skip assignments here the RHS points to the same object as the subject.
- if assignT.Obj == subject.Obj {
- continue
- }
- // The subject was the result of assigning from another identifier.
- callExprs = append(callExprs, assigningCallExprs(pass, assignT, visitedObjects)...)
- default:
- // TODO: inconclusive?
- }
- }
- }
- return callExprs
-}
-
-func selectorToString(pass *TypesInfoExt, selExpr *ast.SelectorExpr) string {
- o := pass.TypesInfo.Uses[selExpr.Sel]
- return fmt.Sprintf("%s.%s", o.Pkg().Path(), o.Name())
-}
diff --git a/vendor/github.com/polyfloyd/go-errorlint/errorlint/analysis.go b/vendor/github.com/polyfloyd/go-errorlint/errorlint/analysis.go
deleted file mode 100644
index 84ebd6cf8..000000000
--- a/vendor/github.com/polyfloyd/go-errorlint/errorlint/analysis.go
+++ /dev/null
@@ -1,116 +0,0 @@
-package errorlint
-
-import (
- "go/ast"
- "go/types"
- "sort"
-
- "golang.org/x/tools/go/analysis"
-)
-
-func NewAnalyzer(opts ...Option) *analysis.Analyzer {
- for _, o := range opts {
- o()
- }
-
- setDefaultAllowedErrors()
-
- a := &analysis.Analyzer{
- Name: "errorlint",
- Doc: "Source code linter for Go software that can be used to find code that will cause problems with the error wrapping scheme introduced in Go 1.13.",
- Run: run,
- }
-
- a.Flags.BoolVar(&checkComparison, "comparison", true, "Check for plain error comparisons")
- a.Flags.BoolVar(&checkAsserts, "asserts", true, "Check for plain type assertions and type switches")
- a.Flags.BoolVar(&checkErrorf, "errorf", false, "Check whether fmt.Errorf uses the %w verb for formatting errors. See the readme for caveats")
- a.Flags.BoolVar(&checkErrorfMulti, "errorf-multi", true, "Permit more than 1 %w verb, valid per Go 1.20 (Requires -errorf=true)")
-
- return a
-}
-
-var (
- checkComparison bool
- checkAsserts bool
- checkErrorf bool
- checkErrorfMulti bool
-)
-
-func run(pass *analysis.Pass) (interface{}, error) {
- var lints []analysis.Diagnostic
- extInfo := newTypesInfoExt(pass)
- if checkComparison {
- l := LintErrorComparisons(extInfo)
- lints = append(lints, l...)
- }
- if checkAsserts {
- l := LintErrorTypeAssertions(pass.Fset, extInfo)
- lints = append(lints, l...)
- }
- if checkErrorf {
- l := LintFmtErrorfCalls(pass.Fset, *pass.TypesInfo, checkErrorfMulti)
- lints = append(lints, l...)
- }
- sort.Sort(ByPosition(lints))
-
- for _, l := range lints {
- pass.Report(l)
- }
- return nil, nil
-}
-
-type TypesInfoExt struct {
- *analysis.Pass
-
- // Maps AST nodes back to the node they are contained within.
- NodeParent map[ast.Node]ast.Node
-
- // Maps an object back to all identifiers to refer to it.
- IdentifiersForObject map[types.Object][]*ast.Ident
-}
-
-func newTypesInfoExt(pass *analysis.Pass) *TypesInfoExt {
- nodeParent := map[ast.Node]ast.Node{}
- for node := range pass.TypesInfo.Scopes {
- file, ok := node.(*ast.File)
- if !ok {
- continue
- }
- stack := []ast.Node{file}
- ast.Inspect(file, func(n ast.Node) bool {
- nodeParent[n] = stack[len(stack)-1]
- if n == nil {
- stack = stack[:len(stack)-1]
- } else {
- stack = append(stack, n)
- }
- return true
- })
- }
-
- identifiersForObject := map[types.Object][]*ast.Ident{}
- for node, obj := range pass.TypesInfo.Defs {
- identifiersForObject[obj] = append(identifiersForObject[obj], node)
- }
- for node, obj := range pass.TypesInfo.Uses {
- identifiersForObject[obj] = append(identifiersForObject[obj], node)
- }
-
- return &TypesInfoExt{
- Pass: pass,
- NodeParent: nodeParent,
- IdentifiersForObject: identifiersForObject,
- }
-}
-
-func (info *TypesInfoExt) ContainingFuncDecl(node ast.Node) *ast.FuncDecl {
- for parent := info.NodeParent[node]; ; parent = info.NodeParent[parent] {
- if _, ok := parent.(*ast.File); ok {
- break
- }
- if fun, ok := parent.(*ast.FuncDecl); ok {
- return fun
- }
- }
- return nil
-}
diff --git a/vendor/github.com/polyfloyd/go-errorlint/errorlint/lint.go b/vendor/github.com/polyfloyd/go-errorlint/errorlint/lint.go
deleted file mode 100644
index ed3dd0dc6..000000000
--- a/vendor/github.com/polyfloyd/go-errorlint/errorlint/lint.go
+++ /dev/null
@@ -1,385 +0,0 @@
-package errorlint
-
-import (
- "fmt"
- "go/ast"
- "go/constant"
- "go/token"
- "go/types"
-
- "golang.org/x/tools/go/analysis"
-)
-
-type ByPosition []analysis.Diagnostic
-
-func (l ByPosition) Len() int { return len(l) }
-func (l ByPosition) Swap(i, j int) { l[i], l[j] = l[j], l[i] }
-
-func (l ByPosition) Less(i, j int) bool {
- return l[i].Pos < l[j].Pos
-}
-
-func LintFmtErrorfCalls(fset *token.FileSet, info types.Info, multipleWraps bool) []analysis.Diagnostic {
- var lints []analysis.Diagnostic
-
- for expr, t := range info.Types {
- // Search for error expressions that are the result of fmt.Errorf
- // invocations.
- if t.Type.String() != "error" {
- continue
- }
- call, ok := isFmtErrorfCallExpr(info, expr)
- if !ok {
- continue
- }
-
- // Find all % fields in the format string.
- formatVerbs, ok := printfFormatStringVerbs(info, call)
- if !ok {
- continue
- }
-
- // For any arguments that are errors, check whether the wrapping verb is used. %w may occur
- // for multiple errors in one Errorf invocation, unless multipleWraps is true. We raise an
- // issue if at least one error does not have a corresponding wrapping verb.
- args := call.Args[1:]
- if !multipleWraps {
- wrapCount := 0
- for i := 0; i < len(args) && i < len(formatVerbs); i++ {
- arg := args[i]
- if !implementsError(info.Types[arg].Type) {
- continue
- }
- verb := formatVerbs[i]
-
- if verb.format == "w" {
- wrapCount++
- if wrapCount > 1 {
- lints = append(lints, analysis.Diagnostic{
- Message: "only one %w verb is permitted per format string",
- Pos: arg.Pos(),
- })
- break
- }
- }
-
- if wrapCount == 0 {
- lints = append(lints, analysis.Diagnostic{
- Message: "non-wrapping format verb for fmt.Errorf. Use `%w` to format errors",
- Pos: args[i].Pos(),
- })
- break
- }
- }
-
- } else {
- var lint *analysis.Diagnostic
- argIndex := 0
- for _, verb := range formatVerbs {
- if verb.index != -1 {
- argIndex = verb.index
- } else {
- argIndex++
- }
-
- if verb.format == "w" || verb.format == "T" {
- continue
- }
- if argIndex-1 >= len(args) {
- continue
- }
- arg := args[argIndex-1]
- if !implementsError(info.Types[arg].Type) {
- continue
- }
-
- strStart := call.Args[0].Pos()
- if lint == nil {
- lint = &analysis.Diagnostic{
- Message: "non-wrapping format verb for fmt.Errorf. Use `%w` to format errors",
- Pos: arg.Pos(),
- }
- }
- lint.SuggestedFixes = append(lint.SuggestedFixes, analysis.SuggestedFix{
- Message: "Use `%w` to format errors",
- TextEdits: []analysis.TextEdit{{
- Pos: strStart + token.Pos(verb.formatOffset) + 1,
- End: strStart + token.Pos(verb.formatOffset) + 2,
- NewText: []byte("w"),
- }},
- })
- }
- if lint != nil {
- lints = append(lints, *lint)
- }
- }
- }
- return lints
-}
-
-// printfFormatStringVerbs returns a normalized list of all the verbs that are used per argument to
-// the printf function. The index of each returned element corresponds to the index of the
-// respective argument.
-func printfFormatStringVerbs(info types.Info, call *ast.CallExpr) ([]verb, bool) {
- if len(call.Args) <= 1 {
- return nil, false
- }
- strLit, ok := call.Args[0].(*ast.BasicLit)
- if !ok {
- // Ignore format strings that are not literals.
- return nil, false
- }
- formatString := constant.StringVal(info.Types[strLit].Value)
-
- pp := printfParser{str: formatString}
- verbs, err := pp.ParseAllVerbs()
- if err != nil {
- return nil, false
- }
-
- return verbs, true
-}
-
-func isFmtErrorfCallExpr(info types.Info, expr ast.Expr) (*ast.CallExpr, bool) {
- call, ok := expr.(*ast.CallExpr)
- if !ok {
- return nil, false
- }
- fn, ok := call.Fun.(*ast.SelectorExpr)
- if !ok {
- // TODO: Support fmt.Errorf variable aliases?
- return nil, false
- }
- obj := info.Uses[fn.Sel]
-
- pkg := obj.Pkg()
- if pkg != nil && pkg.Name() == "fmt" && obj.Name() == "Errorf" {
- return call, true
- }
- return nil, false
-}
-
-func LintErrorComparisons(info *TypesInfoExt) []analysis.Diagnostic {
- var lints []analysis.Diagnostic
-
- for expr := range info.TypesInfo.Types {
- // Find == and != operations.
- binExpr, ok := expr.(*ast.BinaryExpr)
- if !ok {
- continue
- }
- if binExpr.Op != token.EQL && binExpr.Op != token.NEQ {
- continue
- }
- // Comparing errors with nil is okay.
- if isNil(binExpr.X) || isNil(binExpr.Y) {
- continue
- }
- // Find comparisons of which one side is a of type error.
- if !isErrorType(info.TypesInfo, binExpr.X) && !isErrorType(info.TypesInfo, binExpr.Y) {
- continue
- }
- // Some errors that are returned from some functions are exempt.
- if isAllowedErrorComparison(info, binExpr.X, binExpr.Y) {
- continue
- }
- // Comparisons that happen in `func (type) Is(error) bool` are okay.
- if isNodeInErrorIsFunc(info, binExpr) {
- continue
- }
-
- lints = append(lints, analysis.Diagnostic{
- Message: fmt.Sprintf("comparing with %s will fail on wrapped errors. Use errors.Is to check for a specific error", binExpr.Op),
- Pos: binExpr.Pos(),
- })
- }
-
- for scope := range info.TypesInfo.Scopes {
- // Find value switch blocks.
- switchStmt, ok := scope.(*ast.SwitchStmt)
- if !ok {
- continue
- }
- // Check whether the switch operates on an error type.
- if !isErrorType(info.TypesInfo, switchStmt.Tag) {
- continue
- }
-
- var problematicCaseClause *ast.CaseClause
- outer:
- for _, stmt := range switchStmt.Body.List {
- caseClause := stmt.(*ast.CaseClause)
- for _, caseExpr := range caseClause.List {
- if isNil(caseExpr) {
- continue
- }
- // Some errors that are returned from some functions are exempt.
- if !isAllowedErrorComparison(info, switchStmt.Tag, caseExpr) {
- problematicCaseClause = caseClause
- break outer
- }
- }
- }
- if problematicCaseClause == nil {
- continue
- }
- // Comparisons that happen in `func (type) Is(error) bool` are okay.
- if isNodeInErrorIsFunc(info, switchStmt) {
- continue
- }
-
- if switchComparesNonNil(switchStmt) {
- lints = append(lints, analysis.Diagnostic{
- Message: "switch on an error will fail on wrapped errors. Use errors.Is to check for specific errors",
- Pos: problematicCaseClause.Pos(),
- })
- }
- }
-
- return lints
-}
-
-func isNil(ex ast.Expr) bool {
- ident, ok := ex.(*ast.Ident)
- return ok && ident.Name == "nil"
-}
-
-func isErrorType(info *types.Info, ex ast.Expr) bool {
- t := info.Types[ex].Type
- return t != nil && t.String() == "error"
-}
-
-func isNodeInErrorIsFunc(info *TypesInfoExt, node ast.Node) bool {
- funcDecl := info.ContainingFuncDecl(node)
- if funcDecl == nil {
- return false
- }
-
- if funcDecl.Name.Name != "Is" {
- return false
- }
- if funcDecl.Recv == nil {
- return false
- }
- // There should be 1 argument of type error.
- if ii := funcDecl.Type.Params.List; len(ii) != 1 || info.TypesInfo.Types[ii[0].Type].Type.String() != "error" {
- return false
- }
- // The return type should be bool.
- if ii := funcDecl.Type.Results.List; len(ii) != 1 || info.TypesInfo.Types[ii[0].Type].Type.String() != "bool" {
- return false
- }
-
- return true
-}
-
-// switchComparesNonNil returns true if one of its clauses compares by value.
-func switchComparesNonNil(switchStmt *ast.SwitchStmt) bool {
- for _, caseBlock := range switchStmt.Body.List {
- caseClause, ok := caseBlock.(*ast.CaseClause)
- if !ok {
- continue
- }
- for _, clause := range caseClause.List {
- switch clause := clause.(type) {
- case nil:
- // default label is safe
- continue
- case *ast.Ident:
- // `case nil` is safe
- if clause.Name == "nil" {
- continue
- }
- }
- // anything else (including an Ident other than nil) isn't safe
- return true
- }
- }
- return false
-}
-
-func LintErrorTypeAssertions(fset *token.FileSet, info *TypesInfoExt) []analysis.Diagnostic {
- var lints []analysis.Diagnostic
-
- for expr := range info.TypesInfo.Types {
- // Find type assertions.
- typeAssert, ok := expr.(*ast.TypeAssertExpr)
- if !ok {
- continue
- }
-
- // Find type assertions that operate on values of type error.
- if !isErrorTypeAssertion(*info.TypesInfo, typeAssert) {
- continue
- }
-
- if isNodeInErrorIsFunc(info, typeAssert) {
- continue
- }
-
- // If the asserted type is not an error, allow the expression.
- if !implementsError(info.TypesInfo.Types[typeAssert.Type].Type) {
- continue
- }
-
- lints = append(lints, analysis.Diagnostic{
- Message: "type assertion on error will fail on wrapped errors. Use errors.As to check for specific errors",
- Pos: typeAssert.Pos(),
- })
- }
-
- for scope := range info.TypesInfo.Scopes {
- // Find type switches.
- typeSwitch, ok := scope.(*ast.TypeSwitchStmt)
- if !ok {
- continue
- }
-
- // Find the type assertion in the type switch.
- var typeAssert *ast.TypeAssertExpr
- switch t := typeSwitch.Assign.(type) {
- case *ast.ExprStmt:
- typeAssert = t.X.(*ast.TypeAssertExpr)
- case *ast.AssignStmt:
- typeAssert = t.Rhs[0].(*ast.TypeAssertExpr)
- }
-
- // Check whether the type switch is on a value of type error.
- if !isErrorTypeAssertion(*info.TypesInfo, typeAssert) {
- continue
- }
-
- if isNodeInErrorIsFunc(info, typeSwitch) {
- continue
- }
-
- lints = append(lints, analysis.Diagnostic{
- Message: "type switch on error will fail on wrapped errors. Use errors.As to check for specific errors",
- Pos: typeAssert.Pos(),
- })
- }
-
- return lints
-}
-
-func isErrorTypeAssertion(info types.Info, typeAssert *ast.TypeAssertExpr) bool {
- t := info.Types[typeAssert.X]
- return t.Type.String() == "error"
-}
-
-func implementsError(t types.Type) bool {
- mset := types.NewMethodSet(t)
-
- for i := 0; i < mset.Len(); i++ {
- if mset.At(i).Kind() != types.MethodVal {
- continue
- }
-
- obj := mset.At(i).Obj()
- if obj.Name() == "Error" && obj.Type().String() == "func() string" {
- return true
- }
- }
-
- return false
-}
diff --git a/vendor/github.com/polyfloyd/go-errorlint/errorlint/options.go b/vendor/github.com/polyfloyd/go-errorlint/errorlint/options.go
deleted file mode 100644
index 4d7c742d8..000000000
--- a/vendor/github.com/polyfloyd/go-errorlint/errorlint/options.go
+++ /dev/null
@@ -1,15 +0,0 @@
-package errorlint
-
-type Option func()
-
-func WithAllowedErrors(ap []AllowPair) Option {
- return func() {
- allowedMapAppend(ap)
- }
-}
-
-func WithAllowedWildcard(ap []AllowPair) Option {
- return func() {
- allowedWildcardAppend(ap)
- }
-}
diff --git a/vendor/github.com/polyfloyd/go-errorlint/errorlint/printf.go b/vendor/github.com/polyfloyd/go-errorlint/errorlint/printf.go
deleted file mode 100644
index 4c0e12525..000000000
--- a/vendor/github.com/polyfloyd/go-errorlint/errorlint/printf.go
+++ /dev/null
@@ -1,122 +0,0 @@
-package errorlint
-
-import (
- "fmt"
- "io"
- "strconv"
- "strings"
-)
-
-type verb struct {
- format string
- formatOffset int
- index int
-}
-
-type printfParser struct {
- str string
- at int
-}
-
-func (pp *printfParser) ParseAllVerbs() ([]verb, error) {
- verbs := []verb{}
- for {
- verb, err := pp.parseVerb()
- if err == io.EOF {
- break
- } else if err != nil {
- return nil, err
- }
- verbs = append(verbs, *verb)
- }
- return verbs, nil
-}
-
-func (pp *printfParser) parseVerb() (*verb, error) {
- if err := pp.skipToPercent(); err != nil {
- return nil, err
- }
- if pp.next() != '%' {
- return nil, fmt.Errorf("expected '%%'")
- }
-
- index := -1
- for {
- switch pp.peek() {
- case '%':
- pp.next()
- return pp.parseVerb()
- case '+', '#':
- pp.next()
- continue
- case '[':
- var err error
- index, err = pp.parseIndex()
- if err != nil {
- return nil, err
- }
- case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '.':
- pp.parsePrecision()
- case 0:
- return nil, io.EOF
- }
- break
- }
-
- format := pp.next()
-
- return &verb{format: string(format), formatOffset: pp.at - 1, index: index}, nil
-}
-
-func (pp *printfParser) parseIndex() (int, error) {
- if pp.next() != '[' {
- return -1, fmt.Errorf("expected '['")
- }
- end := strings.Index(pp.str, "]")
- if end == -1 {
- return -1, fmt.Errorf("unterminated indexed verb")
- }
- index, err := strconv.Atoi(pp.str[:end])
- if err != nil {
- return -1, err
- }
- pp.str = pp.str[end+1:]
- pp.at += end + 1
- return index, nil
-}
-
-func (pp *printfParser) parsePrecision() {
- for {
- if r := pp.peek(); (r < '0' || '9' < r) && r != '.' {
- break
- }
- pp.next()
- }
-}
-
-func (pp *printfParser) skipToPercent() error {
- i := strings.Index(pp.str, "%")
- if i == -1 {
- return io.EOF
- }
- pp.str = pp.str[i:]
- pp.at += i
- return nil
-}
-
-func (pp *printfParser) peek() rune {
- if len(pp.str) == 0 {
- return 0
- }
- return rune(pp.str[0])
-}
-
-func (pp *printfParser) next() rune {
- if len(pp.str) == 0 {
- return 0
- }
- r := rune(pp.str[0])
- pp.str = pp.str[1:]
- pp.at++
- return r
-}