aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/github.com/kisielk
diff options
context:
space:
mode:
authorTaras Madan <tarasmadan@google.com>2022-09-05 14:27:54 +0200
committerGitHub <noreply@github.com>2022-09-05 12:27:54 +0000
commitb2f2446b46bf02821d90ebedadae2bf7ae0e880e (patch)
tree923cf42842918d6bebca1d6bbdc08abed54d274d /vendor/github.com/kisielk
parente6654faff4bcca4be92e9a8596fd4b77f747c39e (diff)
go.mod, vendor: update (#3358)
* go.mod, vendor: remove unnecessary dependencies Commands: 1. go mod tidy 2. go mod vendor * go.mod, vendor: update cloud.google.com/go Commands: 1. go get -u cloud.google.com/go 2. go mod tidy 3. go mod vendor * go.mod, vendor: update cloud.google.com/* Commands: 1. go get -u cloud.google.com/storage cloud.google.com/logging 2. go mod tidy 3. go mod vendor * go.mod, .golangci.yml, vendor: update *lint* Commands: 1. go get -u golang.org/x/tools github.com/golangci/golangci-lint@v1.47.0 2. go mod tidy 3. go mod vendor 4. edit .golangci.yml to suppress new errors (resolved in the same PR later) * all: fix lint errors hash.go: copy() recommended by gosimple parse.go: ent is never nil verifier.go: signal.Notify() with unbuffered channel is bad. Have no idea why. * .golangci.yml: adjust godot rules check-all is deprecated, but still work if you're hesitating too - I'll remove this commit
Diffstat (limited to 'vendor/github.com/kisielk')
-rw-r--r--vendor/github.com/kisielk/errcheck/LICENSE22
-rw-r--r--vendor/github.com/kisielk/errcheck/errcheck/analyzer.go77
-rw-r--r--vendor/github.com/kisielk/errcheck/errcheck/embedded_walker.go143
-rw-r--r--vendor/github.com/kisielk/errcheck/errcheck/errcheck.go643
-rw-r--r--vendor/github.com/kisielk/errcheck/errcheck/excludes.go83
-rw-r--r--vendor/github.com/kisielk/errcheck/errcheck/tags.go12
-rw-r--r--vendor/github.com/kisielk/errcheck/errcheck/tags_compat.go13
7 files changed, 993 insertions, 0 deletions
diff --git a/vendor/github.com/kisielk/errcheck/LICENSE b/vendor/github.com/kisielk/errcheck/LICENSE
new file mode 100644
index 000000000..a2b16b5bd
--- /dev/null
+++ b/vendor/github.com/kisielk/errcheck/LICENSE
@@ -0,0 +1,22 @@
+Copyright (c) 2013 Kamil Kisiel
+
+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/kisielk/errcheck/errcheck/analyzer.go b/vendor/github.com/kisielk/errcheck/errcheck/analyzer.go
new file mode 100644
index 000000000..68593cc9a
--- /dev/null
+++ b/vendor/github.com/kisielk/errcheck/errcheck/analyzer.go
@@ -0,0 +1,77 @@
+package errcheck
+
+import (
+ "fmt"
+ "go/ast"
+ "reflect"
+ "regexp"
+
+ "golang.org/x/tools/go/analysis"
+)
+
+var Analyzer = &analysis.Analyzer{
+ Name: "errcheck",
+ Doc: "check for unchecked errors",
+ Run: runAnalyzer,
+ ResultType: reflect.TypeOf(Result{}),
+}
+
+var (
+ argBlank bool
+ argAsserts bool
+ argExcludeFile string
+ argExcludeOnly bool
+)
+
+func init() {
+ Analyzer.Flags.BoolVar(&argBlank, "blank", false, "if true, check for errors assigned to blank identifier")
+ Analyzer.Flags.BoolVar(&argAsserts, "assert", false, "if true, check for ignored type assertion results")
+ Analyzer.Flags.StringVar(&argExcludeFile, "exclude", "", "Path to a file containing a list of functions to exclude from checking")
+ Analyzer.Flags.BoolVar(&argExcludeOnly, "excludeonly", false, "Use only excludes from exclude file")
+}
+
+func runAnalyzer(pass *analysis.Pass) (interface{}, error) {
+
+ exclude := map[string]bool{}
+ if !argExcludeOnly {
+ for _, name := range DefaultExcludedSymbols {
+ exclude[name] = true
+ }
+ }
+ if argExcludeFile != "" {
+ excludes, err := ReadExcludes(argExcludeFile)
+ if err != nil {
+ return nil, fmt.Errorf("Could not read exclude file: %v\n", err)
+ }
+ for _, name := range excludes {
+ exclude[name] = true
+ }
+ }
+
+ var allErrors []UncheckedError
+ for _, f := range pass.Files {
+ v := &visitor{
+ typesInfo: pass.TypesInfo,
+ fset: pass.Fset,
+ blank: argBlank,
+ asserts: argAsserts,
+ exclude: exclude,
+ ignore: map[string]*regexp.Regexp{}, // deprecated & not used
+ lines: make(map[string][]string),
+ errors: nil,
+ }
+
+ ast.Walk(v, f)
+
+ for _, err := range v.errors {
+ pass.Report(analysis.Diagnostic{
+ Pos: pass.Fset.File(f.Pos()).Pos(err.Pos.Offset),
+ Message: "unchecked error",
+ })
+ }
+
+ allErrors = append(allErrors, v.errors...)
+ }
+
+ return Result{UncheckedErrors: allErrors}, nil
+}
diff --git a/vendor/github.com/kisielk/errcheck/errcheck/embedded_walker.go b/vendor/github.com/kisielk/errcheck/errcheck/embedded_walker.go
new file mode 100644
index 000000000..dff391797
--- /dev/null
+++ b/vendor/github.com/kisielk/errcheck/errcheck/embedded_walker.go
@@ -0,0 +1,143 @@
+package errcheck
+
+import (
+ "fmt"
+ "go/types"
+)
+
+// walkThroughEmbeddedInterfaces returns a slice of Interfaces that
+// we need to walk through in order to reach the actual definition,
+// in an Interface, of the method selected by the given selection.
+//
+// false will be returned in the second return value if:
+// - the right side of the selection is not a function
+// - the actual definition of the function is not in an Interface
+//
+// The returned slice will contain all the interface types that need
+// to be walked through to reach the actual definition.
+//
+// For example, say we have:
+//
+// type Inner interface {Method()}
+// type Middle interface {Inner}
+// type Outer interface {Middle}
+// type T struct {Outer}
+// type U struct {T}
+// type V struct {U}
+//
+// And then the selector:
+//
+// V.Method
+//
+// We'll return [Outer, Middle, Inner] by first walking through the embedded structs
+// until we reach the Outer interface, then descending through the embedded interfaces
+// until we find the one that actually explicitly defines Method.
+func walkThroughEmbeddedInterfaces(sel *types.Selection) ([]types.Type, bool) {
+ fn, ok := sel.Obj().(*types.Func)
+ if !ok {
+ return nil, false
+ }
+
+ // Start off at the receiver.
+ currentT := sel.Recv()
+
+ // First, we can walk through any Struct fields provided
+ // by the selection Index() method. We ignore the last
+ // index because it would give the method itself.
+ indexes := sel.Index()
+ for _, fieldIndex := range indexes[:len(indexes)-1] {
+ currentT = getTypeAtFieldIndex(currentT, fieldIndex)
+ }
+
+ // Now currentT is either a type implementing the actual function,
+ // an Invalid type (if the receiver is a package), or an interface.
+ //
+ // If it's not an Interface, then we're done, as this function
+ // only cares about Interface-defined functions.
+ //
+ // If it is an Interface, we potentially need to continue digging until
+ // we find the Interface that actually explicitly defines the function.
+ interfaceT, ok := maybeUnname(currentT).(*types.Interface)
+ if !ok {
+ return nil, false
+ }
+
+ // The first interface we pass through is this one we've found. We return the possibly
+ // wrapping types.Named because it is more useful to work with for callers.
+ result := []types.Type{currentT}
+
+ // If this interface itself explicitly defines the given method
+ // then we're done digging.
+ for !explicitlyDefinesMethod(interfaceT, fn) {
+ // Otherwise, we find which of the embedded interfaces _does_
+ // define the method, add it to our list, and loop.
+ namedInterfaceT, ok := getEmbeddedInterfaceDefiningMethod(interfaceT, fn)
+ if !ok {
+ // Returned a nil interface, we are done.
+ break
+ }
+ result = append(result, namedInterfaceT)
+ interfaceT = namedInterfaceT.Underlying().(*types.Interface)
+ }
+
+ return result, true
+}
+
+func getTypeAtFieldIndex(startingAt types.Type, fieldIndex int) types.Type {
+ t := maybeUnname(maybeDereference(startingAt))
+ s, ok := t.(*types.Struct)
+ if !ok {
+ panic(fmt.Sprintf("cannot get Field of a type that is not a struct, got a %T", t))
+ }
+
+ return s.Field(fieldIndex).Type()
+}
+
+// getEmbeddedInterfaceDefiningMethod searches through any embedded interfaces of the
+// passed interface searching for one that defines the given function. If found, the
+// types.Named wrapping that interface will be returned along with true in the second value.
+//
+// If no such embedded interface is found, nil and false are returned.
+func getEmbeddedInterfaceDefiningMethod(interfaceT *types.Interface, fn *types.Func) (*types.Named, bool) {
+ for i := 0; i < interfaceT.NumEmbeddeds(); i++ {
+ embedded := interfaceT.Embedded(i)
+ if embedded != nil && definesMethod(embedded.Underlying().(*types.Interface), fn) {
+ return embedded, true
+ }
+ }
+ return nil, false
+}
+
+func explicitlyDefinesMethod(interfaceT *types.Interface, fn *types.Func) bool {
+ for i := 0; i < interfaceT.NumExplicitMethods(); i++ {
+ if interfaceT.ExplicitMethod(i) == fn {
+ return true
+ }
+ }
+ return false
+}
+
+func definesMethod(interfaceT *types.Interface, fn *types.Func) bool {
+ for i := 0; i < interfaceT.NumMethods(); i++ {
+ if interfaceT.Method(i) == fn {
+ return true
+ }
+ }
+ return false
+}
+
+func maybeDereference(t types.Type) types.Type {
+ p, ok := t.(*types.Pointer)
+ if ok {
+ return p.Elem()
+ }
+ return t
+}
+
+func maybeUnname(t types.Type) types.Type {
+ n, ok := t.(*types.Named)
+ if ok {
+ return n.Underlying()
+ }
+ return t
+}
diff --git a/vendor/github.com/kisielk/errcheck/errcheck/errcheck.go b/vendor/github.com/kisielk/errcheck/errcheck/errcheck.go
new file mode 100644
index 000000000..0a4067f92
--- /dev/null
+++ b/vendor/github.com/kisielk/errcheck/errcheck/errcheck.go
@@ -0,0 +1,643 @@
+// Package errcheck is the library used to implement the errcheck command-line tool.
+package errcheck
+
+import (
+ "bufio"
+ "errors"
+ "fmt"
+ "go/ast"
+ "go/token"
+ "go/types"
+ "os"
+ "regexp"
+ "sort"
+ "strings"
+
+ "golang.org/x/tools/go/packages"
+)
+
+var errorType *types.Interface
+
+func init() {
+ errorType = types.Universe.Lookup("error").Type().Underlying().(*types.Interface)
+}
+
+var (
+ // ErrNoGoFiles is returned when CheckPackage is run on a package with no Go source files
+ ErrNoGoFiles = errors.New("package contains no go source files")
+)
+
+// UncheckedError indicates the position of an unchecked error return.
+type UncheckedError struct {
+ Pos token.Position
+ Line string
+ FuncName string
+ SelectorName string
+}
+
+// Result is returned from the CheckPackage function, and holds all the errors
+// that were found to be unchecked in a package.
+//
+// Aggregation can be done using the Append method for users that want to
+// combine results from multiple packages.
+type Result struct {
+ // UncheckedErrors is a list of all the unchecked errors in the package.
+ // Printing an error reports its position within the file and the contents of the line.
+ UncheckedErrors []UncheckedError
+}
+
+type byName []UncheckedError
+
+// Less reports whether the element with index i should sort before the element with index j.
+func (b byName) Less(i, j int) bool {
+ ei, ej := b[i], b[j]
+
+ pi, pj := ei.Pos, ej.Pos
+
+ if pi.Filename != pj.Filename {
+ return pi.Filename < pj.Filename
+ }
+ if pi.Line != pj.Line {
+ return pi.Line < pj.Line
+ }
+ if pi.Column != pj.Column {
+ return pi.Column < pj.Column
+ }
+
+ return ei.Line < ej.Line
+}
+
+func (b byName) Swap(i, j int) {
+ b[i], b[j] = b[j], b[i]
+}
+
+func (b byName) Len() int {
+ return len(b)
+}
+
+// Append appends errors to e. Append does not do any duplicate checking.
+func (r *Result) Append(other Result) {
+ r.UncheckedErrors = append(r.UncheckedErrors, other.UncheckedErrors...)
+}
+
+// Returns the unique errors that have been accumulated. Duplicates may occur
+// when a file containing an unchecked error belongs to > 1 package.
+//
+// The method receiver remains unmodified after the call to Unique.
+func (r Result) Unique() Result {
+ result := make([]UncheckedError, len(r.UncheckedErrors))
+ copy(result, r.UncheckedErrors)
+ sort.Sort((byName)(result))
+ uniq := result[:0] // compact in-place
+ for i, err := range result {
+ if i == 0 || err != result[i-1] {
+ uniq = append(uniq, err)
+ }
+ }
+ return Result{UncheckedErrors: uniq}
+}
+
+// Exclusions define symbols and language elements that will be not checked
+type Exclusions struct {
+
+ // Packages lists paths of excluded packages.
+ Packages []string
+
+ // SymbolRegexpsByPackage maps individual package paths to regular
+ // expressions that match symbols to be excluded.
+ //
+ // Packages whose paths appear both here and in Packages list will
+ // be excluded entirely.
+ //
+ // This is a legacy input that will be deprecated in errcheck version 2 and
+ // should not be used.
+ SymbolRegexpsByPackage map[string]*regexp.Regexp
+
+ // Symbols lists patterns that exclude individual package symbols.
+ //
+ // For example:
+ //
+ // "fmt.Errorf" // function
+ // "fmt.Fprintf(os.Stderr)" // function with set argument value
+ // "(hash.Hash).Write" // method
+ //
+ Symbols []string
+
+ // TestFiles excludes _test.go files.
+ TestFiles bool
+
+ // GeneratedFiles excludes generated source files.
+ //
+ // Source file is assumed to be generated if its contents
+ // match the following regular expression:
+ //
+ // ^// Code generated .* DO NOT EDIT\\.$
+ //
+ GeneratedFiles bool
+
+ // BlankAssignments ignores assignments to blank identifier.
+ BlankAssignments bool
+
+ // TypeAssertions ignores unchecked type assertions.
+ TypeAssertions bool
+}
+
+// Checker checks that you checked errors.
+type Checker struct {
+ // Exclusions defines code packages, symbols, and other elements that will not be checked.
+ Exclusions Exclusions
+
+ // Tags are a list of build tags to use.
+ Tags []string
+
+ // The mod flag for go build.
+ Mod string
+}
+
+// loadPackages is used for testing.
+var loadPackages = func(cfg *packages.Config, paths ...string) ([]*packages.Package, error) {
+ return packages.Load(cfg, paths...)
+}
+
+// LoadPackages loads all the packages in all the paths provided. It uses the
+// exclusions and build tags provided to by the user when loading the packages.
+func (c *Checker) LoadPackages(paths ...string) ([]*packages.Package, error) {
+ buildFlags := []string{fmtTags(c.Tags)}
+ if c.Mod != "" {
+ buildFlags = append(buildFlags, fmt.Sprintf("-mod=%s", c.Mod))
+ }
+ cfg := &packages.Config{
+ Mode: packages.LoadAllSyntax,
+ Tests: !c.Exclusions.TestFiles,
+ BuildFlags: buildFlags,
+ }
+ return loadPackages(cfg, paths...)
+}
+
+var generatedCodeRegexp = regexp.MustCompile("^// Code generated .* DO NOT EDIT\\.$")
+var dotStar = regexp.MustCompile(".*")
+
+func (c *Checker) shouldSkipFile(file *ast.File) bool {
+ if !c.Exclusions.GeneratedFiles {
+ return false
+ }
+
+ for _, cg := range file.Comments {
+ for _, comment := range cg.List {
+ if generatedCodeRegexp.MatchString(comment.Text) {
+ return true
+ }
+ }
+ }
+
+ return false
+}
+
+// CheckPackage checks packages for errors that have not been checked.
+//
+// It will exclude specific errors from analysis if the user has configured
+// exclusions.
+func (c *Checker) CheckPackage(pkg *packages.Package) Result {
+ excludedSymbols := map[string]bool{}
+ for _, sym := range c.Exclusions.Symbols {
+ excludedSymbols[sym] = true
+ }
+
+ ignore := map[string]*regexp.Regexp{}
+ // Apply SymbolRegexpsByPackage first so that if the same path appears in
+ // Packages, a more narrow regexp will be superceded by dotStar below.
+ if regexps := c.Exclusions.SymbolRegexpsByPackage; regexps != nil {
+ for pkg, re := range regexps {
+ // TODO warn if previous entry overwritten?
+ ignore[nonVendoredPkgPath(pkg)] = re
+ }
+ }
+ for _, pkg := range c.Exclusions.Packages {
+ // TODO warn if previous entry overwritten?
+ ignore[nonVendoredPkgPath(pkg)] = dotStar
+ }
+
+ v := &visitor{
+ typesInfo: pkg.TypesInfo,
+ fset: pkg.Fset,
+ ignore: ignore,
+ blank: !c.Exclusions.BlankAssignments,
+ asserts: !c.Exclusions.TypeAssertions,
+ lines: make(map[string][]string),
+ exclude: excludedSymbols,
+ errors: []UncheckedError{},
+ }
+
+ for _, astFile := range pkg.Syntax {
+ if c.shouldSkipFile(astFile) {
+ continue
+ }
+ ast.Walk(v, astFile)
+ }
+ return Result{UncheckedErrors: v.errors}
+}
+
+// visitor implements the errcheck algorithm
+type visitor struct {
+ typesInfo *types.Info
+ fset *token.FileSet
+ ignore map[string]*regexp.Regexp
+ blank bool
+ asserts bool
+ lines map[string][]string
+ exclude map[string]bool
+
+ errors []UncheckedError
+}
+
+// selectorAndFunc tries to get the selector and function from call expression.
+// For example, given the call expression representing "a.b()", the selector
+// is "a.b" and the function is "b" itself.
+//
+// The final return value will be true if it is able to do extract a selector
+// from the call and look up the function object it refers to.
+//
+// If the call does not include a selector (like if it is a plain "f()" function call)
+// then the final return value will be false.
+func (v *visitor) selectorAndFunc(call *ast.CallExpr) (*ast.SelectorExpr, *types.Func, bool) {
+ sel, ok := call.Fun.(*ast.SelectorExpr)
+ if !ok {
+ return nil, nil, false
+ }
+
+ fn, ok := v.typesInfo.ObjectOf(sel.Sel).(*types.Func)
+ if !ok {
+ // Shouldn't happen, but be paranoid
+ return nil, nil, false
+ }
+
+ return sel, fn, true
+
+}
+
+// fullName will return a package / receiver-type qualified name for a called function
+// if the function is the result of a selector. Otherwise it will return
+// the empty string.
+//
+// The name is fully qualified by the import path, possible type,
+// function/method name and pointer receiver.
+//
+// For example,
+// - for "fmt.Printf(...)" it will return "fmt.Printf"
+// - for "base64.StdEncoding.Decode(...)" it will return "(*encoding/base64.Encoding).Decode"
+// - for "myFunc()" it will return ""
+func (v *visitor) fullName(call *ast.CallExpr) string {
+ _, fn, ok := v.selectorAndFunc(call)
+ if !ok {
+ return ""
+ }
+
+ // TODO(dh): vendored packages will have /vendor/ in their name,
+ // thus not matching vendored standard library packages. If we
+ // want to support vendored stdlib packages, we need to implement
+ // FullName with our own logic.
+ return fn.FullName()
+}
+
+func getSelectorName(sel *ast.SelectorExpr) string {
+ if ident, ok := sel.X.(*ast.Ident); ok {
+ return fmt.Sprintf("%s.%s", ident.Name, sel.Sel.Name)
+ }
+ if s, ok := sel.X.(*ast.SelectorExpr); ok {
+ return fmt.Sprintf("%s.%s", getSelectorName(s), sel.Sel.Name)
+ }
+
+ return ""
+}
+
+// selectorName will return a name for a called function
+// if the function is the result of a selector. Otherwise it will return
+// the empty string.
+//
+// The name is fully qualified by the import path, possible type,
+// function/method name and pointer receiver.
+//
+// For example,
+// - for "fmt.Printf(...)" it will return "fmt.Printf"
+// - for "base64.StdEncoding.Decode(...)" it will return "base64.StdEncoding.Decode"
+// - for "myFunc()" it will return ""
+func (v *visitor) selectorName(call *ast.CallExpr) string {
+ sel, _, ok := v.selectorAndFunc(call)
+ if !ok {
+ return ""
+ }
+
+ return getSelectorName(sel)
+}
+
+// namesForExcludeCheck will return a list of fully-qualified function names
+// from a function call that can be used to check against the exclusion list.
+//
+// If a function call is against a local function (like "myFunc()") then no
+// names are returned. If the function is package-qualified (like "fmt.Printf()")
+// then just that function's fullName is returned.
+//
+// Otherwise, we walk through all the potentially embeddded interfaces of the receiver
+// the collect a list of type-qualified function names that we will check.
+func (v *visitor) namesForExcludeCheck(call *ast.CallExpr) []string {
+ sel, fn, ok := v.selectorAndFunc(call)
+ if !ok {
+ return nil
+ }
+
+ name := v.fullName(call)
+ if name == "" {
+ return nil
+ }
+
+ // This will be missing for functions without a receiver (like fmt.Printf),
+ // so just fall back to the the function's fullName in that case.
+ selection, ok := v.typesInfo.Selections[sel]
+ if !ok {
+ return []string{name}
+ }
+
+ // This will return with ok false if the function isn't defined
+ // on an interface, so just fall back to the fullName.
+ ts, ok := walkThroughEmbeddedInterfaces(selection)
+ if !ok {
+ return []string{name}
+ }
+
+ result := make([]string, len(ts))
+ for i, t := range ts {
+ // Like in fullName, vendored packages will have /vendor/ in their name,
+ // thus not matching vendored standard library packages. If we
+ // want to support vendored stdlib packages, we need to implement
+ // additional logic here.
+ result[i] = fmt.Sprintf("(%s).%s", t.String(), fn.Name())
+ }
+ return result
+}
+
+// isBufferType checks if the expression type is a known in-memory buffer type.
+func (v *visitor) argName(expr ast.Expr) string {
+ // Special-case literal "os.Stdout" and "os.Stderr"
+ if sel, ok := expr.(*ast.SelectorExpr); ok {
+ if obj := v.typesInfo.ObjectOf(sel.Sel); obj != nil {
+ vr, ok := obj.(*types.Var)
+ if ok && vr.Pkg() != nil && vr.Pkg().Name() == "os" && (vr.Name() == "Stderr" || vr.Name() == "Stdout") {
+ return "os." + vr.Name()
+ }
+ }
+ }
+ t := v.typesInfo.TypeOf(expr)
+ if t == nil {
+ return ""
+ }
+ return t.String()
+}
+
+func (v *visitor) excludeCall(call *ast.CallExpr) bool {
+ var arg0 string
+ if len(call.Args) > 0 {
+ arg0 = v.argName(call.Args[0])
+ }
+ for _, name := range v.namesForExcludeCheck(call) {
+ if v.exclude[name] {
+ return true
+ }
+ if arg0 != "" && v.exclude[name+"("+arg0+")"] {
+ return true
+ }
+ }
+ return false
+}
+
+func (v *visitor) ignoreCall(call *ast.CallExpr) bool {
+ if v.excludeCall(call) {
+ return true
+ }
+
+ // Try to get an identifier.
+ // Currently only supports simple expressions:
+ // 1. f()
+ // 2. x.y.f()
+ var id *ast.Ident
+ switch exp := call.Fun.(type) {
+ case (*ast.Ident):
+ id = exp
+ case (*ast.SelectorExpr):
+ id = exp.Sel
+ default:
+ // eg: *ast.SliceExpr, *ast.IndexExpr
+ }
+
+ if id == nil {
+ return false
+ }
+
+ // If we got an identifier for the function, see if it is ignored
+ if re, ok := v.ignore[""]; ok && re.MatchString(id.Name) {
+ return true
+ }
+
+ if obj := v.typesInfo.Uses[id]; obj != nil {
+ if pkg := obj.Pkg(); pkg != nil {
+ if re, ok := v.ignore[nonVendoredPkgPath(pkg.Path())]; ok {
+ return re.MatchString(id.Name)
+ }
+ }
+ }
+
+ return false
+}
+
+// nonVendoredPkgPath returns the unvendored version of the provided package
+// path (or returns the provided path if it does not represent a vendored
+// path).
+func nonVendoredPkgPath(pkgPath string) string {
+ lastVendorIndex := strings.LastIndex(pkgPath, "/vendor/")
+ if lastVendorIndex == -1 {
+ return pkgPath
+ }
+ return pkgPath[lastVendorIndex+len("/vendor/"):]
+}
+
+// errorsByArg returns a slice s such that
+// len(s) == number of return types of call
+// s[i] == true iff return type at position i from left is an error type
+func (v *visitor) errorsByArg(call *ast.CallExpr) []bool {
+ switch t := v.typesInfo.Types[call].Type.(type) {
+ case *types.Named:
+ // Single return
+ return []bool{isErrorType(t)}
+ case *types.Pointer:
+ // Single return via pointer
+ return []bool{isErrorType(t)}
+ case *types.Tuple:
+ // Multiple returns
+ s := make([]bool, t.Len())
+ for i := 0; i < t.Len(); i++ {
+ switch et := t.At(i).Type().(type) {
+ case *types.Named:
+ // Single return
+ s[i] = isErrorType(et)
+ case *types.Pointer:
+ // Single return via pointer
+ s[i] = isErrorType(et)
+ default:
+ s[i] = false
+ }
+ }
+ return s
+ }
+ return []bool{false}
+}
+
+func (v *visitor) callReturnsError(call *ast.CallExpr) bool {
+ if v.isRecover(call) {
+ return true
+ }
+ for _, isError := range v.errorsByArg(call) {
+ if isError {
+ return true
+ }
+ }
+ return false
+}
+
+// isRecover returns true if the given CallExpr is a call to the built-in recover() function.
+func (v *visitor) isRecover(call *ast.CallExpr) bool {
+ if fun, ok := call.Fun.(*ast.Ident); ok {
+ if _, ok := v.typesInfo.Uses[fun].(*types.Builtin); ok {
+ return fun.Name == "recover"
+ }
+ }
+ return false
+}
+
+// TODO (dtcaciuc) collect token.Pos and then convert them to UncheckedErrors
+// after visitor is done running. This will allow to integrate more cleanly
+// with analyzer so that we don't have to convert Position back to Pos.
+func (v *visitor) addErrorAtPosition(position token.Pos, call *ast.CallExpr) {
+ pos := v.fset.Position(position)
+ lines, ok := v.lines[pos.Filename]
+ if !ok {
+ lines = readfile(pos.Filename)
+ v.lines[pos.Filename] = lines
+ }
+
+ line := "??"
+ if pos.Line-1 < len(lines) {
+ line = strings.TrimSpace(lines[pos.Line-1])
+ }
+
+ var name string
+ var sel string
+ if call != nil {
+ name = v.fullName(call)
+ sel = v.selectorName(call)
+ }
+
+ v.errors = append(v.errors, UncheckedError{pos, line, name, sel})
+}
+
+func readfile(filename string) []string {
+ var f, err = os.Open(filename)
+ if err != nil {
+ return nil
+ }
+ defer f.Close()
+
+ var lines []string
+ var scanner = bufio.NewScanner(f)
+ for scanner.Scan() {
+ lines = append(lines, scanner.Text())
+ }
+ return lines
+}
+
+func (v *visitor) Visit(node ast.Node) ast.Visitor {
+ switch stmt := node.(type) {
+ case *ast.ExprStmt:
+ if call, ok := stmt.X.(*ast.CallExpr); ok {
+ if !v.ignoreCall(call) && v.callReturnsError(call) {
+ v.addErrorAtPosition(call.Lparen, call)
+ }
+ }
+ case *ast.GoStmt:
+ if !v.ignoreCall(stmt.Call) && v.callReturnsError(stmt.Call) {
+ v.addErrorAtPosition(stmt.Call.Lparen, stmt.Call)
+ }
+ case *ast.DeferStmt:
+ if !v.ignoreCall(stmt.Call) && v.callReturnsError(stmt.Call) {
+ v.addErrorAtPosition(stmt.Call.Lparen, stmt.Call)
+ }
+ case *ast.AssignStmt:
+ if len(stmt.Rhs) == 1 {
+ // single value on rhs; check against lhs identifiers
+ if call, ok := stmt.Rhs[0].(*ast.CallExpr); ok {
+ if !v.blank {
+ break
+ }
+ if v.ignoreCall(call) {
+ break
+ }
+ isError := v.errorsByArg(call)
+ for i := 0; i < len(stmt.Lhs); i++ {
+ if id, ok := stmt.Lhs[i].(*ast.Ident); ok {
+ // We shortcut calls to recover() because errorsByArg can't
+ // check its return types for errors since it returns interface{}.
+ if id.Name == "_" && (v.isRecover(call) || isError[i]) {
+ v.addErrorAtPosition(id.NamePos, call)
+ }
+ }
+ }
+ } else if assert, ok := stmt.Rhs[0].(*ast.TypeAssertExpr); ok {
+ if !v.asserts {
+ break
+ }
+ if assert.Type == nil {
+ // type switch
+ break
+ }
+ if len(stmt.Lhs) < 2 {
+ // assertion result not read
+ v.addErrorAtPosition(stmt.Rhs[0].Pos(), nil)
+ } else if id, ok := stmt.Lhs[1].(*ast.Ident); ok && v.blank && id.Name == "_" {
+ // assertion result ignored
+ v.addErrorAtPosition(id.NamePos, nil)
+ }
+ }
+ } else {
+ // multiple value on rhs; in this case a call can't return
+ // multiple values. Assume len(stmt.Lhs) == len(stmt.Rhs)
+ for i := 0; i < len(stmt.Lhs); i++ {
+ if id, ok := stmt.Lhs[i].(*ast.Ident); ok {
+ if call, ok := stmt.Rhs[i].(*ast.CallExpr); ok {
+ if !v.blank {
+ continue
+ }
+ if v.ignoreCall(call) {
+ continue
+ }
+ if id.Name == "_" && v.callReturnsError(call) {
+ v.addErrorAtPosition(id.NamePos, call)
+ }
+ } else if assert, ok := stmt.Rhs[i].(*ast.TypeAssertExpr); ok {
+ if !v.asserts {
+ continue
+ }
+ if assert.Type == nil {
+ // Shouldn't happen anyway, no multi assignment in type switches
+ continue
+ }
+ v.addErrorAtPosition(id.NamePos, nil)
+ }
+ }
+ }
+ }
+ default:
+ }
+ return v
+}
+
+func isErrorType(t types.Type) bool {
+ return types.Implements(t, errorType)
+}
diff --git a/vendor/github.com/kisielk/errcheck/errcheck/excludes.go b/vendor/github.com/kisielk/errcheck/errcheck/excludes.go
new file mode 100644
index 000000000..22db9fe11
--- /dev/null
+++ b/vendor/github.com/kisielk/errcheck/errcheck/excludes.go
@@ -0,0 +1,83 @@
+package errcheck
+
+import (
+ "bufio"
+ "bytes"
+ "io/ioutil"
+ "strings"
+)
+
+var (
+ // DefaultExcludedSymbols is a list of symbol names that are usually excluded from checks by default.
+ //
+ // Note, that they still need to be explicitly copied to Checker.Exclusions.Symbols
+ DefaultExcludedSymbols = []string{
+ // bytes
+ "(*bytes.Buffer).Write",
+ "(*bytes.Buffer).WriteByte",
+ "(*bytes.Buffer).WriteRune",
+ "(*bytes.Buffer).WriteString",
+
+ // fmt
+ "fmt.Errorf",
+ "fmt.Print",
+ "fmt.Printf",
+ "fmt.Println",
+ "fmt.Fprint(*bytes.Buffer)",
+ "fmt.Fprintf(*bytes.Buffer)",
+ "fmt.Fprintln(*bytes.Buffer)",
+ "fmt.Fprint(*strings.Builder)",
+ "fmt.Fprintf(*strings.Builder)",
+ "fmt.Fprintln(*strings.Builder)",
+ "fmt.Fprint(os.Stderr)",
+ "fmt.Fprintf(os.Stderr)",
+ "fmt.Fprintln(os.Stderr)",
+
+ // io
+ "(*io.PipeReader).CloseWithError",
+ "(*io.PipeWriter).CloseWithError",
+
+ // math/rand
+ "math/rand.Read",
+ "(*math/rand.Rand).Read",
+
+ // strings
+ "(*strings.Builder).Write",
+ "(*strings.Builder).WriteByte",
+ "(*strings.Builder).WriteRune",
+ "(*strings.Builder).WriteString",
+
+ // hash
+ "(hash.Hash).Write",
+ }
+)
+
+// ReadExcludes reads an excludes file, a newline delimited file that lists
+// patterns for which to allow unchecked errors.
+//
+// Lines that start with two forward slashes are considered comments and are ignored.
+//
+func ReadExcludes(path string) ([]string, error) {
+ var excludes []string
+
+ buf, err := ioutil.ReadFile(path)
+ if err != nil {
+ return nil, err
+ }
+
+ scanner := bufio.NewScanner(bytes.NewReader(buf))
+
+ for scanner.Scan() {
+ name := scanner.Text()
+ // Skip comments and empty lines.
+ if strings.HasPrefix(name, "//") || name == "" {
+ continue
+ }
+ excludes = append(excludes, name)
+ }
+ if err := scanner.Err(); err != nil {
+ return nil, err
+ }
+
+ return excludes, nil
+}
diff --git a/vendor/github.com/kisielk/errcheck/errcheck/tags.go b/vendor/github.com/kisielk/errcheck/errcheck/tags.go
new file mode 100644
index 000000000..7b423ca69
--- /dev/null
+++ b/vendor/github.com/kisielk/errcheck/errcheck/tags.go
@@ -0,0 +1,12 @@
+// +build go1.13
+
+package errcheck
+
+import (
+ "fmt"
+ "strings"
+)
+
+func fmtTags(tags []string) string {
+ return fmt.Sprintf("-tags=%s", strings.Join(tags, ","))
+}
diff --git a/vendor/github.com/kisielk/errcheck/errcheck/tags_compat.go b/vendor/github.com/kisielk/errcheck/errcheck/tags_compat.go
new file mode 100644
index 000000000..2f534f40a
--- /dev/null
+++ b/vendor/github.com/kisielk/errcheck/errcheck/tags_compat.go
@@ -0,0 +1,13 @@
+// +build go1.11
+// +build !go1.13
+
+package errcheck
+
+import (
+ "fmt"
+ "strings"
+)
+
+func fmtTags(tags []string) string {
+ return fmt.Sprintf("-tags=%s", strings.Join(tags, " "))
+}