aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/github.com/Antonboom
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/Antonboom
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/Antonboom')
-rw-r--r--vendor/github.com/Antonboom/errname/LICENSE21
-rw-r--r--vendor/github.com/Antonboom/errname/pkg/analyzer/analyzer.go134
-rw-r--r--vendor/github.com/Antonboom/errname/pkg/analyzer/facts.go266
-rw-r--r--vendor/github.com/Antonboom/nilnil/LICENSE21
-rw-r--r--vendor/github.com/Antonboom/nilnil/pkg/analyzer/analyzer.go148
-rw-r--r--vendor/github.com/Antonboom/nilnil/pkg/analyzer/config.go77
-rw-r--r--vendor/github.com/Antonboom/nilnil/pkg/analyzer/func_type_stack.go29
7 files changed, 696 insertions, 0 deletions
diff --git a/vendor/github.com/Antonboom/errname/LICENSE b/vendor/github.com/Antonboom/errname/LICENSE
new file mode 100644
index 000000000..e2002e4d4
--- /dev/null
+++ b/vendor/github.com/Antonboom/errname/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2021 Anton Telyshev
+
+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/Antonboom/errname/pkg/analyzer/analyzer.go b/vendor/github.com/Antonboom/errname/pkg/analyzer/analyzer.go
new file mode 100644
index 000000000..6425db137
--- /dev/null
+++ b/vendor/github.com/Antonboom/errname/pkg/analyzer/analyzer.go
@@ -0,0 +1,134 @@
+package analyzer
+
+import (
+ "go/ast"
+ "go/token"
+ "strconv"
+ "strings"
+ "unicode"
+
+ "golang.org/x/tools/go/analysis"
+ "golang.org/x/tools/go/analysis/passes/inspect"
+ "golang.org/x/tools/go/ast/inspector"
+)
+
+// New returns new errname analyzer.
+func New() *analysis.Analyzer {
+ return &analysis.Analyzer{
+ Name: "errname",
+ Doc: "Checks that sentinel errors are prefixed with the `Err` and error types are suffixed with the `Error`.",
+ Run: run,
+ Requires: []*analysis.Analyzer{inspect.Analyzer},
+ }
+}
+
+type stringSet = map[string]struct{}
+
+var (
+ imports = []ast.Node{(*ast.ImportSpec)(nil)}
+ types = []ast.Node{(*ast.TypeSpec)(nil)}
+ funcs = []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(imports, 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(types, func(node ast.Node) {
+ t := node.(*ast.TypeSpec)
+ allTypes[t.Name.Name] = struct{}{}
+ typesSpecs[t.Name.Name] = t
+ })
+
+ errorTypes := stringSet{}
+ insp.Preorder(funcs, 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("no specification for type " + 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(funcs, func(node ast.Node) {
+ f := node.(*ast.FuncDecl)
+ if isFuncReturningErr(f.Type, allTypes, errorTypes) {
+ errorFuncs[f.Name.Name] = struct{}{}
+ }
+ })
+
+ 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)
+ }
+ }
+ 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) {
+ var form string
+ if unicode.IsLower([]rune(typeName)[0]) {
+ form = "xxxError"
+ } else {
+ form = "XxxError"
+ }
+
+ if isArrayType {
+ form += "s"
+ }
+ pass.Reportf(typePos, "the type name `%s` should conform to the `%s` format", typeName, form)
+}
+
+func reportAboutErrorVar(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:]
+}
diff --git a/vendor/github.com/Antonboom/errname/pkg/analyzer/facts.go b/vendor/github.com/Antonboom/errname/pkg/analyzer/facts.go
new file mode 100644
index 000000000..8711f9cf5
--- /dev/null
+++ b/vendor/github.com/Antonboom/errname/pkg/analyzer/facts.go
@@ -0,0 +1,266 @@
+package analyzer
+
+import (
+ "go/ast"
+ "go/token"
+ "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
+ }
+ }
+ return ""
+ }
+
+ switch rt := f.Recv.List[0].Type; v := rt.(type) {
+ case *ast.Ident, *ast.IndexExpr: // SomeError, SomeError[T]
+ receiverType = unwrapIdentName(rt)
+
+ case *ast.StarExpr: // *SomeError, *SomeError[T]
+ receiverType = unwrapIdentName(v.X)
+ }
+
+ return receiverType, returnType.Name == "string"
+}
+
+func isValidErrorTypeName(s string) bool {
+ if isInitialism(s) {
+ return true
+ }
+
+ words := split(s)
+ wordsCnt := wordsCount(words)
+
+ if wordsCnt["error"] != 1 {
+ return false
+ }
+ return words[len(words)-1] == "error"
+}
+
+func isValidErrorArrayTypeName(s string) bool {
+ if isInitialism(s) {
+ return true
+ }
+
+ 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 {
+ 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
+}
+
+func isValidErrorVarName(s string) bool {
+ if isInitialism(s) {
+ return true
+ }
+
+ words := split(s)
+ wordsCnt := wordsCount(words)
+
+ if wordsCnt["err"] != 1 {
+ return false
+ }
+ return words[0] == "err"
+}
+
+func isInitialism(s string) bool {
+ return strings.ToLower(s) == s || strings.ToUpper(s) == s
+}
+
+func split(s string) []string {
+ var words []string
+ ss := []rune(s)
+
+ var b strings.Builder
+ b.WriteRune(ss[0])
+
+ for _, r := range ss[1:] {
+ if unicode.IsUpper(r) {
+ words = append(words, strings.ToLower(b.String()))
+ b.Reset()
+ }
+ b.WriteRune(r)
+ }
+
+ words = append(words, strings.ToLower(b.String()))
+ return words
+}
+
+func wordsCount(w []string) map[string]int {
+ result := make(map[string]int, len(w))
+ for _, ww := range w {
+ result[ww]++
+ }
+ return result
+}
diff --git a/vendor/github.com/Antonboom/nilnil/LICENSE b/vendor/github.com/Antonboom/nilnil/LICENSE
new file mode 100644
index 000000000..e2002e4d4
--- /dev/null
+++ b/vendor/github.com/Antonboom/nilnil/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2021 Anton Telyshev
+
+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/Antonboom/nilnil/pkg/analyzer/analyzer.go b/vendor/github.com/Antonboom/nilnil/pkg/analyzer/analyzer.go
new file mode 100644
index 000000000..71a9ddf40
--- /dev/null
+++ b/vendor/github.com/Antonboom/nilnil/pkg/analyzer/analyzer.go
@@ -0,0 +1,148 @@
+package analyzer
+
+import (
+ "go/ast"
+
+ "golang.org/x/tools/go/analysis"
+ "golang.org/x/tools/go/analysis/passes/inspect"
+ "golang.org/x/tools/go/ast/inspector"
+)
+
+const (
+ name = "nilnil"
+ doc = "Checks that there is no simultaneous return of `nil` error and an invalid value."
+
+ reportMsg = "return both the `nil` error and invalid value: use a sentinel error instead"
+)
+
+// New returns new nilnil analyzer.
+func New() *analysis.Analyzer {
+ n := newNilNil()
+
+ a := &analysis.Analyzer{
+ Name: name,
+ Doc: doc,
+ Run: n.run,
+ Requires: []*analysis.Analyzer{inspect.Analyzer},
+ }
+ a.Flags.Var(&n.checkedTypes, "checked-types", "coma separated list")
+
+ return a
+}
+
+type nilNil struct {
+ checkedTypes checkedTypes
+}
+
+func newNilNil() *nilNil {
+ return &nilNil{
+ checkedTypes: newDefaultCheckedTypes(),
+ }
+}
+
+var (
+ types = []ast.Node{(*ast.TypeSpec)(nil)}
+
+ funcAndReturns = []ast.Node{
+ (*ast.FuncDecl)(nil),
+ (*ast.FuncLit)(nil),
+ (*ast.ReturnStmt)(nil),
+ }
+)
+
+type typeSpecByName map[string]*ast.TypeSpec
+
+func (n *nilNil) run(pass *analysis.Pass) (interface{}, error) {
+ insp := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
+
+ typeSpecs := typeSpecByName{}
+ insp.Preorder(types, func(node ast.Node) {
+ t := node.(*ast.TypeSpec)
+ typeSpecs[t.Name.Name] = t
+ })
+
+ var fs funcTypeStack
+ insp.Nodes(funcAndReturns, func(node ast.Node, push bool) (proceed bool) {
+ switch v := node.(type) {
+ case *ast.FuncLit:
+ if push {
+ fs.Push(v.Type)
+ } else {
+ fs.Pop()
+ }
+
+ case *ast.FuncDecl:
+ if push {
+ fs.Push(v.Type)
+ } else {
+ fs.Pop()
+ }
+
+ case *ast.ReturnStmt:
+ ft := fs.Top() // Current function.
+
+ if !push || len(v.Results) != 2 || ft == nil || ft.Results == nil || len(ft.Results.List) != 2 {
+ return false
+ }
+
+ fRes1, fRes2 := ft.Results.List[0], ft.Results.List[1]
+ if !(n.isDangerNilField(fRes1, typeSpecs) && n.isErrorField(fRes2)) {
+ return
+ }
+
+ rRes1, rRes2 := v.Results[0], v.Results[1]
+ if isNil(rRes1) && isNil(rRes2) {
+ pass.Reportf(v.Pos(), reportMsg)
+ }
+ }
+
+ return true
+ })
+
+ return nil, nil //nolint:nilnil
+}
+
+func (n *nilNil) isDangerNilField(f *ast.Field, typeSpecs typeSpecByName) bool {
+ return n.isDangerNilType(f.Type, typeSpecs)
+}
+
+func (n *nilNil) isDangerNilType(t ast.Expr, typeSpecs typeSpecByName) bool {
+ switch v := t.(type) {
+ case *ast.StarExpr:
+ return n.checkedTypes.Contains(ptrType)
+
+ case *ast.FuncType:
+ return n.checkedTypes.Contains(funcType)
+
+ case *ast.InterfaceType:
+ return n.checkedTypes.Contains(ifaceType)
+
+ case *ast.MapType:
+ return n.checkedTypes.Contains(mapType)
+
+ case *ast.ChanType:
+ return n.checkedTypes.Contains(chanType)
+
+ case *ast.Ident:
+ if t, ok := typeSpecs[v.Name]; ok {
+ return n.isDangerNilType(t.Type, nil)
+ }
+ }
+ return false
+}
+
+func (n *nilNil) isErrorField(f *ast.Field) bool {
+ return isIdent(f.Type, "error")
+}
+
+func isNil(e ast.Expr) bool {
+ return isIdent(e, "nil")
+}
+
+func isIdent(n ast.Node, name string) bool {
+ i, ok := n.(*ast.Ident)
+ if !ok {
+ return false
+ }
+ return i.Name == name
+}
diff --git a/vendor/github.com/Antonboom/nilnil/pkg/analyzer/config.go b/vendor/github.com/Antonboom/nilnil/pkg/analyzer/config.go
new file mode 100644
index 000000000..520b813a5
--- /dev/null
+++ b/vendor/github.com/Antonboom/nilnil/pkg/analyzer/config.go
@@ -0,0 +1,77 @@
+package analyzer
+
+import (
+ "fmt"
+ "sort"
+ "strings"
+)
+
+func newDefaultCheckedTypes() checkedTypes {
+ return checkedTypes{
+ ptrType: struct{}{},
+ funcType: struct{}{},
+ ifaceType: struct{}{},
+ mapType: struct{}{},
+ chanType: struct{}{},
+ }
+}
+
+const separator = ','
+
+type typeName string
+
+func (t typeName) S() string {
+ return string(t)
+}
+
+const (
+ ptrType typeName = "ptr"
+ funcType typeName = "func"
+ ifaceType typeName = "iface"
+ mapType typeName = "map"
+ chanType typeName = "chan"
+)
+
+var knownTypes = []typeName{ptrType, funcType, ifaceType, mapType, chanType}
+
+type checkedTypes map[typeName]struct{}
+
+func (c checkedTypes) Contains(t typeName) bool {
+ _, ok := c[t]
+ return ok
+}
+
+func (c checkedTypes) String() string {
+ result := make([]string, 0, len(c))
+ for t := range c {
+ result = append(result, t.S())
+ }
+
+ sort.Strings(result)
+ return strings.Join(result, string(separator))
+}
+
+func (c checkedTypes) Set(s string) error {
+ types := strings.FieldsFunc(s, func(c rune) bool { return c == separator })
+ if len(types) == 0 {
+ return nil
+ }
+
+ c.disableAll()
+ for _, t := range types {
+ switch tt := typeName(t); tt {
+ case ptrType, funcType, ifaceType, mapType, chanType:
+ c[tt] = struct{}{}
+ default:
+ return fmt.Errorf("unknown checked type name %q (see help)", t)
+ }
+ }
+
+ return nil
+}
+
+func (c checkedTypes) disableAll() {
+ for k := range c {
+ delete(c, k)
+ }
+}
diff --git a/vendor/github.com/Antonboom/nilnil/pkg/analyzer/func_type_stack.go b/vendor/github.com/Antonboom/nilnil/pkg/analyzer/func_type_stack.go
new file mode 100644
index 000000000..081761547
--- /dev/null
+++ b/vendor/github.com/Antonboom/nilnil/pkg/analyzer/func_type_stack.go
@@ -0,0 +1,29 @@
+package analyzer
+
+import (
+ "go/ast"
+)
+
+type funcTypeStack []*ast.FuncType
+
+func (s *funcTypeStack) Push(f *ast.FuncType) {
+ *s = append(*s, f)
+}
+
+func (s *funcTypeStack) Pop() *ast.FuncType {
+ if len(*s) == 0 {
+ return nil
+ }
+
+ last := len(*s) - 1
+ f := (*s)[last]
+ *s = (*s)[:last]
+ return f
+}
+
+func (s *funcTypeStack) Top() *ast.FuncType {
+ if len(*s) == 0 {
+ return nil
+ }
+ return (*s)[len(*s)-1]
+}