aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/github.com/ashanbrown
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2021-02-22 20:37:25 +0100
committerDmitry Vyukov <dvyukov@google.com>2021-02-22 21:02:12 +0100
commitfcc6d71be2c3ce7d9305c04fc2e87af554571bac (patch)
treeb01dbb3d1e2988e28ea158d2d543d603ec0b9569 /vendor/github.com/ashanbrown
parent8f23c528ad5a943b9ffec5dcaf332fd0f614006e (diff)
go.mod: update golangci-lint to v1.37
Diffstat (limited to 'vendor/github.com/ashanbrown')
-rw-r--r--vendor/github.com/ashanbrown/forbidigo/LICENSE13
-rw-r--r--vendor/github.com/ashanbrown/forbidigo/forbidigo/config_options.go45
-rw-r--r--vendor/github.com/ashanbrown/forbidigo/forbidigo/forbidigo.go193
-rw-r--r--vendor/github.com/ashanbrown/makezero/LICENSE13
-rw-r--r--vendor/github.com/ashanbrown/makezero/makezero/makezero.go197
5 files changed, 461 insertions, 0 deletions
diff --git a/vendor/github.com/ashanbrown/forbidigo/LICENSE b/vendor/github.com/ashanbrown/forbidigo/LICENSE
new file mode 100644
index 000000000..dc1d47ad5
--- /dev/null
+++ b/vendor/github.com/ashanbrown/forbidigo/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/forbidigo/forbidigo/config_options.go b/vendor/github.com/ashanbrown/forbidigo/forbidigo/config_options.go
new file mode 100644
index 000000000..a39f754f0
--- /dev/null
+++ b/vendor/github.com/ashanbrown/forbidigo/forbidigo/config_options.go
@@ -0,0 +1,45 @@
+package forbidigo
+
+// Code generated by github.com/launchdarkly/go-options. DO NOT EDIT.
+
+type ApplyOptionFunc func(c *config) error
+
+func (f ApplyOptionFunc) apply(c *config) error {
+ return f(c)
+}
+
+func newConfig(options ...Option) (config, error) {
+ var c config
+ err := applyConfigOptions(&c, options...)
+ return c, err
+}
+
+func applyConfigOptions(c *config, options ...Option) error {
+ c.ExcludeGodocExamples = true
+ for _, o := range options {
+ if err := o.apply(c); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+type Option interface {
+ apply(*config) error
+}
+
+// OptionExcludeGodocExamples don't check inside Godoc examples (see https://blog.golang.org/examples)
+func OptionExcludeGodocExamples(o bool) ApplyOptionFunc {
+ return func(c *config) error {
+ c.ExcludeGodocExamples = o
+ return nil
+ }
+}
+
+// OptionIgnorePermitDirectives don't check for `permit` directives(for example, in favor of `nolint`)
+func OptionIgnorePermitDirectives(o bool) ApplyOptionFunc {
+ return func(c *config) error {
+ c.IgnorePermitDirectives = o
+ return nil
+ }
+}
diff --git a/vendor/github.com/ashanbrown/forbidigo/forbidigo/forbidigo.go b/vendor/github.com/ashanbrown/forbidigo/forbidigo/forbidigo.go
new file mode 100644
index 000000000..794a43ad2
--- /dev/null
+++ b/vendor/github.com/ashanbrown/forbidigo/forbidigo/forbidigo.go
@@ -0,0 +1,193 @@
+// forbidigo provides a linter for forbidding the use of specific identifiers
+package forbidigo
+
+import (
+ "bytes"
+ "fmt"
+ "go/ast"
+ "go/printer"
+ "go/token"
+ "log"
+ "regexp"
+ "strings"
+
+ "github.com/pkg/errors"
+)
+
+type Issue interface {
+ Details() string
+ Position() token.Position
+ String() string
+}
+
+type UsedIssue struct {
+ identifier string
+ pattern string
+ position token.Position
+}
+
+func (a UsedIssue) Details() string {
+ return fmt.Sprintf("use of `%s` forbidden by pattern `%s`", a.identifier, a.pattern)
+}
+
+func (a UsedIssue) Position() token.Position {
+ return a.position
+}
+
+func (a UsedIssue) String() string { return toString(a) }
+
+func toString(i Issue) string {
+ return fmt.Sprintf("%s at %s", i.Details(), i.Position())
+}
+
+type Linter struct {
+ cfg config
+ patterns []*regexp.Regexp
+}
+
+func DefaultPatterns() []string {
+ return []string{`^fmt\.Print(|f|ln)$`}
+}
+
+//go:generate go-options config
+type config struct {
+ // don't check inside Godoc examples (see https://blog.golang.org/examples)
+ ExcludeGodocExamples bool `options:",true"`
+ IgnorePermitDirectives bool // don't check for `permit` directives(for example, in favor of `nolint`)
+}
+
+func NewLinter(patterns []string, options ...Option) (*Linter, error) {
+ cfg, err := newConfig(options...)
+ if err != nil {
+ return nil, errors.Wrapf(err, "failed to process options")
+ }
+
+ if len(patterns) == 0 {
+ patterns = DefaultPatterns()
+ }
+ compiledPatterns := make([]*regexp.Regexp, 0, len(patterns))
+ for _, p := range patterns {
+ re, err := regexp.Compile(p)
+ if err != nil {
+ return nil, fmt.Errorf("unable to compile pattern `%s`: %s", p, err)
+ }
+ compiledPatterns = append(compiledPatterns, re)
+ }
+ return &Linter{
+ cfg: cfg,
+ patterns: compiledPatterns,
+ }, nil
+}
+
+type visitor struct {
+ cfg config
+ isTestFile bool // godoc only runs on test files
+
+ linter *Linter
+ comments []*ast.CommentGroup
+
+ fset *token.FileSet
+ issues []Issue
+}
+
+func (l *Linter) Run(fset *token.FileSet, nodes ...ast.Node) ([]Issue, error) {
+ var issues []Issue // nolint:prealloc // we don't know how many there will be
+ for _, node := range nodes {
+ var comments []*ast.CommentGroup
+ isTestFile := false
+ isWholeFileExample := false
+ if file, ok := node.(*ast.File); ok {
+ comments = file.Comments
+ fileName := fset.Position(file.Pos()).Filename
+ isTestFile = strings.HasSuffix(fileName, "_test.go")
+
+ // From https://blog.golang.org/examples, a "whole file example" is:
+ // a file that ends in _test.go and contains exactly one example function,
+ // no test or benchmark functions, and at least one other package-level declaration.
+ if l.cfg.ExcludeGodocExamples && isTestFile && len(file.Decls) > 1 {
+ numExamples := 0
+ numTestsAndBenchmarks := 0
+ for _, decl := range file.Decls {
+ funcDecl, isFuncDecl := decl.(*ast.FuncDecl)
+ // consider only functions, not methods
+ if !isFuncDecl || funcDecl.Recv != nil || funcDecl.Name == nil {
+ continue
+ }
+ funcName := funcDecl.Name.Name
+ if strings.HasPrefix(funcName, "Test") || strings.HasPrefix(funcName, "Benchmark") {
+ numTestsAndBenchmarks++
+ break // not a whole file example
+ }
+ if strings.HasPrefix(funcName, "Example") {
+ numExamples++
+ }
+ }
+
+ // if this is a whole file example, skip this node
+ isWholeFileExample = numExamples == 1 && numTestsAndBenchmarks == 0
+ }
+ }
+ if isWholeFileExample {
+ continue
+ }
+ visitor := visitor{
+ cfg: l.cfg,
+ isTestFile: isTestFile,
+ linter: l,
+ 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.FuncDecl:
+ // don't descend into godoc examples if we are ignoring them
+ isGodocExample := v.isTestFile && node.Recv == nil && node.Name != nil && strings.HasPrefix(node.Name.Name, "Example")
+ if isGodocExample && v.cfg.ExcludeGodocExamples {
+ return nil
+ }
+ return v
+ case *ast.SelectorExpr:
+ case *ast.Ident:
+ default:
+ return v
+ }
+ for _, p := range v.linter.patterns {
+ if p.MatchString(v.textFor(node)) && !v.permit(node) {
+ v.issues = append(v.issues, UsedIssue{
+ identifier: v.textFor(node),
+ pattern: p.String(),
+ position: v.fset.Position(node.Pos()),
+ })
+ }
+ }
+ return nil
+}
+
+func (v *visitor) textFor(node ast.Node) string {
+ buf := new(bytes.Buffer)
+ if err := printer.Fprint(buf, v.fset, node); err != nil {
+ log.Fatalf("ERROR: unable to print node at %s: %s", v.fset.Position(node.Pos()), err)
+ }
+ return buf.String()
+}
+
+func (v *visitor) permit(node ast.Node) bool {
+ if v.cfg.IgnorePermitDirectives {
+ return false
+ }
+ nodePos := v.fset.Position(node.Pos())
+ var nolint = regexp.MustCompile(fmt.Sprintf(`^permit:%s\b`, regexp.QuoteMeta(v.textFor(node))))
+ for _, c := range v.comments {
+ commentPos := v.fset.Position(c.Pos())
+ if commentPos.Line == nodePos.Line && nolint.MatchString(c.Text()) {
+ return true
+ }
+ }
+ return false
+}
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
+}