From 712de1c63d9db97c81af68cd0dc4372c53d2e57a Mon Sep 17 00:00:00 2001 From: Dmitry Vyukov Date: Tue, 15 Sep 2020 18:05:35 +0200 Subject: vendor/github.com/golangci/golangci-lint: update to v1.31 --- vendor/github.com/tetafro/godot/.golangci.yml | 67 +++++++ vendor/github.com/tetafro/godot/.goreleaser.yml | 3 +- vendor/github.com/tetafro/godot/Makefile | 10 + vendor/github.com/tetafro/godot/README.md | 17 +- vendor/github.com/tetafro/godot/godot.go | 246 ++++++++++++++++++++---- 5 files changed, 299 insertions(+), 44 deletions(-) create mode 100644 vendor/github.com/tetafro/godot/.golangci.yml (limited to 'vendor/github.com/tetafro') diff --git a/vendor/github.com/tetafro/godot/.golangci.yml b/vendor/github.com/tetafro/godot/.golangci.yml new file mode 100644 index 000000000..2b799b265 --- /dev/null +++ b/vendor/github.com/tetafro/godot/.golangci.yml @@ -0,0 +1,67 @@ +run: + concurrency: 2 + deadline: 5m + +skip-dirs: + - path: ./testdata/ + +linters: + disable-all: true + enable: + - deadcode + - errcheck + - gosimple + - govet + - ineffassign + - staticcheck + - structcheck + - typecheck + - unused + - varcheck + - bodyclose + - depguard + - dogsled + - dupl + - funlen + - gochecknoinits + - goconst + - gocritic + - gocyclo + - godot + - gofmt + - gofumpt + - goimports + - golint + - gomnd + - gomodguard + - goprintffuncname + - gosec + - lll + - maligned + - misspell + - nakedret + - nestif + - prealloc + - rowserrcheck + - scopelint + - stylecheck + - unconvert + - unparam + - whitespace + +linters-settings: + godot: + check-all: true + +issues: + exclude-use-default: false + exclude-rules: + - path: _test\.go + linters: + - dupl + - errcheck + - funlen + - gosec + - path: cmd/godot/main\.go + linters: + - gomnd diff --git a/vendor/github.com/tetafro/godot/.goreleaser.yml b/vendor/github.com/tetafro/godot/.goreleaser.yml index 87a05a2a7..c0fc2b6b1 100644 --- a/vendor/github.com/tetafro/godot/.goreleaser.yml +++ b/vendor/github.com/tetafro/godot/.goreleaser.yml @@ -8,5 +8,4 @@ changelog: sort: asc filters: exclude: - - '^docs:' - - '^test:' + - '^Merge pull request' diff --git a/vendor/github.com/tetafro/godot/Makefile b/vendor/github.com/tetafro/godot/Makefile index fee7693ae..98a691d78 100644 --- a/vendor/github.com/tetafro/godot/Makefile +++ b/vendor/github.com/tetafro/godot/Makefile @@ -2,6 +2,16 @@ test: go test ./... +.PHONY: cover +cover: + go test -coverprofile cover.out ./... + go tool cover -html=cover.out + rm -f cover.out + +.PHONY: lint +lint: + golangci-lint run + .PHONY: build build: go build -o godot ./cmd/godot diff --git a/vendor/github.com/tetafro/godot/README.md b/vendor/github.com/tetafro/godot/README.md index e2d2f6b0d..864767e3c 100644 --- a/vendor/github.com/tetafro/godot/README.md +++ b/vendor/github.com/tetafro/godot/README.md @@ -13,23 +13,32 @@ end of the last sentence if needed. > Comments should begin with the name of the thing being described > and end in a period -## Install and run +## Install *NOTE: Godot is available as a part of [GolangCI Lint](https://github.com/golangci/golangci-lint) (disabled by default).* Build from source + ```sh go get -u github.com/tetafro/godot/cmd/godot ``` or download binary from [releases page](https://github.com/tetafro/godot/releases). -Run +## Run + ```sh godot ./myproject ``` +Autofix flags are also available + +```sh +godot -f ./myproject # fix issues and print the result +godot -w ./myproject # fix issues and replace the original file +``` + ## Examples Code @@ -50,5 +59,5 @@ Top level comment should end in a period: math/math.go:3:1 ``` See more examples in test files: -- [for default mode](testdata/example_default.go) -- [for using --all flag](testdata/example_checkall.go) +- [for default mode](testdata/default/in/main.go) +- [for using --all flag](testdata/checkall/in/main.go) diff --git a/vendor/github.com/tetafro/godot/godot.go b/vendor/github.com/tetafro/godot/godot.go index 5eec83579..81211d725 100644 --- a/vendor/github.com/tetafro/godot/godot.go +++ b/vendor/github.com/tetafro/godot/godot.go @@ -3,19 +3,25 @@ package godot import ( + "fmt" "go/ast" "go/token" + "io/ioutil" + "os" "regexp" + "sort" "strings" ) -const noPeriodMessage = "Top level comment should end in a period" - -// Message contains a message of linting error. -type Message struct { - Pos token.Position - Message string -} +const ( + // noPeriodMessage is an error message to return. + noPeriodMessage = "Top level comment should end in a period" + // topLevelColumn is just the most left column of the file. + topLevelColumn = 1 + // topLevelGroupColumn is the most left column inside a group declaration + // on the top level. + topLevelGroupColumn = 2 +) // Settings contains linter settings. type Settings struct { @@ -23,12 +29,25 @@ type Settings struct { CheckAll bool } +// Issue contains a description of linting error and a possible replacement. +type Issue struct { + Pos token.Position + Message string + Replacement string +} + +// position is an position inside a comment (might be multiline comment). +type position struct { + line int + column int +} + var ( // List of valid last characters. lastChars = []string{".", "?", "!"} - // Special tags in comments like "nolint" or "build". - tags = regexp.MustCompile("^[a-z]+:") + // Special tags in comments like "// nolint:", or "// +k8s:". + tags = regexp.MustCompile(`^\+?[a-z0-9]+:`) // Special hashtags in comments like "#nosec". hashtags = regexp.MustCompile("^#[a-z]+ ") @@ -38,43 +57,150 @@ var ( ) // Run runs this linter on the provided code. -func Run(file *ast.File, fset *token.FileSet, settings Settings) []Message { - msgs := []Message{} +func Run(file *ast.File, fset *token.FileSet, settings Settings) []Issue { + issues := checkBlocks(file, fset) // Check all top-level comments if settings.CheckAll { - for _, group := range file.Comments { - if ok, msg := check(fset, group); !ok { - msgs = append(msgs, msg) - } - } - return msgs + issues = append(issues, checkTopLevel(file, fset)...) + sortIssues(issues) + return issues } // Check only declaration comments + issues = append(issues, checkDeclarations(file, fset)...) + sortIssues(issues) + return issues +} + +// Fix fixes all issues and return new version of file content. +func Fix(path string, file *ast.File, fset *token.FileSet, settings Settings) ([]byte, error) { + // Read file + content, err := ioutil.ReadFile(path) // nolint: gosec + if err != nil { + return nil, fmt.Errorf("read file: %v", err) + } + if len(content) == 0 { + return nil, nil + } + + issues := Run(file, fset, settings) + + // slice -> map + m := map[int]Issue{} + for _, iss := range issues { + m[iss.Pos.Line] = iss + } + + // Replace lines from issues + fixed := make([]byte, 0, len(content)) + for i, line := range strings.Split(string(content), "\n") { + newline := line + if iss, ok := m[i+1]; ok { + newline = iss.Replacement + } + fixed = append(fixed, []byte(newline+"\n")...) + } + fixed = fixed[:len(fixed)-1] // trim last "\n" + + return fixed, nil +} + +// Replace rewrites original file with it's fixed version. +func Replace(path string, file *ast.File, fset *token.FileSet, settings Settings) error { + info, err := os.Stat(path) + if err != nil { + return fmt.Errorf("check file: %v", err) + } + mode := info.Mode() + + fixed, err := Fix(path, file, fset, settings) + if err != nil { + return fmt.Errorf("fix issues: %v", err) + } + + if err := ioutil.WriteFile(path, fixed, mode); err != nil { + return fmt.Errorf("write file: %v", err) + } + return nil +} + +// sortIssues sorts by filename, line and column. +func sortIssues(iss []Issue) { + sort.Slice(iss, func(i, j int) bool { + if iss[i].Pos.Filename != iss[j].Pos.Filename { + return iss[i].Pos.Filename < iss[j].Pos.Filename + } + if iss[i].Pos.Line != iss[j].Pos.Line { + return iss[i].Pos.Line < iss[j].Pos.Line + } + return iss[i].Pos.Column < iss[j].Pos.Column + }) +} + +// checkTopLevel checks all top-level comments. +func checkTopLevel(file *ast.File, fset *token.FileSet) (issues []Issue) { + for _, group := range file.Comments { + if iss, ok := check(fset, group, topLevelColumn); !ok { + issues = append(issues, iss) + } + } + return issues +} + +// checkDeclarations checks top level declaration comments. +func checkDeclarations(file *ast.File, fset *token.FileSet) (issues []Issue) { for _, decl := range file.Decls { switch d := decl.(type) { case *ast.GenDecl: - if ok, msg := check(fset, d.Doc); !ok { - msgs = append(msgs, msg) + if iss, ok := check(fset, d.Doc, topLevelColumn); !ok { + issues = append(issues, iss) } case *ast.FuncDecl: - if ok, msg := check(fset, d.Doc); !ok { - msgs = append(msgs, msg) + if iss, ok := check(fset, d.Doc, topLevelColumn); !ok { + issues = append(issues, iss) + } + } + } + return issues +} + +// checkBlocks checks comments inside top level blocks (var (...), const (...), etc). +func checkBlocks(file *ast.File, fset *token.FileSet) (issues []Issue) { + for _, decl := range file.Decls { + d, ok := decl.(*ast.GenDecl) + if !ok { + continue + } + // No parenthesis == no block + if d.Lparen == 0 { + continue + } + for _, group := range file.Comments { + // Skip comments outside this block + if d.Lparen > group.Pos() || group.Pos() > d.Rparen { + continue + } + // Skip comments that are not top-level for this block + if fset.Position(group.Pos()).Column != topLevelGroupColumn { + continue + } + if iss, ok := check(fset, group, topLevelGroupColumn); !ok { + issues = append(issues, iss) } } } - return msgs + return issues } -func check(fset *token.FileSet, group *ast.CommentGroup) (ok bool, msg Message) { +func check(fset *token.FileSet, group *ast.CommentGroup, level int) (iss Issue, ok bool) { if group == nil || len(group.List) == 0 { - return true, Message{} + return Issue{}, true } // Check only top-level comments - if fset.Position(group.Pos()).Column > 1 { - return true, Message{} + if fset.Position(group.Pos()).Column > level { + return Issue{}, true } // Get last element from comment group - it can be either @@ -82,29 +208,40 @@ func check(fset *token.FileSet, group *ast.CommentGroup) (ok bool, msg Message) // for "/*"-comment last := group.List[len(group.List)-1] - line, ok := checkComment(last.Text) + p, ok := checkComment(last.Text) if ok { - return true, Message{} + return Issue{}, true } + pos := fset.Position(last.Slash) - pos.Line += line - return false, Message{ - Pos: pos, - Message: noPeriodMessage, + pos.Line += p.line + pos.Column = p.column + level - 1 + + indent := strings.Repeat("\t", level-1) + + iss = Issue{ + Pos: pos, + Message: noPeriodMessage, + Replacement: indent + makeReplacement(last.Text, p), } + return iss, false } -func checkComment(comment string) (line int, ok bool) { +func checkComment(comment string) (pos position, ok bool) { // Check last line of "//"-comment if strings.HasPrefix(comment, "//") { + pos.column = len([]rune(comment)) // runes for non-latin chars comment = strings.TrimPrefix(comment, "//") - return 0, checkLastChar(comment) + if checkLastChar(comment) { + return position{}, true + } + return pos, false } // Skip cgo code blocks - // TODO: Find a better way to detect cgo code. + // TODO: Find a better way to detect cgo code if strings.Contains(comment, "#include") || strings.Contains(comment, "#define") { - return 0, true + return position{}, true } // Check last non-empty line in multiline "/*"-comment block @@ -116,9 +253,19 @@ func checkComment(comment string) (line int, ok bool) { } break } - comment = strings.TrimPrefix(lines[i], "/*") + pos.line = i + comment = lines[i] comment = strings.TrimSuffix(comment, "*/") - return i, checkLastChar(comment) + comment = strings.TrimRight(comment, " ") + // Get position of the last non-space char in comment line, use runes + // in case of non-latin chars + pos.column = len([]rune(comment)) + comment = strings.TrimPrefix(comment, "/*") + + if checkLastChar(comment) { + return position{}, true + } + return pos, false } func checkLastChar(s string) bool { @@ -142,6 +289,8 @@ func checkLastChar(s string) bool { if s == "" { return true } + // Trim parenthesis for cases when the whole sentence is inside parenthesis + s = strings.TrimRight(s, ")") for _, ch := range lastChars { if string(s[len(s)-1]) == ch { return true @@ -149,3 +298,24 @@ func checkLastChar(s string) bool { } return false } + +// makeReplacement basically just inserts a period into comment on +// the given position. +func makeReplacement(s string, pos position) string { + lines := strings.Split(s, "\n") + if len(lines) < pos.line { + // This should never happen + return s + } + line := []rune(lines[pos.line]) + if len(line) < pos.column { + // This should never happen + return s + } + // Insert a period + newline := append( + line[:pos.column], + append([]rune{'.'}, line[pos.column:]...)..., + ) + return string(newline) +} -- cgit mrf-deployment