Add dogsled linter. (#705)
This commit is contained in:
parent
6a979fb40d
commit
92168d033d
@ -201,6 +201,9 @@ linters-settings:
|
|||||||
- NOTE
|
- NOTE
|
||||||
- OPTIMIZE # marks code that should be optimized before merging
|
- OPTIMIZE # marks code that should be optimized before merging
|
||||||
- HACK # marks hack-arounds that should be removed before merging
|
- HACK # marks hack-arounds that should be removed before merging
|
||||||
|
dogsled:
|
||||||
|
# checks assignments with too many blank identifiers; default is 2
|
||||||
|
max-blank-identifiers: 2
|
||||||
|
|
||||||
linters:
|
linters:
|
||||||
enable:
|
enable:
|
||||||
|
@ -49,6 +49,7 @@ linters:
|
|||||||
- bodyclose
|
- bodyclose
|
||||||
- deadcode
|
- deadcode
|
||||||
- depguard
|
- depguard
|
||||||
|
# - dogsled - TODO: enable it when golangci.com will support it.
|
||||||
- dupl
|
- dupl
|
||||||
- errcheck
|
- errcheck
|
||||||
# - funlen - TODO: enable it when golangci.com will support it.
|
# - funlen - TODO: enable it when golangci.com will support it.
|
||||||
|
@ -195,6 +195,7 @@ $ golangci-lint help linters
|
|||||||
Disabled by default linters:
|
Disabled by default linters:
|
||||||
bodyclose: checks whether HTTP response body is closed successfully [fast: false, auto-fix: false]
|
bodyclose: checks whether HTTP response body is closed successfully [fast: false, auto-fix: false]
|
||||||
depguard: Go linter that checks if package imports are in a list of acceptable packages [fast: true, auto-fix: false]
|
depguard: Go linter that checks if package imports are in a list of acceptable packages [fast: true, auto-fix: false]
|
||||||
|
dogsled: Checks assignments with too many blank identifiers (e.g. x, _, _, _, := f()) [fast: true, auto-fix: false]
|
||||||
dupl: Tool for code clone detection [fast: true, auto-fix: false]
|
dupl: Tool for code clone detection [fast: true, auto-fix: false]
|
||||||
funlen: Tool for detection of long functions [fast: true, auto-fix: false]
|
funlen: Tool for detection of long functions [fast: true, auto-fix: false]
|
||||||
gochecknoglobals: Checks that no globals are present in Go code [fast: true, auto-fix: false]
|
gochecknoglobals: Checks that no globals are present in Go code [fast: true, auto-fix: false]
|
||||||
@ -454,6 +455,7 @@ golangci-lint help linters
|
|||||||
- [misspell](https://github.com/client9/misspell) - Finds commonly misspelled English words in comments
|
- [misspell](https://github.com/client9/misspell) - Finds commonly misspelled English words in comments
|
||||||
- [lll](https://github.com/walle/lll) - Reports long lines
|
- [lll](https://github.com/walle/lll) - Reports long lines
|
||||||
- [unparam](https://github.com/mvdan/unparam) - Reports unused function parameters
|
- [unparam](https://github.com/mvdan/unparam) - Reports unused function parameters
|
||||||
|
- [dogsled](https://github.com/alexkohler/dogsled) - Checks assignments with too many blank identifiers (e.g. x, _, _, _, := f())
|
||||||
- [nakedret](https://github.com/alexkohler/nakedret) - Finds naked returns in functions greater than a specified function length
|
- [nakedret](https://github.com/alexkohler/nakedret) - Finds naked returns in functions greater than a specified function length
|
||||||
- [prealloc](https://github.com/alexkohler/prealloc) - Finds slice declarations that could potentially be preallocated
|
- [prealloc](https://github.com/alexkohler/prealloc) - Finds slice declarations that could potentially be preallocated
|
||||||
- [scopelint](https://github.com/kyoh86/scopelint) - Scopelint checks for unpinned variables in go programs
|
- [scopelint](https://github.com/kyoh86/scopelint) - Scopelint checks for unpinned variables in go programs
|
||||||
@ -783,6 +785,9 @@ linters-settings:
|
|||||||
- NOTE
|
- NOTE
|
||||||
- OPTIMIZE # marks code that should be optimized before merging
|
- OPTIMIZE # marks code that should be optimized before merging
|
||||||
- HACK # marks hack-arounds that should be removed before merging
|
- HACK # marks hack-arounds that should be removed before merging
|
||||||
|
dogsled:
|
||||||
|
# checks assignments with too many blank identifiers; default is 2
|
||||||
|
max-blank-identifiers: 2
|
||||||
|
|
||||||
linters:
|
linters:
|
||||||
enable:
|
enable:
|
||||||
@ -916,6 +921,7 @@ linters:
|
|||||||
- bodyclose
|
- bodyclose
|
||||||
- deadcode
|
- deadcode
|
||||||
- depguard
|
- depguard
|
||||||
|
# - dogsled - TODO: enable it when golangci.com will support it.
|
||||||
- dupl
|
- dupl
|
||||||
- errcheck
|
- errcheck
|
||||||
# - funlen - TODO: enable it when golangci.com will support it.
|
# - funlen - TODO: enable it when golangci.com will support it.
|
||||||
|
@ -178,6 +178,7 @@ type LintersSettings struct {
|
|||||||
Errcheck ErrcheckSettings
|
Errcheck ErrcheckSettings
|
||||||
Gocritic GocriticSettings
|
Gocritic GocriticSettings
|
||||||
Godox GodoxSettings
|
Godox GodoxSettings
|
||||||
|
Dogsled DogsledSettings
|
||||||
}
|
}
|
||||||
|
|
||||||
type GovetSettings struct {
|
type GovetSettings struct {
|
||||||
@ -234,6 +235,10 @@ type GodoxSettings struct {
|
|||||||
Keywords []string
|
Keywords []string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type DogsledSettings struct {
|
||||||
|
MaxBlankIdentifiers int `mapstructure:"max-blank-identifiers"`
|
||||||
|
}
|
||||||
|
|
||||||
var defaultLintersSettings = LintersSettings{
|
var defaultLintersSettings = LintersSettings{
|
||||||
Lll: LllSettings{
|
Lll: LllSettings{
|
||||||
LineLength: 120,
|
LineLength: 120,
|
||||||
@ -256,6 +261,9 @@ var defaultLintersSettings = LintersSettings{
|
|||||||
Godox: GodoxSettings{
|
Godox: GodoxSettings{
|
||||||
Keywords: []string{},
|
Keywords: []string{},
|
||||||
},
|
},
|
||||||
|
Dogsled: DogsledSettings{
|
||||||
|
MaxBlankIdentifiers: 2,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
type Linters struct {
|
type Linters struct {
|
||||||
|
79
pkg/golinters/dogsled.go
Normal file
79
pkg/golinters/dogsled.go
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
package golinters
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"go/ast"
|
||||||
|
"go/token"
|
||||||
|
|
||||||
|
"github.com/golangci/golangci-lint/pkg/lint/linter"
|
||||||
|
"github.com/golangci/golangci-lint/pkg/result"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Dogsled struct{}
|
||||||
|
|
||||||
|
func (Dogsled) Name() string {
|
||||||
|
return "dogsled"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (Dogsled) Desc() string {
|
||||||
|
return "Checks assignments with too many blank identifiers (e.g. x, _, _, _, := f())"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d Dogsled) Run(ctx context.Context, lintCtx *linter.Context) ([]result.Issue, error) {
|
||||||
|
|
||||||
|
var res []result.Issue
|
||||||
|
for _, f := range lintCtx.ASTCache.GetAllValidFiles() {
|
||||||
|
v := returnsVisitor{
|
||||||
|
maxBlanks: lintCtx.Settings().Dogsled.MaxBlankIdentifiers,
|
||||||
|
f: f.Fset,
|
||||||
|
}
|
||||||
|
ast.Walk(&v, f.F)
|
||||||
|
res = append(res, v.issues...)
|
||||||
|
}
|
||||||
|
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type returnsVisitor struct {
|
||||||
|
f *token.FileSet
|
||||||
|
maxBlanks int
|
||||||
|
issues []result.Issue
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *returnsVisitor) Visit(node ast.Node) ast.Visitor {
|
||||||
|
funcDecl, ok := node.(*ast.FuncDecl)
|
||||||
|
if !ok {
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
if funcDecl.Body == nil {
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, expr := range funcDecl.Body.List {
|
||||||
|
assgnStmt, ok := expr.(*ast.AssignStmt)
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
numBlank := 0
|
||||||
|
for _, left := range assgnStmt.Lhs {
|
||||||
|
ident, ok := left.(*ast.Ident)
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if ident.Name == "_" {
|
||||||
|
numBlank++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if numBlank > v.maxBlanks {
|
||||||
|
v.issues = append(v.issues, result.Issue{
|
||||||
|
FromLinter: Dogsled{}.Name(),
|
||||||
|
Text: fmt.Sprintf("declaration has %v blank identifiers", numBlank),
|
||||||
|
Pos: v.f.Position(assgnStmt.Pos()),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return v
|
||||||
|
}
|
@ -215,6 +215,10 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config {
|
|||||||
WithLoadDepsTypeInfo().
|
WithLoadDepsTypeInfo().
|
||||||
WithSSA().
|
WithSSA().
|
||||||
WithURL("https://github.com/mvdan/unparam"),
|
WithURL("https://github.com/mvdan/unparam"),
|
||||||
|
linter.NewConfig(golinters.Dogsled{}).
|
||||||
|
WithPresets(linter.PresetStyle).
|
||||||
|
WithSpeed(10).
|
||||||
|
WithURL("https://github.com/alexkohler/dogsled"),
|
||||||
linter.NewConfig(golinters.Nakedret{}).
|
linter.NewConfig(golinters.Nakedret{}).
|
||||||
WithPresets(linter.PresetComplexity).
|
WithPresets(linter.PresetComplexity).
|
||||||
WithSpeed(10).
|
WithSpeed(10).
|
||||||
|
25
test/testdata/dogsled.go
vendored
Normal file
25
test/testdata/dogsled.go
vendored
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
//args: -Edogsled
|
||||||
|
package testdata
|
||||||
|
|
||||||
|
func Dogsled() {
|
||||||
|
_ = ret1()
|
||||||
|
_, _ = ret2()
|
||||||
|
_, _, _ = ret3() // ERROR "declaration has 3 blank identifiers"
|
||||||
|
_, _, _, _ = ret4() // ERROR "declaration has 4 blank identifiers"
|
||||||
|
}
|
||||||
|
|
||||||
|
func ret1() (a int) {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
func ret2() (a, b int) {
|
||||||
|
return 1, 2
|
||||||
|
}
|
||||||
|
|
||||||
|
func ret3() (a, b, c int) {
|
||||||
|
return 1, 2, 3
|
||||||
|
}
|
||||||
|
|
||||||
|
func ret4() (a, b, c, d int) {
|
||||||
|
return 1, 2, 3, 4
|
||||||
|
}
|
21
third_party/dogsled/LICENSE
vendored
Normal file
21
third_party/dogsled/LICENSE
vendored
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2018 Alex Kohler
|
||||||
|
|
||||||
|
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.
|
Loading…
x
Reference in New Issue
Block a user