aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/github.com/breml
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/breml
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/breml')
-rw-r--r--vendor/github.com/breml/bidichk/LICENSE21
-rw-r--r--vendor/github.com/breml/bidichk/pkg/bidichk/bidichk.go180
-rw-r--r--vendor/github.com/breml/bidichk/pkg/bidichk/version.go19
-rw-r--r--vendor/github.com/breml/errchkjson/.gitignore29
-rw-r--r--vendor/github.com/breml/errchkjson/.goreleaser.yml33
-rw-r--r--vendor/github.com/breml/errchkjson/LICENSE21
-rw-r--r--vendor/github.com/breml/errchkjson/README.md131
-rw-r--r--vendor/github.com/breml/errchkjson/errchkjson.go348
-rw-r--r--vendor/github.com/breml/errchkjson/go.mod11
-rw-r--r--vendor/github.com/breml/errchkjson/go.sum30
-rw-r--r--vendor/github.com/breml/errchkjson/noexported_error.go23
-rw-r--r--vendor/github.com/breml/errchkjson/unsupported_error.go23
-rw-r--r--vendor/github.com/breml/errchkjson/version.go19
13 files changed, 888 insertions, 0 deletions
diff --git a/vendor/github.com/breml/bidichk/LICENSE b/vendor/github.com/breml/bidichk/LICENSE
new file mode 100644
index 000000000..47a8419ce
--- /dev/null
+++ b/vendor/github.com/breml/bidichk/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2021 Lucas Bremgartner
+
+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/breml/bidichk/pkg/bidichk/bidichk.go b/vendor/github.com/breml/bidichk/pkg/bidichk/bidichk.go
new file mode 100644
index 000000000..2e1e89934
--- /dev/null
+++ b/vendor/github.com/breml/bidichk/pkg/bidichk/bidichk.go
@@ -0,0 +1,180 @@
+package bidichk
+
+import (
+ "bytes"
+ "flag"
+ "fmt"
+ "go/token"
+ "os"
+ "sort"
+ "strings"
+ "unicode/utf8"
+
+ "golang.org/x/tools/go/analysis"
+)
+
+const (
+ doc = "bidichk detects dangerous unicode character sequences"
+ disallowedDoc = `coma separated list of disallowed runes (full name or short name)
+
+Supported runes
+
+LEFT-TO-RIGHT-EMBEDDING, LRE (u+202A)
+RIGHT-TO-LEFT-EMBEDDING, RLE (u+202B)
+POP-DIRECTIONAL-FORMATTING, PDF (u+202C)
+LEFT-TO-RIGHT-OVERRIDE, LRO (u+202D)
+RIGHT-TO-LEFT-OVERRIDE, RLO (u+202E)
+LEFT-TO-RIGHT-ISOLATE, LRI (u+2066)
+RIGHT-TO-LEFT-ISOLATE, RLI (u+2067)
+FIRST-STRONG-ISOLATE, FSI (u+2068)
+POP-DIRECTIONAL-ISOLATE, PDI (u+2069)
+`
+)
+
+type disallowedRunes map[string]rune
+
+func (m disallowedRunes) String() string {
+ ss := make([]string, 0, len(m))
+ for s := range m {
+ ss = append(ss, s)
+ }
+ sort.Strings(ss)
+ return strings.Join(ss, ",")
+}
+
+func (m disallowedRunes) Set(s string) error {
+ ss := strings.FieldsFunc(s, func(c rune) bool { return c == ',' })
+ if len(ss) == 0 {
+ return nil
+ }
+
+ for k := range m {
+ delete(m, k)
+ }
+
+ for _, v := range ss {
+ switch v {
+ case runeShortNameLRE, runeShortNameRLE, runeShortNamePDF,
+ runeShortNameLRO, runeShortNameRLO, runeShortNameLRI,
+ runeShortNameRLI, runeShortNameFSI, runeShortNamePDI:
+ v = shortNameLookup[v]
+ fallthrough
+ case runeNameLRE, runeNameRLE, runeNamePDF,
+ runeNameLRO, runeNameRLO, runeNameLRI,
+ runeNameRLI, runeNameFSI, runeNamePDI:
+ m[v] = runeLookup[v]
+ default:
+ return fmt.Errorf("unknown check name %q (see help for full list)", v)
+ }
+ }
+ return nil
+}
+
+const (
+ runeNameLRE = "LEFT-TO-RIGHT-EMBEDDING"
+ runeNameRLE = "RIGHT-TO-LEFT-EMBEDDING"
+ runeNamePDF = "POP-DIRECTIONAL-FORMATTING"
+ runeNameLRO = "LEFT-TO-RIGHT-OVERRIDE"
+ runeNameRLO = "RIGHT-TO-LEFT-OVERRIDE"
+ runeNameLRI = "LEFT-TO-RIGHT-ISOLATE"
+ runeNameRLI = "RIGHT-TO-LEFT-ISOLATE"
+ runeNameFSI = "FIRST-STRONG-ISOLATE"
+ runeNamePDI = "POP-DIRECTIONAL-ISOLATE"
+
+ runeShortNameLRE = "LRE" // LEFT-TO-RIGHT-EMBEDDING
+ runeShortNameRLE = "RLE" // RIGHT-TO-LEFT-EMBEDDING
+ runeShortNamePDF = "PDF" // POP-DIRECTIONAL-FORMATTING
+ runeShortNameLRO = "LRO" // LEFT-TO-RIGHT-OVERRIDE
+ runeShortNameRLO = "RLO" // RIGHT-TO-LEFT-OVERRIDE
+ runeShortNameLRI = "LRI" // LEFT-TO-RIGHT-ISOLATE
+ runeShortNameRLI = "RLI" // RIGHT-TO-LEFT-ISOLATE
+ runeShortNameFSI = "FSI" // FIRST-STRONG-ISOLATE
+ runeShortNamePDI = "PDI" // POP-DIRECTIONAL-ISOLATE
+)
+
+var runeLookup = map[string]rune{
+ runeNameLRE: '\u202A', // LEFT-TO-RIGHT-EMBEDDING
+ runeNameRLE: '\u202B', // RIGHT-TO-LEFT-EMBEDDING
+ runeNamePDF: '\u202C', // POP-DIRECTIONAL-FORMATTING
+ runeNameLRO: '\u202D', // LEFT-TO-RIGHT-OVERRIDE
+ runeNameRLO: '\u202E', // RIGHT-TO-LEFT-OVERRIDE
+ runeNameLRI: '\u2066', // LEFT-TO-RIGHT-ISOLATE
+ runeNameRLI: '\u2067', // RIGHT-TO-LEFT-ISOLATE
+ runeNameFSI: '\u2068', // FIRST-STRONG-ISOLATE
+ runeNamePDI: '\u2069', // POP-DIRECTIONAL-ISOLATE
+}
+
+var shortNameLookup = map[string]string{
+ runeShortNameLRE: runeNameLRE,
+ runeShortNameRLE: runeNameRLE,
+ runeShortNamePDF: runeNamePDF,
+ runeShortNameLRO: runeNameLRO,
+ runeShortNameRLO: runeNameRLO,
+ runeShortNameLRI: runeNameLRI,
+ runeShortNameRLI: runeNameRLI,
+ runeShortNameFSI: runeNameFSI,
+ runeShortNamePDI: runeNamePDI,
+}
+
+type bidichk struct {
+ disallowedRunes disallowedRunes
+}
+
+// NewAnalyzer return a new bidichk analyzer.
+func NewAnalyzer() *analysis.Analyzer {
+ bidichk := bidichk{}
+ bidichk.disallowedRunes = make(map[string]rune, len(runeLookup))
+ for k, v := range runeLookup {
+ bidichk.disallowedRunes[k] = v
+ }
+
+ a := &analysis.Analyzer{
+ Name: "bidichk",
+ Doc: doc,
+ Run: bidichk.run,
+ }
+
+ a.Flags.Init("bidichk", flag.ExitOnError)
+ a.Flags.Var(&bidichk.disallowedRunes, "disallowed-runes", disallowedDoc)
+ a.Flags.Var(versionFlag{}, "V", "print version and exit")
+
+ return a
+}
+
+func (b bidichk) run(pass *analysis.Pass) (interface{}, error) {
+ var err error
+
+ pass.Fset.Iterate(func(f *token.File) bool {
+ if strings.HasPrefix(f.Name(), "$GOROOT") {
+ return true
+ }
+
+ return b.check(f.Name(), f.Pos(0), pass) == nil
+ })
+
+ return nil, err
+}
+
+func (b bidichk) check(filename string, pos token.Pos, pass *analysis.Pass) error {
+ body, err := os.ReadFile(filename)
+ if err != nil {
+ return err
+ }
+
+ for name, r := range b.disallowedRunes {
+ start := 0
+ for {
+ idx := bytes.IndexRune(body[start:], r)
+ if idx == -1 {
+ break
+ }
+ start += idx
+
+ pass.Reportf(pos+token.Pos(start), "found dangerous unicode character sequence %s", name)
+
+ start += utf8.RuneLen(r)
+ }
+ }
+
+ return nil
+}
diff --git a/vendor/github.com/breml/bidichk/pkg/bidichk/version.go b/vendor/github.com/breml/bidichk/pkg/bidichk/version.go
new file mode 100644
index 000000000..4cfc57dd1
--- /dev/null
+++ b/vendor/github.com/breml/bidichk/pkg/bidichk/version.go
@@ -0,0 +1,19 @@
+package bidichk
+
+import (
+ "fmt"
+ "os"
+)
+
+var Version = "bidichk version dev"
+
+type versionFlag struct{}
+
+func (versionFlag) IsBoolFlag() bool { return true }
+func (versionFlag) Get() interface{} { return nil }
+func (versionFlag) String() string { return "" }
+func (versionFlag) Set(s string) error {
+ fmt.Println(Version)
+ os.Exit(0)
+ return nil
+}
diff --git a/vendor/github.com/breml/errchkjson/.gitignore b/vendor/github.com/breml/errchkjson/.gitignore
new file mode 100644
index 000000000..0362de301
--- /dev/null
+++ b/vendor/github.com/breml/errchkjson/.gitignore
@@ -0,0 +1,29 @@
+# Binaries for programs and plugins
+*.exe
+*.exe~
+*.dll
+*.so
+*.dylib
+/errchkjson
+/cmd/errchkjson/errchkjson
+
+# Test binary, build with `go test -c`
+*.test
+
+# Output of the go coverage tool, specifically when used with LiteIDE
+*.out
+coverage.html
+
+# Log files
+*.log
+
+# Env files
+.env
+
+# Exclude todo
+TODO.md
+
+# Exclude IDE settings
+.idea/
+*.iml
+.vscode/
diff --git a/vendor/github.com/breml/errchkjson/.goreleaser.yml b/vendor/github.com/breml/errchkjson/.goreleaser.yml
new file mode 100644
index 000000000..5f23690f1
--- /dev/null
+++ b/vendor/github.com/breml/errchkjson/.goreleaser.yml
@@ -0,0 +1,33 @@
+# This is an example .goreleaser.yml file with some sane defaults.
+# Make sure to check the documentation at http://goreleaser.com
+before:
+ hooks:
+ # You may remove this if you don't use go modules.
+ - go mod tidy
+builds:
+ - main: ./cmd/errchkjson
+ binary: errchkjson
+ env:
+ - CGO_ENABLED=0
+ goos:
+ - linux
+ - windows
+ - darwin
+archives:
+ - name_template: "{{ .Binary }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}"
+ replacements:
+ darwin: Darwin
+ linux: Linux
+ windows: Windows
+ 386: i386
+ amd64: x86_64
+snapshot:
+ name_template: "{{ .Tag }}-next"
+changelog:
+ skip: true
+release:
+ github:
+ owner: breml
+ name: errchkjson
+gomod:
+ proxy: true
diff --git a/vendor/github.com/breml/errchkjson/LICENSE b/vendor/github.com/breml/errchkjson/LICENSE
new file mode 100644
index 000000000..08db5cb6f
--- /dev/null
+++ b/vendor/github.com/breml/errchkjson/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2019 Lucas Bremgartner
+
+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/breml/errchkjson/README.md b/vendor/github.com/breml/errchkjson/README.md
new file mode 100644
index 000000000..197959738
--- /dev/null
+++ b/vendor/github.com/breml/errchkjson/README.md
@@ -0,0 +1,131 @@
+# errchkjson
+
+[![Test Status](https://github.com/breml/errchkjson/actions/workflows/ci.yml/badge.svg)](https://github.com/breml/errchkjson/actions/workflows/ci.yml) [![Go Report Card](https://goreportcard.com/badge/github.com/breml/errchkjson)](https://goreportcard.com/report/github.com/breml/errchkjson) [![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
+
+Checks types passed to the json encoding functions. Reports unsupported types and reports occurrences where the check for the returned error can be omitted.
+
+Consider this [http.Handler](https://pkg.go.dev/net/http#Handler):
+
+```Go
+func JSONHelloWorld(w http.ResponseWriter, r *http.Request) {
+ response := struct {
+ Message string
+ Code int
+ }{
+ Message: "Hello World",
+ Code: 200,
+ }
+
+ body, err := json.Marshal(response)
+ if err != nil {
+ panic(err) // unreachable, because json encoding of a struct with just a string and an int will never return an error.
+ }
+
+ w.Write(body)
+}
+```
+
+Because the `panic` is not possible to happen, one might refactor the code like this:
+
+```Go
+func JSONHelloWorld(w http.ResponseWriter, r *http.Request) {
+ response := struct {
+ Message string
+ Code int
+ }{
+ Message: "Hello World",
+ Code: 200,
+ }
+
+ body, _ := json.Marshal(response)
+
+ w.Write(body)
+}
+```
+
+This is ok, as long as the struct is not altered in such a way, that could potentially lead
+to `json.Marshal` returning an error.
+
+`errchkjson` allows you to lint your code such that the above error returned from `json.Marshal`
+can be omitted while still staying safe, because as soon as an unsafe type is added to the
+response type, the linter will warn you.
+
+## Installation
+
+Download `errchkjson` from the [releases](https://github.com/breml/errchkjson/releases) or get the latest version from source with:
+
+```shell
+go get github.com/breml/errchkjson/cmd/errchkjson
+```
+
+## Usage
+
+### Shell
+
+Check everything:
+
+```shell
+errchkjson ./...
+```
+
+`errchkjson` also recognizes the following command-line options:
+
+The `-omit-safe` flag disables checking for safe returns of errors from json.Marshal
+
+## Types
+
+### Safe
+
+The following types are safe to use with [json encoding functions](https://pkg.go.dev/encoding/json), that is, the encoding to JSON can not fail:
+
+Safe basic types:
+
+* `bool`
+* `int`, `int8`, `int16`, `int32`, `int64`, `uint`, `uint8`, `uint16`, `uint32`, `uint64`, `uintptr`
+* `string`
+* Pointer type of the above listed basic types
+
+Composed types (struct, map, slice, array) are safe, if the type of the value is
+safe. For structs, only exported fields are relevant. For maps, the key needs to be either an integer type or a string.
+
+### Unsafe
+
+The following types are unsafe to use with [json encoding functions](https://pkg.go.dev/encoding/json), that is, the encoding to JSON can fail (return an error):
+
+Unsafe basic types:
+
+* `float32`, `float64`
+* `interface{}`
+* Pointer type of the above listed basic types
+
+Any composed types (struct, map, slice, array) containing an unsafe basic type.
+
+If a type implements the `json.Marshaler` or `encoding.TextMarshaler` interface (e.g. `json.Number`).
+
+### Forbidden
+
+Forbidden basic types:
+
+* `complex64`, `complex128`
+* `chan`
+* `func`
+* `unsafe.Pointer`
+
+Any composed types (struct, map, slice, array) containing a forbidden basic type. Any map
+using a key with a forbidden type (`bool`, `float32`, `float64`, `struct`).
+
+## Accepted edge case
+
+For `encoding/json.MarshalIndent`, there is a (pathological) edge case, where this
+function could [return an error](https://cs.opensource.google/go/go/+/refs/tags/go1.18:src/encoding/json/scanner.go;drc=refs%2Ftags%2Fgo1.18;l=181) for an otherwise safe argument, if the argument has
+a nesting depth larger than [`10000`](https://cs.opensource.google/go/go/+/refs/tags/go1.18:src/encoding/json/scanner.go;drc=refs%2Ftags%2Fgo1.18;l=144) (as of Go 1.18).
+
+## Bugs found during development
+
+During the development of `errcheckjson`, the following issues in package `encoding/json` of the Go standard library have been found and PR have been merged:
+
+* [Issue #34154: encoding/json: string option (struct tag) on string field with SetEscapeHTML(false) escapes anyway](https://github.com/golang/go/issues/34154)
+* [PR #34127: encoding/json: fix and optimize marshal for quoted string](https://github.com/golang/go/pull/34127)
+* [Issue #34268: encoding/json: wrong encoding for json.Number field with string option (struct tag)](https://github.com/golang/go/issues/34268)
+* [PR #34269: encoding/json: make Number with the ,string option marshal with quotes](https://github.com/golang/go/pull/34269)
+* [PR #34272: encoding/json: validate strings when decoding into Number](https://github.com/golang/go/pull/34272)
diff --git a/vendor/github.com/breml/errchkjson/errchkjson.go b/vendor/github.com/breml/errchkjson/errchkjson.go
new file mode 100644
index 000000000..746709c76
--- /dev/null
+++ b/vendor/github.com/breml/errchkjson/errchkjson.go
@@ -0,0 +1,348 @@
+// Package errchkjson defines an Analyzer that finds places, where it is
+// safe to omit checking the error returned from json.Marshal.
+package errchkjson
+
+import (
+ "flag"
+ "fmt"
+ "go/ast"
+ "go/token"
+ "go/types"
+ "reflect"
+
+ "golang.org/x/tools/go/analysis"
+ "golang.org/x/tools/go/types/typeutil"
+)
+
+type errchkjson struct {
+ omitSafe bool // -omit-safe flag
+ reportNoExported bool // -report-no-exported flag
+}
+
+// NewAnalyzer returns a new errchkjson analyzer.
+func NewAnalyzer() *analysis.Analyzer {
+ errchkjson := &errchkjson{}
+
+ a := &analysis.Analyzer{
+ Name: "errchkjson",
+ Doc: "Checks types passed to the json encoding functions. Reports unsupported types and reports occations, where the check for the returned error can be omitted.",
+ Run: errchkjson.run,
+ }
+
+ a.Flags.Init("errchkjson", flag.ExitOnError)
+ a.Flags.BoolVar(&errchkjson.omitSafe, "omit-safe", false, "if omit-safe is true, checking of safe returns is omitted")
+ a.Flags.BoolVar(&errchkjson.reportNoExported, "report-no-exported", false, "if report-no-exported is true, encoding a struct without exported fields is reported as issue")
+ a.Flags.Var(versionFlag{}, "V", "print version and exit")
+
+ return a
+}
+
+func (e *errchkjson) run(pass *analysis.Pass) (interface{}, error) {
+ for _, file := range pass.Files {
+ ast.Inspect(file, func(n ast.Node) bool {
+ if n == nil {
+ return true
+ }
+
+ // if the error is returned, it is the caller's responsibility to check
+ // the return value.
+ if _, ok := n.(*ast.ReturnStmt); ok {
+ return false
+ }
+
+ ce, ok := n.(*ast.CallExpr)
+ if ok {
+ fn, _ := typeutil.Callee(pass.TypesInfo, ce).(*types.Func)
+ if fn == nil {
+ return true
+ }
+
+ switch fn.FullName() {
+ case "encoding/json.Marshal", "encoding/json.MarshalIndent":
+ e.handleJSONMarshal(pass, ce, fn.FullName(), blankIdentifier, e.omitSafe)
+ case "(*encoding/json.Encoder).Encode":
+ e.handleJSONMarshal(pass, ce, fn.FullName(), blankIdentifier, true)
+ default:
+ e.inspectArgs(pass, ce.Args)
+ }
+ return false
+ }
+
+ as, ok := n.(*ast.AssignStmt)
+ if !ok {
+ return true
+ }
+
+ ce, ok = as.Rhs[0].(*ast.CallExpr)
+ if !ok {
+ return true
+ }
+
+ fn, _ := typeutil.Callee(pass.TypesInfo, ce).(*types.Func)
+ if fn == nil {
+ return true
+ }
+
+ switch fn.FullName() {
+ case "encoding/json.Marshal", "encoding/json.MarshalIndent":
+ e.handleJSONMarshal(pass, ce, fn.FullName(), evaluateMarshalErrorTarget(as.Lhs[1]), e.omitSafe)
+ case "(*encoding/json.Encoder).Encode":
+ e.handleJSONMarshal(pass, ce, fn.FullName(), evaluateMarshalErrorTarget(as.Lhs[0]), true)
+ default:
+ return true
+ }
+ return false
+ })
+ }
+
+ return nil, nil
+}
+
+func evaluateMarshalErrorTarget(n ast.Expr) marshalErrorTarget {
+ if errIdent, ok := n.(*ast.Ident); ok {
+ if errIdent.Name == "_" {
+ return blankIdentifier
+ }
+ }
+ return variableAssignment
+}
+
+type marshalErrorTarget int
+
+const (
+ blankIdentifier = iota // the returned error from the JSON marshal function is assigned to the blank identifier "_".
+ variableAssignment // the returned error from the JSON marshal function is assigned to a variable.
+ functionArgument // the returned error from the JSON marshal function is passed to an other function as argument.
+)
+
+func (e *errchkjson) handleJSONMarshal(pass *analysis.Pass, ce *ast.CallExpr, fnName string, errorTarget marshalErrorTarget, omitSafe bool) {
+ t := pass.TypesInfo.TypeOf(ce.Args[0])
+ if t == nil {
+ // Not sure, if this is at all possible
+ if errorTarget == blankIdentifier {
+ pass.Reportf(ce.Pos(), "Type of argument to `%s` could not be evaluated and error return value is not checked", fnName)
+ }
+ return
+ }
+
+ if _, ok := t.(*types.Pointer); ok {
+ t = t.(*types.Pointer).Elem()
+ }
+
+ err := e.jsonSafe(t, 0, map[types.Type]struct{}{})
+ if err != nil {
+ if _, ok := err.(unsupported); ok {
+ pass.Reportf(ce.Pos(), "`%s` for %v", fnName, err)
+ return
+ }
+ if _, ok := err.(noexported); ok {
+ pass.Reportf(ce.Pos(), "Error argument passed to `%s` does not contain any exported field", fnName)
+ }
+ // Only care about unsafe types if they are assigned to the blank identifier.
+ if errorTarget == blankIdentifier {
+ pass.Reportf(ce.Pos(), "Error return value of `%s` is not checked: %v", fnName, err)
+ }
+ }
+ if err == nil && errorTarget == variableAssignment && !omitSafe {
+ pass.Reportf(ce.Pos(), "Error return value of `%s` is checked but passed argument is safe", fnName)
+ }
+ // Report an error, if err for json.Marshal is not checked and safe types are omitted
+ if err == nil && errorTarget == blankIdentifier && omitSafe {
+ pass.Reportf(ce.Pos(), "Error return value of `%s` is not checked", fnName)
+ }
+}
+
+const (
+ allowedBasicTypes = types.IsBoolean | types.IsInteger | types.IsString
+ allowedMapKeyBasicTypes = types.IsInteger | types.IsString
+ unsupportedBasicTypes = types.IsComplex
+)
+
+func (e *errchkjson) jsonSafe(t types.Type, level int, seenTypes map[types.Type]struct{}) error {
+ if _, ok := seenTypes[t]; ok {
+ return nil
+ }
+
+ if types.Implements(t, textMarshalerInterface()) || types.Implements(t, jsonMarshalerInterface()) {
+ return fmt.Errorf("unsafe type `%s` found", t.String())
+ }
+
+ switch ut := t.Underlying().(type) {
+ case *types.Basic:
+ if ut.Info()&allowedBasicTypes > 0 { // bool, int-family, string
+ if ut.Info()&types.IsString > 0 && t.String() == "encoding/json.Number" {
+ return fmt.Errorf("unsafe type `%s` found", t.String())
+ }
+ return nil
+ }
+ if ut.Info()&unsupportedBasicTypes > 0 { // complex64, complex128
+ return newUnsupportedError(fmt.Errorf("unsupported type `%s` found", ut.String()))
+ }
+ switch ut.Kind() {
+ case types.UntypedNil:
+ return nil
+ case types.UnsafePointer:
+ return newUnsupportedError(fmt.Errorf("unsupported type `%s` found", ut.String()))
+ default:
+ // E.g. float32, float64
+ return fmt.Errorf("unsafe type `%s` found", ut.String())
+ }
+
+ case *types.Array:
+ err := e.jsonSafe(ut.Elem(), level+1, seenTypes)
+ if err != nil {
+ return err
+ }
+ return nil
+
+ case *types.Slice:
+ err := e.jsonSafe(ut.Elem(), level+1, seenTypes)
+ if err != nil {
+ return err
+ }
+ return nil
+
+ case *types.Struct:
+ seenTypes[t] = struct{}{}
+ exported := 0
+ for i := 0; i < ut.NumFields(); i++ {
+ if !ut.Field(i).Exported() {
+ // Unexported fields can be ignored
+ continue
+ }
+ if tag, ok := reflect.StructTag(ut.Tag(i)).Lookup("json"); ok {
+ if tag == "-" {
+ // Fields omitted in json can be ignored
+ continue
+ }
+ }
+ err := e.jsonSafe(ut.Field(i).Type(), level+1, seenTypes)
+ if err != nil {
+ return err
+ }
+ exported++
+ }
+ if e.reportNoExported && level == 0 && exported == 0 {
+ return newNoexportedError(fmt.Errorf("struct does not export any field"))
+ }
+ return nil
+
+ case *types.Pointer:
+ err := e.jsonSafe(ut.Elem(), level+1, seenTypes)
+ if err != nil {
+ return err
+ }
+ return nil
+
+ case *types.Map:
+ err := jsonSafeMapKey(ut.Key())
+ if err != nil {
+ return err
+ }
+ err = e.jsonSafe(ut.Elem(), level+1, seenTypes)
+ if err != nil {
+ return err
+ }
+ return nil
+
+ case *types.Chan, *types.Signature:
+ // Types that are not supported for encoding to json:
+ return newUnsupportedError(fmt.Errorf("unsupported type `%s` found", ut.String()))
+
+ default:
+ // Types that are not supported for encoding to json or are not completely safe, like: interfaces
+ return fmt.Errorf("unsafe type `%s` found", t.String())
+ }
+}
+
+func jsonSafeMapKey(t types.Type) error {
+ if types.Implements(t, textMarshalerInterface()) || types.Implements(t, jsonMarshalerInterface()) {
+ return fmt.Errorf("unsafe type `%s` as map key found", t.String())
+ }
+ switch ut := t.Underlying().(type) {
+ case *types.Basic:
+ if ut.Info()&types.IsString > 0 && t.String() == "encoding/json.Number" {
+ return fmt.Errorf("unsafe type `%s` as map key found", t.String())
+ }
+ if ut.Info()&allowedMapKeyBasicTypes > 0 { // bool, int-family, string
+ return nil
+ }
+ // E.g. bool, float32, float64, complex64, complex128
+ return newUnsupportedError(fmt.Errorf("unsupported type `%s` as map key found", t.String()))
+ case *types.Interface:
+ return fmt.Errorf("unsafe type `%s` as map key found", t.String())
+ default:
+ // E.g. struct composed solely of basic types, that are comparable
+ return newUnsupportedError(fmt.Errorf("unsupported type `%s` as map key found", t.String()))
+ }
+}
+
+func (e *errchkjson) inspectArgs(pass *analysis.Pass, args []ast.Expr) {
+ for _, a := range args {
+ ast.Inspect(a, func(n ast.Node) bool {
+ if n == nil {
+ return true
+ }
+
+ ce, ok := n.(*ast.CallExpr)
+ if !ok {
+ return false
+ }
+
+ fn, _ := typeutil.Callee(pass.TypesInfo, ce).(*types.Func)
+ if fn == nil {
+ return true
+ }
+
+ switch fn.FullName() {
+ case "encoding/json.Marshal", "encoding/json.MarshalIndent":
+ e.handleJSONMarshal(pass, ce, fn.FullName(), functionArgument, e.omitSafe)
+ case "(*encoding/json.Encoder).Encode":
+ e.handleJSONMarshal(pass, ce, fn.FullName(), functionArgument, true)
+ default:
+ e.inspectArgs(pass, ce.Args)
+ }
+ return false
+ })
+ }
+}
+
+// Construct *types.Interface for interface encoding.TextMarshaler
+// type TextMarshaler interface {
+// MarshalText() (text []byte, err error)
+// }
+//
+func textMarshalerInterface() *types.Interface {
+ textMarshalerInterface := types.NewInterfaceType([]*types.Func{
+ types.NewFunc(token.NoPos, nil, "MarshalText", types.NewSignature(
+ nil, nil, types.NewTuple(
+ types.NewVar(token.NoPos, nil, "text",
+ types.NewSlice(
+ types.Universe.Lookup("byte").Type())),
+ types.NewVar(token.NoPos, nil, "err", types.Universe.Lookup("error").Type())),
+ false)),
+ }, nil)
+ textMarshalerInterface.Complete()
+
+ return textMarshalerInterface
+}
+
+// Construct *types.Interface for interface json.Marshaler
+// type Marshaler interface {
+// MarshalJSON() ([]byte, error)
+// }
+//
+func jsonMarshalerInterface() *types.Interface {
+ textMarshalerInterface := types.NewInterfaceType([]*types.Func{
+ types.NewFunc(token.NoPos, nil, "MarshalJSON", types.NewSignature(
+ nil, nil, types.NewTuple(
+ types.NewVar(token.NoPos, nil, "",
+ types.NewSlice(
+ types.Universe.Lookup("byte").Type())),
+ types.NewVar(token.NoPos, nil, "", types.Universe.Lookup("error").Type())),
+ false)),
+ }, nil)
+ textMarshalerInterface.Complete()
+
+ return textMarshalerInterface
+}
diff --git a/vendor/github.com/breml/errchkjson/go.mod b/vendor/github.com/breml/errchkjson/go.mod
new file mode 100644
index 000000000..75704c4bb
--- /dev/null
+++ b/vendor/github.com/breml/errchkjson/go.mod
@@ -0,0 +1,11 @@
+module github.com/breml/errchkjson
+
+go 1.17
+
+require golang.org/x/tools v0.1.10
+
+require (
+ golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 // indirect
+ golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8 // indirect
+ golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
+)
diff --git a/vendor/github.com/breml/errchkjson/go.sum b/vendor/github.com/breml/errchkjson/go.sum
new file mode 100644
index 000000000..0e4a1ee18
--- /dev/null
+++ b/vendor/github.com/breml/errchkjson/go.sum
@@ -0,0 +1,30 @@
+github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
+golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 h1:kQgndtyPBW/JIYERgdxfwMYh3AVStj88WQTlNDi2a+o=
+golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
+golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
+golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8 h1:OH54vjqzRWmbJ62fjuhxy7AxFFgoHN0/DPc/UrL8cAs=
+golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.1.10 h1:QjFRCZxdOhBJ/UNgnBZLbNV13DlbnK0quyivTnXJM20=
+golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E=
+golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
+golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
diff --git a/vendor/github.com/breml/errchkjson/noexported_error.go b/vendor/github.com/breml/errchkjson/noexported_error.go
new file mode 100644
index 000000000..07b7a07d2
--- /dev/null
+++ b/vendor/github.com/breml/errchkjson/noexported_error.go
@@ -0,0 +1,23 @@
+package errchkjson
+
+type noexported interface {
+ noexported()
+}
+
+var _ noexported = noexportedError{}
+
+type noexportedError struct {
+ err error
+}
+
+func newNoexportedError(err error) error {
+ return noexportedError{
+ err: err,
+ }
+}
+
+func (u noexportedError) noexported() {}
+
+func (u noexportedError) Error() string {
+ return u.err.Error()
+}
diff --git a/vendor/github.com/breml/errchkjson/unsupported_error.go b/vendor/github.com/breml/errchkjson/unsupported_error.go
new file mode 100644
index 000000000..1a38c3f53
--- /dev/null
+++ b/vendor/github.com/breml/errchkjson/unsupported_error.go
@@ -0,0 +1,23 @@
+package errchkjson
+
+type unsupported interface {
+ unsupported()
+}
+
+var _ unsupported = unsupportedError{}
+
+type unsupportedError struct {
+ err error
+}
+
+func newUnsupportedError(err error) error {
+ return unsupportedError{
+ err: err,
+ }
+}
+
+func (u unsupportedError) unsupported() {}
+
+func (u unsupportedError) Error() string {
+ return u.err.Error()
+}
diff --git a/vendor/github.com/breml/errchkjson/version.go b/vendor/github.com/breml/errchkjson/version.go
new file mode 100644
index 000000000..77d8ef8bb
--- /dev/null
+++ b/vendor/github.com/breml/errchkjson/version.go
@@ -0,0 +1,19 @@
+package errchkjson
+
+import (
+ "fmt"
+ "os"
+)
+
+var Version = "errchkjson version dev"
+
+type versionFlag struct{}
+
+func (versionFlag) IsBoolFlag() bool { return true }
+func (versionFlag) Get() interface{} { return nil }
+func (versionFlag) String() string { return "" }
+func (versionFlag) Set(s string) error {
+ fmt.Println(Version)
+ os.Exit(0)
+ return nil
+}