Add makezero linter (#1520)
makezero ensures that objects recognized as slices are initialized with length 0. By default, this is only required when we find a subsequent append to the object, but can also be enabled at all times as a way of discouraging the use of integer variables (i.e. "i") to index slices.
This commit is contained in:
parent
f7a0c3c2e6
commit
cf32a7b706
@ -341,6 +341,9 @@ linters-settings:
|
||||
errorlint:
|
||||
# Report non-wrapping error creation using fmt.Errorf
|
||||
errorf: true
|
||||
makezero:
|
||||
# Allow only slices initialized with a length of zero. Default is false.
|
||||
always: false
|
||||
|
||||
# The custom section can be used to define linter plugins to be loaded at runtime. See README doc
|
||||
# for more info.
|
||||
|
1
go.mod
1
go.mod
@ -6,6 +6,7 @@ require (
|
||||
4d63.com/gochecknoglobals v0.0.0-20201008074935-acfc0b28355a
|
||||
github.com/Djarvur/go-err113 v0.0.0-20200511133814-5174e21577d5
|
||||
github.com/OpenPeeDeeP/depguard v1.0.1
|
||||
github.com/ashanbrown/makezero v0.0.0-20201205152432-7b7cdbb3025a
|
||||
github.com/bombsimon/wsl/v3 v3.1.0
|
||||
github.com/daixiang0/gci v0.2.4
|
||||
github.com/denis-tingajkin/go-header v0.3.1
|
||||
|
5
go.sum
generated
5
go.sum
generated
@ -31,6 +31,10 @@ github.com/andybalholm/brotli v1.0.0/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu
|
||||
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
|
||||
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
|
||||
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
||||
github.com/ashanbrown/makezero v0.0.0-20201122223944-6aa12ecc2e71 h1:I5vCM3EzMpsjllkzez2fjY/FXJNbtulB33LudiHuMNo=
|
||||
github.com/ashanbrown/makezero v0.0.0-20201122223944-6aa12ecc2e71/go.mod h1:oG9Dnez7/ESBqc4EdrdNlryeo7d0KcW1ftXHm7nU/UU=
|
||||
github.com/ashanbrown/makezero v0.0.0-20201205152432-7b7cdbb3025a h1:/U9tbJzDRof4fOR51vwzWdIBsIH6R2yU0KG1MBRM2Js=
|
||||
github.com/ashanbrown/makezero v0.0.0-20201205152432-7b7cdbb3025a/go.mod h1:oG9Dnez7/ESBqc4EdrdNlryeo7d0KcW1ftXHm7nU/UU=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
|
||||
@ -527,6 +531,7 @@ golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgw
|
||||
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20190910044552-dd2b5c81c578/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20190916130336-e45ffcd953cc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
|
@ -266,6 +266,7 @@ type LintersSettings struct {
|
||||
Exhaustive ExhaustiveSettings
|
||||
Gofumpt GofumptSettings
|
||||
ErrorLint ErrorLintSettings
|
||||
Makezero MakezeroSettings
|
||||
|
||||
Custom map[string]CustomLinterSettings
|
||||
}
|
||||
@ -386,6 +387,10 @@ type ErrorLintSettings struct {
|
||||
Errorf bool `mapstructure:"errorf"`
|
||||
}
|
||||
|
||||
type MakezeroSettings struct {
|
||||
Always bool
|
||||
}
|
||||
|
||||
var defaultLintersSettings = LintersSettings{
|
||||
Lll: LllSettings{
|
||||
LineLength: 120,
|
||||
|
60
pkg/golinters/makezero.go
Normal file
60
pkg/golinters/makezero.go
Normal file
@ -0,0 +1,60 @@
|
||||
package golinters
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/ashanbrown/makezero/makezero"
|
||||
"github.com/pkg/errors"
|
||||
"golang.org/x/tools/go/analysis"
|
||||
|
||||
"github.com/golangci/golangci-lint/pkg/golinters/goanalysis"
|
||||
"github.com/golangci/golangci-lint/pkg/lint/linter"
|
||||
"github.com/golangci/golangci-lint/pkg/result"
|
||||
)
|
||||
|
||||
const makezeroName = "makezero"
|
||||
|
||||
func NewMakezero() *goanalysis.Linter {
|
||||
var mu sync.Mutex
|
||||
var resIssues []goanalysis.Issue
|
||||
|
||||
analyzer := &analysis.Analyzer{
|
||||
Name: makezeroName,
|
||||
Doc: goanalysis.TheOnlyanalyzerDoc,
|
||||
}
|
||||
return goanalysis.NewLinter(
|
||||
makezeroName,
|
||||
"Finds slice declarations with non-zero initial length",
|
||||
[]*analysis.Analyzer{analyzer},
|
||||
nil,
|
||||
).WithContextSetter(func(lintCtx *linter.Context) {
|
||||
s := &lintCtx.Settings().Makezero
|
||||
|
||||
analyzer.Run = func(pass *analysis.Pass) (interface{}, error) {
|
||||
var res []goanalysis.Issue
|
||||
linter := makezero.NewLinter(s.Always)
|
||||
for _, file := range pass.Files {
|
||||
hints, err := linter.Run(pass.Fset, pass.TypesInfo, file)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "makezero linter failed on file %q", file.Name.String())
|
||||
}
|
||||
for _, hint := range hints {
|
||||
res = append(res, goanalysis.NewIssue(&result.Issue{
|
||||
Pos: hint.Position(),
|
||||
Text: hint.Details(),
|
||||
FromLinter: makezeroName,
|
||||
}, pass))
|
||||
}
|
||||
}
|
||||
if len(res) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
mu.Lock()
|
||||
resIssues = append(resIssues, res...)
|
||||
mu.Unlock()
|
||||
return nil, nil
|
||||
}
|
||||
}).WithIssuesReporter(func(*linter.Context) []goanalysis.Issue {
|
||||
return resIssues
|
||||
}).WithLoadMode(goanalysis.LoadModeSyntax | goanalysis.LoadModeTypesInfo)
|
||||
}
|
@ -328,6 +328,9 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config {
|
||||
WithPresets(linter.PresetStyle).
|
||||
WithLoadForGoAnalysis().
|
||||
WithURL("https://github.com/kunwardeep/paralleltest"),
|
||||
linter.NewConfig(golinters.NewMakezero()).
|
||||
WithPresets(linter.PresetStyle, linter.PresetBugs).
|
||||
WithURL("https://github.com/ashanbrown/makezero"),
|
||||
|
||||
// nolintlint must be last because it looks at the results of all the previous linters for unused nolint directives
|
||||
linter.NewConfig(golinters.NewNoLintLint()).
|
||||
|
12
test/testdata/makezero.go
vendored
Normal file
12
test/testdata/makezero.go
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
//args: -Emakezero
|
||||
package testdata
|
||||
|
||||
func Makezero() []int {
|
||||
x := make([]int, 5)
|
||||
return append(x, 1) // ERROR "append to slice `x` with non-zero initialized length"
|
||||
}
|
||||
|
||||
func MakezeroNolint() []int {
|
||||
x := make([]int, 5)
|
||||
return append(x, 1) //nolint:makezero // ok that we're appending to an uninitialized slice
|
||||
}
|
13
test/testdata/makezero_always.go
vendored
Normal file
13
test/testdata/makezero_always.go
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
//args: -Emakezero
|
||||
//config: linters-settings.makezero.always=true
|
||||
package testdata
|
||||
|
||||
func MakezeroAlways() []int {
|
||||
x := make([]int, 5) // ERROR "slice `x` does not have non-zero initial length"
|
||||
return x
|
||||
}
|
||||
|
||||
func MakezeroAlwaysNolint() []int {
|
||||
x := make([]int, 5) //nolint:makezero // ok that this is not initialized
|
||||
return x
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user