From fcc6d71be2c3ce7d9305c04fc2e87af554571bac Mon Sep 17 00:00:00 2001 From: Dmitry Vyukov Date: Mon, 22 Feb 2021 20:37:25 +0100 Subject: go.mod: update golangci-lint to v1.37 --- vendor/github.com/ashanbrown/makezero/LICENSE | 13 ++ .../ashanbrown/makezero/makezero/makezero.go | 197 +++++++++++++++++++++ 2 files changed, 210 insertions(+) create mode 100644 vendor/github.com/ashanbrown/makezero/LICENSE create mode 100644 vendor/github.com/ashanbrown/makezero/makezero/makezero.go (limited to 'vendor/github.com/ashanbrown/makezero') diff --git a/vendor/github.com/ashanbrown/makezero/LICENSE b/vendor/github.com/ashanbrown/makezero/LICENSE new file mode 100644 index 000000000..dc1d47ad5 --- /dev/null +++ b/vendor/github.com/ashanbrown/makezero/LICENSE @@ -0,0 +1,13 @@ +Copyright 2019 Andrew Shannon Brown + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/vendor/github.com/ashanbrown/makezero/makezero/makezero.go b/vendor/github.com/ashanbrown/makezero/makezero/makezero.go new file mode 100644 index 000000000..6bf230b12 --- /dev/null +++ b/vendor/github.com/ashanbrown/makezero/makezero/makezero.go @@ -0,0 +1,197 @@ +// makezero provides a linter for appends to slices initialized with non-zero length. +package makezero + +import ( + "bytes" + "fmt" + "go/ast" + "go/printer" + "go/token" + "go/types" + "log" + "regexp" +) + +type Issue interface { + Details() string + Position() token.Position + String() string +} + +type AppendIssue struct { + name string + position token.Position +} + +func (a AppendIssue) Details() string { + return fmt.Sprintf("append to slice `%s` with non-zero initialized length", a.name) +} + +func (a AppendIssue) Position() token.Position { + return a.position +} + +func (a AppendIssue) String() string { return toString(a) } + +type MustHaveNonZeroInitLenIssue struct { + name string + position token.Position +} + +func (i MustHaveNonZeroInitLenIssue) Details() string { + return fmt.Sprintf("slice `%s` does not have non-zero initial length", i.name) +} + +func (i MustHaveNonZeroInitLenIssue) Position() token.Position { + return i.position +} + +func (i MustHaveNonZeroInitLenIssue) String() string { return toString(i) } + +func toString(i Issue) string { + return fmt.Sprintf("%s at %s", i.Details(), i.Position()) +} + +type visitor struct { + initLenMustBeZero bool + + comments []*ast.CommentGroup // comments to apply during this visit + info *types.Info + + nonZeroLengthSliceDecls map[interface{}]struct{} + fset *token.FileSet + issues []Issue +} + +type Linter struct { + initLenMustBeZero bool +} + +func NewLinter(initialLengthMustBeZero bool) *Linter { + return &Linter{ + initLenMustBeZero: initialLengthMustBeZero, + } +} + +func (l Linter) Run(fset *token.FileSet, info *types.Info, nodes ...ast.Node) ([]Issue, error) { + var issues []Issue // nolint:prealloc // don't know how many there will be + for _, node := range nodes { + var comments []*ast.CommentGroup + if file, ok := node.(*ast.File); ok { + comments = file.Comments + } + visitor := visitor{ + nonZeroLengthSliceDecls: make(map[interface{}]struct{}), + initLenMustBeZero: l.initLenMustBeZero, + info: info, + fset: fset, + comments: comments, + } + ast.Walk(&visitor, node) + issues = append(issues, visitor.issues...) + } + return issues, nil +} + +func (v *visitor) Visit(node ast.Node) ast.Visitor { + switch node := node.(type) { + case *ast.CallExpr: + fun, ok := node.Fun.(*ast.Ident) + if !ok || fun.Name != "append" { + break + } + if sliceIdent, ok := node.Args[0].(*ast.Ident); ok && + v.hasNonZeroInitialLength(sliceIdent) && + !v.hasNoLintOnSameLine(fun) { + v.issues = append(v.issues, AppendIssue{name: sliceIdent.Name, position: v.fset.Position(fun.Pos())}) + } + case *ast.AssignStmt: + for i, right := range node.Rhs { + if right, ok := right.(*ast.CallExpr); ok { + fun, ok := right.Fun.(*ast.Ident) + if !ok || fun.Name != "make" { + continue + } + left := node.Lhs[i] + if len(right.Args) == 2 { + // ignore if not a slice or it has explicit zero length + if !v.isSlice(right.Args[0]) { + break + } else if lit, ok := right.Args[1].(*ast.BasicLit); ok && lit.Kind == token.INT && lit.Value == "0" { + break + } + if v.initLenMustBeZero && !v.hasNoLintOnSameLine(fun) { + v.issues = append(v.issues, MustHaveNonZeroInitLenIssue{ + name: v.textFor(left), + position: v.fset.Position(node.Pos()), + }) + } + v.recordNonZeroLengthSlices(left) + } + } + } + } + return v +} + +func (v *visitor) textFor(node ast.Node) string { + typeBuf := new(bytes.Buffer) + if err := printer.Fprint(typeBuf, v.fset, node); err != nil { + log.Fatalf("ERROR: unable to print type: %s", err) + } + return typeBuf.String() +} + +func (v *visitor) hasNonZeroInitialLength(ident *ast.Ident) bool { + if ident.Obj == nil { + log.Printf("WARNING: could not determine with %q at %s is a slice (missing object type)", + ident.Name, v.fset.Position(ident.Pos()).String()) + return false + } + _, exists := v.nonZeroLengthSliceDecls[ident.Obj.Decl] + return exists +} + +func (v *visitor) recordNonZeroLengthSlices(node ast.Node) { + ident, ok := node.(*ast.Ident) + if !ok { + return + } + v.nonZeroLengthSliceDecls[ident.Obj.Decl] = struct{}{} +} + +func (v *visitor) isSlice(node ast.Node) bool { + // determine type if this is a user-defined type + if ident, ok := node.(*ast.Ident); ok { + obj := ident.Obj + if obj == nil { + if v.info != nil { + _, ok := v.info.ObjectOf(ident).Type().(*types.Slice) + return ok + } + return false + } + spec, ok := obj.Decl.(*ast.TypeSpec) + if !ok { + return false + } + node = spec.Type + } + + if node, ok := node.(*ast.ArrayType); ok { + return node.Len == nil // only slices have zero length + } + return false +} + +func (v *visitor) hasNoLintOnSameLine(node ast.Node) bool { + var nolint = regexp.MustCompile(`^\s*nozero\b`) + nodePos := v.fset.Position(node.Pos()) + for _, c := range v.comments { + commentPos := v.fset.Position(c.Pos()) + if commentPos.Line == nodePos.Line && nolint.MatchString(c.Text()) { + return true + } + } + return false +} -- cgit mrf-deployment