aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/github.com/mgechev
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/mgechev
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/mgechev')
-rw-r--r--vendor/github.com/mgechev/dots/.travis.yml2
-rw-r--r--vendor/github.com/mgechev/dots/LICENSE21
-rw-r--r--vendor/github.com/mgechev/dots/README.md100
-rw-r--r--vendor/github.com/mgechev/dots/resolve.go456
-rw-r--r--vendor/github.com/mgechev/revive/config/config.go84
-rw-r--r--vendor/github.com/mgechev/revive/formatter/checkstyle.go9
-rw-r--r--vendor/github.com/mgechev/revive/formatter/default.go4
-rw-r--r--vendor/github.com/mgechev/revive/formatter/friendly.go22
-rw-r--r--vendor/github.com/mgechev/revive/formatter/json.go4
-rw-r--r--vendor/github.com/mgechev/revive/formatter/ndjson.go4
-rw-r--r--vendor/github.com/mgechev/revive/formatter/plain.go4
-rw-r--r--vendor/github.com/mgechev/revive/formatter/sarif.go107
-rw-r--r--vendor/github.com/mgechev/revive/formatter/stylish.go8
-rw-r--r--vendor/github.com/mgechev/revive/formatter/unix.go4
-rw-r--r--vendor/github.com/mgechev/revive/internal/typeparams/typeparams.go29
-rw-r--r--vendor/github.com/mgechev/revive/internal/typeparams/typeparams_go117.go12
-rw-r--r--vendor/github.com/mgechev/revive/internal/typeparams/typeparams_go118.go20
-rw-r--r--vendor/github.com/mgechev/revive/lint/config.go3
-rw-r--r--vendor/github.com/mgechev/revive/lint/file.go29
-rw-r--r--vendor/github.com/mgechev/revive/lint/linter.go78
-rw-r--r--vendor/github.com/mgechev/revive/lint/package.go84
-rw-r--r--vendor/github.com/mgechev/revive/lint/rule.go4
-rw-r--r--vendor/github.com/mgechev/revive/rule/add-constant.go110
-rw-r--r--vendor/github.com/mgechev/revive/rule/argument-limit.go40
-rw-r--r--vendor/github.com/mgechev/revive/rule/atomic.go6
-rw-r--r--vendor/github.com/mgechev/revive/rule/banned-characters.go90
-rw-r--r--vendor/github.com/mgechev/revive/rule/bare-return.go6
-rw-r--r--vendor/github.com/mgechev/revive/rule/blank-imports.go83
-rw-r--r--vendor/github.com/mgechev/revive/rule/bool-literal-in-expr.go6
-rw-r--r--vendor/github.com/mgechev/revive/rule/call-to-gc.go8
-rw-r--r--vendor/github.com/mgechev/revive/rule/cognitive-complexity.go39
-rw-r--r--vendor/github.com/mgechev/revive/rule/confusing-naming.go9
-rw-r--r--vendor/github.com/mgechev/revive/rule/confusing-results.go5
-rw-r--r--vendor/github.com/mgechev/revive/rule/constant-logical-expr.go20
-rw-r--r--vendor/github.com/mgechev/revive/rule/context-as-argument.go80
-rw-r--r--vendor/github.com/mgechev/revive/rule/context-keys-type.go6
-rw-r--r--vendor/github.com/mgechev/revive/rule/cyclomatic.go38
-rw-r--r--vendor/github.com/mgechev/revive/rule/datarace.go142
-rw-r--r--vendor/github.com/mgechev/revive/rule/deep-exit.go12
-rw-r--r--vendor/github.com/mgechev/revive/rule/defer.go61
-rw-r--r--vendor/github.com/mgechev/revive/rule/dot-imports.go4
-rw-r--r--vendor/github.com/mgechev/revive/rule/duplicated-imports.go4
-rw-r--r--vendor/github.com/mgechev/revive/rule/early-return.go4
-rw-r--r--vendor/github.com/mgechev/revive/rule/empty-block.go6
-rw-r--r--vendor/github.com/mgechev/revive/rule/empty-lines.go88
-rw-r--r--vendor/github.com/mgechev/revive/rule/error-naming.go4
-rw-r--r--vendor/github.com/mgechev/revive/rule/error-return.go4
-rw-r--r--vendor/github.com/mgechev/revive/rule/error-strings.go127
-rw-r--r--vendor/github.com/mgechev/revive/rule/errorf.go4
-rw-r--r--vendor/github.com/mgechev/revive/rule/exported.go94
-rw-r--r--vendor/github.com/mgechev/revive/rule/file-header.go41
-rw-r--r--vendor/github.com/mgechev/revive/rule/flag-param.go7
-rw-r--r--vendor/github.com/mgechev/revive/rule/function-length.go168
-rw-r--r--vendor/github.com/mgechev/revive/rule/function-result-limit.go39
-rw-r--r--vendor/github.com/mgechev/revive/rule/get-return.go4
-rw-r--r--vendor/github.com/mgechev/revive/rule/identical-branches.go6
-rw-r--r--vendor/github.com/mgechev/revive/rule/if-return.go4
-rw-r--r--vendor/github.com/mgechev/revive/rule/import-shadowing.go18
-rw-r--r--vendor/github.com/mgechev/revive/rule/imports-blacklist.go59
-rw-r--r--vendor/github.com/mgechev/revive/rule/increment-decrement.go5
-rw-r--r--vendor/github.com/mgechev/revive/rule/indent-error-flow.go4
-rw-r--r--vendor/github.com/mgechev/revive/rule/line-length-limit.go37
-rw-r--r--vendor/github.com/mgechev/revive/rule/max-public-structs.go34
-rw-r--r--vendor/github.com/mgechev/revive/rule/modifies-param.go4
-rw-r--r--vendor/github.com/mgechev/revive/rule/modifies-value-receiver.go4
-rw-r--r--vendor/github.com/mgechev/revive/rule/nested-structs.go67
-rw-r--r--vendor/github.com/mgechev/revive/rule/optimize-operands-order.go77
-rw-r--r--vendor/github.com/mgechev/revive/rule/package-comments.go64
-rw-r--r--vendor/github.com/mgechev/revive/rule/range-val-address.go69
-rw-r--r--vendor/github.com/mgechev/revive/rule/range-val-in-closure.go20
-rw-r--r--vendor/github.com/mgechev/revive/rule/range.go4
-rw-r--r--vendor/github.com/mgechev/revive/rule/receiver-naming.go8
-rw-r--r--vendor/github.com/mgechev/revive/rule/redefines-builtin-id.go187
-rw-r--r--vendor/github.com/mgechev/revive/rule/string-format.go281
-rw-r--r--vendor/github.com/mgechev/revive/rule/string-of-int.go6
-rw-r--r--vendor/github.com/mgechev/revive/rule/struct-tag.go140
-rw-r--r--vendor/github.com/mgechev/revive/rule/superfluous-else.go16
-rw-r--r--vendor/github.com/mgechev/revive/rule/time-equal.go76
-rw-r--r--vendor/github.com/mgechev/revive/rule/time-naming.go12
-rw-r--r--vendor/github.com/mgechev/revive/rule/unconditional-recursion.go16
-rw-r--r--vendor/github.com/mgechev/revive/rule/unexported-naming.go4
-rw-r--r--vendor/github.com/mgechev/revive/rule/unexported-return.go17
-rw-r--r--vendor/github.com/mgechev/revive/rule/unhandled-error.go38
-rw-r--r--vendor/github.com/mgechev/revive/rule/unnecessary-stmt.go4
-rw-r--r--vendor/github.com/mgechev/revive/rule/unreachable-code.go18
-rw-r--r--vendor/github.com/mgechev/revive/rule/unused-param.go4
-rw-r--r--vendor/github.com/mgechev/revive/rule/use-any.go54
-rw-r--r--vendor/github.com/mgechev/revive/rule/useless-break.go82
-rw-r--r--vendor/github.com/mgechev/revive/rule/utils.go46
-rw-r--r--vendor/github.com/mgechev/revive/rule/var-declarations.go4
-rw-r--r--vendor/github.com/mgechev/revive/rule/var-naming.go66
-rw-r--r--vendor/github.com/mgechev/revive/rule/waitgroup-by-value.go4
92 files changed, 2696 insertions, 1310 deletions
diff --git a/vendor/github.com/mgechev/dots/.travis.yml b/vendor/github.com/mgechev/dots/.travis.yml
deleted file mode 100644
index f4a4a7363..000000000
--- a/vendor/github.com/mgechev/dots/.travis.yml
+++ /dev/null
@@ -1,2 +0,0 @@
-language: go
-go: master
diff --git a/vendor/github.com/mgechev/dots/LICENSE b/vendor/github.com/mgechev/dots/LICENSE
deleted file mode 100644
index c617c7e01..000000000
--- a/vendor/github.com/mgechev/dots/LICENSE
+++ /dev/null
@@ -1,21 +0,0 @@
-MIT License
-
-Copyright (c) 2018 Minko Gechev
-
-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/mgechev/dots/README.md b/vendor/github.com/mgechev/dots/README.md
deleted file mode 100644
index 1203aef5f..000000000
--- a/vendor/github.com/mgechev/dots/README.md
+++ /dev/null
@@ -1,100 +0,0 @@
-[![Build Status](https://travis-ci.org/mgechev/dots.svg?branch=master)](https://travis-ci.org/mgechev/dots)
-
-# Dots
-
-Implements the wildcard file matching in Go used by golint, go test etc.
-
-## Usage
-
-```go
-import "github.com/mgechev/dots"
-
-func main() {
- result, err := dots.Resolve([]string{"./fixtures/..."}, []string{"./fixtures/foo"})
- for _, f := range result {
- fmt.Println(f);
- }
-}
-```
-
-If we suppose that we have the following directory structure:
-
-```text
-├── README.md
-├── fixtures
-│   ├── bar
-│   │   ├── bar1.go
-│   │   └── bar2.go
-│   ├── baz
-│   │   ├── baz1.go
-│   │   ├── baz2.go
-│   │   └── baz3.go
-│   └── foo
-│   ├── foo1.go
-│   ├── foo2.go
-│   └── foo3.go
-└── main.go
-```
-
-The result will be:
-
-```text
-fixtures/bar/bar1.go
-fixtures/bar/bar2.go
-fixtures/baz/baz1.go
-fixtures/baz/baz2.go
-fixtures/baz/baz3.go
-```
-
-`dots` supports wildcard in both - the first and the last argument of `Resolve`, which means that you can ignore files based on a wildcard:
-
-```go
-dots.Resolve([]string{"github.com/mgechev/dots"}, []string{"./..."}) // empty list
-dots.Resolve([]string{"./fixtures/bar/..."}, []string{"./fixture/foo/...", "./fixtures/baz/..."}) // bar1.go, bar2.go
-```
-
-## Preserve package structure
-
-`dots` allow you to receive a slice of slices where each nested slice represents an individual package:
-
-```go
-dots.ResolvePackages([]string{"github.com/mgechev/dots/..."}, []string{})
-```
-
-So we will get the result:
-
-```text
-[
- [
- "$GOROOT/src/github.com/mgechev/dots/fixtures/dummy/bar/bar1.go",
- "$GOROOT/src/github.com/mgechev/dots/fixtures/dummy/bar/bar2.go"
- ],
- [
- "$GOROOT/src/github.com/mgechev/dots/fixtures/dummy/baz/baz1.go",
- "$GOROOT/src/github.com/mgechev/dots/fixtures/dummy/baz/baz2.go",
- "$GOROOT/src/github.com/mgechev/dots/fixtures/dummy/baz/baz3.go"
- ],
- [
- "$GOROOT/src/github.com/mgechev/dots/fixtures/dummy/foo/foo1.go",
- "$GOROOT/src/github.com/mgechev/dots/fixtures/dummy/foo/foo2.go",
- "$GOROOT/src/github.com/mgechev/dots/fixtures/dummy/foo/foo3.go"
- ],
- [
- "$GOROOT/src/github.com/mgechev/dots/fixtures/pkg/baz/baz1.go",
- "$GOROOT/src/github.com/mgechev/dots/fixtures/pkg/baz/baz2.go"
- ],
- [
- "$GOROOT/src/github.com/mgechev/dots/fixtures/pkg/foo/foo1.go",
- "$GOROOT/src/github.com/mgechev/dots/fixtures/pkg/foo/foo2.go"
- ],
- [
- "$GOROOT/src/github.com/mgechev/dots/fixtures/pkg/foo/bar/bar1.go"
- ]
-]
-```
-
-This method is especially useful, when you want to perform type checking over given package from the result.
-
-## License
-
-MIT
diff --git a/vendor/github.com/mgechev/dots/resolve.go b/vendor/github.com/mgechev/dots/resolve.go
deleted file mode 100644
index 309ba18ad..000000000
--- a/vendor/github.com/mgechev/dots/resolve.go
+++ /dev/null
@@ -1,456 +0,0 @@
-package dots
-
-import (
- "go/build"
- "log"
- "os"
- "path"
- "path/filepath"
- "regexp"
- "runtime"
- "strings"
-)
-
-var (
- buildContext = build.Default
- goroot = filepath.Clean(runtime.GOROOT())
- gorootSrc = filepath.Join(goroot, "src")
-)
-
-func flatten(arr [][]string) []string {
- var res []string
- for _, e := range arr {
- res = append(res, e...)
- }
- return res
-}
-
-// Resolve accepts a slice of paths with optional "..." placeholder and a slice with paths to be skipped.
-// The final result is the set of all files from the selected directories subtracted with
-// the files in the skip slice.
-func Resolve(includePatterns, skipPatterns []string) ([]string, error) {
- skip, err := resolvePatterns(skipPatterns)
- filter := newPathFilter(flatten(skip))
- if err != nil {
- return nil, err
- }
-
- pathSet := map[string]bool{}
- includePackages, err := resolvePatterns(includePatterns)
- include := flatten(includePackages)
- if err != nil {
- return nil, err
- }
-
- var result []string
- for _, i := range include {
- if _, ok := pathSet[i]; !ok && !filter(i) {
- pathSet[i] = true
- result = append(result, i)
- }
- }
- return result, err
-}
-
-// ResolvePackages accepts a slice of paths with optional "..." placeholder and a slice with paths to be skipped.
-// The final result is the set of all files from the selected directories subtracted with
-// the files in the skip slice. The difference between `Resolve` and `ResolvePackages`
-// is that `ResolvePackages` preserves the package structure in the nested slices.
-func ResolvePackages(includePatterns, skipPatterns []string) ([][]string, error) {
- skip, err := resolvePatterns(skipPatterns)
- filter := newPathFilter(flatten(skip))
- if err != nil {
- return nil, err
- }
-
- pathSet := map[string]bool{}
- include, err := resolvePatterns(includePatterns)
- if err != nil {
- return nil, err
- }
-
- var result [][]string
- for _, p := range include {
- var packageFiles []string
- for _, f := range p {
- if _, ok := pathSet[f]; !ok && !filter(f) {
- pathSet[f] = true
- packageFiles = append(packageFiles, f)
- }
- }
- result = append(result, packageFiles)
- }
- return result, err
-}
-
-func isDir(filename string) bool {
- fi, err := os.Stat(filename)
- return err == nil && fi.IsDir()
-}
-
-func exists(filename string) bool {
- _, err := os.Stat(filename)
- return err == nil
-}
-
-func resolveDir(dirname string) ([]string, error) {
- pkg, err := build.ImportDir(dirname, 0)
- return resolveImportedPackage(pkg, err)
-}
-
-func resolvePackage(pkgname string) ([]string, error) {
- pkg, err := build.Import(pkgname, ".", 0)
- return resolveImportedPackage(pkg, err)
-}
-
-func resolveImportedPackage(pkg *build.Package, err error) ([]string, error) {
- if err != nil {
- if _, nogo := err.(*build.NoGoError); nogo {
- // Don't complain if the failure is due to no Go source files.
- return nil, nil
- }
- return nil, err
- }
-
- var files []string
- files = append(files, pkg.GoFiles...)
- files = append(files, pkg.CgoFiles...)
- files = append(files, pkg.TestGoFiles...)
- if pkg.Dir != "." {
- for i, f := range files {
- files[i] = filepath.Join(pkg.Dir, f)
- }
- }
- return files, nil
-}
-
-func resolvePatterns(patterns []string) ([][]string, error) {
- var files [][]string
- for _, pattern := range patterns {
- f, err := resolvePattern(pattern)
- if err != nil {
- return nil, err
- }
- files = append(files, f...)
- }
- return files, nil
-}
-
-func resolvePattern(pattern string) ([][]string, error) {
- // dirsRun, filesRun, and pkgsRun indicate whether golint is applied to
- // directory, file or package targets. The distinction affects which
- // checks are run. It is no valid to mix target types.
- var dirsRun, filesRun, pkgsRun int
- var matches []string
-
- if strings.HasSuffix(pattern, "/...") && isDir(pattern[:len(pattern)-len("/...")]) {
- dirsRun = 1
- for _, dirname := range matchPackagesInFS(pattern) {
- matches = append(matches, dirname)
- }
- } else if isDir(pattern) {
- dirsRun = 1
- matches = append(matches, pattern)
- } else if exists(pattern) {
- filesRun = 1
- matches = append(matches, pattern)
- } else {
- pkgsRun = 1
- matches = append(matches, pattern)
- }
-
- result := [][]string{}
- switch {
- case dirsRun == 1:
- for _, dir := range matches {
- res, err := resolveDir(dir)
- if err != nil {
- return nil, err
- }
- result = append(result, res)
- }
- case filesRun == 1:
- return [][]string{matches}, nil
- case pkgsRun == 1:
- for _, pkg := range importPaths(matches) {
- res, err := resolvePackage(pkg)
- if err != nil {
- return nil, err
- }
- result = append(result, res)
- }
- }
- return result, nil
-}
-
-func newPathFilter(skip []string) func(string) bool {
- filter := map[string]bool{}
- for _, name := range skip {
- filter[name] = true
- }
-
- return func(path string) bool {
- base := filepath.Base(path)
- if filter[base] || filter[path] {
- return true
- }
- return base != "." && base != ".." && strings.ContainsAny(base[0:1], "_.")
- }
-}
-
-// importPathsNoDotExpansion returns the import paths to use for the given
-// command line, but it does no ... expansion.
-func importPathsNoDotExpansion(args []string) []string {
- if len(args) == 0 {
- return []string{"."}
- }
- var out []string
- for _, a := range args {
- // Arguments are supposed to be import paths, but
- // as a courtesy to Windows developers, rewrite \ to /
- // in command-line arguments. Handles .\... and so on.
- if filepath.Separator == '\\' {
- a = strings.Replace(a, `\`, `/`, -1)
- }
-
- // Put argument in canonical form, but preserve leading ./.
- if strings.HasPrefix(a, "./") {
- a = "./" + path.Clean(a)
- if a == "./." {
- a = "."
- }
- } else {
- a = path.Clean(a)
- }
- if a == "all" || a == "std" {
- out = append(out, matchPackages(a)...)
- continue
- }
- out = append(out, a)
- }
- return out
-}
-
-// importPaths returns the import paths to use for the given command line.
-func importPaths(args []string) []string {
- args = importPathsNoDotExpansion(args)
- var out []string
- for _, a := range args {
- if strings.Contains(a, "...") {
- if build.IsLocalImport(a) {
- out = append(out, matchPackagesInFS(a)...)
- } else {
- out = append(out, matchPackages(a)...)
- }
- continue
- }
- out = append(out, a)
- }
- return out
-}
-
-// matchPattern(pattern)(name) reports whether
-// name matches pattern. Pattern is a limited glob
-// pattern in which '...' means 'any string' and there
-// is no other special syntax.
-func matchPattern(pattern string) func(name string) bool {
- re := regexp.QuoteMeta(pattern)
- re = strings.Replace(re, `\.\.\.`, `.*`, -1)
- // Special case: foo/... matches foo too.
- if strings.HasSuffix(re, `/.*`) {
- re = re[:len(re)-len(`/.*`)] + `(/.*)?`
- }
- reg := regexp.MustCompile(`^` + re + `$`)
- return func(name string) bool {
- return reg.MatchString(name)
- }
-}
-
-// hasPathPrefix reports whether the path s begins with the
-// elements in prefix.
-func hasPathPrefix(s, prefix string) bool {
- switch {
- default:
- return false
- case len(s) == len(prefix):
- return s == prefix
- case len(s) > len(prefix):
- if prefix != "" && prefix[len(prefix)-1] == '/' {
- return strings.HasPrefix(s, prefix)
- }
- return s[len(prefix)] == '/' && s[:len(prefix)] == prefix
- }
-}
-
-// treeCanMatchPattern(pattern)(name) reports whether
-// name or children of name can possibly match pattern.
-// Pattern is the same limited glob accepted by matchPattern.
-func treeCanMatchPattern(pattern string) func(name string) bool {
- wildCard := false
- if i := strings.Index(pattern, "..."); i >= 0 {
- wildCard = true
- pattern = pattern[:i]
- }
- return func(name string) bool {
- return len(name) <= len(pattern) && hasPathPrefix(pattern, name) ||
- wildCard && strings.HasPrefix(name, pattern)
- }
-}
-
-func matchPackages(pattern string) []string {
- match := func(string) bool { return true }
- treeCanMatch := func(string) bool { return true }
- if pattern != "all" && pattern != "std" {
- match = matchPattern(pattern)
- treeCanMatch = treeCanMatchPattern(pattern)
- }
-
- have := map[string]bool{
- "builtin": true, // ignore pseudo-package that exists only for documentation
- }
- if !buildContext.CgoEnabled {
- have["runtime/cgo"] = true // ignore during walk
- }
- var pkgs []string
-
- // Commands
- cmd := filepath.Join(goroot, "src/cmd") + string(filepath.Separator)
- filepath.Walk(cmd, func(path string, fi os.FileInfo, err error) error {
- if err != nil || !fi.IsDir() || path == cmd {
- return nil
- }
- name := path[len(cmd):]
- if !treeCanMatch(name) {
- return filepath.SkipDir
- }
- // Commands are all in cmd/, not in subdirectories.
- if strings.Contains(name, string(filepath.Separator)) {
- return filepath.SkipDir
- }
-
- // We use, e.g., cmd/gofmt as the pseudo import path for gofmt.
- name = "cmd/" + name
- if have[name] {
- return nil
- }
- have[name] = true
- if !match(name) {
- return nil
- }
- _, err = buildContext.ImportDir(path, 0)
- if err != nil {
- if _, noGo := err.(*build.NoGoError); !noGo {
- log.Print(err)
- }
- return nil
- }
- pkgs = append(pkgs, name)
- return nil
- })
-
- for _, src := range buildContext.SrcDirs() {
- if (pattern == "std" || pattern == "cmd") && src != gorootSrc {
- continue
- }
- src = filepath.Clean(src) + string(filepath.Separator)
- root := src
- if pattern == "cmd" {
- root += "cmd" + string(filepath.Separator)
- }
- filepath.Walk(root, func(path string, fi os.FileInfo, err error) error {
- if err != nil || !fi.IsDir() || path == src {
- return nil
- }
-
- // Avoid .foo, _foo, and testdata directory trees.
- _, elem := filepath.Split(path)
- if strings.HasPrefix(elem, ".") || strings.HasPrefix(elem, "_") || elem == "testdata" {
- return filepath.SkipDir
- }
-
- name := filepath.ToSlash(path[len(src):])
- if pattern == "std" && (strings.Contains(name, ".") || name == "cmd") {
- // The name "std" is only the standard library.
- // If the name is cmd, it's the root of the command tree.
- return filepath.SkipDir
- }
- if !treeCanMatch(name) {
- return filepath.SkipDir
- }
- if have[name] {
- return nil
- }
- have[name] = true
- if !match(name) {
- return nil
- }
- _, err = buildContext.ImportDir(path, 0)
- if err != nil {
- if _, noGo := err.(*build.NoGoError); noGo {
- return nil
- }
- }
- pkgs = append(pkgs, name)
- return nil
- })
- }
- return pkgs
-}
-
-func matchPackagesInFS(pattern string) []string {
- // Find directory to begin the scan.
- // Could be smarter but this one optimization
- // is enough for now, since ... is usually at the
- // end of a path.
- i := strings.Index(pattern, "...")
- dir, _ := path.Split(pattern[:i])
-
- // pattern begins with ./ or ../.
- // path.Clean will discard the ./ but not the ../.
- // We need to preserve the ./ for pattern matching
- // and in the returned import paths.
- prefix := ""
- if strings.HasPrefix(pattern, "./") {
- prefix = "./"
- }
- match := matchPattern(pattern)
-
- var pkgs []string
- filepath.Walk(dir, func(path string, fi os.FileInfo, err error) error {
- if err != nil || !fi.IsDir() {
- return nil
- }
- if path == dir {
- // filepath.Walk starts at dir and recurses. For the recursive case,
- // the path is the result of filepath.Join, which calls filepath.Clean.
- // The initial case is not Cleaned, though, so we do this explicitly.
- //
- // This converts a path like "./io/" to "io". Without this step, running
- // "cd $GOROOT/src/pkg; go list ./io/..." would incorrectly skip the io
- // package, because prepending the prefix "./" to the unclean path would
- // result in "././io", and match("././io") returns false.
- path = filepath.Clean(path)
- }
-
- // Avoid .foo, _foo, and testdata directory trees, but do not avoid "." or "..".
- _, elem := filepath.Split(path)
- dot := strings.HasPrefix(elem, ".") && elem != "." && elem != ".."
- if dot || strings.HasPrefix(elem, "_") || elem == "testdata" {
- return filepath.SkipDir
- }
-
- name := prefix + filepath.ToSlash(path)
- if !match(name) {
- return nil
- }
- if _, err = build.ImportDir(path, 0); err != nil {
- if _, noGo := err.(*build.NoGoError); !noGo {
- log.Print(err)
- }
- return nil
- }
- pkgs = append(pkgs, name)
- return nil
- })
- return pkgs
-}
diff --git a/vendor/github.com/mgechev/revive/config/config.go b/vendor/github.com/mgechev/revive/config/config.go
index 1357bc744..5c63f35b3 100644
--- a/vendor/github.com/mgechev/revive/config/config.go
+++ b/vendor/github.com/mgechev/revive/config/config.go
@@ -20,7 +20,6 @@ var defaultRules = []lint.Rule{
&rule.ExportedRule{},
&rule.VarNamingRule{},
&rule.IndentErrorFlowRule{},
- &rule.IfReturnRule{},
&rule.RangeRule{},
&rule.ErrorfRule{},
&rule.ErrorNamingRule{},
@@ -72,11 +71,21 @@ var allRules = append([]lint.Rule{
&rule.UnhandledErrorRule{},
&rule.CognitiveComplexityRule{},
&rule.StringOfIntRule{},
+ &rule.StringFormatRule{},
&rule.EarlyReturnRule{},
&rule.UnconditionalRecursionRule{},
&rule.IdenticalBranchesRule{},
&rule.DeferRule{},
&rule.UnexportedNamingRule{},
+ &rule.FunctionLength{},
+ &rule.NestedStructs{},
+ &rule.IfReturnRule{},
+ &rule.UselessBreak{},
+ &rule.TimeEqualRule{},
+ &rule.BannedCharsRule{},
+ &rule.OptimizeOperandsOrderRule{},
+ &rule.UseAnyRule{},
+ &rule.DataRaceRule{},
}, defaultRules...)
var allFormatters = []lint.Formatter{
@@ -88,6 +97,7 @@ var allFormatters = []lint.Formatter{
&formatter.Unix{},
&formatter.Checkstyle{},
&formatter.Plain{},
+ &formatter.Sarif{},
}
func getFormatters() map[string]lint.Formatter {
@@ -98,42 +108,65 @@ func getFormatters() map[string]lint.Formatter {
return result
}
-// GetLintingRules yields the linting rules activated in the configuration
-func GetLintingRules(config *lint.Config) ([]lint.Rule, error) {
+// GetLintingRules yields the linting rules that must be applied by the linter
+func GetLintingRules(config *lint.Config, extraRules []lint.Rule) ([]lint.Rule, error) {
rulesMap := map[string]lint.Rule{}
for _, r := range allRules {
rulesMap[r.Name()] = r
}
+ for _, r := range extraRules {
+ if _, ok := rulesMap[r.Name()]; ok {
+ continue
+ }
+ rulesMap[r.Name()] = r
+ }
- lintingRules := []lint.Rule{}
- for name := range config.Rules {
- rule, ok := rulesMap[name]
+ var lintingRules []lint.Rule
+ for name, ruleConfig := range config.Rules {
+ r, ok := rulesMap[name]
if !ok {
return nil, fmt.Errorf("cannot find rule: %s", name)
}
- lintingRules = append(lintingRules, rule)
+
+ if ruleConfig.Disabled {
+ continue // skip disabled rules
+ }
+
+ lintingRules = append(lintingRules, r)
}
return lintingRules, nil
}
-func parseConfig(path string) (*lint.Config, error) {
- config := &lint.Config{}
+func parseConfig(path string, config *lint.Config) error {
file, err := ioutil.ReadFile(path)
if err != nil {
- return nil, errors.New("cannot read the config file")
+ return errors.New("cannot read the config file")
}
_, err = toml.Decode(string(file), config)
if err != nil {
- return nil, fmt.Errorf("cannot parse the config file: %v", err)
+ return fmt.Errorf("cannot parse the config file: %v", err)
}
- return config, nil
+ return nil
}
func normalizeConfig(config *lint.Config) {
- if config.Confidence == 0 {
- config.Confidence = 0.8
+ if len(config.Rules) == 0 {
+ config.Rules = map[string]lint.RuleConfig{}
}
+ if config.EnableAllRules {
+ // Add to the configuration all rules not yet present in it
+ for _, r := range allRules {
+ ruleName := r.Name()
+ _, alreadyInConf := config.Rules[ruleName]
+ if alreadyInConf {
+ continue
+ }
+ // Add the rule with an empty conf for
+ config.Rules[ruleName] = lint.RuleConfig{}
+ }
+ }
+
severity := config.Severity
if severity != "" {
for k, v := range config.Rules {
@@ -151,16 +184,23 @@ func normalizeConfig(config *lint.Config) {
}
}
+const defaultConfidence = 0.8
+
// GetConfig yields the configuration
func GetConfig(configPath string) (*lint.Config, error) {
- config := defaultConfig()
- if configPath != "" {
- var err error
- config, err = parseConfig(configPath)
+ config := &lint.Config{}
+ switch {
+ case configPath != "":
+ config.Confidence = defaultConfidence
+ err := parseConfig(configPath, config)
if err != nil {
return nil, err
}
+
+ default: // no configuration provided
+ config = defaultConfig()
}
+
normalizeConfig(config)
return config, nil
}
@@ -168,20 +208,20 @@ func GetConfig(configPath string) (*lint.Config, error) {
// GetFormatter yields the formatter for lint failures
func GetFormatter(formatterName string) (lint.Formatter, error) {
formatters := getFormatters()
- formatter := formatters["default"]
+ fmtr := formatters["default"]
if formatterName != "" {
f, ok := formatters[formatterName]
if !ok {
return nil, fmt.Errorf("unknown formatter %v", formatterName)
}
- formatter = f
+ fmtr = f
}
- return formatter, nil
+ return fmtr, nil
}
func defaultConfig() *lint.Config {
defaultConfig := lint.Config{
- Confidence: 0.0,
+ Confidence: defaultConfidence,
Severity: lint.SeverityWarning,
Rules: map[string]lint.RuleConfig{},
}
diff --git a/vendor/github.com/mgechev/revive/formatter/checkstyle.go b/vendor/github.com/mgechev/revive/formatter/checkstyle.go
index bd20da888..33a3b2ca1 100644
--- a/vendor/github.com/mgechev/revive/formatter/checkstyle.go
+++ b/vendor/github.com/mgechev/revive/formatter/checkstyle.go
@@ -3,8 +3,9 @@ package formatter
import (
"bytes"
"encoding/xml"
- "github.com/mgechev/revive/lint"
plainTemplate "text/template"
+
+ "github.com/mgechev/revive/lint"
)
// Checkstyle is an implementation of the Formatter interface
@@ -14,7 +15,7 @@ type Checkstyle struct {
}
// Name returns the name of the formatter
-func (f *Checkstyle) Name() string {
+func (*Checkstyle) Name() string {
return "checkstyle"
}
@@ -28,8 +29,8 @@ type issue struct {
}
// Format formats the failures gotten from the lint.
-func (f *Checkstyle) Format(failures <-chan lint.Failure, config lint.Config) (string, error) {
- var issues = map[string][]issue{}
+func (*Checkstyle) Format(failures <-chan lint.Failure, config lint.Config) (string, error) {
+ issues := map[string][]issue{}
for failure := range failures {
buf := new(bytes.Buffer)
xml.Escape(buf, []byte(failure.Failure))
diff --git a/vendor/github.com/mgechev/revive/formatter/default.go b/vendor/github.com/mgechev/revive/formatter/default.go
index 145e6d548..f76a7b29a 100644
--- a/vendor/github.com/mgechev/revive/formatter/default.go
+++ b/vendor/github.com/mgechev/revive/formatter/default.go
@@ -13,12 +13,12 @@ type Default struct {
}
// Name returns the name of the formatter
-func (f *Default) Name() string {
+func (*Default) Name() string {
return "default"
}
// Format formats the failures gotten from the lint.
-func (f *Default) Format(failures <-chan lint.Failure, _ lint.Config) (string, error) {
+func (*Default) Format(failures <-chan lint.Failure, _ lint.Config) (string, error) {
for failure := range failures {
fmt.Printf("%v: %s\n", failure.Position.Start, failure.Failure)
}
diff --git a/vendor/github.com/mgechev/revive/formatter/friendly.go b/vendor/github.com/mgechev/revive/formatter/friendly.go
index d0a3099f8..ced8fa46c 100644
--- a/vendor/github.com/mgechev/revive/formatter/friendly.go
+++ b/vendor/github.com/mgechev/revive/formatter/friendly.go
@@ -10,16 +10,6 @@ import (
"github.com/olekukonko/tablewriter"
)
-var newLines = map[rune]bool{
- 0x000A: true,
- 0x000B: true,
- 0x000C: true,
- 0x000D: true,
- 0x0085: true,
- 0x2028: true,
- 0x2029: true,
-}
-
func getErrorEmoji() string {
return color.RedString("✘")
}
@@ -35,7 +25,7 @@ type Friendly struct {
}
// Name returns the name of the formatter
-func (f *Friendly) Name() string {
+func (*Friendly) Name() string {
return "friendly"
}
@@ -49,11 +39,11 @@ func (f *Friendly) Format(failures <-chan lint.Failure, config lint.Config) (str
sev := severity(config, failure)
f.printFriendlyFailure(failure, sev)
if sev == lint.SeverityWarning {
- warningMap[failure.RuleName] = warningMap[failure.RuleName] + 1
+ warningMap[failure.RuleName]++
totalWarnings++
}
if sev == lint.SeverityError {
- errorMap[failure.RuleName] = errorMap[failure.RuleName] + 1
+ errorMap[failure.RuleName]++
totalErrors++
}
}
@@ -78,7 +68,7 @@ func (f *Friendly) printHeaderRow(failure lint.Failure, severity lint.Severity)
fmt.Print(f.table([][]string{{emoji, "https://revive.run/r#" + failure.RuleName, color.GreenString(failure.Failure)}}))
}
-func (f *Friendly) printFilePosition(failure lint.Failure) {
+func (*Friendly) printFilePosition(failure lint.Failure) {
fmt.Printf(" %s:%d:%d", failure.GetFilename(), failure.Position.Start.Line, failure.Position.Start.Column)
}
@@ -87,7 +77,7 @@ type statEntry struct {
failures int
}
-func (f *Friendly) printSummary(errors, warnings int) {
+func (*Friendly) printSummary(errors, warnings int) {
emoji := getWarningEmoji()
if errors > 0 {
emoji = getErrorEmoji()
@@ -136,7 +126,7 @@ func (f *Friendly) printStatistics(header string, stats map[string]int) {
fmt.Println(f.table(formatted))
}
-func (f *Friendly) table(rows [][]string) string {
+func (*Friendly) table(rows [][]string) string {
buf := new(bytes.Buffer)
table := tablewriter.NewWriter(buf)
table.SetBorder(false)
diff --git a/vendor/github.com/mgechev/revive/formatter/json.go b/vendor/github.com/mgechev/revive/formatter/json.go
index 9c939face..7cace89ec 100644
--- a/vendor/github.com/mgechev/revive/formatter/json.go
+++ b/vendor/github.com/mgechev/revive/formatter/json.go
@@ -13,7 +13,7 @@ type JSON struct {
}
// Name returns the name of the formatter
-func (f *JSON) Name() string {
+func (*JSON) Name() string {
return "json"
}
@@ -24,7 +24,7 @@ type jsonObject struct {
}
// Format formats the failures gotten from the lint.
-func (f *JSON) Format(failures <-chan lint.Failure, config lint.Config) (string, error) {
+func (*JSON) Format(failures <-chan lint.Failure, config lint.Config) (string, error) {
var slice []jsonObject
for failure := range failures {
obj := jsonObject{}
diff --git a/vendor/github.com/mgechev/revive/formatter/ndjson.go b/vendor/github.com/mgechev/revive/formatter/ndjson.go
index aa2b1d636..a02d9c80f 100644
--- a/vendor/github.com/mgechev/revive/formatter/ndjson.go
+++ b/vendor/github.com/mgechev/revive/formatter/ndjson.go
@@ -14,12 +14,12 @@ type NDJSON struct {
}
// Name returns the name of the formatter
-func (f *NDJSON) Name() string {
+func (*NDJSON) Name() string {
return "ndjson"
}
// Format formats the failures gotten from the lint.
-func (f *NDJSON) Format(failures <-chan lint.Failure, config lint.Config) (string, error) {
+func (*NDJSON) Format(failures <-chan lint.Failure, config lint.Config) (string, error) {
enc := json.NewEncoder(os.Stdout)
for failure := range failures {
obj := jsonObject{}
diff --git a/vendor/github.com/mgechev/revive/formatter/plain.go b/vendor/github.com/mgechev/revive/formatter/plain.go
index a854d2562..6e083bcfd 100644
--- a/vendor/github.com/mgechev/revive/formatter/plain.go
+++ b/vendor/github.com/mgechev/revive/formatter/plain.go
@@ -13,12 +13,12 @@ type Plain struct {
}
// Name returns the name of the formatter
-func (f *Plain) Name() string {
+func (*Plain) Name() string {
return "plain"
}
// Format formats the failures gotten from the lint.
-func (f *Plain) Format(failures <-chan lint.Failure, _ lint.Config) (string, error) {
+func (*Plain) Format(failures <-chan lint.Failure, _ lint.Config) (string, error) {
for failure := range failures {
fmt.Printf("%v: %s %s\n", failure.Position.Start, failure.Failure, "https://revive.run/r#"+failure.RuleName)
}
diff --git a/vendor/github.com/mgechev/revive/formatter/sarif.go b/vendor/github.com/mgechev/revive/formatter/sarif.go
new file mode 100644
index 000000000..ee62adcc0
--- /dev/null
+++ b/vendor/github.com/mgechev/revive/formatter/sarif.go
@@ -0,0 +1,107 @@
+package formatter
+
+import (
+ "bytes"
+ "fmt"
+ "strings"
+
+ "github.com/chavacava/garif"
+ "github.com/mgechev/revive/lint"
+)
+
+// Sarif is an implementation of the Formatter interface
+// which formats revive failures into SARIF format.
+type Sarif struct {
+ Metadata lint.FormatterMetadata
+}
+
+// Name returns the name of the formatter
+func (*Sarif) Name() string {
+ return "sarif"
+}
+
+const reviveSite = "https://revive.run"
+
+// Format formats the failures gotten from the lint.
+func (*Sarif) Format(failures <-chan lint.Failure, cfg lint.Config) (string, error) {
+ sarifLog := newReviveRunLog(cfg)
+
+ for failure := range failures {
+ sarifLog.AddResult(failure)
+ }
+
+ buf := new(bytes.Buffer)
+ sarifLog.PrettyWrite(buf)
+
+ return buf.String(), nil
+}
+
+type reviveRunLog struct {
+ *garif.LogFile
+ run *garif.Run
+ rules map[string]lint.RuleConfig
+}
+
+func newReviveRunLog(cfg lint.Config) *reviveRunLog {
+ run := garif.NewRun(garif.NewTool(garif.NewDriver("revive").WithInformationUri(reviveSite)))
+ log := garif.NewLogFile([]*garif.Run{run}, garif.Version210)
+
+ reviveLog := &reviveRunLog{
+ log,
+ run,
+ cfg.Rules,
+ }
+
+ reviveLog.addRules(cfg.Rules)
+
+ return reviveLog
+}
+
+func (l *reviveRunLog) addRules(cfg map[string]lint.RuleConfig) {
+ for name, ruleCfg := range cfg {
+ rule := garif.NewRule(name).WithHelpUri(reviveSite + "/r#" + name)
+ setRuleProperties(rule, ruleCfg)
+ driver := l.run.Tool.Driver
+
+ if driver.Rules == nil {
+ driver.Rules = []*garif.ReportingDescriptor{rule}
+ return
+ }
+
+ driver.Rules = append(driver.Rules, rule)
+ }
+}
+
+func (l *reviveRunLog) AddResult(failure lint.Failure) {
+ positiveOrZero := func(x int) int {
+ if x > 0 {
+ return x
+ }
+ return 0
+ }
+ position := failure.Position
+ filename := position.Start.Filename
+ line := positiveOrZero(position.Start.Line - 1) // https://docs.oasis-open.org/sarif/sarif/v2.1.0/csprd01/sarif-v2.1.0-csprd01.html#def_line
+ column := positiveOrZero(position.Start.Column - 1) // https://docs.oasis-open.org/sarif/sarif/v2.1.0/csprd01/sarif-v2.1.0-csprd01.html#def_column
+
+ result := garif.NewResult(garif.NewMessageFromText(failure.Failure))
+ location := garif.NewLocation().WithURI(filename).WithLineColumn(line, column)
+ result.Locations = append(result.Locations, location)
+ result.RuleId = failure.RuleName
+ result.Level = l.rules[failure.RuleName].Severity
+
+ l.run.Results = append(l.run.Results, result)
+}
+
+func setRuleProperties(sarifRule *garif.ReportingDescriptor, lintRule lint.RuleConfig) {
+ arguments := make([]string, len(lintRule.Arguments))
+ for i, arg := range lintRule.Arguments {
+ arguments[i] = fmt.Sprintf("%+v", arg)
+ }
+
+ if len(arguments) > 0 {
+ sarifRule.WithProperties("arguments", strings.Join(arguments, ","))
+ }
+
+ sarifRule.WithProperties("severity", string(lintRule.Severity))
+}
diff --git a/vendor/github.com/mgechev/revive/formatter/stylish.go b/vendor/github.com/mgechev/revive/formatter/stylish.go
index cd81fdae7..828228c72 100644
--- a/vendor/github.com/mgechev/revive/formatter/stylish.go
+++ b/vendor/github.com/mgechev/revive/formatter/stylish.go
@@ -16,7 +16,7 @@ type Stylish struct {
}
// Name returns the name of the formatter
-func (f *Stylish) Name() string {
+func (*Stylish) Name() string {
return "stylish"
}
@@ -32,10 +32,10 @@ func formatFailure(failure lint.Failure, severity lint.Severity) []string {
}
// Format formats the failures gotten from the lint.
-func (f *Stylish) Format(failures <-chan lint.Failure, config lint.Config) (string, error) {
+func (*Stylish) Format(failures <-chan lint.Failure, config lint.Config) (string, error) {
var result [][]string
- var totalErrors = 0
- var total = 0
+ totalErrors := 0
+ total := 0
for f := range failures {
total++
diff --git a/vendor/github.com/mgechev/revive/formatter/unix.go b/vendor/github.com/mgechev/revive/formatter/unix.go
index b9ae62d38..ef2f1613a 100644
--- a/vendor/github.com/mgechev/revive/formatter/unix.go
+++ b/vendor/github.com/mgechev/revive/formatter/unix.go
@@ -14,12 +14,12 @@ type Unix struct {
}
// Name returns the name of the formatter
-func (f *Unix) Name() string {
+func (*Unix) Name() string {
return "unix"
}
// Format formats the failures gotten from the lint.
-func (f *Unix) Format(failures <-chan lint.Failure, _ lint.Config) (string, error) {
+func (*Unix) Format(failures <-chan lint.Failure, _ lint.Config) (string, error) {
for failure := range failures {
fmt.Printf("%v: [%s] %s\n", failure.Position.Start, failure.RuleName, failure.Failure)
}
diff --git a/vendor/github.com/mgechev/revive/internal/typeparams/typeparams.go b/vendor/github.com/mgechev/revive/internal/typeparams/typeparams.go
new file mode 100644
index 000000000..33c4f203e
--- /dev/null
+++ b/vendor/github.com/mgechev/revive/internal/typeparams/typeparams.go
@@ -0,0 +1,29 @@
+// Package typeparams provides utilities for working with Go ASTs with support
+// for type parameters when built with Go 1.18 and higher.
+package typeparams
+
+import (
+ "go/ast"
+)
+
+// Enabled reports whether type parameters are enabled in the current build
+// environment.
+func Enabled() bool {
+ return enabled
+}
+
+// ReceiverType returns the named type of the method receiver, sans "*" and type
+// parameters, or "invalid-type" if fn.Recv is ill formed.
+func ReceiverType(fn *ast.FuncDecl) string {
+ e := fn.Recv.List[0].Type
+ if s, ok := e.(*ast.StarExpr); ok {
+ e = s.X
+ }
+ if enabled {
+ e = unpackIndexExpr(e)
+ }
+ if id, ok := e.(*ast.Ident); ok {
+ return id.Name
+ }
+ return "invalid-type"
+}
diff --git a/vendor/github.com/mgechev/revive/internal/typeparams/typeparams_go117.go b/vendor/github.com/mgechev/revive/internal/typeparams/typeparams_go117.go
new file mode 100644
index 000000000..913a7316e
--- /dev/null
+++ b/vendor/github.com/mgechev/revive/internal/typeparams/typeparams_go117.go
@@ -0,0 +1,12 @@
+//go:build !go1.18
+// +build !go1.18
+
+package typeparams
+
+import (
+ "go/ast"
+)
+
+const enabled = false
+
+func unpackIndexExpr(e ast.Expr) ast.Expr { return e }
diff --git a/vendor/github.com/mgechev/revive/internal/typeparams/typeparams_go118.go b/vendor/github.com/mgechev/revive/internal/typeparams/typeparams_go118.go
new file mode 100644
index 000000000..0f7fd88d3
--- /dev/null
+++ b/vendor/github.com/mgechev/revive/internal/typeparams/typeparams_go118.go
@@ -0,0 +1,20 @@
+//go:build go1.18
+// +build go1.18
+
+package typeparams
+
+import (
+ "go/ast"
+)
+
+const enabled = true
+
+func unpackIndexExpr(e ast.Expr) ast.Expr {
+ switch e := e.(type) {
+ case *ast.IndexExpr:
+ return e.X
+ case *ast.IndexListExpr:
+ return e.X
+ }
+ return e
+}
diff --git a/vendor/github.com/mgechev/revive/lint/config.go b/vendor/github.com/mgechev/revive/lint/config.go
index fe65ace52..276305804 100644
--- a/vendor/github.com/mgechev/revive/lint/config.go
+++ b/vendor/github.com/mgechev/revive/lint/config.go
@@ -7,6 +7,7 @@ type Arguments = []interface{}
type RuleConfig struct {
Arguments Arguments
Severity Severity
+ Disabled bool
}
// RulesConfig defines the config for all rules.
@@ -25,8 +26,10 @@ type Config struct {
IgnoreGeneratedHeader bool `toml:"ignoreGeneratedHeader"`
Confidence float64
Severity Severity
+ EnableAllRules bool `toml:"enableAllRules"`
Rules RulesConfig `toml:"rule"`
ErrorCode int `toml:"errorCode"`
WarningCode int `toml:"warningCode"`
Directives DirectivesConfig `toml:"directive"`
+ Exclude []string `toml:"exclude"`
}
diff --git a/vendor/github.com/mgechev/revive/lint/file.go b/vendor/github.com/mgechev/revive/lint/file.go
index 8bef9c220..dcf0e608f 100644
--- a/vendor/github.com/mgechev/revive/lint/file.go
+++ b/vendor/github.com/mgechev/revive/lint/file.go
@@ -47,7 +47,7 @@ func (f *File) ToPosition(pos token.Pos) token.Position {
return f.Pkg.fset.Position(pos)
}
-// Render renters a node.
+// Render renders a node.
func (f *File) Render(x interface{}) string {
var buf bytes.Buffer
if err := printer.Fprint(&buf, f.Pkg.fset, x); err != nil {
@@ -74,10 +74,10 @@ var basicTypeKinds = map[types.BasicKind]string{
// and indicates what its default type is.
// scope may be nil.
func (f *File) IsUntypedConst(expr ast.Expr) (defType string, ok bool) {
- // Re-evaluate expr outside of its context to see if it's untyped.
+ // Re-evaluate expr outside its context to see if it's untyped.
// (An expr evaluated within, for example, an assignment context will get the type of the LHS.)
exprStr := f.Render(expr)
- tv, err := types.Eval(f.Pkg.fset, f.Pkg.TypesPkg, expr.Pos(), exprStr)
+ tv, err := types.Eval(f.Pkg.fset, f.Pkg.TypesPkg(), expr.Pos(), exprStr)
if err != nil {
return "", false
}
@@ -91,10 +91,7 @@ func (f *File) IsUntypedConst(expr ast.Expr) (defType string, ok bool) {
}
func (f *File) isMain() bool {
- if f.AST.Name.Name == "main" {
- return true
- }
- return false
+ return f.AST.Name.Name == "main"
}
const directiveSpecifyDisableReason = "specify-disable-reason"
@@ -129,11 +126,13 @@ type enableDisableConfig struct {
position int
}
-const directiveRE = `^//[\s]*revive:(enable|disable)(?:-(line|next-line))?(?::([^\s]+))?[\s]*(?: (.+))?$`
-const directivePos = 1
-const modifierPos = 2
-const rulesPos = 3
-const reasonPos = 4
+const (
+ directiveRE = `^//[\s]*revive:(enable|disable)(?:-(line|next-line))?(?::([^\s]+))?[\s]*(?: (.+))?$`
+ directivePos = 1
+ modifierPos = 2
+ rulesPos = 3
+ reasonPos = 4
+)
var re = regexp.MustCompile(directiveRE)
@@ -207,11 +206,11 @@ func (f *File) disabledIntervals(rules []Rule, mustSpecifyDisableReason bool, fa
for _, c := range comments {
match := re.FindStringSubmatch(c.Text)
if len(match) == 0 {
- return
+ continue
}
-
ruleNames := []string{}
tempNames := strings.Split(match[rulesPos], ",")
+
for _, name := range tempNames {
name = strings.Trim(name, "\n")
if len(name) > 0 {
@@ -250,7 +249,7 @@ func (f *File) disabledIntervals(rules []Rule, mustSpecifyDisableReason bool, fa
return getEnabledDisabledIntervals()
}
-func (f *File) filterFailures(failures []Failure, disabledIntervals disabledIntervalsMap) []Failure {
+func (File) filterFailures(failures []Failure, disabledIntervals disabledIntervalsMap) []Failure {
result := []Failure{}
for _, failure := range failures {
fStart := failure.Position.Start.Line
diff --git a/vendor/github.com/mgechev/revive/lint/linter.go b/vendor/github.com/mgechev/revive/lint/linter.go
index cdca84fb5..fb1ab6f28 100644
--- a/vendor/github.com/mgechev/revive/lint/linter.go
+++ b/vendor/github.com/mgechev/revive/lint/linter.go
@@ -6,6 +6,8 @@ import (
"fmt"
"go/token"
"os"
+ "regexp"
+ "strconv"
"sync"
)
@@ -16,12 +18,34 @@ type disabledIntervalsMap = map[string][]DisabledInterval
// Linter is used for linting set of files.
type Linter struct {
- reader ReadFile
+ reader ReadFile
+ fileReadTokens chan struct{}
}
// New creates a new Linter
-func New(reader ReadFile) Linter {
- return Linter{reader: reader}
+func New(reader ReadFile, maxOpenFiles int) Linter {
+ var fileReadTokens chan struct{}
+ if maxOpenFiles > 0 {
+ fileReadTokens = make(chan struct{}, maxOpenFiles)
+ }
+ return Linter{
+ reader: reader,
+ fileReadTokens: fileReadTokens,
+ }
+}
+
+func (l Linter) readFile(path string) (result []byte, err error) {
+ if l.fileReadTokens != nil {
+ // "take" a token by writing to the channel.
+ // It will block if no more space in the channel's buffer
+ l.fileReadTokens <- struct{}{}
+ defer func() {
+ // "free" a token by reading from the channel
+ <-l.fileReadTokens
+ }()
+ }
+
+ return l.reader(path)
}
var (
@@ -57,20 +81,20 @@ func (l *Linter) lintPackage(filenames []string, ruleSet []Rule, config Config,
pkg := &Package{
fset: token.NewFileSet(),
files: map[string]*File{},
- mu: sync.Mutex{},
}
for _, filename := range filenames {
- content, err := l.reader(filename)
+ content, err := l.readFile(filename)
if err != nil {
return err
}
- if isGenerated(content) && !config.IgnoreGeneratedHeader {
+ if !config.IgnoreGeneratedHeader && isGenerated(content) {
continue
}
file, err := NewFile(filename, content, pkg)
if err != nil {
- return err
+ addInvalidFileFailure(filename, err.Error(), failures)
+ continue
}
pkg.files[filename] = file
}
@@ -97,3 +121,43 @@ func isGenerated(src []byte) bool {
}
return false
}
+
+// addInvalidFileFailure adds a failure for an invalid formatted file
+func addInvalidFileFailure(filename, errStr string, failures chan Failure) {
+ position := getPositionInvalidFile(filename, errStr)
+ failures <- Failure{
+ Confidence: 1,
+ Failure: fmt.Sprintf("invalid file %s: %v", filename, errStr),
+ Category: "validity",
+ Position: position,
+ }
+}
+
+// errPosRegexp matches with an NewFile error message
+// i.e. : corrupted.go:10:4: expected '}', found 'EOF
+// first group matches the line and the second group, the column
+var errPosRegexp = regexp.MustCompile(`.*:(\d*):(\d*):.*$`)
+
+// getPositionInvalidFile gets the position of the error in an invalid file
+func getPositionInvalidFile(filename, s string) FailurePosition {
+ pos := errPosRegexp.FindStringSubmatch(s)
+ if len(pos) < 3 {
+ return FailurePosition{}
+ }
+ line, err := strconv.Atoi(pos[1])
+ if err != nil {
+ return FailurePosition{}
+ }
+ column, err := strconv.Atoi(pos[2])
+ if err != nil {
+ return FailurePosition{}
+ }
+
+ return FailurePosition{
+ Start: token.Position{
+ Filename: filename,
+ Line: line,
+ Column: column,
+ },
+ }
+}
diff --git a/vendor/github.com/mgechev/revive/lint/package.go b/vendor/github.com/mgechev/revive/lint/package.go
index 7b6046fd7..5976acf99 100644
--- a/vendor/github.com/mgechev/revive/lint/package.go
+++ b/vendor/github.com/mgechev/revive/lint/package.go
@@ -2,11 +2,12 @@ package lint
import (
"go/ast"
+ "go/importer"
"go/token"
"go/types"
"sync"
- "golang.org/x/tools/go/gcexportdata"
+ "github.com/mgechev/revive/internal/typeparams"
)
// Package represents a package in the project.
@@ -14,18 +15,14 @@ type Package struct {
fset *token.FileSet
files map[string]*File
- TypesPkg *types.Package
- TypesInfo *types.Info
+ typesPkg *types.Package
+ typesInfo *types.Info
// sortable is the set of types in the package that implement sort.Interface.
- Sortable map[string]bool
+ sortable map[string]bool
// main is whether this is a "main" package.
main int
- mu sync.Mutex
-}
-
-var newImporter = func(fset *token.FileSet) types.ImporterFrom {
- return gcexportdata.NewImporter(fset, make(map[string]*types.Package))
+ sync.RWMutex
}
var (
@@ -34,8 +31,16 @@ var (
notSet = 3
)
+// Files return package's files.
+func (p *Package) Files() map[string]*File {
+ return p.files
+}
+
// IsMain returns if that's the main package.
func (p *Package) IsMain() bool {
+ p.Lock()
+ defer p.Unlock()
+
if p.main == trueValue {
return true
} else if p.main == falseValue {
@@ -51,19 +56,41 @@ func (p *Package) IsMain() bool {
return false
}
+// TypesPkg yields information on this package
+func (p *Package) TypesPkg() *types.Package {
+ p.RLock()
+ defer p.RUnlock()
+ return p.typesPkg
+}
+
+// TypesInfo yields type information of this package identifiers
+func (p *Package) TypesInfo() *types.Info {
+ p.RLock()
+ defer p.RUnlock()
+ return p.typesInfo
+}
+
+// Sortable yields a map of sortable types in this package
+func (p *Package) Sortable() map[string]bool {
+ p.RLock()
+ defer p.RUnlock()
+ return p.sortable
+}
+
// TypeCheck performs type checking for given package.
func (p *Package) TypeCheck() error {
- p.mu.Lock()
+ p.Lock()
+ defer p.Unlock()
+
// If type checking has already been performed
// skip it.
- if p.TypesInfo != nil || p.TypesPkg != nil {
- p.mu.Unlock()
+ if p.typesInfo != nil || p.typesPkg != nil {
return nil
}
config := &types.Config{
// By setting a no-op error reporter, the type checker does as much work as possible.
Error: func(error) {},
- Importer: newImporter(p.fset),
+ Importer: importer.Default(),
}
info := &types.Info{
Types: make(map[ast.Expr]types.TypeAndValue),
@@ -82,9 +109,9 @@ func (p *Package) TypeCheck() error {
// Remember the typechecking info, even if config.Check failed,
// since we will get partial information.
- p.TypesPkg = typesPkg
- p.TypesInfo = info
- p.mu.Unlock()
+ p.typesPkg = typesPkg
+ p.typesInfo = info
+
return err
}
@@ -104,10 +131,10 @@ func check(config *types.Config, n string, fset *token.FileSet, astFiles []*ast.
// TypeOf returns the type of an expression.
func (p *Package) TypeOf(expr ast.Expr) types.Type {
- if p.TypesInfo == nil {
+ if p.typesInfo == nil {
return nil
}
- return p.TypesInfo.TypeOf(expr)
+ return p.typesInfo.TypeOf(expr)
}
type walker struct {
@@ -121,7 +148,7 @@ func (w *walker) Visit(n ast.Node) ast.Visitor {
return w
}
// TODO(dsymonds): We could check the signature to be more precise.
- recv := receiverType(fn)
+ recv := typeparams.ReceiverType(fn)
if i, ok := w.nmap[fn.Name.Name]; ok {
w.has[recv] |= i
}
@@ -129,7 +156,7 @@ func (w *walker) Visit(n ast.Node) ast.Visitor {
}
func (p *Package) scanSortable() {
- p.Sortable = make(map[string]bool)
+ p.sortable = make(map[string]bool)
// bitfield for which methods exist on each type.
const (
@@ -144,24 +171,9 @@ func (p *Package) scanSortable() {
}
for typ, ms := range has {
if ms == Len|Less|Swap {
- p.Sortable[typ] = true
- }
- }
-}
-
-// receiverType returns the named type of the method receiver, sans "*",
-// or "invalid-type" if fn.Recv is ill formed.
-func receiverType(fn *ast.FuncDecl) string {
- switch e := fn.Recv.List[0].Type.(type) {
- case *ast.Ident:
- return e.Name
- case *ast.StarExpr:
- if id, ok := e.X.(*ast.Ident); ok {
- return id.Name
+ p.sortable[typ] = true
}
}
- // The parser accepts much more than just the legal forms.
- return "invalid-type"
}
func (p *Package) lint(rules []Rule, config Config, failures chan Failure) {
diff --git a/vendor/github.com/mgechev/revive/lint/rule.go b/vendor/github.com/mgechev/revive/lint/rule.go
index 815abfdd8..ccc66691c 100644
--- a/vendor/github.com/mgechev/revive/lint/rule.go
+++ b/vendor/github.com/mgechev/revive/lint/rule.go
@@ -11,7 +11,7 @@ type DisabledInterval struct {
RuleName string
}
-// Rule defines an abstract rule interaface
+// Rule defines an abstract rule interface
type Rule interface {
Name() string
Apply(*File, Arguments) []Failure
@@ -23,7 +23,7 @@ type AbstractRule struct {
}
// ToFailurePosition returns the failure position.
-func ToFailurePosition(start token.Pos, end token.Pos, file *File) FailurePosition {
+func ToFailurePosition(start, end token.Pos, file *File) FailurePosition {
return FailurePosition{
Start: file.ToPosition(start),
End: file.ToPosition(end),
diff --git a/vendor/github.com/mgechev/revive/rule/add-constant.go b/vendor/github.com/mgechev/revive/rule/add-constant.go
index 881bbd073..414be38c3 100644
--- a/vendor/github.com/mgechev/revive/rule/add-constant.go
+++ b/vendor/github.com/mgechev/revive/rule/add-constant.go
@@ -2,10 +2,12 @@ package rule
import (
"fmt"
- "github.com/mgechev/revive/lint"
"go/ast"
"strconv"
"strings"
+ "sync"
+
+ "github.com/mgechev/revive/lint"
)
const (
@@ -18,10 +20,10 @@ const (
type whiteList map[string]map[string]bool
func newWhiteList() whiteList {
- return map[string]map[string]bool{kindINT: map[string]bool{}, kindFLOAT: map[string]bool{}, kindSTRING: map[string]bool{}}
+ return map[string]map[string]bool{kindINT: {}, kindFLOAT: {}, kindSTRING: {}}
}
-func (wl whiteList) add(kind string, list string) {
+func (wl whiteList) add(kind, list string) {
elems := strings.Split(list, ",")
for _, e := range elems {
wl[kind][e] = true
@@ -29,51 +31,15 @@ func (wl whiteList) add(kind string, list string) {
}
// AddConstantRule lints unused params in functions.
-type AddConstantRule struct{}
+type AddConstantRule struct {
+ whiteList whiteList
+ strLitLimit int
+ sync.Mutex
+}
// Apply applies the rule to given file.
func (r *AddConstantRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure {
- strLitLimit := defaultStrLitLimit
- var whiteList = newWhiteList()
- if len(arguments) > 0 {
- args, ok := arguments[0].(map[string]interface{})
- if !ok {
- panic(fmt.Sprintf("Invalid argument to the add-constant rule. Expecting a k,v map, got %T", arguments[0]))
- }
- for k, v := range args {
- kind := ""
- switch k {
- case "allowFloats":
- kind = kindFLOAT
- fallthrough
- case "allowInts":
- if kind == "" {
- kind = kindINT
- }
- fallthrough
- case "allowStrs":
- if kind == "" {
- kind = kindSTRING
- }
- list, ok := v.(string)
- if !ok {
- panic(fmt.Sprintf("Invalid argument to the add-constant rule, string expected. Got '%v' (%T)", v, v))
- }
- whiteList.add(kind, list)
- case "maxLitCount":
- sl, ok := v.(string)
- if !ok {
- panic(fmt.Sprintf("Invalid argument to the add-constant rule, expecting string representation of an integer. Got '%v' (%T)", v, v))
- }
-
- limit, err := strconv.Atoi(sl)
- if err != nil {
- panic(fmt.Sprintf("Invalid argument to the add-constant rule, expecting string representation of an integer. Got '%v'", v))
- }
- strLitLimit = limit
- }
- }
- }
+ r.configure(arguments)
var failures []lint.Failure
@@ -81,7 +47,7 @@ func (r *AddConstantRule) Apply(file *lint.File, arguments lint.Arguments) []lin
failures = append(failures, failure)
}
- w := lintAddConstantRule{onFailure: onFailure, strLits: make(map[string]int, 0), strLitLimit: strLitLimit, whiteLst: whiteList}
+ w := lintAddConstantRule{onFailure: onFailure, strLits: make(map[string]int), strLitLimit: r.strLitLimit, whiteLst: r.whiteList}
ast.Walk(w, file.AST)
@@ -89,7 +55,7 @@ func (r *AddConstantRule) Apply(file *lint.File, arguments lint.Arguments) []lin
}
// Name returns the rule name.
-func (r *AddConstantRule) Name() string {
+func (*AddConstantRule) Name() string {
return "add-constant"
}
@@ -114,7 +80,6 @@ func (w lintAddConstantRule) Visit(node ast.Node) ast.Visitor {
}
return w
-
}
func (w lintAddConstantRule) checkStrLit(n *ast.BasicLit) {
@@ -149,3 +114,52 @@ func (w lintAddConstantRule) checkNumLit(kind string, n *ast.BasicLit) {
Failure: fmt.Sprintf("avoid magic numbers like '%s', create a named constant for it", n.Value),
})
}
+
+func (r *AddConstantRule) configure(arguments lint.Arguments) {
+ r.Lock()
+ defer r.Unlock()
+
+ if r.whiteList == nil {
+ r.strLitLimit = defaultStrLitLimit
+ r.whiteList = newWhiteList()
+ if len(arguments) > 0 {
+ args, ok := arguments[0].(map[string]interface{})
+ if !ok {
+ panic(fmt.Sprintf("Invalid argument to the add-constant rule. Expecting a k,v map, got %T", arguments[0]))
+ }
+ for k, v := range args {
+ kind := ""
+ switch k {
+ case "allowFloats":
+ kind = kindFLOAT
+ fallthrough
+ case "allowInts":
+ if kind == "" {
+ kind = kindINT
+ }
+ fallthrough
+ case "allowStrs":
+ if kind == "" {
+ kind = kindSTRING
+ }
+ list, ok := v.(string)
+ if !ok {
+ panic(fmt.Sprintf("Invalid argument to the add-constant rule, string expected. Got '%v' (%T)", v, v))
+ }
+ r.whiteList.add(kind, list)
+ case "maxLitCount":
+ sl, ok := v.(string)
+ if !ok {
+ panic(fmt.Sprintf("Invalid argument to the add-constant rule, expecting string representation of an integer. Got '%v' (%T)", v, v))
+ }
+
+ limit, err := strconv.Atoi(sl)
+ if err != nil {
+ panic(fmt.Sprintf("Invalid argument to the add-constant rule, expecting string representation of an integer. Got '%v'", v))
+ }
+ r.strLitLimit = limit
+ }
+ }
+ }
+ }
+}
diff --git a/vendor/github.com/mgechev/revive/rule/argument-limit.go b/vendor/github.com/mgechev/revive/rule/argument-limit.go
index 2b11d4982..8042da15e 100644
--- a/vendor/github.com/mgechev/revive/rule/argument-limit.go
+++ b/vendor/github.com/mgechev/revive/rule/argument-limit.go
@@ -3,31 +3,43 @@ package rule
import (
"fmt"
"go/ast"
+ "sync"
"github.com/mgechev/revive/lint"
)
// ArgumentsLimitRule lints given else constructs.
-type ArgumentsLimitRule struct{}
+type ArgumentsLimitRule struct {
+ total int
+ sync.Mutex
+}
-// Apply applies the rule to given file.
-func (r *ArgumentsLimitRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure {
- if len(arguments) != 1 {
- panic(`invalid configuration for "argument-limit"`)
- }
+func (r *ArgumentsLimitRule) configure(arguments lint.Arguments) {
+ r.Lock()
+ if r.total == 0 {
+ checkNumberOfArguments(1, arguments, r.Name())
- total, ok := arguments[0].(int64) // Alt. non panicking version
- if !ok {
- panic(`invalid value passed as argument number to the "argument-list" rule`)
+ total, ok := arguments[0].(int64) // Alt. non panicking version
+ if !ok {
+ panic(`invalid value passed as argument number to the "argument-limit" rule`)
+ }
+ r.total = int(total)
}
+ r.Unlock()
+}
+
+// Apply applies the rule to given file.
+func (r *ArgumentsLimitRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure {
+ r.configure(arguments)
var failures []lint.Failure
+ onFailure := func(failure lint.Failure) {
+ failures = append(failures, failure)
+ }
walker := lintArgsNum{
- total: int(total),
- onFailure: func(failure lint.Failure) {
- failures = append(failures, failure)
- },
+ total: r.total,
+ onFailure: onFailure,
}
ast.Walk(walker, file.AST)
@@ -36,7 +48,7 @@ func (r *ArgumentsLimitRule) Apply(file *lint.File, arguments lint.Arguments) []
}
// Name returns the rule name.
-func (r *ArgumentsLimitRule) Name() string {
+func (*ArgumentsLimitRule) Name() string {
return "argument-limit"
}
diff --git a/vendor/github.com/mgechev/revive/rule/atomic.go b/vendor/github.com/mgechev/revive/rule/atomic.go
index 572e141da..287b28c21 100644
--- a/vendor/github.com/mgechev/revive/rule/atomic.go
+++ b/vendor/github.com/mgechev/revive/rule/atomic.go
@@ -12,10 +12,10 @@ import (
type AtomicRule struct{}
// Apply applies the rule to given file.
-func (r *AtomicRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
+func (*AtomicRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
var failures []lint.Failure
walker := atomic{
- pkgTypesInfo: file.Pkg.TypesInfo,
+ pkgTypesInfo: file.Pkg.TypesInfo(),
onFailure: func(failure lint.Failure) {
failures = append(failures, failure)
},
@@ -27,7 +27,7 @@ func (r *AtomicRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
}
// Name returns the rule name.
-func (r *AtomicRule) Name() string {
+func (*AtomicRule) Name() string {
return "atomic"
}
diff --git a/vendor/github.com/mgechev/revive/rule/banned-characters.go b/vendor/github.com/mgechev/revive/rule/banned-characters.go
new file mode 100644
index 000000000..76fa2235a
--- /dev/null
+++ b/vendor/github.com/mgechev/revive/rule/banned-characters.go
@@ -0,0 +1,90 @@
+package rule
+
+import (
+ "fmt"
+ "go/ast"
+ "strings"
+ "sync"
+
+ "github.com/mgechev/revive/lint"
+)
+
+// BannedCharsRule checks if a file contains banned characters.
+type BannedCharsRule struct {
+ bannedCharList []string
+ sync.Mutex
+}
+
+const bannedCharsRuleName = "banned-characters"
+
+func (r *BannedCharsRule) configure(arguments lint.Arguments) {
+ r.Lock()
+ if r.bannedCharList == nil {
+ checkNumberOfArguments(1, arguments, bannedCharsRuleName)
+ r.bannedCharList = r.getBannedCharsList(arguments)
+ }
+ r.Unlock()
+}
+
+// Apply applied the rule to the given file.
+func (r *BannedCharsRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure {
+ r.configure(arguments)
+
+ var failures []lint.Failure
+ onFailure := func(failure lint.Failure) {
+ failures = append(failures, failure)
+ }
+
+ w := lintBannedCharsRule{
+ bannedChars: r.bannedCharList,
+ onFailure: onFailure,
+ }
+
+ ast.Walk(w, file.AST)
+ return failures
+}
+
+// Name returns the rule name
+func (*BannedCharsRule) Name() string {
+ return bannedCharsRuleName
+}
+
+// getBannedCharsList converts arguments into the banned characters list
+func (r *BannedCharsRule) getBannedCharsList(args lint.Arguments) []string {
+ var bannedChars []string
+ for _, char := range args {
+ charStr, ok := char.(string)
+ if !ok {
+ panic(fmt.Sprintf("Invalid argument for the %s rule: expecting a string, got %T", r.Name(), char))
+ }
+ bannedChars = append(bannedChars, charStr)
+ }
+
+ return bannedChars
+}
+
+type lintBannedCharsRule struct {
+ bannedChars []string
+ onFailure func(lint.Failure)
+}
+
+// Visit checks for each node if an identifier contains banned characters
+func (w lintBannedCharsRule) Visit(node ast.Node) ast.Visitor {
+ n, ok := node.(*ast.Ident)
+ if !ok {
+ return w
+ }
+ for _, c := range w.bannedChars {
+ ok := strings.Contains(n.Name, c)
+ if ok {
+ w.onFailure(lint.Failure{
+ Confidence: 1,
+ Failure: fmt.Sprintf("banned character found: %s", c),
+ RuleName: bannedCharsRuleName,
+ Node: n,
+ })
+ }
+ }
+
+ return w
+}
diff --git a/vendor/github.com/mgechev/revive/rule/bare-return.go b/vendor/github.com/mgechev/revive/rule/bare-return.go
index 3ee4c4adc..147fa84db 100644
--- a/vendor/github.com/mgechev/revive/rule/bare-return.go
+++ b/vendor/github.com/mgechev/revive/rule/bare-return.go
@@ -10,7 +10,7 @@ import (
type BareReturnRule struct{}
// Apply applies the rule to given file.
-func (r *BareReturnRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
+func (*BareReturnRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
var failures []lint.Failure
onFailure := func(failure lint.Failure) {
@@ -23,7 +23,7 @@ func (r *BareReturnRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure
}
// Name returns the rule name.
-func (r *BareReturnRule) Name() string {
+func (*BareReturnRule) Name() string {
return "bare-return"
}
@@ -61,7 +61,7 @@ func (w bareReturnFinder) Visit(node ast.Node) ast.Visitor {
_, ok := node.(*ast.FuncLit)
if ok {
// skip analysing function literals
- // they will analyzed by the lintBareReturnRule.Visit method
+ // they will be analysed by the lintBareReturnRule.Visit method
return nil
}
diff --git a/vendor/github.com/mgechev/revive/rule/blank-imports.go b/vendor/github.com/mgechev/revive/rule/blank-imports.go
index 0a00e3707..a3d50b4f7 100644
--- a/vendor/github.com/mgechev/revive/rule/blank-imports.go
+++ b/vendor/github.com/mgechev/revive/rule/blank-imports.go
@@ -2,6 +2,7 @@ package rule
import (
"go/ast"
+ "strings"
"github.com/mgechev/revive/lint"
)
@@ -9,66 +10,66 @@ import (
// BlankImportsRule lints given else constructs.
type BlankImportsRule struct{}
-// Apply applies the rule to given file.
-func (r *BlankImportsRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
- var failures []lint.Failure
-
- fileAst := file.AST
- walker := lintBlankImports{
- file: file,
- fileAst: fileAst,
- onFailure: func(failure lint.Failure) {
- failures = append(failures, failure)
- },
- }
-
- ast.Walk(walker, fileAst)
-
- return failures
-}
-
// Name returns the rule name.
-func (r *BlankImportsRule) Name() string {
+func (*BlankImportsRule) Name() string {
return "blank-imports"
}
-type lintBlankImports struct {
- fileAst *ast.File
- file *lint.File
- onFailure func(lint.Failure)
-}
-
-func (w lintBlankImports) Visit(_ ast.Node) ast.Visitor {
- // In package main and in tests, we don't complain about blank imports.
- if w.file.Pkg.IsMain() || w.file.IsTest() {
+// Apply applies the rule to given file.
+func (r *BlankImportsRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
+ if file.Pkg.IsMain() || file.IsTest() {
return nil
}
+ const (
+ message = "a blank import should be only in a main or test package, or have a comment justifying it"
+ category = "imports"
+
+ embedImportPath = `"embed"`
+ )
+
+ var failures []lint.Failure
+
// The first element of each contiguous group of blank imports should have
// an explanatory comment of some kind.
- for i, imp := range w.fileAst.Imports {
- pos := w.file.ToPosition(imp.Pos())
+ for i, imp := range file.AST.Imports {
+ pos := file.ToPosition(imp.Pos())
if !isBlank(imp.Name) {
continue // Ignore non-blank imports.
}
+
if i > 0 {
- prev := w.fileAst.Imports[i-1]
- prevPos := w.file.ToPosition(prev.Pos())
- if isBlank(prev.Name) && prevPos.Line+1 == pos.Line {
- continue // A subsequent blank in a group.
+ prev := file.AST.Imports[i-1]
+ prevPos := file.ToPosition(prev.Pos())
+
+ isSubsequentBlancInAGroup := prevPos.Line+1 == pos.Line && prev.Path.Value != embedImportPath && isBlank(prev.Name)
+ if isSubsequentBlancInAGroup {
+ continue
}
}
+ if imp.Path.Value == embedImportPath && r.fileHasValidEmbedComment(file.AST) {
+ continue
+ }
+
// This is the first blank import of a group.
if imp.Doc == nil && imp.Comment == nil {
- w.onFailure(lint.Failure{
- Node: imp,
- Failure: "a blank import should be only in a main or test package, or have a comment justifying it",
- Confidence: 1,
- Category: "imports",
- })
+ failures = append(failures, lint.Failure{Failure: message, Category: category, Node: imp, Confidence: 1})
}
}
- return nil
+
+ return failures
+}
+
+func (*BlankImportsRule) fileHasValidEmbedComment(fileAst *ast.File) bool {
+ for _, commentGroup := range fileAst.Comments {
+ for _, comment := range commentGroup.List {
+ if strings.HasPrefix(comment.Text, "//go:embed ") {
+ return true
+ }
+ }
+ }
+
+ return false
}
diff --git a/vendor/github.com/mgechev/revive/rule/bool-literal-in-expr.go b/vendor/github.com/mgechev/revive/rule/bool-literal-in-expr.go
index 0a4e696c6..d6150339b 100644
--- a/vendor/github.com/mgechev/revive/rule/bool-literal-in-expr.go
+++ b/vendor/github.com/mgechev/revive/rule/bool-literal-in-expr.go
@@ -11,7 +11,7 @@ import (
type BoolLiteralRule struct{}
// Apply applies the rule to given file.
-func (r *BoolLiteralRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
+func (*BoolLiteralRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
var failures []lint.Failure
onFailure := func(failure lint.Failure) {
@@ -26,7 +26,7 @@ func (r *BoolLiteralRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failur
}
// Name returns the rule name.
-func (r *BoolLiteralRule) Name() string {
+func (*BoolLiteralRule) Name() string {
return "bool-literal-in-expr"
}
@@ -63,7 +63,7 @@ func (w *lintBoolLiteral) Visit(node ast.Node) ast.Visitor {
return w
}
-func (w lintBoolLiteral) addFailure(node ast.Node, msg string, cat string) {
+func (w lintBoolLiteral) addFailure(node ast.Node, msg, cat string) {
w.onFailure(lint.Failure{
Confidence: 1,
Node: node,
diff --git a/vendor/github.com/mgechev/revive/rule/call-to-gc.go b/vendor/github.com/mgechev/revive/rule/call-to-gc.go
index 06126611b..9c68380a4 100644
--- a/vendor/github.com/mgechev/revive/rule/call-to-gc.go
+++ b/vendor/github.com/mgechev/revive/rule/call-to-gc.go
@@ -10,14 +10,14 @@ import (
type CallToGCRule struct{}
// Apply applies the rule to given file.
-func (r *CallToGCRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
+func (*CallToGCRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
var failures []lint.Failure
onFailure := func(failure lint.Failure) {
failures = append(failures, failure)
}
- var gcTriggeringFunctions = map[string]map[string]bool{
- "runtime": map[string]bool{"GC": true},
+ gcTriggeringFunctions := map[string]map[string]bool{
+ "runtime": {"GC": true},
}
w := lintCallToGC{onFailure, gcTriggeringFunctions}
@@ -27,7 +27,7 @@ func (r *CallToGCRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
}
// Name returns the rule name.
-func (r *CallToGCRule) Name() string {
+func (*CallToGCRule) Name() string {
return "call-to-gc"
}
diff --git a/vendor/github.com/mgechev/revive/rule/cognitive-complexity.go b/vendor/github.com/mgechev/revive/rule/cognitive-complexity.go
index ccd36bd09..a9c11a7d0 100644
--- a/vendor/github.com/mgechev/revive/rule/cognitive-complexity.go
+++ b/vendor/github.com/mgechev/revive/rule/cognitive-complexity.go
@@ -4,42 +4,53 @@ import (
"fmt"
"go/ast"
"go/token"
+ "sync"
"github.com/mgechev/revive/lint"
"golang.org/x/tools/go/ast/astutil"
)
// CognitiveComplexityRule lints given else constructs.
-type CognitiveComplexityRule struct{}
+type CognitiveComplexityRule struct {
+ maxComplexity int
+ sync.Mutex
+}
+
+func (r *CognitiveComplexityRule) configure(arguments lint.Arguments) {
+ r.Lock()
+ if r.maxComplexity == 0 {
+ checkNumberOfArguments(1, arguments, r.Name())
+
+ complexity, ok := arguments[0].(int64)
+ if !ok {
+ panic(fmt.Sprintf("invalid argument type for cognitive-complexity, expected int64, got %T", arguments[0]))
+ }
+ r.maxComplexity = int(complexity)
+ }
+ r.Unlock()
+}
// Apply applies the rule to given file.
func (r *CognitiveComplexityRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure {
- var failures []lint.Failure
+ r.configure(arguments)
- const expectedArgumentsCount = 1
- if len(arguments) < expectedArgumentsCount {
- panic(fmt.Sprintf("not enough arguments for cognitive-complexity, expected %d, got %d", expectedArgumentsCount, len(arguments)))
- }
- complexity, ok := arguments[0].(int64)
- if !ok {
- panic(fmt.Sprintf("invalid argument type for cognitive-complexity, expected int64, got %T", arguments[0]))
- }
+ var failures []lint.Failure
linter := cognitiveComplexityLinter{
file: file,
- maxComplexity: int(complexity),
+ maxComplexity: r.maxComplexity,
onFailure: func(failure lint.Failure) {
failures = append(failures, failure)
},
}
- linter.lint()
+ linter.lintCognitiveComplexity()
return failures
}
// Name returns the rule name.
-func (r *CognitiveComplexityRule) Name() string {
+func (*CognitiveComplexityRule) Name() string {
return "cognitive-complexity"
}
@@ -49,7 +60,7 @@ type cognitiveComplexityLinter struct {
onFailure func(lint.Failure)
}
-func (w cognitiveComplexityLinter) lint() {
+func (w cognitiveComplexityLinter) lintCognitiveComplexity() {
f := w.file
for _, decl := range f.AST.Decls {
if fn, ok := decl.(*ast.FuncDecl); ok && fn.Body != nil {
diff --git a/vendor/github.com/mgechev/revive/rule/confusing-naming.go b/vendor/github.com/mgechev/revive/rule/confusing-naming.go
index 143bb18c3..34cdb907a 100644
--- a/vendor/github.com/mgechev/revive/rule/confusing-naming.go
+++ b/vendor/github.com/mgechev/revive/rule/confusing-naming.go
@@ -3,7 +3,6 @@ package rule
import (
"fmt"
"go/ast"
-
"strings"
"sync"
@@ -49,7 +48,7 @@ var allPkgs = packages{pkgs: make([]pkgMethods, 1)}
type ConfusingNamingRule struct{}
// Apply applies the rule to given file.
-func (r *ConfusingNamingRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
+func (*ConfusingNamingRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
var failures []lint.Failure
fileAst := file.AST
pkgm := allPkgs.methodNames(file.Pkg)
@@ -67,11 +66,11 @@ func (r *ConfusingNamingRule) Apply(file *lint.File, _ lint.Arguments) []lint.Fa
}
// Name returns the rule name.
-func (r *ConfusingNamingRule) Name() string {
+func (*ConfusingNamingRule) Name() string {
return "confusing-naming"
}
-//checkMethodName checks if a given method/function name is similar (just case differences) to other method/function of the same struct/file.
+// checkMethodName checks if a given method/function name is similar (just case differences) to other method/function of the same struct/file.
func checkMethodName(holder string, id *ast.Ident, w *lintConfusingNames) {
if id.Name == "init" && holder == defaultStructName {
// ignore init functions
@@ -128,7 +127,7 @@ type lintConfusingNames struct {
const defaultStructName = "_" // used to map functions
-//getStructName of a function receiver. Defaults to defaultStructName
+// getStructName of a function receiver. Defaults to defaultStructName
func getStructName(r *ast.FieldList) string {
result := defaultStructName
diff --git a/vendor/github.com/mgechev/revive/rule/confusing-results.go b/vendor/github.com/mgechev/revive/rule/confusing-results.go
index 1d386b3db..1b79ada9c 100644
--- a/vendor/github.com/mgechev/revive/rule/confusing-results.go
+++ b/vendor/github.com/mgechev/revive/rule/confusing-results.go
@@ -10,7 +10,7 @@ import (
type ConfusingResultsRule struct{}
// Apply applies the rule to given file.
-func (r *ConfusingResultsRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
+func (*ConfusingResultsRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
var failures []lint.Failure
fileAst := file.AST
@@ -26,7 +26,7 @@ func (r *ConfusingResultsRule) Apply(file *lint.File, _ lint.Arguments) []lint.F
}
// Name returns the rule name.
-func (r *ConfusingResultsRule) Name() string {
+func (*ConfusingResultsRule) Name() string {
return "confusing-results"
}
@@ -60,7 +60,6 @@ func (w lintConfusingResults) Visit(n ast.Node) ast.Visitor {
break
}
lastType = t.Name
-
}
return w
diff --git a/vendor/github.com/mgechev/revive/rule/constant-logical-expr.go b/vendor/github.com/mgechev/revive/rule/constant-logical-expr.go
index 6a9156111..9abc95d67 100644
--- a/vendor/github.com/mgechev/revive/rule/constant-logical-expr.go
+++ b/vendor/github.com/mgechev/revive/rule/constant-logical-expr.go
@@ -1,9 +1,10 @@
package rule
import (
- "github.com/mgechev/revive/lint"
"go/ast"
"go/token"
+
+ "github.com/mgechev/revive/lint"
)
// ConstantLogicalExprRule warns on constant logical expressions.
@@ -24,7 +25,7 @@ func (r *ConstantLogicalExprRule) Apply(file *lint.File, _ lint.Arguments) []lin
}
// Name returns the rule name.
-func (r *ConstantLogicalExprRule) Name() string {
+func (*ConstantLogicalExprRule) Name() string {
return "constant-logical-expr"
}
@@ -44,11 +45,13 @@ func (w *lintConstantLogicalExpr) Visit(node ast.Node) ast.Visitor {
return w
}
- if n.Op == token.EQL {
+ // Handles cases like: a <= a, a == a, a >= a
+ if w.isEqualityOperator(n.Op) {
w.newFailure(n, "expression always evaluates to true")
return w
}
+ // Handles cases like: a < a, a > a, a != a
if w.isInequalityOperator(n.Op) {
w.newFailure(n, "expression always evaluates to false")
return w
@@ -69,9 +72,18 @@ func (w *lintConstantLogicalExpr) isOperatorWithLogicalResult(t token.Token) boo
return false
}
+func (w *lintConstantLogicalExpr) isEqualityOperator(t token.Token) bool {
+ switch t {
+ case token.EQL, token.LEQ, token.GEQ:
+ return true
+ }
+
+ return false
+}
+
func (w *lintConstantLogicalExpr) isInequalityOperator(t token.Token) bool {
switch t {
- case token.LSS, token.GTR, token.NEQ, token.LEQ, token.GEQ:
+ case token.LSS, token.GTR, token.NEQ:
return true
}
diff --git a/vendor/github.com/mgechev/revive/rule/context-as-argument.go b/vendor/github.com/mgechev/revive/rule/context-as-argument.go
index 0ed28a82a..3c400065e 100644
--- a/vendor/github.com/mgechev/revive/rule/context-as-argument.go
+++ b/vendor/github.com/mgechev/revive/rule/context-as-argument.go
@@ -1,41 +1,51 @@
package rule
import (
+ "fmt"
"go/ast"
+ "strings"
+ "sync"
"github.com/mgechev/revive/lint"
)
// ContextAsArgumentRule lints given else constructs.
-type ContextAsArgumentRule struct{}
+type ContextAsArgumentRule struct {
+ allowTypesLUT map[string]struct{}
+ sync.Mutex
+}
// Apply applies the rule to given file.
-func (r *ContextAsArgumentRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
- var failures []lint.Failure
+func (r *ContextAsArgumentRule) Apply(file *lint.File, args lint.Arguments) []lint.Failure {
+ r.Lock()
+ if r.allowTypesLUT == nil {
+ r.allowTypesLUT = getAllowTypesFromArguments(args)
+ }
+ r.Unlock()
- fileAst := file.AST
+ var failures []lint.Failure
+ r.Lock()
walker := lintContextArguments{
- file: file,
- fileAst: fileAst,
+ allowTypesLUT: r.allowTypesLUT,
onFailure: func(failure lint.Failure) {
failures = append(failures, failure)
},
}
+ r.Unlock()
- ast.Walk(walker, fileAst)
+ ast.Walk(walker, file.AST)
return failures
}
// Name returns the rule name.
-func (r *ContextAsArgumentRule) Name() string {
+func (*ContextAsArgumentRule) Name() string {
return "context-as-argument"
}
type lintContextArguments struct {
- file *lint.File
- fileAst *ast.File
- onFailure func(lint.Failure)
+ allowTypesLUT map[string]struct{}
+ onFailure func(lint.Failure)
}
func (w lintContextArguments) Visit(n ast.Node) ast.Visitor {
@@ -43,18 +53,58 @@ func (w lintContextArguments) Visit(n ast.Node) ast.Visitor {
if !ok || len(fn.Type.Params.List) <= 1 {
return w
}
+
+ fnArgs := fn.Type.Params.List
+
// A context.Context should be the first parameter of a function.
// Flag any that show up after the first.
- for _, arg := range fn.Type.Params.List[1:] {
- if isPkgDot(arg.Type, "context", "Context") {
+ isCtxStillAllowed := true
+ for _, arg := range fnArgs {
+ argIsCtx := isPkgDot(arg.Type, "context", "Context")
+ if argIsCtx && !isCtxStillAllowed {
w.onFailure(lint.Failure{
- Node: fn,
+ Node: arg,
Category: "arg-order",
Failure: "context.Context should be the first parameter of a function",
Confidence: 0.9,
})
break // only flag one
}
+
+ typeName := gofmt(arg.Type)
+ // a parameter of type context.Context is still allowed if the current arg type is in the LUT
+ _, isCtxStillAllowed = w.allowTypesLUT[typeName]
+ }
+
+ return nil // avoid visiting the function body
+}
+
+func getAllowTypesFromArguments(args lint.Arguments) map[string]struct{} {
+ allowTypesBefore := []string{}
+ if len(args) >= 1 {
+ argKV, ok := args[0].(map[string]interface{})
+ if !ok {
+ panic(fmt.Sprintf("Invalid argument to the context-as-argument rule. Expecting a k,v map, got %T", args[0]))
+ }
+ for k, v := range argKV {
+ switch k {
+ case "allowTypesBefore":
+ typesBefore, ok := v.(string)
+ if !ok {
+ panic(fmt.Sprintf("Invalid argument to the context-as-argument.allowTypesBefore rule. Expecting a string, got %T", v))
+ }
+ allowTypesBefore = append(allowTypesBefore, strings.Split(typesBefore, ",")...)
+ default:
+ panic(fmt.Sprintf("Invalid argument to the context-as-argument rule. Unrecognized key %s", k))
+ }
+ }
+ }
+
+ result := make(map[string]struct{}, len(allowTypesBefore))
+ for _, v := range allowTypesBefore {
+ result[v] = struct{}{}
}
- return w
+
+ result["context.Context"] = struct{}{} // context.Context is always allowed before another context.Context
+ return result
}
diff --git a/vendor/github.com/mgechev/revive/rule/context-keys-type.go b/vendor/github.com/mgechev/revive/rule/context-keys-type.go
index 9c2f0bbd7..60ccec560 100644
--- a/vendor/github.com/mgechev/revive/rule/context-keys-type.go
+++ b/vendor/github.com/mgechev/revive/rule/context-keys-type.go
@@ -12,7 +12,7 @@ import (
type ContextKeysType struct{}
// Apply applies the rule to given file.
-func (r *ContextKeysType) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
+func (*ContextKeysType) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
var failures []lint.Failure
fileAst := file.AST
@@ -31,7 +31,7 @@ func (r *ContextKeysType) Apply(file *lint.File, _ lint.Arguments) []lint.Failur
}
// Name returns the rule name.
-func (r *ContextKeysType) Name() string {
+func (*ContextKeysType) Name() string {
return "context-keys-type"
}
@@ -68,7 +68,7 @@ func checkContextKeyType(w lintContextKeyTypes, x *ast.CallExpr) {
if len(x.Args) != 3 {
return
}
- key := f.Pkg.TypesInfo.Types[x.Args[1]]
+ key := f.Pkg.TypesInfo().Types[x.Args[1]]
if ktyp, ok := key.Type.(*types.Basic); ok && ktyp.Kind() != types.Invalid {
w.onFailure(lint.Failure{
diff --git a/vendor/github.com/mgechev/revive/rule/cyclomatic.go b/vendor/github.com/mgechev/revive/rule/cyclomatic.go
index 48ea80a6a..afd41818b 100644
--- a/vendor/github.com/mgechev/revive/rule/cyclomatic.go
+++ b/vendor/github.com/mgechev/revive/rule/cyclomatic.go
@@ -4,6 +4,7 @@ import (
"fmt"
"go/ast"
"go/token"
+ "sync"
"github.com/mgechev/revive/lint"
)
@@ -11,21 +12,35 @@ import (
// Based on https://github.com/fzipp/gocyclo
// CyclomaticRule lints given else constructs.
-type CyclomaticRule struct{}
+type CyclomaticRule struct {
+ maxComplexity int
+ sync.Mutex
+}
-// Apply applies the rule to given file.
-func (r *CyclomaticRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure {
- var failures []lint.Failure
+func (r *CyclomaticRule) configure(arguments lint.Arguments) {
+ r.Lock()
+ if r.maxComplexity == 0 {
+ checkNumberOfArguments(1, arguments, r.Name())
- complexity, ok := arguments[0].(int64) // Alt. non panicking version
- if !ok {
- panic("invalid argument for cyclomatic complexity")
+ complexity, ok := arguments[0].(int64) // Alt. non panicking version
+ if !ok {
+ panic(fmt.Sprintf("invalid argument for cyclomatic complexity; expected int but got %T", arguments[0]))
+ }
+ r.maxComplexity = int(complexity)
}
+ r.Unlock()
+}
+// Apply applies the rule to given file.
+func (r *CyclomaticRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure {
+ r.configure(arguments)
+
+ var failures []lint.Failure
fileAst := file.AST
+
walker := lintCyclomatic{
file: file,
- complexity: int(complexity),
+ complexity: r.maxComplexity,
onFailure: func(failure lint.Failure) {
failures = append(failures, failure)
},
@@ -37,7 +52,7 @@ func (r *CyclomaticRule) Apply(file *lint.File, arguments lint.Arguments) []lint
}
// Name returns the rule name.
-func (r *CyclomaticRule) Name() string {
+func (*CyclomaticRule) Name() string {
return "cyclomatic"
}
@@ -56,8 +71,9 @@ func (w lintCyclomatic) Visit(_ ast.Node) ast.Visitor {
w.onFailure(lint.Failure{
Confidence: 1,
Category: "maintenance",
- Failure: fmt.Sprintf("function %s has cyclomatic complexity %d", funcName(fn), c),
- Node: fn,
+ Failure: fmt.Sprintf("function %s has cyclomatic complexity %d (> max enabled %d)",
+ funcName(fn), c, w.complexity),
+ Node: fn,
})
}
}
diff --git a/vendor/github.com/mgechev/revive/rule/datarace.go b/vendor/github.com/mgechev/revive/rule/datarace.go
new file mode 100644
index 000000000..26fcadcdc
--- /dev/null
+++ b/vendor/github.com/mgechev/revive/rule/datarace.go
@@ -0,0 +1,142 @@
+package rule
+
+import (
+ "fmt"
+ "go/ast"
+
+ "github.com/mgechev/revive/lint"
+)
+
+// DataRaceRule lints assignments to value method-receivers.
+type DataRaceRule struct{}
+
+// Apply applies the rule to given file.
+func (*DataRaceRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
+ var failures []lint.Failure
+ onFailure := func(failure lint.Failure) {
+ failures = append(failures, failure)
+ }
+ w := lintDataRaces{onFailure: onFailure}
+
+ ast.Walk(w, file.AST)
+
+ return failures
+}
+
+// Name returns the rule name.
+func (*DataRaceRule) Name() string {
+ return "datarace"
+}
+
+type lintDataRaces struct {
+ onFailure func(failure lint.Failure)
+}
+
+func (w lintDataRaces) Visit(n ast.Node) ast.Visitor {
+ node, ok := n.(*ast.FuncDecl)
+ if !ok {
+ return w // not function declaration
+ }
+ if node.Body == nil {
+ return nil // empty body
+ }
+
+ results := node.Type.Results
+
+ returnIDs := map[*ast.Object]struct{}{}
+ if results != nil {
+ returnIDs = w.ExtractReturnIDs(results.List)
+ }
+ fl := &lintFunctionForDataRaces{onFailure: w.onFailure, returnIDs: returnIDs, rangeIDs: map[*ast.Object]struct{}{}}
+ ast.Walk(fl, node.Body)
+
+ return nil
+}
+
+func (w lintDataRaces) ExtractReturnIDs(fields []*ast.Field) map[*ast.Object]struct{} {
+ r := map[*ast.Object]struct{}{}
+ for _, f := range fields {
+ for _, id := range f.Names {
+ r[id.Obj] = struct{}{}
+ }
+ }
+
+ return r
+}
+
+type lintFunctionForDataRaces struct {
+ _ struct{}
+ onFailure func(failure lint.Failure)
+ returnIDs map[*ast.Object]struct{}
+ rangeIDs map[*ast.Object]struct{}
+}
+
+func (w lintFunctionForDataRaces) Visit(node ast.Node) ast.Visitor {
+ switch n := node.(type) {
+ case *ast.RangeStmt:
+ if n.Body == nil {
+ return nil
+ }
+
+ getIds := func(exprs ...ast.Expr) []*ast.Ident {
+ r := []*ast.Ident{}
+ for _, expr := range exprs {
+ if id, ok := expr.(*ast.Ident); ok {
+ r = append(r, id)
+ }
+ }
+ return r
+ }
+
+ ids := getIds(n.Key, n.Value)
+ for _, id := range ids {
+ w.rangeIDs[id.Obj] = struct{}{}
+ }
+
+ ast.Walk(w, n.Body)
+
+ for _, id := range ids {
+ delete(w.rangeIDs, id.Obj)
+ }
+
+ return nil // do not visit the body of the range, it has been already visited
+ case *ast.GoStmt:
+ f := n.Call.Fun
+ funcLit, ok := f.(*ast.FuncLit)
+ if !ok {
+ return nil
+ }
+ selectIDs := func(n ast.Node) bool {
+ _, ok := n.(*ast.Ident)
+ return ok
+ }
+
+ ids := pick(funcLit.Body, selectIDs, nil)
+ for _, id := range ids {
+ id := id.(*ast.Ident)
+ _, isRangeID := w.rangeIDs[id.Obj]
+ _, isReturnID := w.returnIDs[id.Obj]
+
+ switch {
+ case isRangeID:
+ w.onFailure(lint.Failure{
+ Confidence: 1,
+ Node: id,
+ Category: "logic",
+ Failure: fmt.Sprintf("datarace: range value %s is captured (by-reference) in goroutine", id.Name),
+ })
+ case isReturnID:
+ w.onFailure(lint.Failure{
+ Confidence: 0.8,
+ Node: id,
+ Category: "logic",
+ Failure: fmt.Sprintf("potential datarace: return value %s is captured (by-reference) in goroutine", id.Name),
+ })
+ }
+ }
+
+ return nil
+ }
+
+ return w
+}
diff --git a/vendor/github.com/mgechev/revive/rule/deep-exit.go b/vendor/github.com/mgechev/revive/rule/deep-exit.go
index f49e93dd4..918d4294a 100644
--- a/vendor/github.com/mgechev/revive/rule/deep-exit.go
+++ b/vendor/github.com/mgechev/revive/rule/deep-exit.go
@@ -11,16 +11,16 @@ import (
type DeepExitRule struct{}
// Apply applies the rule to given file.
-func (r *DeepExitRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
+func (*DeepExitRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
var failures []lint.Failure
onFailure := func(failure lint.Failure) {
failures = append(failures, failure)
}
- var exitFunctions = map[string]map[string]bool{
- "os": map[string]bool{"Exit": true},
- "syscall": map[string]bool{"Exit": true},
- "log": map[string]bool{
+ exitFunctions := map[string]map[string]bool{
+ "os": {"Exit": true},
+ "syscall": {"Exit": true},
+ "log": {
"Fatal": true,
"Fatalf": true,
"Fatalln": true,
@@ -36,7 +36,7 @@ func (r *DeepExitRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
}
// Name returns the rule name.
-func (r *DeepExitRule) Name() string {
+func (*DeepExitRule) Name() string {
return "deep-exit"
}
diff --git a/vendor/github.com/mgechev/revive/rule/defer.go b/vendor/github.com/mgechev/revive/rule/defer.go
index 2ec7ef47c..f8224fd4d 100644
--- a/vendor/github.com/mgechev/revive/rule/defer.go
+++ b/vendor/github.com/mgechev/revive/rule/defer.go
@@ -3,23 +3,34 @@ package rule
import (
"fmt"
"go/ast"
+ "sync"
"github.com/mgechev/revive/lint"
)
// DeferRule lints unused params in functions.
-type DeferRule struct{}
+type DeferRule struct {
+ allow map[string]bool
+ sync.Mutex
+}
+
+func (r *DeferRule) configure(arguments lint.Arguments) {
+ r.Lock()
+ if r.allow == nil {
+ r.allow = r.allowFromArgs(arguments)
+ }
+ r.Unlock()
+}
// Apply applies the rule to given file.
func (r *DeferRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure {
- allow := r.allowFromArgs(arguments)
+ r.configure(arguments)
var failures []lint.Failure
onFailure := func(failure lint.Failure) {
failures = append(failures, failure)
}
-
- w := lintDeferRule{onFailure: onFailure, allow: allow}
+ w := lintDeferRule{onFailure: onFailure, allow: r.allow}
ast.Walk(w, file.AST)
@@ -27,18 +38,19 @@ func (r *DeferRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Fail
}
// Name returns the rule name.
-func (r *DeferRule) Name() string {
+func (*DeferRule) Name() string {
return "defer"
}
-func (r *DeferRule) allowFromArgs(args lint.Arguments) map[string]bool {
+func (*DeferRule) allowFromArgs(args lint.Arguments) map[string]bool {
if len(args) < 1 {
allow := map[string]bool{
- "loop": true,
- "call-chain": true,
- "method-call": true,
- "return": true,
- "recover": true,
+ "loop": true,
+ "call-chain": true,
+ "method-call": true,
+ "return": true,
+ "recover": true,
+ "immediate-recover": true,
}
return allow
@@ -85,12 +97,30 @@ func (w lintDeferRule) Visit(node ast.Node) ast.Visitor {
w.newFailure("return in a defer function has no effect", n, 1.0, "logic", "return")
}
case *ast.CallExpr:
- if isIdent(n.Fun, "recover") && !w.inADefer {
+ if !w.inADefer && isIdent(n.Fun, "recover") {
+ // func fn() { recover() }
+ //
// confidence is not 1 because recover can be in a function that is deferred elsewhere
w.newFailure("recover must be called inside a deferred function", n, 0.8, "logic", "recover")
+ } else if w.inADefer && !w.inAFuncLit && isIdent(n.Fun, "recover") {
+ // defer helper(recover())
+ //
+ // confidence is not truly 1 because this could be in a correctly-deferred func,
+ // but it is very likely to be a misunderstanding of defer's behavior around arguments.
+ w.newFailure("recover must be called inside a deferred function, this is executing recover immediately", n, 1, "logic", "immediate-recover")
}
case *ast.DeferStmt:
+ if isIdent(n.Call.Fun, "recover") {
+ // defer recover()
+ //
+ // confidence is not truly 1 because this could be in a correctly-deferred func,
+ // but normally this doesn't suppress a panic, and even if it did it would silently discard the value.
+ w.newFailure("recover must be called inside a deferred function, this is executing recover immediately", n, 1, "logic", "immediate-recover")
+ }
w.visitSubtree(n.Call.Fun, true, false, false)
+ for _, a := range n.Call.Args {
+ w.visitSubtree(a, true, false, false) // check arguments, they should not contain recover()
+ }
if w.inALoop {
w.newFailure("prefer not to defer inside loops", n, 1.0, "bad practice", "loop")
@@ -114,16 +144,17 @@ func (w lintDeferRule) Visit(node ast.Node) ast.Visitor {
}
func (w lintDeferRule) visitSubtree(n ast.Node, inADefer, inALoop, inAFuncLit bool) {
- nw := &lintDeferRule{
+ nw := lintDeferRule{
onFailure: w.onFailure,
inADefer: inADefer,
inALoop: inALoop,
inAFuncLit: inAFuncLit,
- allow: w.allow}
+ allow: w.allow,
+ }
ast.Walk(nw, n)
}
-func (w lintDeferRule) newFailure(msg string, node ast.Node, confidence float64, cat string, subcase string) {
+func (w lintDeferRule) newFailure(msg string, node ast.Node, confidence float64, cat, subcase string) {
if !w.allow[subcase] {
return
}
diff --git a/vendor/github.com/mgechev/revive/rule/dot-imports.go b/vendor/github.com/mgechev/revive/rule/dot-imports.go
index 78419d7d6..25ff526cb 100644
--- a/vendor/github.com/mgechev/revive/rule/dot-imports.go
+++ b/vendor/github.com/mgechev/revive/rule/dot-imports.go
@@ -10,7 +10,7 @@ import (
type DotImportsRule struct{}
// Apply applies the rule to given file.
-func (r *DotImportsRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
+func (*DotImportsRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
var failures []lint.Failure
fileAst := file.AST
@@ -28,7 +28,7 @@ func (r *DotImportsRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure
}
// Name returns the rule name.
-func (r *DotImportsRule) Name() string {
+func (*DotImportsRule) Name() string {
return "dot-imports"
}
diff --git a/vendor/github.com/mgechev/revive/rule/duplicated-imports.go b/vendor/github.com/mgechev/revive/rule/duplicated-imports.go
index 485b6a2ea..2b177fac6 100644
--- a/vendor/github.com/mgechev/revive/rule/duplicated-imports.go
+++ b/vendor/github.com/mgechev/revive/rule/duplicated-imports.go
@@ -10,7 +10,7 @@ import (
type DuplicatedImportsRule struct{}
// Apply applies the rule to given file.
-func (r *DuplicatedImportsRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
+func (*DuplicatedImportsRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
var failures []lint.Failure
impPaths := map[string]struct{}{}
@@ -34,6 +34,6 @@ func (r *DuplicatedImportsRule) Apply(file *lint.File, _ lint.Arguments) []lint.
}
// Name returns the rule name.
-func (r *DuplicatedImportsRule) Name() string {
+func (*DuplicatedImportsRule) Name() string {
return "duplicated-imports"
}
diff --git a/vendor/github.com/mgechev/revive/rule/early-return.go b/vendor/github.com/mgechev/revive/rule/early-return.go
index ffb568a86..bfbf6717c 100644
--- a/vendor/github.com/mgechev/revive/rule/early-return.go
+++ b/vendor/github.com/mgechev/revive/rule/early-return.go
@@ -10,7 +10,7 @@ import (
type EarlyReturnRule struct{}
// Apply applies the rule to given file.
-func (r *EarlyReturnRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
+func (*EarlyReturnRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
var failures []lint.Failure
onFailure := func(failure lint.Failure) {
@@ -23,7 +23,7 @@ func (r *EarlyReturnRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failur
}
// Name returns the rule name.
-func (r *EarlyReturnRule) Name() string {
+func (*EarlyReturnRule) Name() string {
return "early-return"
}
diff --git a/vendor/github.com/mgechev/revive/rule/empty-block.go b/vendor/github.com/mgechev/revive/rule/empty-block.go
index fbec4d93c..8a4a0fef1 100644
--- a/vendor/github.com/mgechev/revive/rule/empty-block.go
+++ b/vendor/github.com/mgechev/revive/rule/empty-block.go
@@ -10,20 +10,20 @@ import (
type EmptyBlockRule struct{}
// Apply applies the rule to given file.
-func (r *EmptyBlockRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
+func (*EmptyBlockRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
var failures []lint.Failure
onFailure := func(failure lint.Failure) {
failures = append(failures, failure)
}
- w := lintEmptyBlock{make(map[*ast.BlockStmt]bool, 0), onFailure}
+ w := lintEmptyBlock{make(map[*ast.BlockStmt]bool), onFailure}
ast.Walk(w, file.AST)
return failures
}
// Name returns the rule name.
-func (r *EmptyBlockRule) Name() string {
+func (*EmptyBlockRule) Name() string {
return "empty-block"
}
diff --git a/vendor/github.com/mgechev/revive/rule/empty-lines.go b/vendor/github.com/mgechev/revive/rule/empty-lines.go
index 61d9281bf..12866072e 100644
--- a/vendor/github.com/mgechev/revive/rule/empty-lines.go
+++ b/vendor/github.com/mgechev/revive/rule/empty-lines.go
@@ -18,25 +18,25 @@ func (r *EmptyLinesRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure
failures = append(failures, failure)
}
- w := lintEmptyLines{file, file.CommentMap(), onFailure}
+ w := lintEmptyLines{file, r.commentLines(file.CommentMap(), file), onFailure}
ast.Walk(w, file.AST)
return failures
}
// Name returns the rule name.
-func (r *EmptyLinesRule) Name() string {
+func (*EmptyLinesRule) Name() string {
return "empty-lines"
}
type lintEmptyLines struct {
file *lint.File
- cmap ast.CommentMap
+ cmap map[int]struct{}
onFailure func(lint.Failure)
}
func (w lintEmptyLines) Visit(node ast.Node) ast.Visitor {
block, ok := node.(*ast.BlockStmt)
- if !ok {
+ if !ok || len(block.List) == 0 {
return w
}
@@ -47,67 +47,59 @@ func (w lintEmptyLines) Visit(node ast.Node) ast.Visitor {
}
func (w lintEmptyLines) checkStart(block *ast.BlockStmt) {
- if len(block.List) == 0 {
- return
- }
-
- start := w.position(block.Lbrace)
+ blockStart := w.position(block.Lbrace)
firstNode := block.List[0]
+ firstStmt := w.position(firstNode.Pos())
- if w.commentBetween(start, firstNode) {
+ firstBlockLineIsStmt := firstStmt.Line-(blockStart.Line+1) == 0
+ _, firstBlockLineIsComment := w.cmap[blockStart.Line+1]
+ if firstBlockLineIsStmt || firstBlockLineIsComment {
return
}
- first := w.position(firstNode.Pos())
- if first.Line-start.Line > 1 {
- w.onFailure(lint.Failure{
- Confidence: 1,
- Node: block,
- Category: "style",
- Failure: "extra empty line at the start of a block",
- })
- }
+ w.onFailure(lint.Failure{
+ Confidence: 1,
+ Node: block,
+ Category: "style",
+ Failure: "extra empty line at the start of a block",
+ })
}
func (w lintEmptyLines) checkEnd(block *ast.BlockStmt) {
- if len(block.List) < 1 {
- return
- }
-
- end := w.position(block.Rbrace)
+ blockEnd := w.position(block.Rbrace)
lastNode := block.List[len(block.List)-1]
+ lastStmt := w.position(lastNode.End())
- if w.commentBetween(end, lastNode) {
+ lastBlockLineIsStmt := (blockEnd.Line-1)-lastStmt.Line == 0
+ _, lastBlockLineIsComment := w.cmap[blockEnd.Line-1]
+ if lastBlockLineIsStmt || lastBlockLineIsComment {
return
}
- last := w.position(lastNode.End())
- if end.Line-last.Line > 1 {
- w.onFailure(lint.Failure{
- Confidence: 1,
- Node: lastNode,
- Category: "style",
- Failure: "extra empty line at the end of a block",
- })
- }
+ w.onFailure(lint.Failure{
+ Confidence: 1,
+ Node: block,
+ Category: "style",
+ Failure: "extra empty line at the end of a block",
+ })
}
-func (w lintEmptyLines) commentBetween(position token.Position, node ast.Node) bool {
- comments := w.cmap.Filter(node).Comments()
- if len(comments) == 0 {
- return false
- }
+func (w lintEmptyLines) position(pos token.Pos) token.Position {
+ return w.file.ToPosition(pos)
+}
+
+func (*EmptyLinesRule) commentLines(cmap ast.CommentMap, file *lint.File) map[int]struct{} {
+ result := map[int]struct{}{}
- for _, comment := range comments {
- start, end := w.position(comment.Pos()), w.position(comment.End())
- if start.Line-position.Line == 1 || position.Line-end.Line == 1 {
- return true
+ for _, comments := range cmap {
+ for _, comment := range comments {
+ start := file.ToPosition(comment.Pos())
+ end := file.ToPosition(comment.End())
+ for i := start.Line; i <= end.Line; i++ {
+ result[i] = struct{}{}
+ }
}
}
- return false
-}
-
-func (w lintEmptyLines) position(pos token.Pos) token.Position {
- return w.file.ToPosition(pos)
+ return result
}
diff --git a/vendor/github.com/mgechev/revive/rule/error-naming.go b/vendor/github.com/mgechev/revive/rule/error-naming.go
index 3a1080625..a4f24f3f0 100644
--- a/vendor/github.com/mgechev/revive/rule/error-naming.go
+++ b/vendor/github.com/mgechev/revive/rule/error-naming.go
@@ -13,7 +13,7 @@ import (
type ErrorNamingRule struct{}
// Apply applies the rule to given file.
-func (r *ErrorNamingRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
+func (*ErrorNamingRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
var failures []lint.Failure
fileAst := file.AST
@@ -31,7 +31,7 @@ func (r *ErrorNamingRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failur
}
// Name returns the rule name.
-func (r *ErrorNamingRule) Name() string {
+func (*ErrorNamingRule) Name() string {
return "error-naming"
}
diff --git a/vendor/github.com/mgechev/revive/rule/error-return.go b/vendor/github.com/mgechev/revive/rule/error-return.go
index 737d8c66f..a724e001c 100644
--- a/vendor/github.com/mgechev/revive/rule/error-return.go
+++ b/vendor/github.com/mgechev/revive/rule/error-return.go
@@ -10,7 +10,7 @@ import (
type ErrorReturnRule struct{}
// Apply applies the rule to given file.
-func (r *ErrorReturnRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
+func (*ErrorReturnRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
var failures []lint.Failure
fileAst := file.AST
@@ -28,7 +28,7 @@ func (r *ErrorReturnRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failur
}
// Name returns the rule name.
-func (r *ErrorReturnRule) Name() string {
+func (*ErrorReturnRule) Name() string {
return "error-return"
}
diff --git a/vendor/github.com/mgechev/revive/rule/error-strings.go b/vendor/github.com/mgechev/revive/rule/error-strings.go
index b8a5b7ed7..81ebda540 100644
--- a/vendor/github.com/mgechev/revive/rule/error-strings.go
+++ b/vendor/github.com/mgechev/revive/rule/error-strings.go
@@ -4,6 +4,8 @@ import (
"go/ast"
"go/token"
"strconv"
+ "strings"
+ "sync"
"unicode"
"unicode/utf8"
@@ -11,16 +13,60 @@ import (
)
// ErrorStringsRule lints given else constructs.
-type ErrorStringsRule struct{}
+type ErrorStringsRule struct {
+ errorFunctions map[string]map[string]struct{}
+ sync.Mutex
+}
+
+func (r *ErrorStringsRule) configure(arguments lint.Arguments) {
+ r.Lock()
+ defer r.Unlock()
+
+ if r.errorFunctions != nil {
+ return
+ }
+
+ r.errorFunctions = map[string]map[string]struct{}{
+ "fmt": {
+ "Errorf": {},
+ },
+ "errors": {
+ "Errorf": {},
+ "WithMessage": {},
+ "Wrap": {},
+ "New": {},
+ "WithMessagef": {},
+ "Wrapf": {},
+ },
+ }
+
+ var invalidCustomFunctions []string
+ for _, argument := range arguments {
+ if functionName, ok := argument.(string); ok {
+ fields := strings.Split(strings.TrimSpace(functionName), ".")
+ if len(fields) != 2 || len(fields[0]) == 0 || len(fields[1]) == 0 {
+ invalidCustomFunctions = append(invalidCustomFunctions, functionName)
+ continue
+ }
+ r.errorFunctions[fields[0]] = map[string]struct{}{fields[1]: {}}
+ }
+ }
+ if len(invalidCustomFunctions) != 0 {
+ panic("found invalid custom function: " + strings.Join(invalidCustomFunctions, ","))
+ }
+}
// Apply applies the rule to given file.
-func (r *ErrorStringsRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
+func (r *ErrorStringsRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure {
var failures []lint.Failure
+ r.configure(arguments)
+
fileAst := file.AST
walker := lintErrorStrings{
- file: file,
- fileAst: fileAst,
+ file: file,
+ fileAst: fileAst,
+ errorFunctions: r.errorFunctions,
onFailure: func(failure lint.Failure) {
failures = append(failures, failure)
},
@@ -32,29 +78,36 @@ func (r *ErrorStringsRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failu
}
// Name returns the rule name.
-func (r *ErrorStringsRule) Name() string {
+func (*ErrorStringsRule) Name() string {
return "error-strings"
}
type lintErrorStrings struct {
- file *lint.File
- fileAst *ast.File
- onFailure func(lint.Failure)
+ file *lint.File
+ fileAst *ast.File
+ errorFunctions map[string]map[string]struct{}
+ onFailure func(lint.Failure)
}
+// Visit browses the AST
func (w lintErrorStrings) Visit(n ast.Node) ast.Visitor {
ce, ok := n.(*ast.CallExpr)
if !ok {
return w
}
- if !isPkgDot(ce.Fun, "errors", "New") && !isPkgDot(ce.Fun, "fmt", "Errorf") {
+
+ if len(ce.Args) < 1 {
return w
}
- if len(ce.Args) < 1 {
+
+ // expression matches the known pkg.function
+ ok = w.match(ce)
+ if !ok {
return w
}
- str, ok := ce.Args[0].(*ast.BasicLit)
- if !ok || str.Kind != token.STRING {
+
+ str, ok := w.getMessage(ce)
+ if !ok {
return w
}
s, _ := strconv.Unquote(str.Value) // can assume well-formed Go
@@ -65,7 +118,6 @@ func (w lintErrorStrings) Visit(n ast.Node) ast.Visitor {
if clean {
return w
}
-
w.onFailure(lint.Failure{
Node: str,
Confidence: conf,
@@ -75,6 +127,55 @@ func (w lintErrorStrings) Visit(n ast.Node) ast.Visitor {
return w
}
+// match returns true if the expression corresponds to the known pkg.function
+// i.e.: errors.Wrap
+func (w lintErrorStrings) match(expr *ast.CallExpr) bool {
+ sel, ok := expr.Fun.(*ast.SelectorExpr)
+ if !ok {
+ return false
+ }
+ // retrieve the package
+ id, ok := sel.X.(*ast.Ident)
+ if !ok {
+ return false
+ }
+ functions, ok := w.errorFunctions[id.Name]
+ if !ok {
+ return false
+ }
+ // retrieve the function
+ _, ok = functions[sel.Sel.Name]
+ return ok
+}
+
+// getMessage returns the message depending on its position
+// returns false if the cast is unsuccessful
+func (w lintErrorStrings) getMessage(expr *ast.CallExpr) (s *ast.BasicLit, success bool) {
+ str, ok := w.checkArg(expr, 0)
+ if ok {
+ return str, true
+ }
+ if len(expr.Args) < 2 {
+ return s, false
+ }
+ str, ok = w.checkArg(expr, 1)
+ if !ok {
+ return s, false
+ }
+ return str, true
+}
+
+func (lintErrorStrings) checkArg(expr *ast.CallExpr, arg int) (s *ast.BasicLit, success bool) {
+ str, ok := expr.Args[arg].(*ast.BasicLit)
+ if !ok {
+ return s, false
+ }
+ if str.Kind != token.STRING {
+ return s, false
+ }
+ return str, true
+}
+
func lintErrorString(s string) (isClean bool, conf float64) {
const basicConfidence = 0.8
const capConfidence = basicConfidence - 0.2
diff --git a/vendor/github.com/mgechev/revive/rule/errorf.go b/vendor/github.com/mgechev/revive/rule/errorf.go
index 1bffbab5b..1588a745d 100644
--- a/vendor/github.com/mgechev/revive/rule/errorf.go
+++ b/vendor/github.com/mgechev/revive/rule/errorf.go
@@ -13,7 +13,7 @@ import (
type ErrorfRule struct{}
// Apply applies the rule to given file.
-func (r *ErrorfRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
+func (*ErrorfRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
var failures []lint.Failure
fileAst := file.AST
@@ -32,7 +32,7 @@ func (r *ErrorfRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
}
// Name returns the rule name.
-func (r *ErrorfRule) Name() string {
+func (*ErrorfRule) Name() string {
return "errorf"
}
diff --git a/vendor/github.com/mgechev/revive/rule/exported.go b/vendor/github.com/mgechev/revive/rule/exported.go
index b68f2bacc..b8663c48c 100644
--- a/vendor/github.com/mgechev/revive/rule/exported.go
+++ b/vendor/github.com/mgechev/revive/rule/exported.go
@@ -5,24 +5,49 @@ import (
"go/ast"
"go/token"
"strings"
+ "sync"
"unicode"
"unicode/utf8"
+ "github.com/mgechev/revive/internal/typeparams"
"github.com/mgechev/revive/lint"
)
// ExportedRule lints given else constructs.
-type ExportedRule struct{}
+type ExportedRule struct {
+ configured bool
+ checkPrivateReceivers bool
+ disableStutteringCheck bool
+ stuttersMsg string
+ sync.Mutex
+}
+
+func (r *ExportedRule) configure(arguments lint.Arguments) {
+ r.Lock()
+ if !r.configured {
+ var sayRepetitiveInsteadOfStutters bool
+ r.checkPrivateReceivers, r.disableStutteringCheck, sayRepetitiveInsteadOfStutters = r.getConf(arguments)
+ r.stuttersMsg = "stutters"
+ if sayRepetitiveInsteadOfStutters {
+ r.stuttersMsg = "is repetitive"
+ }
+
+ r.configured = true
+ }
+ r.Unlock()
+}
// Apply applies the rule to given file.
-func (r *ExportedRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
- var failures []lint.Failure
+func (r *ExportedRule) Apply(file *lint.File, args lint.Arguments) []lint.Failure {
+ r.configure(args)
- if isTest(file) {
+ var failures []lint.Failure
+ if file.IsTest() {
return failures
}
fileAst := file.AST
+
walker := lintExported{
file: file,
fileAst: fileAst,
@@ -30,6 +55,9 @@ func (r *ExportedRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
failures = append(failures, failure)
},
genDeclMissingComments: make(map[*ast.GenDecl]bool),
+ checkPrivateReceivers: r.checkPrivateReceivers,
+ disableStutteringCheck: r.disableStutteringCheck,
+ stuttersMsg: r.stuttersMsg,
}
ast.Walk(&walker, fileAst)
@@ -38,16 +66,45 @@ func (r *ExportedRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
}
// Name returns the rule name.
-func (r *ExportedRule) Name() string {
+func (*ExportedRule) Name() string {
return "exported"
}
+func (r *ExportedRule) getConf(args lint.Arguments) (checkPrivateReceivers, disableStutteringCheck, sayRepetitiveInsteadOfStutters bool) {
+ // if any, we expect a slice of strings as configuration
+ if len(args) < 1 {
+ return
+ }
+ for _, flag := range args {
+ flagStr, ok := flag.(string)
+ if !ok {
+ panic(fmt.Sprintf("Invalid argument for the %s rule: expecting a string, got %T", r.Name(), flag))
+ }
+
+ switch flagStr {
+ case "checkPrivateReceivers":
+ checkPrivateReceivers = true
+ case "disableStutteringCheck":
+ disableStutteringCheck = true
+ case "sayRepetitiveInsteadOfStutters":
+ sayRepetitiveInsteadOfStutters = true
+ default:
+ panic(fmt.Sprintf("Unknown configuration flag %s for %s rule", flagStr, r.Name()))
+ }
+ }
+
+ return
+}
+
type lintExported struct {
file *lint.File
fileAst *ast.File
lastGen *ast.GenDecl
genDeclMissingComments map[*ast.GenDecl]bool
onFailure func(lint.Failure)
+ checkPrivateReceivers bool
+ disableStutteringCheck bool
+ stuttersMsg string
}
func (w *lintExported) lintFuncDoc(fn *ast.FuncDecl) {
@@ -60,8 +117,8 @@ func (w *lintExported) lintFuncDoc(fn *ast.FuncDecl) {
if fn.Recv != nil && len(fn.Recv.List) > 0 {
// method
kind = "method"
- recv := receiverType(fn)
- if !ast.IsExported(recv) {
+ recv := typeparams.ReceiverType(fn)
+ if !w.checkPrivateReceivers && !ast.IsExported(recv) {
// receiver is unexported
return
}
@@ -70,7 +127,8 @@ func (w *lintExported) lintFuncDoc(fn *ast.FuncDecl) {
}
switch name {
case "Len", "Less", "Swap":
- if w.file.Pkg.Sortable[recv] {
+ sortables := w.file.Pkg.Sortable()
+ if sortables[recv] {
return
}
}
@@ -98,6 +156,10 @@ func (w *lintExported) lintFuncDoc(fn *ast.FuncDecl) {
}
func (w *lintExported) checkStutter(id *ast.Ident, thing string) {
+ if w.disableStutteringCheck {
+ return
+ }
+
pkg, name := w.fileAst.Name.Name, id.Name
if !ast.IsExported(name) {
// unexported name
@@ -122,7 +184,7 @@ func (w *lintExported) checkStutter(id *ast.Ident, thing string) {
Node: id,
Confidence: 0.8,
Category: "naming",
- Failure: fmt.Sprintf("%s name will be used as %s.%s by other packages, and that stutters; consider calling this %s", thing, pkg, name, rem),
+ Failure: fmt.Sprintf("%s name will be used as %s.%s by other packages, and that %s; consider calling this %s", thing, pkg, name, w.stuttersMsg, rem),
})
}
}
@@ -189,7 +251,7 @@ func (w *lintExported) lintValueSpecDoc(vs *ast.ValueSpec, gd *ast.GenDecl, genD
return
}
- if vs.Doc == nil && gd.Doc == nil {
+ if vs.Doc == nil && vs.Comment == nil && gd.Doc == nil {
if genDeclMissingComments[gd] {
return
}
@@ -207,15 +269,21 @@ func (w *lintExported) lintValueSpecDoc(vs *ast.ValueSpec, gd *ast.GenDecl, genD
return
}
// If this GenDecl has parens and a comment, we don't check its comment form.
- if gd.Lparen.IsValid() && gd.Doc != nil {
+ if gd.Doc != nil && gd.Lparen.IsValid() {
return
}
// The relevant text to check will be on either vs.Doc or gd.Doc.
// Use vs.Doc preferentially.
- doc := vs.Doc
- if doc == nil {
+ var doc *ast.CommentGroup
+ switch {
+ case vs.Doc != nil:
+ doc = vs.Doc
+ case vs.Comment != nil && gd.Doc == nil:
+ doc = vs.Comment
+ default:
doc = gd.Doc
}
+
prefix := name + " "
s := normalizeText(doc.Text())
if !strings.HasPrefix(s, prefix) {
diff --git a/vendor/github.com/mgechev/revive/rule/file-header.go b/vendor/github.com/mgechev/revive/rule/file-header.go
index 6df974e91..76f548f51 100644
--- a/vendor/github.com/mgechev/revive/rule/file-header.go
+++ b/vendor/github.com/mgechev/revive/rule/file-header.go
@@ -1,29 +1,40 @@
package rule
import (
+ "fmt"
"regexp"
+ "sync"
"github.com/mgechev/revive/lint"
)
// FileHeaderRule lints given else constructs.
-type FileHeaderRule struct{}
+type FileHeaderRule struct {
+ header string
+ sync.Mutex
+}
var (
- multiRegexp = regexp.MustCompile("^/\\*")
+ multiRegexp = regexp.MustCompile(`^/\*`)
singleRegexp = regexp.MustCompile("^//")
)
-// Apply applies the rule to given file.
-func (r *FileHeaderRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure {
- if len(arguments) != 1 {
- panic(`invalid configuration for "file-header" rule`)
+func (r *FileHeaderRule) configure(arguments lint.Arguments) {
+ r.Lock()
+ if r.header == "" {
+ checkNumberOfArguments(1, arguments, r.Name())
+ var ok bool
+ r.header, ok = arguments[0].(string)
+ if !ok {
+ panic(fmt.Sprintf("invalid argument for \"file-header\" rule: first argument should be a string, got %T", arguments[0]))
+ }
}
+ r.Unlock()
+}
- header, ok := arguments[0].(string)
- if !ok {
- panic(`invalid argument for "file-header" rule: first argument should be a string`)
- }
+// Apply applies the rule to given file.
+func (r *FileHeaderRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure {
+ r.configure(arguments)
failure := []lint.Failure{
{
@@ -44,26 +55,26 @@ func (r *FileHeaderRule) Apply(file *lint.File, arguments lint.Arguments) []lint
comment := ""
for _, c := range g.List {
text := c.Text
- if multiRegexp.Match([]byte(text)) {
+ if multiRegexp.MatchString(text) {
text = text[2 : len(text)-2]
- } else if singleRegexp.Match([]byte(text)) {
+ } else if singleRegexp.MatchString(text) {
text = text[2:]
}
comment += text
}
- regex, err := regexp.Compile(header)
+ regex, err := regexp.Compile(r.header)
if err != nil {
panic(err.Error())
}
- if !regex.Match([]byte(comment)) {
+ if !regex.MatchString(comment) {
return failure
}
return nil
}
// Name returns the rule name.
-func (r *FileHeaderRule) Name() string {
+func (*FileHeaderRule) Name() string {
return "file-header"
}
diff --git a/vendor/github.com/mgechev/revive/rule/flag-param.go b/vendor/github.com/mgechev/revive/rule/flag-param.go
index 6cb6daea9..19a05f9fe 100644
--- a/vendor/github.com/mgechev/revive/rule/flag-param.go
+++ b/vendor/github.com/mgechev/revive/rule/flag-param.go
@@ -2,15 +2,16 @@ package rule
import (
"fmt"
- "github.com/mgechev/revive/lint"
"go/ast"
+
+ "github.com/mgechev/revive/lint"
)
// FlagParamRule lints given else constructs.
type FlagParamRule struct{}
// Apply applies the rule to given file.
-func (r *FlagParamRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
+func (*FlagParamRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
var failures []lint.Failure
onFailure := func(failure lint.Failure) {
@@ -23,7 +24,7 @@ func (r *FlagParamRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure
}
// Name returns the rule name.
-func (r *FlagParamRule) Name() string {
+func (*FlagParamRule) Name() string {
return "flag-parameter"
}
diff --git a/vendor/github.com/mgechev/revive/rule/function-length.go b/vendor/github.com/mgechev/revive/rule/function-length.go
new file mode 100644
index 000000000..717ddbf7b
--- /dev/null
+++ b/vendor/github.com/mgechev/revive/rule/function-length.go
@@ -0,0 +1,168 @@
+package rule
+
+import (
+ "fmt"
+ "go/ast"
+ "reflect"
+ "sync"
+
+ "github.com/mgechev/revive/lint"
+)
+
+// FunctionLength lint.
+type FunctionLength struct {
+ maxStmt int
+ maxLines int
+ sync.Mutex
+}
+
+func (r *FunctionLength) configure(arguments lint.Arguments) {
+ r.Lock()
+ if r.maxLines == 0 {
+ maxStmt, maxLines := r.parseArguments(arguments)
+ r.maxStmt = int(maxStmt)
+ r.maxLines = int(maxLines)
+ }
+ r.Unlock()
+}
+
+// Apply applies the rule to given file.
+func (r *FunctionLength) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure {
+ r.configure(arguments)
+
+ var failures []lint.Failure
+
+ walker := lintFuncLength{
+ file: file,
+ maxStmt: r.maxStmt,
+ maxLines: r.maxLines,
+ onFailure: func(failure lint.Failure) {
+ failures = append(failures, failure)
+ },
+ }
+
+ ast.Walk(walker, file.AST)
+
+ return failures
+}
+
+// Name returns the rule name.
+func (*FunctionLength) Name() string {
+ return "function-length"
+}
+
+func (*FunctionLength) parseArguments(arguments lint.Arguments) (maxStmt, maxLines int64) {
+ if len(arguments) != 2 {
+ panic(fmt.Sprintf(`invalid configuration for "function-length" rule, expected 2 arguments but got %d`, len(arguments)))
+ }
+
+ maxStmt, maxStmtOk := arguments[0].(int64)
+ if !maxStmtOk {
+ panic(fmt.Sprintf(`invalid configuration value for max statements in "function-length" rule; need int64 but got %T`, arguments[0]))
+ }
+ if maxStmt < 0 {
+ panic(fmt.Sprintf(`the configuration value for max statements in "function-length" rule cannot be negative, got %d`, maxStmt))
+ }
+
+ maxLines, maxLinesOk := arguments[1].(int64)
+ if !maxLinesOk {
+ panic(fmt.Sprintf(`invalid configuration value for max lines in "function-length" rule; need int64 but got %T`, arguments[1]))
+ }
+ if maxLines < 0 {
+ panic(fmt.Sprintf(`the configuration value for max statements in "function-length" rule cannot be negative, got %d`, maxLines))
+ }
+
+ return maxStmt, maxLines
+}
+
+type lintFuncLength struct {
+ file *lint.File
+ maxStmt int
+ maxLines int
+ onFailure func(lint.Failure)
+}
+
+func (w lintFuncLength) Visit(n ast.Node) ast.Visitor {
+ node, ok := n.(*ast.FuncDecl)
+ if !ok {
+ return w
+ }
+
+ body := node.Body
+ if body == nil || len(node.Body.List) == 0 {
+ return nil
+ }
+
+ if w.maxStmt > 0 {
+ stmtCount := w.countStmts(node.Body.List)
+ if stmtCount > w.maxStmt {
+ w.onFailure(lint.Failure{
+ Confidence: 1,
+ Failure: fmt.Sprintf("maximum number of statements per function exceeded; max %d but got %d", w.maxStmt, stmtCount),
+ Node: node,
+ })
+ }
+ }
+
+ if w.maxLines > 0 {
+ lineCount := w.countLines(node.Body)
+ if lineCount > w.maxLines {
+ w.onFailure(lint.Failure{
+ Confidence: 1,
+ Failure: fmt.Sprintf("maximum number of lines per function exceeded; max %d but got %d", w.maxLines, lineCount),
+ Node: node,
+ })
+ }
+ }
+
+ return nil
+}
+
+func (w lintFuncLength) countLines(b *ast.BlockStmt) int {
+ return w.file.ToPosition(b.End()).Line - w.file.ToPosition(b.Pos()).Line - 1
+}
+
+func (w lintFuncLength) countStmts(b []ast.Stmt) int {
+ count := 0
+ for _, s := range b {
+ switch stmt := s.(type) {
+ case *ast.BlockStmt:
+ count += w.countStmts(stmt.List)
+ case *ast.IfStmt:
+ count += 1 + w.countBodyListStmts(stmt)
+ if stmt.Else != nil {
+ elseBody, ok := stmt.Else.(*ast.BlockStmt)
+ if ok {
+ count += w.countStmts(elseBody.List)
+ }
+ }
+ case *ast.ForStmt, *ast.RangeStmt,
+ *ast.SwitchStmt, *ast.TypeSwitchStmt, *ast.SelectStmt:
+ count += 1 + w.countBodyListStmts(stmt)
+ case *ast.CaseClause:
+ count += w.countStmts(stmt.Body)
+ case *ast.AssignStmt:
+ count += 1 + w.countFuncLitStmts(stmt.Rhs[0])
+ case *ast.GoStmt:
+ count += 1 + w.countFuncLitStmts(stmt.Call.Fun)
+ case *ast.DeferStmt:
+ count += 1 + w.countFuncLitStmts(stmt.Call.Fun)
+ default:
+ count++
+ }
+ }
+
+ return count
+}
+
+func (w lintFuncLength) countFuncLitStmts(stmt ast.Expr) int {
+ if block, ok := stmt.(*ast.FuncLit); ok {
+ return w.countStmts(block.Body.List)
+ }
+ return 0
+}
+
+func (w lintFuncLength) countBodyListStmts(t interface{}) int {
+ i := reflect.ValueOf(t).Elem().FieldByName(`Body`).Elem().FieldByName(`List`).Interface()
+ return w.countStmts(i.([]ast.Stmt))
+}
diff --git a/vendor/github.com/mgechev/revive/rule/function-result-limit.go b/vendor/github.com/mgechev/revive/rule/function-result-limit.go
index 1850fc419..5d2b87316 100644
--- a/vendor/github.com/mgechev/revive/rule/function-result-limit.go
+++ b/vendor/github.com/mgechev/revive/rule/function-result-limit.go
@@ -3,31 +3,42 @@ package rule
import (
"fmt"
"go/ast"
+ "sync"
"github.com/mgechev/revive/lint"
)
// FunctionResultsLimitRule lints given else constructs.
-type FunctionResultsLimitRule struct{}
+type FunctionResultsLimitRule struct {
+ max int
+ sync.Mutex
+}
-// Apply applies the rule to given file.
-func (r *FunctionResultsLimitRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure {
- if len(arguments) != 1 {
- panic(`invalid configuration for "function-result-limit"`)
- }
+func (r *FunctionResultsLimitRule) configure(arguments lint.Arguments) {
+ r.Lock()
+ if r.max == 0 {
+ checkNumberOfArguments(1, arguments, r.Name())
- max, ok := arguments[0].(int64) // Alt. non panicking version
- if !ok {
- panic(fmt.Sprintf(`invalid value passed as return results number to the "function-result-limit" rule; need int64 but got %T`, arguments[0]))
- }
- if max < 0 {
- panic(`the value passed as return results number to the "function-result-limit" rule cannot be negative`)
+ max, ok := arguments[0].(int64) // Alt. non panicking version
+ if !ok {
+ panic(fmt.Sprintf(`invalid value passed as return results number to the "function-result-limit" rule; need int64 but got %T`, arguments[0]))
+ }
+ if max < 0 {
+ panic(`the value passed as return results number to the "function-result-limit" rule cannot be negative`)
+ }
+ r.max = int(max)
}
+ r.Unlock()
+}
+
+// Apply applies the rule to given file.
+func (r *FunctionResultsLimitRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure {
+ r.configure(arguments)
var failures []lint.Failure
walker := lintFunctionResultsNum{
- max: int(max),
+ max: r.max,
onFailure: func(failure lint.Failure) {
failures = append(failures, failure)
},
@@ -39,7 +50,7 @@ func (r *FunctionResultsLimitRule) Apply(file *lint.File, arguments lint.Argumen
}
// Name returns the rule name.
-func (r *FunctionResultsLimitRule) Name() string {
+func (*FunctionResultsLimitRule) Name() string {
return "function-result-limit"
}
diff --git a/vendor/github.com/mgechev/revive/rule/get-return.go b/vendor/github.com/mgechev/revive/rule/get-return.go
index 494ab6669..600a40fac 100644
--- a/vendor/github.com/mgechev/revive/rule/get-return.go
+++ b/vendor/github.com/mgechev/revive/rule/get-return.go
@@ -12,7 +12,7 @@ import (
type GetReturnRule struct{}
// Apply applies the rule to given file.
-func (r *GetReturnRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
+func (*GetReturnRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
var failures []lint.Failure
onFailure := func(failure lint.Failure) {
@@ -25,7 +25,7 @@ func (r *GetReturnRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure
}
// Name returns the rule name.
-func (r *GetReturnRule) Name() string {
+func (*GetReturnRule) Name() string {
return "get-return"
}
diff --git a/vendor/github.com/mgechev/revive/rule/identical-branches.go b/vendor/github.com/mgechev/revive/rule/identical-branches.go
index 094a79147..b1a69097f 100644
--- a/vendor/github.com/mgechev/revive/rule/identical-branches.go
+++ b/vendor/github.com/mgechev/revive/rule/identical-branches.go
@@ -10,7 +10,7 @@ import (
type IdenticalBranchesRule struct{}
// Apply applies the rule to given file.
-func (r *IdenticalBranchesRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
+func (*IdenticalBranchesRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
var failures []lint.Failure
onFailure := func(failure lint.Failure) {
@@ -24,7 +24,7 @@ func (r *IdenticalBranchesRule) Apply(file *lint.File, _ lint.Arguments) []lint.
}
// Name returns the rule name.
-func (r *IdenticalBranchesRule) Name() string {
+func (*IdenticalBranchesRule) Name() string {
return "identical-branches"
}
@@ -57,7 +57,7 @@ func (w *lintIdenticalBranches) Visit(node ast.Node) ast.Visitor {
return w
}
-func (w *lintIdenticalBranches) identicalBranches(branches []*ast.BlockStmt) bool {
+func (lintIdenticalBranches) identicalBranches(branches []*ast.BlockStmt) bool {
if len(branches) < 2 {
return false
}
diff --git a/vendor/github.com/mgechev/revive/rule/if-return.go b/vendor/github.com/mgechev/revive/rule/if-return.go
index c275d2766..a6a3113ad 100644
--- a/vendor/github.com/mgechev/revive/rule/if-return.go
+++ b/vendor/github.com/mgechev/revive/rule/if-return.go
@@ -12,7 +12,7 @@ import (
type IfReturnRule struct{}
// Apply applies the rule to given file.
-func (r *IfReturnRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
+func (*IfReturnRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
var failures []lint.Failure
onFailure := func(failure lint.Failure) {
@@ -26,7 +26,7 @@ func (r *IfReturnRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
}
// Name returns the rule name.
-func (r *IfReturnRule) Name() string {
+func (*IfReturnRule) Name() string {
return "if-return"
}
diff --git a/vendor/github.com/mgechev/revive/rule/import-shadowing.go b/vendor/github.com/mgechev/revive/rule/import-shadowing.go
index b78234c59..2bab704d0 100644
--- a/vendor/github.com/mgechev/revive/rule/import-shadowing.go
+++ b/vendor/github.com/mgechev/revive/rule/import-shadowing.go
@@ -13,7 +13,7 @@ import (
type ImportShadowingRule struct{}
// Apply applies the rule to given file.
-func (r *ImportShadowingRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
+func (*ImportShadowingRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
var failures []lint.Failure
importNames := map[string]struct{}{}
@@ -23,7 +23,8 @@ func (r *ImportShadowingRule) Apply(file *lint.File, _ lint.Arguments) []lint.Fa
fileAst := file.AST
walker := importShadowing{
- importNames: importNames,
+ packageNameIdent: fileAst.Name,
+ importNames: importNames,
onFailure: func(failure lint.Failure) {
failures = append(failures, failure)
},
@@ -36,7 +37,7 @@ func (r *ImportShadowingRule) Apply(file *lint.File, _ lint.Arguments) []lint.Fa
}
// Name returns the rule name.
-func (r *ImportShadowingRule) Name() string {
+func (*ImportShadowingRule) Name() string {
return "import-shadowing"
}
@@ -57,9 +58,10 @@ func getName(imp *ast.ImportSpec) string {
}
type importShadowing struct {
- importNames map[string]struct{}
- onFailure func(lint.Failure)
- alreadySeen map[*ast.Object]struct{}
+ packageNameIdent *ast.Ident
+ importNames map[string]struct{}
+ onFailure func(lint.Failure)
+ alreadySeen map[*ast.Object]struct{}
}
// Visit visits AST nodes and checks if id nodes (ast.Ident) shadow an import name
@@ -79,6 +81,10 @@ func (w importShadowing) Visit(n ast.Node) ast.Visitor {
*ast.StructType: // skip analysis of struct type because struct fields can not shadow an import name
return nil
case *ast.Ident:
+ if n == w.packageNameIdent {
+ return nil // skip the ident corresponding to the package name of this file
+ }
+
id := n.Name
if id == "_" {
return w // skip _ id
diff --git a/vendor/github.com/mgechev/revive/rule/imports-blacklist.go b/vendor/github.com/mgechev/revive/rule/imports-blacklist.go
index 31ef901e5..710662815 100644
--- a/vendor/github.com/mgechev/revive/rule/imports-blacklist.go
+++ b/vendor/github.com/mgechev/revive/rule/imports-blacklist.go
@@ -2,38 +2,63 @@ package rule
import (
"fmt"
+ "regexp"
+ "sync"
"github.com/mgechev/revive/lint"
)
// ImportsBlacklistRule lints given else constructs.
-type ImportsBlacklistRule struct{}
+type ImportsBlacklistRule struct {
+ blacklist []*regexp.Regexp
+ sync.Mutex
+}
+
+var replaceRegexp = regexp.MustCompile(`/?\*\*/?`)
+
+func (r *ImportsBlacklistRule) configure(arguments lint.Arguments) {
+ r.Lock()
+ defer r.Unlock()
+
+ if r.blacklist == nil {
+ r.blacklist = make([]*regexp.Regexp, 0)
+
+ for _, arg := range arguments {
+ argStr, ok := arg.(string)
+ if !ok {
+ panic(fmt.Sprintf("Invalid argument to the imports-blacklist rule. Expecting a string, got %T", arg))
+ }
+ regStr, err := regexp.Compile(fmt.Sprintf(`(?m)"%s"$`, replaceRegexp.ReplaceAllString(argStr, `(\W|\w)*`)))
+ if err != nil {
+ panic(fmt.Sprintf("Invalid argument to the imports-blacklist rule. Expecting %q to be a valid regular expression, got: %v", argStr, err))
+ }
+ r.blacklist = append(r.blacklist, regStr)
+ }
+ }
+}
+
+func (r *ImportsBlacklistRule) isBlacklisted(path string) bool {
+ for _, regex := range r.blacklist {
+ if regex.MatchString(path) {
+ return true
+ }
+ }
+ return false
+}
// Apply applies the rule to given file.
func (r *ImportsBlacklistRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure {
+ r.configure(arguments)
+
var failures []lint.Failure
if file.IsTest() {
return failures // skip, test file
}
- blacklist := make(map[string]bool, len(arguments))
-
- for _, arg := range arguments {
- argStr, ok := arg.(string)
- if !ok {
- panic(fmt.Sprintf("Invalid argument to the imports-blacklist rule. Expecting a string, got %T", arg))
- }
- // we add quotes if not present, because when parsed, the value of the AST node, will be quoted
- if len(argStr) > 2 && argStr[0] != '"' && argStr[len(argStr)-1] != '"' {
- argStr = fmt.Sprintf(`"%s"`, argStr)
- }
- blacklist[argStr] = true
- }
-
for _, is := range file.AST.Imports {
path := is.Path
- if path != nil && blacklist[path.Value] {
+ if path != nil && r.isBlacklisted(path.Value) {
failures = append(failures, lint.Failure{
Confidence: 1,
Failure: "should not use the following blacklisted import: " + path.Value,
@@ -47,6 +72,6 @@ func (r *ImportsBlacklistRule) Apply(file *lint.File, arguments lint.Arguments)
}
// Name returns the rule name.
-func (r *ImportsBlacklistRule) Name() string {
+func (*ImportsBlacklistRule) Name() string {
return "imports-blacklist"
}
diff --git a/vendor/github.com/mgechev/revive/rule/increment-decrement.go b/vendor/github.com/mgechev/revive/rule/increment-decrement.go
index 5d6b17671..34a8e1ec5 100644
--- a/vendor/github.com/mgechev/revive/rule/increment-decrement.go
+++ b/vendor/github.com/mgechev/revive/rule/increment-decrement.go
@@ -12,7 +12,7 @@ import (
type IncrementDecrementRule struct{}
// Apply applies the rule to given file.
-func (r *IncrementDecrementRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
+func (*IncrementDecrementRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
var failures []lint.Failure
fileAst := file.AST
@@ -29,13 +29,12 @@ func (r *IncrementDecrementRule) Apply(file *lint.File, _ lint.Arguments) []lint
}
// Name returns the rule name.
-func (r *IncrementDecrementRule) Name() string {
+func (*IncrementDecrementRule) Name() string {
return "increment-decrement"
}
type lintIncrementDecrement struct {
file *lint.File
- fileAst *ast.File
onFailure func(lint.Failure)
}
diff --git a/vendor/github.com/mgechev/revive/rule/indent-error-flow.go b/vendor/github.com/mgechev/revive/rule/indent-error-flow.go
index 4c9799b2a..e455801c4 100644
--- a/vendor/github.com/mgechev/revive/rule/indent-error-flow.go
+++ b/vendor/github.com/mgechev/revive/rule/indent-error-flow.go
@@ -11,7 +11,7 @@ import (
type IndentErrorFlowRule struct{}
// Apply applies the rule to given file.
-func (r *IndentErrorFlowRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
+func (*IndentErrorFlowRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
var failures []lint.Failure
onFailure := func(failure lint.Failure) {
@@ -24,7 +24,7 @@ func (r *IndentErrorFlowRule) Apply(file *lint.File, _ lint.Arguments) []lint.Fa
}
// Name returns the rule name.
-func (r *IndentErrorFlowRule) Name() string {
+func (*IndentErrorFlowRule) Name() string {
return "indent-error-flow"
}
diff --git a/vendor/github.com/mgechev/revive/rule/line-length-limit.go b/vendor/github.com/mgechev/revive/rule/line-length-limit.go
index 5ee057079..9e512c1c2 100644
--- a/vendor/github.com/mgechev/revive/rule/line-length-limit.go
+++ b/vendor/github.com/mgechev/revive/rule/line-length-limit.go
@@ -6,28 +6,41 @@ import (
"fmt"
"go/token"
"strings"
+ "sync"
"unicode/utf8"
"github.com/mgechev/revive/lint"
)
// LineLengthLimitRule lints given else constructs.
-type LineLengthLimitRule struct{}
+type LineLengthLimitRule struct {
+ max int
+ sync.Mutex
+}
-// Apply applies the rule to given file.
-func (r *LineLengthLimitRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure {
- if len(arguments) != 1 {
- panic(`invalid configuration for "line-length-limit"`)
- }
+func (r *LineLengthLimitRule) configure(arguments lint.Arguments) {
+ r.Lock()
+ if r.max == 0 {
+ checkNumberOfArguments(1, arguments, r.Name())
+
+ max, ok := arguments[0].(int64) // Alt. non panicking version
+ if !ok || max < 0 {
+ panic(`invalid value passed as argument number to the "line-length-limit" rule`)
+ }
- max, ok := arguments[0].(int64) // Alt. non panicking version
- if !ok || max < 0 {
- panic(`invalid value passed as argument number to the "line-length-limit" rule`)
+ r.max = int(max)
}
+ r.Unlock()
+}
+
+// Apply applies the rule to given file.
+func (r *LineLengthLimitRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure {
+ r.configure(arguments)
var failures []lint.Failure
+
checker := lintLineLengthNum{
- max: int(max),
+ max: r.max,
file: file,
onFailure: func(failure lint.Failure) {
failures = append(failures, failure)
@@ -40,7 +53,7 @@ func (r *LineLengthLimitRule) Apply(file *lint.File, arguments lint.Arguments) [
}
// Name returns the rule name.
-func (r *LineLengthLimitRule) Name() string {
+func (*LineLengthLimitRule) Name() string {
return "line-length-limit"
}
@@ -57,7 +70,7 @@ func (r lintLineLengthNum) check() {
s := bufio.NewScanner(f)
for s.Scan() {
t := s.Text()
- t = strings.Replace(t, "\t", spaces, -1)
+ t = strings.ReplaceAll(t, "\t", spaces)
c := utf8.RuneCountInString(t)
if c > r.max {
r.onFailure(lint.Failure{
diff --git a/vendor/github.com/mgechev/revive/rule/max-public-structs.go b/vendor/github.com/mgechev/revive/rule/max-public-structs.go
index 9a2d07cbc..e39f49c69 100644
--- a/vendor/github.com/mgechev/revive/rule/max-public-structs.go
+++ b/vendor/github.com/mgechev/revive/rule/max-public-structs.go
@@ -2,20 +2,40 @@ package rule
import (
"go/ast"
-
"strings"
+ "sync"
"github.com/mgechev/revive/lint"
)
// MaxPublicStructsRule lints given else constructs.
-type MaxPublicStructsRule struct{}
+type MaxPublicStructsRule struct {
+ max int64
+ sync.Mutex
+}
+
+func (r *MaxPublicStructsRule) configure(arguments lint.Arguments) {
+ r.Lock()
+ if r.max < 1 {
+ checkNumberOfArguments(1, arguments, r.Name())
+
+ max, ok := arguments[0].(int64) // Alt. non panicking version
+ if !ok {
+ panic(`invalid value passed as argument number to the "max-public-structs" rule`)
+ }
+ r.max = max
+ }
+ r.Unlock()
+}
// Apply applies the rule to given file.
func (r *MaxPublicStructsRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure {
+ r.configure(arguments)
+
var failures []lint.Failure
fileAst := file.AST
+
walker := &lintMaxPublicStructs{
fileAst: fileAst,
onFailure: func(failure lint.Failure) {
@@ -25,12 +45,7 @@ func (r *MaxPublicStructsRule) Apply(file *lint.File, arguments lint.Arguments)
ast.Walk(walker, fileAst)
- max, ok := arguments[0].(int64) // Alt. non panicking version
- if !ok {
- panic(`invalid value passed as argument number to the "max-public-structs" rule`)
- }
-
- if walker.current > max {
+ if walker.current > r.max {
walker.onFailure(lint.Failure{
Failure: "you have exceeded the maximum number of public struct declarations",
Confidence: 1,
@@ -43,7 +58,7 @@ func (r *MaxPublicStructsRule) Apply(file *lint.File, arguments lint.Arguments)
}
// Name returns the rule name.
-func (r *MaxPublicStructsRule) Name() string {
+func (*MaxPublicStructsRule) Name() string {
return "max-public-structs"
}
@@ -61,7 +76,6 @@ func (w *lintMaxPublicStructs) Visit(n ast.Node) ast.Visitor {
if strings.ToUpper(first) == first {
w.current++
}
- break
}
return w
}
diff --git a/vendor/github.com/mgechev/revive/rule/modifies-param.go b/vendor/github.com/mgechev/revive/rule/modifies-param.go
index 55136e6c8..a68ae2501 100644
--- a/vendor/github.com/mgechev/revive/rule/modifies-param.go
+++ b/vendor/github.com/mgechev/revive/rule/modifies-param.go
@@ -11,7 +11,7 @@ import (
type ModifiesParamRule struct{}
// Apply applies the rule to given file.
-func (r *ModifiesParamRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
+func (*ModifiesParamRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
var failures []lint.Failure
onFailure := func(failure lint.Failure) {
@@ -24,7 +24,7 @@ func (r *ModifiesParamRule) Apply(file *lint.File, _ lint.Arguments) []lint.Fail
}
// Name returns the rule name.
-func (r *ModifiesParamRule) Name() string {
+func (*ModifiesParamRule) Name() string {
return "modifies-parameter"
}
diff --git a/vendor/github.com/mgechev/revive/rule/modifies-value-receiver.go b/vendor/github.com/mgechev/revive/rule/modifies-value-receiver.go
index 4fe22ddf3..34e651557 100644
--- a/vendor/github.com/mgechev/revive/rule/modifies-value-receiver.go
+++ b/vendor/github.com/mgechev/revive/rule/modifies-value-receiver.go
@@ -11,7 +11,7 @@ import (
type ModifiesValRecRule struct{}
// Apply applies the rule to given file.
-func (r *ModifiesValRecRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
+func (*ModifiesValRecRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
var failures []lint.Failure
onFailure := func(failure lint.Failure) {
@@ -26,7 +26,7 @@ func (r *ModifiesValRecRule) Apply(file *lint.File, _ lint.Arguments) []lint.Fai
}
// Name returns the rule name.
-func (r *ModifiesValRecRule) Name() string {
+func (*ModifiesValRecRule) Name() string {
return "modifies-value-receiver"
}
diff --git a/vendor/github.com/mgechev/revive/rule/nested-structs.go b/vendor/github.com/mgechev/revive/rule/nested-structs.go
new file mode 100644
index 000000000..b4f7352db
--- /dev/null
+++ b/vendor/github.com/mgechev/revive/rule/nested-structs.go
@@ -0,0 +1,67 @@
+package rule
+
+import (
+ "go/ast"
+
+ "github.com/mgechev/revive/lint"
+)
+
+// NestedStructs lints nested structs.
+type NestedStructs struct{}
+
+// Apply applies the rule to given file.
+func (*NestedStructs) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
+ var failures []lint.Failure
+
+ walker := &lintNestedStructs{
+ fileAST: file.AST,
+ onFailure: func(failure lint.Failure) {
+ failures = append(failures, failure)
+ },
+ }
+
+ ast.Walk(walker, file.AST)
+
+ return failures
+}
+
+// Name returns the rule name.
+func (*NestedStructs) Name() string {
+ return "nested-structs"
+}
+
+type lintNestedStructs struct {
+ fileAST *ast.File
+ onFailure func(lint.Failure)
+}
+
+func (l *lintNestedStructs) Visit(n ast.Node) ast.Visitor {
+ switch v := n.(type) {
+ case *ast.FuncDecl:
+ if v.Body != nil {
+ ast.Walk(l, v.Body)
+ }
+ return nil
+ case *ast.Field:
+ filter := func(n ast.Node) bool {
+ switch n.(type) {
+ case *ast.StructType:
+ return true
+ default:
+ return false
+ }
+ }
+ structs := pick(v, filter, nil)
+ for _, s := range structs {
+ l.onFailure(lint.Failure{
+ Failure: "no nested structs are allowed",
+ Category: "style",
+ Node: s,
+ Confidence: 1,
+ })
+ }
+ return nil // no need to visit (again) the field
+ }
+
+ return l
+}
diff --git a/vendor/github.com/mgechev/revive/rule/optimize-operands-order.go b/vendor/github.com/mgechev/revive/rule/optimize-operands-order.go
new file mode 100644
index 000000000..88928bb98
--- /dev/null
+++ b/vendor/github.com/mgechev/revive/rule/optimize-operands-order.go
@@ -0,0 +1,77 @@
+package rule
+
+import (
+ "fmt"
+ "go/ast"
+ "go/token"
+
+ "github.com/mgechev/revive/lint"
+)
+
+// OptimizeOperandsOrderRule lints given else constructs.
+type OptimizeOperandsOrderRule struct{}
+
+// Apply applies the rule to given file.
+func (*OptimizeOperandsOrderRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
+ var failures []lint.Failure
+
+ onFailure := func(failure lint.Failure) {
+ failures = append(failures, failure)
+ }
+ w := lintOptimizeOperandsOrderlExpr{
+ onFailure: onFailure,
+ }
+ ast.Walk(w, file.AST)
+ return failures
+}
+
+// Name returns the rule name.
+func (*OptimizeOperandsOrderRule) Name() string {
+ return "optimize-operands-order"
+}
+
+type lintOptimizeOperandsOrderlExpr struct {
+ onFailure func(failure lint.Failure)
+}
+
+// Visit checks boolean AND and OR expressions to determine
+// if swapping their operands may result in an execution speedup.
+func (w lintOptimizeOperandsOrderlExpr) Visit(node ast.Node) ast.Visitor {
+ binExpr, ok := node.(*ast.BinaryExpr)
+ if !ok {
+ return w
+ }
+
+ switch binExpr.Op {
+ case token.LAND, token.LOR:
+ default:
+ return w
+ }
+
+ isCaller := func(n ast.Node) bool {
+ _, ok := n.(*ast.CallExpr)
+ return ok
+ }
+
+ // check if the left sub-expression contains a function call
+ nodes := pick(binExpr.X, isCaller, nil)
+ if len(nodes) < 1 {
+ return w
+ }
+
+ // check if the right sub-expression does not contain a function call
+ nodes = pick(binExpr.Y, isCaller, nil)
+ if len(nodes) > 0 {
+ return w
+ }
+
+ newExpr := ast.BinaryExpr{X: binExpr.Y, Y: binExpr.X, Op: binExpr.Op}
+ w.onFailure(lint.Failure{
+ Failure: fmt.Sprintf("for better performance '%v' might be rewritten as '%v'", gofmt(binExpr), gofmt(&newExpr)),
+ Node: node,
+ Category: "optimization",
+ Confidence: 0.3,
+ })
+
+ return w
+}
diff --git a/vendor/github.com/mgechev/revive/rule/package-comments.go b/vendor/github.com/mgechev/revive/rule/package-comments.go
index 00fc5bb91..33963ab97 100644
--- a/vendor/github.com/mgechev/revive/rule/package-comments.go
+++ b/vendor/github.com/mgechev/revive/rule/package-comments.go
@@ -5,6 +5,7 @@ import (
"go/ast"
"go/token"
"strings"
+ "sync"
"github.com/mgechev/revive/lint"
)
@@ -14,13 +15,15 @@ import (
// This has a notable false positive in that a package comment
// could rightfully appear in a different file of the same package,
// but that's not easy to fix since this linter is file-oriented.
-type PackageCommentsRule struct{}
+type PackageCommentsRule struct {
+ checkPackageCommentCache sync.Map
+}
// Apply applies the rule to given file.
func (r *PackageCommentsRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
var failures []lint.Failure
- if isTest(file) {
+ if file.IsTest() {
return failures
}
@@ -29,13 +32,13 @@ func (r *PackageCommentsRule) Apply(file *lint.File, _ lint.Arguments) []lint.Fa
}
fileAst := file.AST
- w := &lintPackageComments{fileAst, file, onFailure}
+ w := &lintPackageComments{fileAst, file, onFailure, r}
ast.Walk(w, fileAst)
return failures
}
// Name returns the rule name.
-func (r *PackageCommentsRule) Name() string {
+func (*PackageCommentsRule) Name() string {
return "package-comments"
}
@@ -43,6 +46,49 @@ type lintPackageComments struct {
fileAst *ast.File
file *lint.File
onFailure func(lint.Failure)
+ rule *PackageCommentsRule
+}
+
+func (l *lintPackageComments) checkPackageComment() []lint.Failure {
+ // deduplicate warnings in package
+ if _, exists := l.rule.checkPackageCommentCache.LoadOrStore(l.file.Pkg, struct{}{}); exists {
+ return nil
+ }
+ var docFile *ast.File // which name is doc.go
+ var packageFile *ast.File // which name is $package.go
+ var firstFile *ast.File
+ var firstFileName string
+ for name, file := range l.file.Pkg.Files() {
+ if file.AST.Doc != nil {
+ return nil
+ }
+ if name == "doc.go" {
+ docFile = file.AST
+ }
+ if name == file.AST.Name.String()+".go" {
+ packageFile = file.AST
+ }
+ if firstFileName == "" || firstFileName > name {
+ firstFile = file.AST
+ firstFileName = name
+ }
+ }
+ // prefer warning on doc.go, $package.go over first file
+ if docFile == nil {
+ docFile = packageFile
+ }
+ if docFile == nil {
+ docFile = firstFile
+ }
+ if docFile != nil {
+ return []lint.Failure{{
+ Category: "comments",
+ Node: docFile,
+ Confidence: 1,
+ Failure: "should have a package comment",
+ }}
+ }
+ return nil
}
func (l *lintPackageComments) Visit(_ ast.Node) ast.Visitor {
@@ -50,7 +96,6 @@ func (l *lintPackageComments) Visit(_ ast.Node) ast.Visitor {
return nil
}
- const ref = styleGuideBase + "#package-comments"
prefix := "Package " + l.fileAst.Name.Name + " "
// Look for a detached package comment.
@@ -90,12 +135,9 @@ func (l *lintPackageComments) Visit(_ ast.Node) ast.Visitor {
}
if l.fileAst.Doc == nil {
- l.onFailure(lint.Failure{
- Category: "comments",
- Node: l.fileAst,
- Confidence: 0.2,
- Failure: "should have a package comment, unless it's in another file for this package",
- })
+ for _, failure := range l.checkPackageComment() {
+ l.onFailure(failure)
+ }
return nil
}
s := l.fileAst.Doc.Text()
diff --git a/vendor/github.com/mgechev/revive/rule/range-val-address.go b/vendor/github.com/mgechev/revive/rule/range-val-address.go
index 18554825a..51ad8e108 100644
--- a/vendor/github.com/mgechev/revive/rule/range-val-address.go
+++ b/vendor/github.com/mgechev/revive/rule/range-val-address.go
@@ -4,6 +4,7 @@ import (
"fmt"
"go/ast"
"go/token"
+ "strings"
"github.com/mgechev/revive/lint"
)
@@ -12,26 +13,29 @@ import (
type RangeValAddress struct{}
// Apply applies the rule to given file.
-func (r *RangeValAddress) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
+func (*RangeValAddress) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
var failures []lint.Failure
walker := rangeValAddress{
+ file: file,
onFailure: func(failure lint.Failure) {
failures = append(failures, failure)
},
}
+ file.Pkg.TypeCheck()
ast.Walk(walker, file.AST)
return failures
}
// Name returns the rule name.
-func (r *RangeValAddress) Name() string {
+func (*RangeValAddress) Name() string {
return "range-val-address"
}
type rangeValAddress struct {
+ file *lint.File
onFailure func(lint.Failure)
}
@@ -46,17 +50,24 @@ func (w rangeValAddress) Visit(node ast.Node) ast.Visitor {
return w
}
+ valueIsStarExpr := false
+ if t := w.file.Pkg.TypeOf(value); t != nil {
+ valueIsStarExpr = strings.HasPrefix(t.String(), "*")
+ }
+
ast.Walk(rangeBodyVisitor{
- valueID: value.Obj,
- onFailure: w.onFailure,
+ valueIsStarExpr: valueIsStarExpr,
+ valueID: value.Obj,
+ onFailure: w.onFailure,
}, n.Body)
return w
}
type rangeBodyVisitor struct {
- valueID *ast.Object
- onFailure func(lint.Failure)
+ valueIsStarExpr bool
+ valueID *ast.Object
+ onFailure func(lint.Failure)
}
func (bw rangeBodyVisitor) Visit(node ast.Node) ast.Visitor {
@@ -77,31 +88,69 @@ func (bw rangeBodyVisitor) Visit(node ast.Node) ast.Visitor {
for _, exp := range asgmt.Rhs {
switch e := exp.(type) {
- case *ast.UnaryExpr: // e.g. ...&value
+ case *ast.UnaryExpr: // e.g. ...&value, ...&value.id
if bw.isAccessingRangeValueAddress(e) {
bw.onFailure(bw.newFailure(e))
}
case *ast.CallExpr:
if fun, ok := e.Fun.(*ast.Ident); ok && fun.Name == "append" { // e.g. ...append(arr, &value)
for _, v := range e.Args {
- if bw.isAccessingRangeValueAddress(v) {
- bw.onFailure(bw.newFailure(e))
+ if lit, ok := v.(*ast.CompositeLit); ok { // e.g. ...append(arr, v{id:&value})
+ bw.checkCompositeLit(lit)
+ continue
+ }
+ if bw.isAccessingRangeValueAddress(v) { // e.g. ...append(arr, &value)
+ bw.onFailure(bw.newFailure(v))
}
}
}
+ case *ast.CompositeLit: // e.g. ...v{id:&value}
+ bw.checkCompositeLit(e)
}
}
return bw
}
+func (bw rangeBodyVisitor) checkCompositeLit(comp *ast.CompositeLit) {
+ for _, exp := range comp.Elts {
+ e, ok := exp.(*ast.KeyValueExpr)
+ if !ok {
+ continue
+ }
+ if bw.isAccessingRangeValueAddress(e.Value) {
+ bw.onFailure(bw.newFailure(e.Value))
+ }
+ }
+}
+
func (bw rangeBodyVisitor) isAccessingRangeValueAddress(exp ast.Expr) bool {
u, ok := exp.(*ast.UnaryExpr)
if !ok {
return false
}
+ if u.Op != token.AND {
+ return false
+ }
+
v, ok := u.X.(*ast.Ident)
- return ok && u.Op == token.AND && v.Obj == bw.valueID
+ if !ok {
+ var s *ast.SelectorExpr
+ s, ok = u.X.(*ast.SelectorExpr)
+ if !ok {
+ return false
+ }
+ v, ok = s.X.(*ast.Ident)
+ if !ok {
+ return false
+ }
+
+ if bw.valueIsStarExpr { // check type of value
+ return false
+ }
+ }
+
+ return ok && v.Obj == bw.valueID
}
func (bw rangeBodyVisitor) newFailure(node ast.Node) lint.Failure {
diff --git a/vendor/github.com/mgechev/revive/rule/range-val-in-closure.go b/vendor/github.com/mgechev/revive/rule/range-val-in-closure.go
index 857787be3..1e85d0d0d 100644
--- a/vendor/github.com/mgechev/revive/rule/range-val-in-closure.go
+++ b/vendor/github.com/mgechev/revive/rule/range-val-in-closure.go
@@ -11,7 +11,7 @@ import (
type RangeValInClosureRule struct{}
// Apply applies the rule to given file.
-func (r *RangeValInClosureRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
+func (*RangeValInClosureRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
var failures []lint.Failure
walker := rangeValInClosure{
@@ -26,7 +26,7 @@ func (r *RangeValInClosureRule) Apply(file *lint.File, _ lint.Arguments) []lint.
}
// Name returns the rule name.
-func (r *RangeValInClosureRule) Name() string {
+func (*RangeValInClosureRule) Name() string {
return "range-val-in-closure"
}
@@ -35,7 +35,6 @@ type rangeValInClosure struct {
}
func (w rangeValInClosure) Visit(node ast.Node) ast.Visitor {
-
// Find the variables updated by the loop statement.
var vars []*ast.Ident
addVar := func(expr ast.Expr) {
@@ -87,15 +86,25 @@ func (w rangeValInClosure) Visit(node ast.Node) ast.Visitor {
if !ok {
return w
}
+
if lit.Type == nil {
// Not referring to a variable (e.g. struct field name)
return w
}
- ast.Inspect(lit.Body, func(n ast.Node) bool {
+
+ var inspector func(n ast.Node) bool
+ inspector = func(n ast.Node) bool {
+ kv, ok := n.(*ast.KeyValueExpr)
+ if ok {
+ // do not check identifiers acting as key in key-value expressions (see issue #637)
+ ast.Inspect(kv.Value, inspector)
+ return false
+ }
id, ok := n.(*ast.Ident)
if !ok || id.Obj == nil {
return true
}
+
for _, v := range vars {
if v.Obj == id.Obj {
w.onFailure(lint.Failure{
@@ -106,6 +115,7 @@ func (w rangeValInClosure) Visit(node ast.Node) ast.Visitor {
}
}
return true
- })
+ }
+ ast.Inspect(lit.Body, inspector)
return w
}
diff --git a/vendor/github.com/mgechev/revive/rule/range.go b/vendor/github.com/mgechev/revive/rule/range.go
index d18492c71..9d483a673 100644
--- a/vendor/github.com/mgechev/revive/rule/range.go
+++ b/vendor/github.com/mgechev/revive/rule/range.go
@@ -12,7 +12,7 @@ import (
type RangeRule struct{}
// Apply applies the rule to given file.
-func (r *RangeRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
+func (*RangeRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
var failures []lint.Failure
onFailure := func(failure lint.Failure) {
@@ -25,7 +25,7 @@ func (r *RangeRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
}
// Name returns the rule name.
-func (r *RangeRule) Name() string {
+func (*RangeRule) Name() string {
return "range"
}
diff --git a/vendor/github.com/mgechev/revive/rule/receiver-naming.go b/vendor/github.com/mgechev/revive/rule/receiver-naming.go
index 589d5f0ef..d79bb9fe8 100644
--- a/vendor/github.com/mgechev/revive/rule/receiver-naming.go
+++ b/vendor/github.com/mgechev/revive/rule/receiver-naming.go
@@ -4,6 +4,7 @@ import (
"fmt"
"go/ast"
+ "github.com/mgechev/revive/internal/typeparams"
"github.com/mgechev/revive/lint"
)
@@ -11,7 +12,7 @@ import (
type ReceiverNamingRule struct{}
// Apply applies the rule to given file.
-func (r *ReceiverNamingRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
+func (*ReceiverNamingRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
var failures []lint.Failure
fileAst := file.AST
@@ -28,7 +29,7 @@ func (r *ReceiverNamingRule) Apply(file *lint.File, _ lint.Arguments) []lint.Fai
}
// Name returns the rule name.
-func (r *ReceiverNamingRule) Name() string {
+func (*ReceiverNamingRule) Name() string {
return "receiver-naming"
}
@@ -47,7 +48,6 @@ func (w lintReceiverName) Visit(n ast.Node) ast.Visitor {
return w
}
name := names[0].Name
- const ref = styleGuideBase + "#receiver-names"
if name == "_" {
w.onFailure(lint.Failure{
Node: n,
@@ -66,7 +66,7 @@ func (w lintReceiverName) Visit(n ast.Node) ast.Visitor {
})
return w
}
- recv := receiverType(fn)
+ recv := typeparams.ReceiverType(fn)
if prev, ok := w.typeReceiver[recv]; ok && prev != name {
w.onFailure(lint.Failure{
Node: n,
diff --git a/vendor/github.com/mgechev/revive/rule/redefines-builtin-id.go b/vendor/github.com/mgechev/revive/rule/redefines-builtin-id.go
index 947b8aac7..23dd85a7a 100644
--- a/vendor/github.com/mgechev/revive/rule/redefines-builtin-id.go
+++ b/vendor/github.com/mgechev/revive/rule/redefines-builtin-id.go
@@ -2,116 +2,125 @@ package rule
import (
"fmt"
- "github.com/mgechev/revive/lint"
"go/ast"
"go/token"
+
+ "github.com/mgechev/revive/lint"
)
+var builtInConstAndVars = map[string]bool{
+ "true": true,
+ "false": true,
+ "iota": true,
+ "nil": true,
+}
+
+var builtFunctions = map[string]bool{
+ "append": true,
+ "cap": true,
+ "close": true,
+ "complex": true,
+ "copy": true,
+ "delete": true,
+ "imag": true,
+ "len": true,
+ "make": true,
+ "new": true,
+ "panic": true,
+ "print": true,
+ "println": true,
+ "real": true,
+ "recover": true,
+}
+
+var builtInTypes = map[string]bool{
+ "bool": true,
+ "byte": true,
+ "complex128": true,
+ "complex64": true,
+ "error": true,
+ "float32": true,
+ "float64": true,
+ "int": true,
+ "int16": true,
+ "int32": true,
+ "int64": true,
+ "int8": true,
+ "rune": true,
+ "string": true,
+ "uint": true,
+ "uint16": true,
+ "uint32": true,
+ "uint64": true,
+ "uint8": true,
+ "uintptr": true,
+ "any": true,
+}
+
// RedefinesBuiltinIDRule warns when a builtin identifier is shadowed.
type RedefinesBuiltinIDRule struct{}
// Apply applies the rule to given file.
-func (r *RedefinesBuiltinIDRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
+func (*RedefinesBuiltinIDRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
var failures []lint.Failure
- var builtInConstAndVars = map[string]bool{
- "true": true,
- "false": true,
- "iota": true,
- "nil": true,
- }
-
- var builtFunctions = map[string]bool{
- "append": true,
- "cap": true,
- "close": true,
- "complex": true,
- "copy": true,
- "delete": true,
- "imag": true,
- "len": true,
- "make": true,
- "new": true,
- "panic": true,
- "print": true,
- "println": true,
- "real": true,
- "recover": true,
- }
-
- var builtInTypes = map[string]bool{
- "ComplexType": true,
- "FloatType": true,
- "IntegerType": true,
- "Type": true,
- "Type1": true,
- "bool": true,
- "byte": true,
- "complex128": true,
- "complex64": true,
- "error": true,
- "float32": true,
- "float64": true,
- "int": true,
- "int16": true,
- "int32": true,
- "int64": true,
- "int8": true,
- "rune": true,
- "string": true,
- "uint": true,
- "uint16": true,
- "uint32": true,
- "uint64": true,
- "uint8": true,
- "uintptr": true,
- }
-
onFailure := func(failure lint.Failure) {
failures = append(failures, failure)
}
astFile := file.AST
- w := &lintRedefinesBuiltinID{builtInConstAndVars, builtFunctions, builtInTypes, onFailure}
+ w := &lintRedefinesBuiltinID{onFailure}
ast.Walk(w, astFile)
return failures
}
// Name returns the rule name.
-func (r *RedefinesBuiltinIDRule) Name() string {
+func (*RedefinesBuiltinIDRule) Name() string {
return "redefines-builtin-id"
}
type lintRedefinesBuiltinID struct {
- constsAndVars map[string]bool
- funcs map[string]bool
- types map[string]bool
- onFailure func(lint.Failure)
+ onFailure func(lint.Failure)
}
func (w *lintRedefinesBuiltinID) Visit(node ast.Node) ast.Visitor {
switch n := node.(type) {
case *ast.GenDecl:
- if n.Tok != token.TYPE {
- return nil // skip if not type declaration
- }
- typeSpec, ok := n.Specs[0].(*ast.TypeSpec)
- if !ok {
- return nil
- }
- id := typeSpec.Name.Name
- if w.types[id] {
- w.addFailure(n, fmt.Sprintf("redefinition of the built-in type %s", id))
+ switch n.Tok {
+ case token.TYPE:
+ typeSpec, ok := n.Specs[0].(*ast.TypeSpec)
+ if !ok {
+ return nil
+ }
+ id := typeSpec.Name.Name
+ if ok, bt := w.isBuiltIn(id); ok {
+ w.addFailure(n, fmt.Sprintf("redefinition of the built-in %s %s", bt, id))
+ }
+ case token.VAR, token.CONST:
+ for _, vs := range n.Specs {
+ valSpec, ok := vs.(*ast.ValueSpec)
+ if !ok {
+ continue
+ }
+ for _, name := range valSpec.Names {
+ if ok, bt := w.isBuiltIn(name.Name); ok {
+ w.addFailure(n, fmt.Sprintf("redefinition of the built-in %s %s", bt, name))
+ }
+ }
+ }
+ default:
+ return nil // skip if not type/var/const declaration
}
+
case *ast.FuncDecl:
if n.Recv != nil {
return w // skip methods
}
id := n.Name.Name
- if w.funcs[id] {
- w.addFailure(n, fmt.Sprintf("redefinition of the built-in function %s", id))
+ if ok, bt := w.isBuiltIn(id); ok {
+ w.addFailure(n, fmt.Sprintf("redefinition of the built-in %s %s", bt, id))
}
case *ast.AssignStmt:
for _, e := range n.Lhs {
@@ -120,13 +129,19 @@ func (w *lintRedefinesBuiltinID) Visit(node ast.Node) ast.Visitor {
continue
}
- if w.constsAndVars[id.Name] {
+ if ok, bt := w.isBuiltIn(id.Name); ok {
var msg string
- if n.Tok == token.DEFINE {
- msg = fmt.Sprintf("assignment creates a shadow of built-in identifier %s", id.Name)
- } else {
- msg = fmt.Sprintf("assignment modifies built-in identifier %s", id.Name)
+ switch bt {
+ case "constant or variable":
+ if n.Tok == token.DEFINE {
+ msg = fmt.Sprintf("assignment creates a shadow of built-in identifier %s", id.Name)
+ } else {
+ msg = fmt.Sprintf("assignment modifies built-in identifier %s", id.Name)
+ }
+ default:
+ msg = fmt.Sprintf("redefinition of the built-in %s %s", bt, id)
}
+
w.addFailure(n, msg)
}
}
@@ -143,3 +158,19 @@ func (w lintRedefinesBuiltinID) addFailure(node ast.Node, msg string) {
Failure: msg,
})
}
+
+func (lintRedefinesBuiltinID) isBuiltIn(id string) (r bool, builtInKind string) {
+ if builtFunctions[id] {
+ return true, "function"
+ }
+
+ if builtInConstAndVars[id] {
+ return true, "constant or variable"
+ }
+
+ if builtInTypes[id] {
+ return true, "type"
+ }
+
+ return false, ""
+}
diff --git a/vendor/github.com/mgechev/revive/rule/string-format.go b/vendor/github.com/mgechev/revive/rule/string-format.go
new file mode 100644
index 000000000..e7841e8c3
--- /dev/null
+++ b/vendor/github.com/mgechev/revive/rule/string-format.go
@@ -0,0 +1,281 @@
+package rule
+
+import (
+ "fmt"
+ "go/ast"
+ "go/token"
+ "regexp"
+ "strconv"
+
+ "github.com/mgechev/revive/lint"
+)
+
+// #region Revive API
+
+// StringFormatRule lints strings and/or comments according to a set of regular expressions given as Arguments
+type StringFormatRule struct{}
+
+// Apply applies the rule to the given file.
+func (*StringFormatRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure {
+ var failures []lint.Failure
+
+ onFailure := func(failure lint.Failure) {
+ failures = append(failures, failure)
+ }
+
+ w := lintStringFormatRule{onFailure: onFailure}
+ w.parseArguments(arguments)
+ ast.Walk(w, file.AST)
+
+ return failures
+}
+
+// Name returns the rule name.
+func (*StringFormatRule) Name() string {
+ return "string-format"
+}
+
+// ParseArgumentsTest is a public wrapper around w.parseArguments used for testing. Returns the error message provided to panic, or nil if no error was encountered
+func (StringFormatRule) ParseArgumentsTest(arguments lint.Arguments) *string {
+ w := lintStringFormatRule{}
+ c := make(chan interface{})
+ // Parse the arguments in a goroutine, defer a recover() call, return the error encountered (or nil if there was no error)
+ go func() {
+ defer func() {
+ err := recover()
+ c <- err
+ }()
+ w.parseArguments(arguments)
+ }()
+ err := <-c
+ if err != nil {
+ e := fmt.Sprintf("%s", err)
+ return &e
+ }
+ return nil
+}
+
+// #endregion
+
+// #region Internal structure
+
+type lintStringFormatRule struct {
+ onFailure func(lint.Failure)
+ rules []stringFormatSubrule
+}
+
+type stringFormatSubrule struct {
+ parent *lintStringFormatRule
+ scope stringFormatSubruleScope
+ regexp *regexp.Regexp
+ errorMessage string
+}
+
+type stringFormatSubruleScope struct {
+ funcName string // Function name the rule is scoped to
+ argument int // (optional) Which argument in calls to the function is checked against the rule (the first argument is checked by default)
+ field string // (optional) If the argument to be checked is a struct, which member of the struct is checked against the rule (top level members only)
+}
+
+// Regex inserted to match valid function/struct field identifiers
+const identRegex = "[_A-Za-z][_A-Za-z0-9]*"
+
+var parseStringFormatScope = regexp.MustCompile(
+ fmt.Sprintf("^(%s(?:\\.%s)?)(?:\\[([0-9]+)\\](?:\\.(%s))?)?$", identRegex, identRegex, identRegex))
+
+// #endregion
+
+// #region Argument parsing
+
+func (w *lintStringFormatRule) parseArguments(arguments lint.Arguments) {
+ for i, argument := range arguments {
+ scope, regex, errorMessage := w.parseArgument(argument, i)
+ w.rules = append(w.rules, stringFormatSubrule{
+ parent: w,
+ scope: scope,
+ regexp: regex,
+ errorMessage: errorMessage,
+ })
+ }
+}
+
+func (w lintStringFormatRule) parseArgument(argument interface{}, ruleNum int) (scope stringFormatSubruleScope, regex *regexp.Regexp, errorMessage string) {
+ g, ok := argument.([]interface{}) // Cast to generic slice first
+ if !ok {
+ w.configError("argument is not a slice", ruleNum, 0)
+ }
+ if len(g) < 2 {
+ w.configError("less than two slices found in argument, scope and regex are required", ruleNum, len(g)-1)
+ }
+ rule := make([]string, len(g))
+ for i, obj := range g {
+ val, ok := obj.(string)
+ if !ok {
+ w.configError("unexpected value, string was expected", ruleNum, i)
+ }
+ rule[i] = val
+ }
+
+ // Validate scope and regex length
+ if rule[0] == "" {
+ w.configError("empty scope provided", ruleNum, 0)
+ } else if len(rule[1]) < 2 {
+ w.configError("regex is too small (regexes should begin and end with '/')", ruleNum, 1)
+ }
+
+ // Parse rule scope
+ scope = stringFormatSubruleScope{}
+ matches := parseStringFormatScope.FindStringSubmatch(rule[0])
+ if matches == nil {
+ // The rule's scope didn't match the parsing regex at all, probably a configuration error
+ w.parseError("unable to parse rule scope", ruleNum, 0)
+ } else if len(matches) != 4 {
+ // The rule's scope matched the parsing regex, but an unexpected number of submatches was returned, probably a bug
+ w.parseError(fmt.Sprintf("unexpected number of submatches when parsing scope: %d, expected 4", len(matches)), ruleNum, 0)
+ }
+ scope.funcName = matches[1]
+ if len(matches[2]) > 0 {
+ var err error
+ scope.argument, err = strconv.Atoi(matches[2])
+ if err != nil {
+ w.parseError("unable to parse argument number in rule scope", ruleNum, 0)
+ }
+ }
+ if len(matches[3]) > 0 {
+ scope.field = matches[3]
+ }
+
+ // Strip / characters from the beginning and end of rule[1] before compiling
+ regex, err := regexp.Compile(rule[1][1 : len(rule[1])-1])
+ if err != nil {
+ w.parseError(fmt.Sprintf("unable to compile %s as regexp", rule[1]), ruleNum, 1)
+ }
+
+ // Use custom error message if provided
+ if len(rule) == 3 {
+ errorMessage = rule[2]
+ }
+ return scope, regex, errorMessage
+}
+
+// Report an invalid config, this is specifically the user's fault
+func (lintStringFormatRule) configError(msg string, ruleNum, option int) {
+ panic(fmt.Sprintf("invalid configuration for string-format: %s [argument %d, option %d]", msg, ruleNum, option))
+}
+
+// Report a general config parsing failure, this may be the user's fault, but it isn't known for certain
+func (lintStringFormatRule) parseError(msg string, ruleNum, option int) {
+ panic(fmt.Sprintf("failed to parse configuration for string-format: %s [argument %d, option %d]", msg, ruleNum, option))
+}
+
+// #endregion
+
+// #region Node traversal
+
+func (w lintStringFormatRule) Visit(node ast.Node) ast.Visitor {
+ // First, check if node is a call expression
+ call, ok := node.(*ast.CallExpr)
+ if !ok {
+ return w
+ }
+
+ // Get the name of the call expression to check against rule scope
+ callName, ok := w.getCallName(call)
+ if !ok {
+ return w
+ }
+
+ for _, rule := range w.rules {
+ if rule.scope.funcName == callName {
+ rule.Apply(call)
+ }
+ }
+
+ return w
+}
+
+// Return the name of a call expression in the form of package.Func or Func
+func (lintStringFormatRule) getCallName(call *ast.CallExpr) (callName string, ok bool) {
+ if ident, ok := call.Fun.(*ast.Ident); ok {
+ // Local function call
+ return ident.Name, true
+ }
+
+ if selector, ok := call.Fun.(*ast.SelectorExpr); ok {
+ // Scoped function call
+ scope, ok := selector.X.(*ast.Ident)
+ if !ok {
+ return "", false
+ }
+ return scope.Name + "." + selector.Sel.Name, true
+ }
+
+ return "", false
+}
+
+// #endregion
+
+// #region Linting logic
+
+// Apply a single format rule to a call expression (should be done after verifying the that the call expression matches the rule's scope)
+func (r *stringFormatSubrule) Apply(call *ast.CallExpr) {
+ if len(call.Args) <= r.scope.argument {
+ return
+ }
+
+ arg := call.Args[r.scope.argument]
+ var lit *ast.BasicLit
+ if len(r.scope.field) > 0 {
+ // Try finding the scope's Field, treating arg as a composite literal
+ composite, ok := arg.(*ast.CompositeLit)
+ if !ok {
+ return
+ }
+ for _, el := range composite.Elts {
+ kv, ok := el.(*ast.KeyValueExpr)
+ if !ok {
+ continue
+ }
+ key, ok := kv.Key.(*ast.Ident)
+ if !ok || key.Name != r.scope.field {
+ continue
+ }
+
+ // We're now dealing with the exact field in the rule's scope, so if anything fails, we can safely return instead of continuing the loop
+ lit, ok = kv.Value.(*ast.BasicLit)
+ if !ok || lit.Kind != token.STRING {
+ return
+ }
+ }
+ } else {
+ var ok bool
+ // Treat arg as a string literal
+ lit, ok = arg.(*ast.BasicLit)
+ if !ok || lit.Kind != token.STRING {
+ return
+ }
+ }
+ // Unquote the string literal before linting
+ unquoted := lit.Value[1 : len(lit.Value)-1]
+ r.lintMessage(unquoted, lit)
+}
+
+func (r *stringFormatSubrule) lintMessage(s string, node ast.Node) {
+ // Fail if the string doesn't match the user's regex
+ if r.regexp.MatchString(s) {
+ return
+ }
+ var failure string
+ if len(r.errorMessage) > 0 {
+ failure = r.errorMessage
+ } else {
+ failure = fmt.Sprintf("string literal doesn't match user defined regex /%s/", r.regexp.String())
+ }
+ r.parent.onFailure(lint.Failure{
+ Confidence: 1,
+ Failure: failure,
+ Node: node,
+ })
+}
+
+// #endregion
diff --git a/vendor/github.com/mgechev/revive/rule/string-of-int.go b/vendor/github.com/mgechev/revive/rule/string-of-int.go
index 38f453a4a..3bec1d6ac 100644
--- a/vendor/github.com/mgechev/revive/rule/string-of-int.go
+++ b/vendor/github.com/mgechev/revive/rule/string-of-int.go
@@ -11,7 +11,7 @@ import (
type StringOfIntRule struct{}
// Apply applies the rule to given file.
-func (r *StringOfIntRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
+func (*StringOfIntRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
var failures []lint.Failure
onFailure := func(failure lint.Failure) {
@@ -28,7 +28,7 @@ func (r *StringOfIntRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failur
}
// Name returns the rule name.
-func (r *StringOfIntRule) Name() string {
+func (*StringOfIntRule) Name() string {
return "string-of-int"
}
@@ -54,7 +54,7 @@ func (w *lintStringInt) Visit(node ast.Node) ast.Visitor {
w.onFailure(lint.Failure{
Confidence: 1,
Node: ce,
- Failure: "dubious convertion of an integer into a string, use strconv.Itoa",
+ Failure: "dubious conversion of an integer into a string, use strconv.Itoa",
})
return w
diff --git a/vendor/github.com/mgechev/revive/rule/struct-tag.go b/vendor/github.com/mgechev/revive/rule/struct-tag.go
index 57cf8103a..3accf58fb 100644
--- a/vendor/github.com/mgechev/revive/rule/struct-tag.go
+++ b/vendor/github.com/mgechev/revive/rule/struct-tag.go
@@ -14,7 +14,7 @@ import (
type StructTagRule struct{}
// Apply applies the rule to given file.
-func (r *StructTagRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
+func (*StructTagRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
var failures []lint.Failure
onFailure := func(failure lint.Failure) {
@@ -29,13 +29,14 @@ func (r *StructTagRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure
}
// Name returns the rule name.
-func (r *StructTagRule) Name() string {
+func (*StructTagRule) Name() string {
return "struct-tag"
}
type lintStructTagRule struct {
- onFailure func(lint.Failure)
- usedTagNbr map[string]bool // list of used tag numbers
+ onFailure func(lint.Failure)
+ usedTagNbr map[int]bool // list of used tag numbers
+ usedTagName map[string]bool // list of used tag keys
}
func (w lintStructTagRule) Visit(node ast.Node) ast.Visitor {
@@ -44,7 +45,8 @@ func (w lintStructTagRule) Visit(node ast.Node) ast.Visitor {
if n.Fields == nil || n.Fields.NumFields() < 1 {
return nil // skip empty structs
}
- w.usedTagNbr = map[string]bool{} // init
+ w.usedTagNbr = map[int]bool{} // init
+ w.usedTagName = map[string]bool{} // init
for _, f := range n.Fields.List {
if f.Tag != nil {
w.checkTaggedField(f)
@@ -53,7 +55,53 @@ func (w lintStructTagRule) Visit(node ast.Node) ast.Visitor {
}
return w
+}
+
+func (w lintStructTagRule) checkTagNameIfNeed(tag *structtag.Tag) (string, bool) {
+ isUnnamedTag := tag.Name == "" || tag.Name == "-"
+ if isUnnamedTag {
+ return "", true
+ }
+
+ needsToCheckTagName := tag.Key == "bson" ||
+ tag.Key == "json" ||
+ tag.Key == "xml" ||
+ tag.Key == "yaml" ||
+ tag.Key == "protobuf"
+
+ if !needsToCheckTagName {
+ return "", true
+ }
+
+ tagName := w.getTagName(tag)
+ if tagName == "" {
+ return "", true // No tag name found
+ }
+
+ // We concat the key and name as the mapping key here
+ // to allow the same tag name in different tag type.
+ key := tag.Key + ":" + tagName
+ if _, ok := w.usedTagName[key]; ok {
+ return fmt.Sprintf("duplicate tag name: '%s'", tagName), false
+ }
+
+ w.usedTagName[key] = true
+ return "", true
+}
+
+func (lintStructTagRule) getTagName(tag *structtag.Tag) string {
+ switch tag.Key {
+ case "protobuf":
+ for _, option := range tag.Options {
+ if strings.HasPrefix(option, "name=") {
+ return strings.TrimLeft(option, "name=")
+ }
+ }
+ return "" //protobuf tag lacks 'name' option
+ default:
+ return tag.Name
+ }
}
// checkTaggedField checks the tag of the given field.
@@ -70,6 +118,10 @@ func (w lintStructTagRule) checkTaggedField(f *ast.Field) {
}
for _, tag := range tags.Tags() {
+ if msg, ok := w.checkTagNameIfNeed(tag); !ok {
+ w.addFailure(f.Tag, msg)
+ }
+
switch key := tag.Key; key {
case "asn1":
msg, ok := w.checkASN1Tag(f.Type, tag)
@@ -91,7 +143,10 @@ func (w lintStructTagRule) checkTaggedField(f *ast.Field) {
w.addFailure(f.Tag, msg)
}
case "protobuf":
- // Not implemented yet
+ msg, ok := w.checkProtobufTag(tag)
+ if !ok {
+ w.addFailure(f.Tag, msg)
+ }
case "required":
if tag.Name != "true" && tag.Name != "false" {
w.addFailure(f.Tag, "required should be 'true' or 'false'")
@@ -122,10 +177,14 @@ func (w lintStructTagRule) checkASN1Tag(t ast.Expr, tag *structtag.Tag) (string,
if strings.HasPrefix(opt, "tag:") {
parts := strings.Split(opt, ":")
tagNumber := parts[1]
- if w.usedTagNbr[tagNumber] {
- return fmt.Sprintf("duplicated tag number %s", tagNumber), false
+ number, err := strconv.Atoi(tagNumber)
+ if err != nil {
+ return fmt.Sprintf("ASN1 tag must be a number, got '%s'", tagNumber), false
+ }
+ if w.usedTagNbr[number] {
+ return fmt.Sprintf("duplicated tag number %v", number), false
}
- w.usedTagNbr[tagNumber] = true
+ w.usedTagNbr[number] = true
continue
}
@@ -149,7 +208,7 @@ func (w lintStructTagRule) checkASN1Tag(t ast.Expr, tag *structtag.Tag) (string,
return "", true
}
-func (w lintStructTagRule) checkBSONTag(options []string) (string, bool) {
+func (lintStructTagRule) checkBSONTag(options []string) (string, bool) {
for _, opt := range options {
switch opt {
case "inline", "minsize", "omitempty":
@@ -161,14 +220,14 @@ func (w lintStructTagRule) checkBSONTag(options []string) (string, bool) {
return "", true
}
-func (w lintStructTagRule) checkJSONTag(name string, options []string) (string, bool) {
+func (lintStructTagRule) checkJSONTag(name string, options []string) (string, bool) {
for _, opt := range options {
switch opt {
case "omitempty", "string":
case "":
// special case for JSON key "-"
if name != "-" {
- return "option can not be empty in JSON tag", false
+ return "option can not be empty in JSON tag", false
}
default:
return fmt.Sprintf("unknown option '%s' in JSON tag", opt), false
@@ -178,7 +237,7 @@ func (w lintStructTagRule) checkJSONTag(name string, options []string) (string,
return "", true
}
-func (w lintStructTagRule) checkXMLTag(options []string) (string, bool) {
+func (lintStructTagRule) checkXMLTag(options []string) (string, bool) {
for _, opt := range options {
switch opt {
case "any", "attr", "cdata", "chardata", "comment", "innerxml", "omitempty", "typeattr":
@@ -190,7 +249,7 @@ func (w lintStructTagRule) checkXMLTag(options []string) (string, bool) {
return "", true
}
-func (w lintStructTagRule) checkYAMLTag(options []string) (string, bool) {
+func (lintStructTagRule) checkYAMLTag(options []string) (string, bool) {
for _, opt := range options {
switch opt {
case "flow", "inline", "omitempty":
@@ -202,7 +261,7 @@ func (w lintStructTagRule) checkYAMLTag(options []string) (string, bool) {
return "", true
}
-func (w lintStructTagRule) typeValueMatch(t ast.Expr, val string) bool {
+func (lintStructTagRule) typeValueMatch(t ast.Expr, val string) bool {
tID, ok := t.(*ast.Ident)
if !ok {
return true
@@ -227,6 +286,57 @@ func (w lintStructTagRule) typeValueMatch(t ast.Expr, val string) bool {
return typeMatches
}
+func (w lintStructTagRule) checkProtobufTag(tag *structtag.Tag) (string, bool) {
+ // check name
+ switch tag.Name {
+ case "bytes", "fixed32", "fixed64", "group", "varint", "zigzag32", "zigzag64":
+ // do nothing
+ default:
+ return fmt.Sprintf("invalid protobuf tag name '%s'", tag.Name), false
+ }
+
+ // check options
+ seenOptions := map[string]bool{}
+ for _, opt := range tag.Options {
+ if number, err := strconv.Atoi(opt); err == nil {
+ _, alreadySeen := w.usedTagNbr[number]
+ if alreadySeen {
+ return fmt.Sprintf("duplicated tag number %v", number), false
+ }
+ w.usedTagNbr[number] = true
+ continue // option is an integer
+ }
+
+ switch {
+ case opt == "opt" || opt == "proto3" || opt == "rep" || opt == "req":
+ // do nothing
+ case strings.Contains(opt, "="):
+ o := strings.Split(opt, "=")[0]
+ _, alreadySeen := seenOptions[o]
+ if alreadySeen {
+ return fmt.Sprintf("protobuf tag has duplicated option '%s'", o), false
+ }
+ seenOptions[o] = true
+ continue
+ }
+ }
+ _, hasName := seenOptions["name"]
+ if !hasName {
+ return "protobuf tag lacks mandatory option 'name'", false
+ }
+
+ for k := range seenOptions {
+ switch k {
+ case "name", "json":
+ // do nothing
+ default:
+ return fmt.Sprintf("unknown option '%s' in protobuf tag", k), false
+ }
+ }
+
+ return "", true
+}
+
func (w lintStructTagRule) addFailure(n ast.Node, msg string) {
w.onFailure(lint.Failure{
Node: n,
diff --git a/vendor/github.com/mgechev/revive/rule/superfluous-else.go b/vendor/github.com/mgechev/revive/rule/superfluous-else.go
index c29be9e0d..a9e4380c9 100644
--- a/vendor/github.com/mgechev/revive/rule/superfluous-else.go
+++ b/vendor/github.com/mgechev/revive/rule/superfluous-else.go
@@ -12,15 +12,15 @@ import (
type SuperfluousElseRule struct{}
// Apply applies the rule to given file.
-func (r *SuperfluousElseRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
+func (*SuperfluousElseRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
var failures []lint.Failure
onFailure := func(failure lint.Failure) {
failures = append(failures, failure)
}
- var branchingFunctions = map[string]map[string]bool{
- "os": map[string]bool{"Exit": true},
- "log": map[string]bool{
+ branchingFunctions := map[string]map[string]bool{
+ "os": {"Exit": true},
+ "log": {
"Fatal": true,
"Fatalf": true,
"Fatalln": true,
@@ -36,7 +36,7 @@ func (r *SuperfluousElseRule) Apply(file *lint.File, _ lint.Arguments) []lint.Fa
}
// Name returns the rule name.
-func (r *SuperfluousElseRule) Name() string {
+func (*SuperfluousElseRule) Name() string {
return "superfluous-else"
}
@@ -82,9 +82,9 @@ func (w lintSuperfluousElse) Visit(node ast.Node) ast.Visitor {
lastStmt := ifStmt.Body.List[len(ifStmt.Body.List)-1]
switch stmt := lastStmt.(type) {
case *ast.BranchStmt:
- token := stmt.Tok.String()
- if token != "fallthrough" {
- w.onFailure(newFailure(ifStmt.Else, "if block ends with a "+token+" statement, so drop this else and outdent its block"+extra))
+ tok := stmt.Tok.String()
+ if tok != "fallthrough" {
+ w.onFailure(newFailure(ifStmt.Else, "if block ends with a "+tok+" statement, so drop this else and outdent its block"+extra))
}
case *ast.ExprStmt:
if ce, ok := stmt.X.(*ast.CallExpr); ok { // it's a function call
diff --git a/vendor/github.com/mgechev/revive/rule/time-equal.go b/vendor/github.com/mgechev/revive/rule/time-equal.go
new file mode 100644
index 000000000..72ecf26fe
--- /dev/null
+++ b/vendor/github.com/mgechev/revive/rule/time-equal.go
@@ -0,0 +1,76 @@
+package rule
+
+import (
+ "fmt"
+ "go/ast"
+ "go/token"
+
+ "github.com/mgechev/revive/lint"
+)
+
+// TimeEqualRule shows where "==" and "!=" used for equality check time.Time
+type TimeEqualRule struct{}
+
+// Apply applies the rule to given file.
+func (*TimeEqualRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
+ var failures []lint.Failure
+
+ onFailure := func(failure lint.Failure) {
+ failures = append(failures, failure)
+ }
+
+ w := &lintTimeEqual{file, onFailure}
+ if w.file.Pkg.TypeCheck() != nil {
+ return nil
+ }
+
+ ast.Walk(w, file.AST)
+ return failures
+}
+
+// Name returns the rule name.
+func (*TimeEqualRule) Name() string {
+ return "time-equal"
+}
+
+type lintTimeEqual struct {
+ file *lint.File
+ onFailure func(lint.Failure)
+}
+
+func (l *lintTimeEqual) Visit(node ast.Node) ast.Visitor {
+ expr, ok := node.(*ast.BinaryExpr)
+ if !ok {
+ return l
+ }
+
+ switch expr.Op {
+ case token.EQL, token.NEQ:
+ default:
+ return l
+ }
+
+ xtyp := l.file.Pkg.TypeOf(expr.X)
+ ytyp := l.file.Pkg.TypeOf(expr.Y)
+
+ if !isNamedType(xtyp, "time", "Time") || !isNamedType(ytyp, "time", "Time") {
+ return l
+ }
+
+ var failure string
+ switch expr.Op {
+ case token.EQL:
+ failure = fmt.Sprintf("use %s.Equal(%s) instead of %q operator", expr.X, expr.Y, expr.Op)
+ case token.NEQ:
+ failure = fmt.Sprintf("use !%s.Equal(%s) instead of %q operator", expr.X, expr.Y, expr.Op)
+ }
+
+ l.onFailure(lint.Failure{
+ Category: "time",
+ Confidence: 1,
+ Node: node,
+ Failure: failure,
+ })
+
+ return l
+}
diff --git a/vendor/github.com/mgechev/revive/rule/time-naming.go b/vendor/github.com/mgechev/revive/rule/time-naming.go
index a93f4b5ae..cea452e61 100644
--- a/vendor/github.com/mgechev/revive/rule/time-naming.go
+++ b/vendor/github.com/mgechev/revive/rule/time-naming.go
@@ -13,7 +13,7 @@ import (
type TimeNamingRule struct{}
// Apply applies the rule to given file.
-func (r *TimeNamingRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
+func (*TimeNamingRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
var failures []lint.Failure
onFailure := func(failure lint.Failure) {
@@ -28,7 +28,7 @@ func (r *TimeNamingRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure
}
// Name returns the rule name.
-func (r *TimeNamingRule) Name() string {
+func (*TimeNamingRule) Name() string {
return "time-naming"
}
@@ -76,10 +76,12 @@ func (w *lintTimeNames) Visit(node ast.Node) ast.Visitor {
// timeSuffixes is a list of name suffixes that imply a time unit.
// This is not an exhaustive list.
var timeSuffixes = []string{
- "Sec", "Secs", "Seconds",
+ "Hour", "Hours",
+ "Min", "Mins", "Minutes", "Minute",
+ "Sec", "Secs", "Seconds", "Second",
"Msec", "Msecs",
- "Milli", "Millis", "Milliseconds",
- "Usec", "Usecs", "Microseconds",
+ "Milli", "Millis", "Milliseconds", "Millisecond",
+ "Usec", "Usecs", "Microseconds", "Microsecond",
"MS", "Ms",
}
diff --git a/vendor/github.com/mgechev/revive/rule/unconditional-recursion.go b/vendor/github.com/mgechev/revive/rule/unconditional-recursion.go
index c06626b5a..f0e83b0ce 100644
--- a/vendor/github.com/mgechev/revive/rule/unconditional-recursion.go
+++ b/vendor/github.com/mgechev/revive/rule/unconditional-recursion.go
@@ -10,7 +10,7 @@ import (
type UnconditionalRecursionRule struct{}
// Apply applies the rule to given file.
-func (r *UnconditionalRecursionRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
+func (*UnconditionalRecursionRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
var failures []lint.Failure
onFailure := func(failure lint.Failure) {
@@ -23,7 +23,7 @@ func (r *UnconditionalRecursionRule) Apply(file *lint.File, _ lint.Arguments) []
}
// Name returns the rule name.
-func (r *UnconditionalRecursionRule) Name() string {
+func (*UnconditionalRecursionRule) Name() string {
return "unconditional-recursion"
}
@@ -61,8 +61,10 @@ func (w lintUnconditionalRecursionRule) Visit(node ast.Node) ast.Visitor {
case *ast.FuncDecl:
var rec *ast.Ident
switch {
- case n.Recv == nil || n.Recv.NumFields() < 1 || len(n.Recv.List[0].Names) < 1:
+ case n.Recv == nil:
rec = nil
+ case n.Recv.NumFields() < 1 || len(n.Recv.List[0].Names) < 1:
+ rec = &ast.Ident{Name: "_"}
default:
rec = n.Recv.List[0].Names[0]
}
@@ -137,9 +139,9 @@ func (w *lintUnconditionalRecursionRule) updateFuncStatus(node ast.Node) {
}
var exitFunctions = map[string]map[string]bool{
- "os": map[string]bool{"Exit": true},
- "syscall": map[string]bool{"Exit": true},
- "log": map[string]bool{
+ "os": {"Exit": true},
+ "syscall": {"Exit": true},
+ "log": {
"Fatal": true,
"Fatalf": true,
"Fatalln": true,
@@ -149,7 +151,7 @@ var exitFunctions = map[string]map[string]bool{
},
}
-func (w *lintUnconditionalRecursionRule) hasControlExit(node ast.Node) bool {
+func (lintUnconditionalRecursionRule) hasControlExit(node ast.Node) bool {
// isExit returns true if the given node makes control exit the function
isExit := func(node ast.Node) bool {
switch n := node.(type) {
diff --git a/vendor/github.com/mgechev/revive/rule/unexported-naming.go b/vendor/github.com/mgechev/revive/rule/unexported-naming.go
index 96cec3e46..0c2b39d41 100644
--- a/vendor/github.com/mgechev/revive/rule/unexported-naming.go
+++ b/vendor/github.com/mgechev/revive/rule/unexported-naming.go
@@ -12,7 +12,7 @@ import (
type UnexportedNamingRule struct{}
// Apply applies the rule to given file.
-func (r *UnexportedNamingRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
+func (*UnexportedNamingRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
var failures []lint.Failure
onFailure := func(failure lint.Failure) {
failures = append(failures, failure)
@@ -25,7 +25,7 @@ func (r *UnexportedNamingRule) Apply(file *lint.File, _ lint.Arguments) []lint.F
}
// Name returns the rule name.
-func (r *UnexportedNamingRule) Name() string {
+func (*UnexportedNamingRule) Name() string {
return "unexported-naming"
}
diff --git a/vendor/github.com/mgechev/revive/rule/unexported-return.go b/vendor/github.com/mgechev/revive/rule/unexported-return.go
index c9c8a41d3..10f8e3fbe 100644
--- a/vendor/github.com/mgechev/revive/rule/unexported-return.go
+++ b/vendor/github.com/mgechev/revive/rule/unexported-return.go
@@ -5,6 +5,7 @@ import (
"go/ast"
"go/types"
+ "github.com/mgechev/revive/internal/typeparams"
"github.com/mgechev/revive/lint"
)
@@ -12,7 +13,7 @@ import (
type UnexportedReturnRule struct{}
// Apply applies the rule to given file.
-func (r *UnexportedReturnRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
+func (*UnexportedReturnRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
var failures []lint.Failure
fileAst := file.AST
@@ -31,7 +32,7 @@ func (r *UnexportedReturnRule) Apply(file *lint.File, _ lint.Arguments) []lint.F
}
// Name returns the rule name.
-func (r *UnexportedReturnRule) Name() string {
+func (*UnexportedReturnRule) Name() string {
return "unexported-return"
}
@@ -55,7 +56,7 @@ func (w lintUnexportedReturn) Visit(n ast.Node) ast.Visitor {
thing := "func"
if fn.Recv != nil && len(fn.Recv.List) > 0 {
thing = "method"
- if !ast.IsExported(receiverType(fn)) {
+ if !ast.IsExported(typeparams.ReceiverType(fn)) {
// Don't report exported methods of unexported types,
// such as private implementations of sort.Interface.
return nil
@@ -82,24 +83,24 @@ func (w lintUnexportedReturn) Visit(n ast.Node) ast.Visitor {
// It is imprecise, and will err on the side of returning true,
// such as for composite types.
func exportedType(typ types.Type) bool {
- switch T := typ.(type) {
+ switch t := typ.(type) {
case *types.Named:
- obj := T.Obj()
+ obj := t.Obj()
switch {
// Builtin types have no package.
case obj.Pkg() == nil:
case obj.Exported():
default:
- _, ok := T.Underlying().(*types.Interface)
+ _, ok := t.Underlying().(*types.Interface)
return ok
}
return true
case *types.Map:
- return exportedType(T.Key()) && exportedType(T.Elem())
+ return exportedType(t.Key()) && exportedType(t.Elem())
case interface {
Elem() types.Type
}: // array, slice, pointer, chan
- return exportedType(T.Elem())
+ return exportedType(t.Elem())
}
// Be conservative about other types, such as struct, interface, etc.
return true
diff --git a/vendor/github.com/mgechev/revive/rule/unhandled-error.go b/vendor/github.com/mgechev/revive/rule/unhandled-error.go
index 0e2f62875..6cde24b7f 100644
--- a/vendor/github.com/mgechev/revive/rule/unhandled-error.go
+++ b/vendor/github.com/mgechev/revive/rule/unhandled-error.go
@@ -4,32 +4,44 @@ import (
"fmt"
"go/ast"
"go/types"
+ "sync"
"github.com/mgechev/revive/lint"
)
// UnhandledErrorRule lints given else constructs.
-type UnhandledErrorRule struct{}
+type UnhandledErrorRule struct {
+ ignoreList ignoreListType
+ sync.Mutex
+}
type ignoreListType map[string]struct{}
-// Apply applies the rule to given file.
-func (r *UnhandledErrorRule) Apply(file *lint.File, args lint.Arguments) []lint.Failure {
- var failures []lint.Failure
+func (r *UnhandledErrorRule) configure(arguments lint.Arguments) {
+ r.Lock()
+ if r.ignoreList == nil {
+ r.ignoreList = make(ignoreListType, len(arguments))
- ignoreList := make(ignoreListType, len(args))
+ for _, arg := range arguments {
+ argStr, ok := arg.(string)
+ if !ok {
+ panic(fmt.Sprintf("Invalid argument to the unhandled-error rule. Expecting a string, got %T", arg))
+ }
- for _, arg := range args {
- argStr, ok := arg.(string)
- if !ok {
- panic(fmt.Sprintf("Invalid argument to the unhandled-error rule. Expecting a string, got %T", arg))
+ r.ignoreList[argStr] = struct{}{}
}
-
- ignoreList[argStr] = struct{}{}
}
+ r.Unlock()
+}
+
+// Apply applies the rule to given file.
+func (r *UnhandledErrorRule) Apply(file *lint.File, args lint.Arguments) []lint.Failure {
+ r.configure(args)
+
+ var failures []lint.Failure
walker := &lintUnhandledErrors{
- ignoreList: ignoreList,
+ ignoreList: r.ignoreList,
pkg: file.Pkg,
onFailure: func(failure lint.Failure) {
failures = append(failures, failure)
@@ -43,7 +55,7 @@ func (r *UnhandledErrorRule) Apply(file *lint.File, args lint.Arguments) []lint.
}
// Name returns the rule name.
-func (r *UnhandledErrorRule) Name() string {
+func (*UnhandledErrorRule) Name() string {
return "unhandled-error"
}
diff --git a/vendor/github.com/mgechev/revive/rule/unnecessary-stmt.go b/vendor/github.com/mgechev/revive/rule/unnecessary-stmt.go
index 732d8a8bb..8e0784ba4 100644
--- a/vendor/github.com/mgechev/revive/rule/unnecessary-stmt.go
+++ b/vendor/github.com/mgechev/revive/rule/unnecessary-stmt.go
@@ -11,7 +11,7 @@ import (
type UnnecessaryStmtRule struct{}
// Apply applies the rule to given file.
-func (r *UnnecessaryStmtRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
+func (*UnnecessaryStmtRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
var failures []lint.Failure
onFailure := func(failure lint.Failure) {
failures = append(failures, failure)
@@ -23,7 +23,7 @@ func (r *UnnecessaryStmtRule) Apply(file *lint.File, _ lint.Arguments) []lint.Fa
}
// Name returns the rule name.
-func (r *UnnecessaryStmtRule) Name() string {
+func (*UnnecessaryStmtRule) Name() string {
return "unnecessary-stmt"
}
diff --git a/vendor/github.com/mgechev/revive/rule/unreachable-code.go b/vendor/github.com/mgechev/revive/rule/unreachable-code.go
index c81e9e733..dcc5b7905 100644
--- a/vendor/github.com/mgechev/revive/rule/unreachable-code.go
+++ b/vendor/github.com/mgechev/revive/rule/unreachable-code.go
@@ -10,15 +10,20 @@ import (
type UnreachableCodeRule struct{}
// Apply applies the rule to given file.
-func (r *UnreachableCodeRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
+func (*UnreachableCodeRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
var failures []lint.Failure
onFailure := func(failure lint.Failure) {
failures = append(failures, failure)
}
- var branchingFunctions = map[string]map[string]bool{
- "os": map[string]bool{"Exit": true},
- "log": map[string]bool{
+ testingFunctions := map[string]bool{
+ "Fatal": true,
+ "Fatalf": true,
+ "FailNow": true,
+ }
+ branchingFunctions := map[string]map[string]bool{
+ "os": {"Exit": true},
+ "log": {
"Fatal": true,
"Fatalf": true,
"Fatalln": true,
@@ -26,6 +31,9 @@ func (r *UnreachableCodeRule) Apply(file *lint.File, _ lint.Arguments) []lint.Fa
"Panicf": true,
"Panicln": true,
},
+ "t": testingFunctions,
+ "b": testingFunctions,
+ "f": testingFunctions,
}
w := lintUnreachableCode{onFailure, branchingFunctions}
@@ -34,7 +42,7 @@ func (r *UnreachableCodeRule) Apply(file *lint.File, _ lint.Arguments) []lint.Fa
}
// Name returns the rule name.
-func (r *UnreachableCodeRule) Name() string {
+func (*UnreachableCodeRule) Name() string {
return "unreachable-code"
}
diff --git a/vendor/github.com/mgechev/revive/rule/unused-param.go b/vendor/github.com/mgechev/revive/rule/unused-param.go
index 60df908d3..ab3da453e 100644
--- a/vendor/github.com/mgechev/revive/rule/unused-param.go
+++ b/vendor/github.com/mgechev/revive/rule/unused-param.go
@@ -11,7 +11,7 @@ import (
type UnusedParamRule struct{}
// Apply applies the rule to given file.
-func (r *UnusedParamRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
+func (*UnusedParamRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
var failures []lint.Failure
onFailure := func(failure lint.Failure) {
@@ -26,7 +26,7 @@ func (r *UnusedParamRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failur
}
// Name returns the rule name.
-func (r *UnusedParamRule) Name() string {
+func (*UnusedParamRule) Name() string {
return "unused-parameter"
}
diff --git a/vendor/github.com/mgechev/revive/rule/use-any.go b/vendor/github.com/mgechev/revive/rule/use-any.go
new file mode 100644
index 000000000..bdf3c936d
--- /dev/null
+++ b/vendor/github.com/mgechev/revive/rule/use-any.go
@@ -0,0 +1,54 @@
+package rule
+
+import (
+ "go/ast"
+
+ "github.com/mgechev/revive/lint"
+)
+
+// UseAnyRule lints given else constructs.
+type UseAnyRule struct{}
+
+// Apply applies the rule to given file.
+func (*UseAnyRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
+ var failures []lint.Failure
+
+ walker := lintUseAny{
+ onFailure: func(failure lint.Failure) {
+ failures = append(failures, failure)
+ },
+ }
+ fileAst := file.AST
+ ast.Walk(walker, fileAst)
+
+ return failures
+}
+
+// Name returns the rule name.
+func (*UseAnyRule) Name() string {
+ return "use-any"
+}
+
+type lintUseAny struct {
+ onFailure func(lint.Failure)
+}
+
+func (w lintUseAny) Visit(n ast.Node) ast.Visitor {
+ it, ok := n.(*ast.InterfaceType)
+ if !ok {
+ return w
+ }
+
+ if len(it.Methods.List) != 0 {
+ return w // it is not and empty interface
+ }
+
+ w.onFailure(lint.Failure{
+ Node: n,
+ Confidence: 1,
+ Category: "naming",
+ Failure: "since GO 1.18 'interface{}' can be replaced by 'any'",
+ })
+
+ return w
+}
diff --git a/vendor/github.com/mgechev/revive/rule/useless-break.go b/vendor/github.com/mgechev/revive/rule/useless-break.go
new file mode 100644
index 000000000..8db20c9b8
--- /dev/null
+++ b/vendor/github.com/mgechev/revive/rule/useless-break.go
@@ -0,0 +1,82 @@
+package rule
+
+import (
+ "go/ast"
+ "go/token"
+
+ "github.com/mgechev/revive/lint"
+)
+
+// UselessBreak lint rule.
+type UselessBreak struct{}
+
+// Apply applies the rule to given file.
+func (*UselessBreak) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
+ var failures []lint.Failure
+
+ onFailure := func(failure lint.Failure) {
+ failures = append(failures, failure)
+ }
+
+ astFile := file.AST
+ w := &lintUselessBreak{onFailure, false}
+ ast.Walk(w, astFile)
+ return failures
+}
+
+// Name returns the rule name.
+func (*UselessBreak) Name() string {
+ return "useless-break"
+}
+
+type lintUselessBreak struct {
+ onFailure func(lint.Failure)
+ inLoopBody bool
+}
+
+func (w *lintUselessBreak) Visit(node ast.Node) ast.Visitor {
+ switch v := node.(type) {
+ case *ast.ForStmt:
+ w.inLoopBody = true
+ ast.Walk(w, v.Body)
+ w.inLoopBody = false
+ return nil
+ case *ast.RangeStmt:
+ w.inLoopBody = true
+ ast.Walk(w, v.Body)
+ w.inLoopBody = false
+ return nil
+ case *ast.CommClause:
+ for _, n := range v.Body {
+ w.inspectCaseStatement(n)
+ }
+ return nil
+ case *ast.CaseClause:
+ for _, n := range v.Body {
+ w.inspectCaseStatement(n)
+ }
+ return nil
+ }
+ return w
+}
+
+func (w *lintUselessBreak) inspectCaseStatement(n ast.Stmt) {
+ switch s := n.(type) {
+ case *ast.BranchStmt:
+ if s.Tok != token.BREAK {
+ return // not a break statement
+ }
+ if s.Label != nil {
+ return // labeled break statement, usually affects a nesting loop
+ }
+ msg := "useless break in case clause"
+ if w.inLoopBody {
+ msg += " (WARN: this break statement affects this switch or select statement and not the loop enclosing it)"
+ }
+ w.onFailure(lint.Failure{
+ Confidence: 1,
+ Node: s,
+ Failure: msg,
+ })
+ }
+}
diff --git a/vendor/github.com/mgechev/revive/rule/utils.go b/vendor/github.com/mgechev/revive/rule/utils.go
index 38677c839..dca1674ca 100644
--- a/vendor/github.com/mgechev/revive/rule/utils.go
+++ b/vendor/github.com/mgechev/revive/rule/utils.go
@@ -13,35 +13,17 @@ import (
"github.com/mgechev/revive/lint"
)
-const styleGuideBase = "https://golang.org/wiki/CodeReviewComments"
-
// isBlank returns whether id is the blank identifier "_".
// If id == nil, the answer is false.
func isBlank(id *ast.Ident) bool { return id != nil && id.Name == "_" }
-func isTest(f *lint.File) bool {
- return strings.HasSuffix(f.Name, "_test.go")
-}
-
var commonMethods = map[string]bool{
"Error": true,
"Read": true,
"ServeHTTP": true,
"String": true,
"Write": true,
-}
-
-func receiverType(fn *ast.FuncDecl) string {
- switch e := fn.Recv.List[0].Type.(type) {
- case *ast.Ident:
- return e.Name
- case *ast.StarExpr:
- if id, ok := e.X.(*ast.Ident); ok {
- return id.Name
- }
- }
- // The parser accepts much more than just the legal forms.
- return "invalid-type"
+ "Unwrap": true,
}
var knownNameExceptions = map[string]bool{
@@ -85,12 +67,13 @@ var zeroLiteral = map[string]bool{
"0i": true,
}
-func validType(T types.Type) bool {
- return T != nil &&
- T != types.Typ[types.Invalid] &&
- !strings.Contains(T.String(), "invalid type") // good but not foolproof
+func validType(t types.Type) bool {
+ return t != nil &&
+ t != types.Typ[types.Invalid] &&
+ !strings.Contains(t.String(), "invalid type") // good but not foolproof
}
+// isPkgDot checks if the expression is <pkg>.<name>
func isPkgDot(expr ast.Expr, pkg, name string) bool {
sel, ok := expr.(*ast.SelectorExpr)
return ok && isIdent(sel.X, pkg) && isIdent(sel.Sel, name)
@@ -110,7 +93,7 @@ func srcLine(src []byte, p token.Position) string {
// pick yields a list of nodes by picking them from a sub-ast with root node n.
// Nodes are selected by applying the fselect function
-// f function is applied to each selected node before inseting it in the final result.
+// f function is applied to each selected node before inserting it in the final result.
// If f==nil then it defaults to the identity function (ie it returns the node itself)
func pick(n ast.Node, fselect func(n ast.Node) bool, f func(n ast.Node) []ast.Node) []ast.Node {
var result []ast.Node
@@ -131,14 +114,6 @@ func pick(n ast.Node, fselect func(n ast.Node) bool, f func(n ast.Node) []ast.No
return result
}
-func pickFromExpList(l []ast.Expr, fselect func(n ast.Node) bool, f func(n ast.Node) []ast.Node) []ast.Node {
- result := make([]ast.Node, 0)
- for _, e := range l {
- result = append(result, pick(e, fselect, f)...)
- }
- return result
-}
-
type picker struct {
fselect func(n ast.Node) bool
onSelect func(n ast.Node)
@@ -189,3 +164,10 @@ func gofmt(x interface{}) string {
printer.Fprint(&buf, fs, x)
return buf.String()
}
+
+// checkNumberOfArguments fails if the given number of arguments is not, at least, the expected one
+func checkNumberOfArguments(expected int, args lint.Arguments, ruleName string) {
+ if len(args) < expected {
+ panic(fmt.Sprintf("not enough arguments for %s rule, expected %d, got %d. Please check the rule's documentation", ruleName, expected, len(args)))
+ }
+}
diff --git a/vendor/github.com/mgechev/revive/rule/var-declarations.go b/vendor/github.com/mgechev/revive/rule/var-declarations.go
index 441132115..a15ff1eb4 100644
--- a/vendor/github.com/mgechev/revive/rule/var-declarations.go
+++ b/vendor/github.com/mgechev/revive/rule/var-declarations.go
@@ -13,7 +13,7 @@ import (
type VarDeclarationsRule struct{}
// Apply applies the rule to given file.
-func (r *VarDeclarationsRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
+func (*VarDeclarationsRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
var failures []lint.Failure
fileAst := file.AST
@@ -32,7 +32,7 @@ func (r *VarDeclarationsRule) Apply(file *lint.File, _ lint.Arguments) []lint.Fa
}
// Name returns the rule name.
-func (r *VarDeclarationsRule) Name() string {
+func (*VarDeclarationsRule) Name() string {
return "var-declaration"
}
diff --git a/vendor/github.com/mgechev/revive/rule/var-naming.go b/vendor/github.com/mgechev/revive/rule/var-naming.go
index 768f65b96..3c0c19cdf 100644
--- a/vendor/github.com/mgechev/revive/rule/var-naming.go
+++ b/vendor/github.com/mgechev/revive/rule/var-naming.go
@@ -5,34 +5,47 @@ import (
"go/ast"
"go/token"
"strings"
+ "sync"
"github.com/mgechev/revive/lint"
)
// VarNamingRule lints given else constructs.
-type VarNamingRule struct{}
-
-// Apply applies the rule to given file.
-func (r *VarNamingRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure {
- var failures []lint.Failure
+type VarNamingRule struct {
+ configured bool
+ whitelist []string
+ blacklist []string
+ sync.Mutex
+}
- var whitelist []string
- var blacklist []string
+func (r *VarNamingRule) configure(arguments lint.Arguments) {
+ r.Lock()
+ if !r.configured {
+ if len(arguments) >= 1 {
+ r.whitelist = getList(arguments[0], "whitelist")
+ }
- if len(arguments) >= 1 {
- whitelist = getList(arguments[0], "whitelist")
+ if len(arguments) >= 2 {
+ r.blacklist = getList(arguments[1], "blacklist")
+ }
+ r.configured = true
}
+ r.Unlock()
+}
- if len(arguments) >= 2 {
- blacklist = getList(arguments[1], "blacklist")
- }
+// Apply applies the rule to given file.
+func (r *VarNamingRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure {
+ r.configure(arguments)
+
+ var failures []lint.Failure
fileAst := file.AST
+
walker := lintNames{
file: file,
fileAst: fileAst,
- whitelist: whitelist,
- blacklist: blacklist,
+ whitelist: r.whitelist,
+ blacklist: r.blacklist,
onFailure: func(failure lint.Failure) {
failures = append(failures, failure)
},
@@ -43,7 +56,7 @@ func (r *VarNamingRule) Apply(file *lint.File, arguments lint.Arguments) []lint.
walker.onFailure(lint.Failure{
Failure: "don't use an underscore in package name",
Confidence: 1,
- Node: walker.fileAst,
+ Node: walker.fileAst.Name,
Category: "naming",
})
}
@@ -54,7 +67,7 @@ func (r *VarNamingRule) Apply(file *lint.File, arguments lint.Arguments) []lint.
}
// Name returns the rule name.
-func (r *VarNamingRule) Name() string {
+func (*VarNamingRule) Name() string {
return "var-naming"
}
@@ -120,13 +133,11 @@ func check(id *ast.Ident, thing string, w *lintNames) {
}
type lintNames struct {
- file *lint.File
- fileAst *ast.File
- lastGen *ast.GenDecl
- genDeclMissingComments map[*ast.GenDecl]bool
- onFailure func(lint.Failure)
- whitelist []string
- blacklist []string
+ file *lint.File
+ fileAst *ast.File
+ onFailure func(lint.Failure)
+ whitelist []string
+ blacklist []string
}
func (w *lintNames) Visit(n ast.Node) ast.Visitor {
@@ -141,7 +152,12 @@ func (w *lintNames) Visit(n ast.Node) ast.Visitor {
}
}
case *ast.FuncDecl:
- if w.file.IsTest() && (strings.HasPrefix(v.Name.Name, "Example") || strings.HasPrefix(v.Name.Name, "Test") || strings.HasPrefix(v.Name.Name, "Benchmark")) {
+ funcName := v.Name.Name
+ if w.file.IsTest() &&
+ (strings.HasPrefix(funcName, "Example") ||
+ strings.HasPrefix(funcName, "Test") ||
+ strings.HasPrefix(funcName, "Benchmark") ||
+ strings.HasPrefix(funcName, "Fuzz")) {
return w
}
@@ -184,7 +200,7 @@ func (w *lintNames) Visit(n ast.Node) ast.Visitor {
}
case *ast.InterfaceType:
// Do not check interface method names.
- // They are often constrainted by the method names of concrete types.
+ // They are often constrained by the method names of concrete types.
for _, x := range v.Methods.List {
ft, ok := x.Type.(*ast.FuncType)
if !ok { // might be an embedded interface name
diff --git a/vendor/github.com/mgechev/revive/rule/waitgroup-by-value.go b/vendor/github.com/mgechev/revive/rule/waitgroup-by-value.go
index b86929136..98644f41c 100644
--- a/vendor/github.com/mgechev/revive/rule/waitgroup-by-value.go
+++ b/vendor/github.com/mgechev/revive/rule/waitgroup-by-value.go
@@ -10,7 +10,7 @@ import (
type WaitGroupByValueRule struct{}
// Apply applies the rule to given file.
-func (r *WaitGroupByValueRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
+func (*WaitGroupByValueRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
var failures []lint.Failure
onFailure := func(failure lint.Failure) {
@@ -23,7 +23,7 @@ func (r *WaitGroupByValueRule) Apply(file *lint.File, _ lint.Arguments) []lint.F
}
// Name returns the rule name.
-func (r *WaitGroupByValueRule) Name() string {
+func (*WaitGroupByValueRule) Name() string {
return "waitgroup-by-value"
}