diff options
| author | Taras Madan <tarasmadan@google.com> | 2022-09-05 14:27:54 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-09-05 12:27:54 +0000 |
| commit | b2f2446b46bf02821d90ebedadae2bf7ae0e880e (patch) | |
| tree | 923cf42842918d6bebca1d6bbdc08abed54d274d /vendor/github.com/GaijinEntertainment | |
| parent | e6654faff4bcca4be92e9a8596fd4b77f747c39e (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/GaijinEntertainment')
4 files changed, 408 insertions, 0 deletions
diff --git a/vendor/github.com/GaijinEntertainment/go-exhaustruct/v2/LICENSE b/vendor/github.com/GaijinEntertainment/go-exhaustruct/v2/LICENSE new file mode 100644 index 000000000..6698196c5 --- /dev/null +++ b/vendor/github.com/GaijinEntertainment/go-exhaustruct/v2/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2022 Gaijin Entertainment + +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/GaijinEntertainment/go-exhaustruct/v2/pkg/analyzer/analyzer.go b/vendor/github.com/GaijinEntertainment/go-exhaustruct/v2/pkg/analyzer/analyzer.go new file mode 100644 index 000000000..49948e12e --- /dev/null +++ b/vendor/github.com/GaijinEntertainment/go-exhaustruct/v2/pkg/analyzer/analyzer.go @@ -0,0 +1,292 @@ +package analyzer + +import ( + "errors" + "flag" + "go/ast" + "go/types" + "strings" + "sync" + + "golang.org/x/tools/go/analysis" + "golang.org/x/tools/go/analysis/passes/inspect" + "golang.org/x/tools/go/ast/inspector" +) + +var ( + ErrEmptyPattern = errors.New("pattern can't be empty") +) + +type analyzer struct { + include PatternsList + exclude PatternsList + + typesProcessCache map[string]bool + typesProcessCacheMu sync.RWMutex + + structFieldsCache map[string]*StructFields + structFieldsCacheMu sync.RWMutex +} + +// NewAnalyzer returns a go/analysis-compatible analyzer. +// -i arguments adds include patterns +// -e arguments adds exclude patterns +func NewAnalyzer(include []string, exclude []string) (*analysis.Analyzer, error) { + a := analyzer{ //nolint:exhaustruct + typesProcessCache: map[string]bool{}, + + structFieldsCache: map[string]*StructFields{}, + } + + var err error + + a.include, err = newPatternsList(include) + if err != nil { + return nil, err + } + + a.exclude, err = newPatternsList(exclude) + if err != nil { + return nil, err + } + + return &analysis.Analyzer{ //nolint:exhaustruct + Name: "exhaustruct", + Doc: "Checks if all structure fields are initialized", + Run: a.run, + Requires: []*analysis.Analyzer{inspect.Analyzer}, + Flags: a.newFlagSet(), + }, nil +} + +func (a *analyzer) newFlagSet() flag.FlagSet { + fs := flag.NewFlagSet("exhaustruct flags", flag.PanicOnError) + + fs.Var( + &reListVar{values: &a.include}, + "i", + "Regular expression to match struct packages and names, can receive multiple flags", + ) + fs.Var( + &reListVar{values: &a.exclude}, + "e", + "Regular expression to exclude struct packages and names, can receive multiple flags", + ) + + return *fs +} + +func (a *analyzer) run(pass *analysis.Pass) (interface{}, error) { + insp := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector) //nolint:forcetypeassert + + nodeTypes := []ast.Node{ + (*ast.CompositeLit)(nil), + (*ast.ReturnStmt)(nil), + } + + insp.Preorder(nodeTypes, a.newVisitor(pass)) + + return nil, nil //nolint:nilnil +} + +//nolint:cyclop +func (a *analyzer) newVisitor(pass *analysis.Pass) func(node ast.Node) { + var ret *ast.ReturnStmt + + return func(node ast.Node) { + if retLit, ok := node.(*ast.ReturnStmt); ok { + // save return statement for future (to detect error-containing returns) + ret = retLit + + return + } + + lit, _ := node.(*ast.CompositeLit) + if lit.Type == nil { + // we're not interested in non-typed literals + return + } + + typ := pass.TypesInfo.TypeOf(lit.Type) + if typ == nil { + return + } + + strct, ok := typ.Underlying().(*types.Struct) + if !ok { + // we also not interested in non-structure literals + return + } + + strctName := exprName(lit.Type) + if strctName == "" { + return + } + + if !a.shouldProcessType(typ.String()) { + return + } + + if len(lit.Elts) == 0 && ret != nil { + if ret.End() < lit.Pos() { + // we're outside last return statement + ret = nil + } else if returnContainsLiteral(ret, lit) && returnContainsError(ret, pass) { + // we're okay with empty literals in return statements with non-nil errors, like + // `return my.Struct{}, fmt.Errorf("non-nil error!")` + return + } + } + + missingFields := a.structMissingFields(lit, strct, typ.String(), pass.Pkg.Path()) + + if len(missingFields) == 1 { + pass.Reportf(node.Pos(), "%s is missing in %s", missingFields[0], strctName) + } else if len(missingFields) > 1 { + pass.Reportf(node.Pos(), "%s are missing in %s", strings.Join(missingFields, ", "), strctName) + } + } +} + +func (a *analyzer) shouldProcessType(typ string) bool { + if len(a.include) == 0 && len(a.exclude) == 0 { + // skip whole part with cache, since we have no restrictions and have to check everything + return true + } + + a.typesProcessCacheMu.RLock() + v, ok := a.typesProcessCache[typ] + a.typesProcessCacheMu.RUnlock() + + if !ok { + a.typesProcessCacheMu.Lock() + defer a.typesProcessCacheMu.Unlock() + + v = true + + if len(a.include) > 0 && !a.include.MatchesAny(typ) { + v = false + } + + if v && a.exclude.MatchesAny(typ) { + v = false + } + + a.typesProcessCache[typ] = v + } + + return v +} + +func (a *analyzer) structMissingFields( + lit *ast.CompositeLit, + strct *types.Struct, + typ string, + pkgPath string, +) []string { + keys, unnamed := literalKeys(lit) + fields := a.structFields(typ, strct) + + var fieldNames []string + + if strings.HasPrefix(typ, pkgPath+".") { + // we're in same package and should match private fields + fieldNames = fields.All + } else { + fieldNames = fields.Public + } + + if unnamed { + return fieldNames[len(keys):] + } + + return difference(fieldNames, keys) +} + +func (a *analyzer) structFields(typ string, strct *types.Struct) *StructFields { + a.structFieldsCacheMu.RLock() + fields, ok := a.structFieldsCache[typ] + a.structFieldsCacheMu.RUnlock() + + if !ok { + a.structFieldsCacheMu.Lock() + defer a.structFieldsCacheMu.Unlock() + + fields = NewStructFields(strct) + a.structFieldsCache[typ] = fields + } + + return fields +} + +func returnContainsLiteral(ret *ast.ReturnStmt, lit *ast.CompositeLit) bool { + for _, result := range ret.Results { + if l, ok := result.(*ast.CompositeLit); ok { + if lit == l { + return true + } + } + } + + return false +} + +func returnContainsError(ret *ast.ReturnStmt, pass *analysis.Pass) bool { + for _, result := range ret.Results { + if pass.TypesInfo.TypeOf(result).String() == "error" { + return true + } + } + + return false +} + +func literalKeys(lit *ast.CompositeLit) (keys []string, unnamed bool) { + for _, elt := range lit.Elts { + if k, ok := elt.(*ast.KeyValueExpr); ok { + if ident, ok := k.Key.(*ast.Ident); ok { + keys = append(keys, ident.Name) + } + + continue + } + + // in case we deal with unnamed initialization - no need to iterate over all + // elements - simply create slice with proper size + unnamed = true + keys = make([]string, len(lit.Elts)) + + return + } + + return +} + +// difference returns elements that are in `a` and not in `b`. +func difference(a, b []string) (diff []string) { + mb := make(map[string]struct{}, len(b)) + for _, x := range b { + mb[x] = struct{}{} + } + + for _, x := range a { + if _, found := mb[x]; !found { + diff = append(diff, x) + } + } + + return diff +} + +func exprName(expr ast.Expr) string { + if i, ok := expr.(*ast.Ident); ok { + return i.Name + } + + s, ok := expr.(*ast.SelectorExpr) + if !ok { + return "" + } + + return s.Sel.Name +} diff --git a/vendor/github.com/GaijinEntertainment/go-exhaustruct/v2/pkg/analyzer/patterns-list.go b/vendor/github.com/GaijinEntertainment/go-exhaustruct/v2/pkg/analyzer/patterns-list.go new file mode 100644 index 000000000..2884cab62 --- /dev/null +++ b/vendor/github.com/GaijinEntertainment/go-exhaustruct/v2/pkg/analyzer/patterns-list.go @@ -0,0 +1,68 @@ +package analyzer + +import ( + "fmt" + "regexp" +) + +type PatternsList []*regexp.Regexp + +// MatchesAny matches provided string against all regexps in a slice. +func (l PatternsList) MatchesAny(str string) bool { + for _, r := range l { + if r.MatchString(str) { + return true + } + } + + return false +} + +// newPatternsList parses slice of strings to a slice of compiled regular +// expressions. +func newPatternsList(in []string) (PatternsList, error) { + list := PatternsList{} + + for _, str := range in { + re, err := strToRegexp(str) + if err != nil { + return nil, err + } + + list = append(list, re) + } + + return list, nil +} + +type reListVar struct { + values *PatternsList +} + +func (v *reListVar) Set(value string) error { + re, err := strToRegexp(value) + if err != nil { + return err + } + + *v.values = append(*v.values, re) + + return nil +} + +func (v *reListVar) String() string { + return "" +} + +func strToRegexp(str string) (*regexp.Regexp, error) { + if str == "" { + return nil, ErrEmptyPattern + } + + re, err := regexp.Compile(str) + if err != nil { + return nil, fmt.Errorf("unable to compile %s as regular expression: %w", str, err) + } + + return re, nil +} diff --git a/vendor/github.com/GaijinEntertainment/go-exhaustruct/v2/pkg/analyzer/struct-fields.go b/vendor/github.com/GaijinEntertainment/go-exhaustruct/v2/pkg/analyzer/struct-fields.go new file mode 100644 index 000000000..e7d004250 --- /dev/null +++ b/vendor/github.com/GaijinEntertainment/go-exhaustruct/v2/pkg/analyzer/struct-fields.go @@ -0,0 +1,27 @@ +package analyzer + +import ( + "go/types" +) + +type StructFields struct { + Public []string + + All []string +} + +func NewStructFields(strct *types.Struct) *StructFields { + sf := StructFields{} //nolint:exhaustruct + + for i := 0; i < strct.NumFields(); i++ { + f := strct.Field(i) + + sf.All = append(sf.All, f.Name()) + + if f.Exported() { + sf.Public = append(sf.Public, f.Name()) + } + } + + return &sf +} |
