add exhaustive linter (#1166)
* wip more add new files run command fixes more * go.mod * order * same package * review comment * enable linter in .golangci.yml * add testcase for default-signifies-exhaustive: true * adjust runGoErrchk instead * disable the linter * cleanup * more cleanup * cleanup
This commit is contained in:
parent
71b2f04e88
commit
f3376cab71
@ -98,6 +98,11 @@ linters-settings:
|
||||
# path to a file containing a list of functions to exclude from checking
|
||||
# see https://github.com/kisielk/errcheck#excluding-functions for details
|
||||
exclude: /path/to/file.txt
|
||||
exhaustive:
|
||||
# indicates that switch statements are to be considered exhaustive if a
|
||||
# 'default' case is present, even if all enum members aren't listed in the
|
||||
# switch
|
||||
default-signifies-exhaustive: false
|
||||
funlen:
|
||||
lines: 60
|
||||
statements: 40
|
||||
|
@ -9,6 +9,8 @@ linters-settings:
|
||||
- github.com/sirupsen/logrus: "logging is allowed only by logutils.Log"
|
||||
dupl:
|
||||
threshold: 100
|
||||
exhaustive:
|
||||
default-signifies-exhaustive: false
|
||||
funlen:
|
||||
lines: 100
|
||||
statements: 50
|
||||
@ -104,6 +106,7 @@ linters:
|
||||
|
||||
# don't enable:
|
||||
# - asciicheck
|
||||
# - exhaustive (TODO: enable after next release; current release at time of writing is v1.27)
|
||||
# - gochecknoglobals
|
||||
# - gocognit
|
||||
# - godot
|
||||
|
3
go.mod
3
go.mod
@ -34,6 +34,7 @@ require (
|
||||
github.com/mitchellh/go-homedir v1.1.0
|
||||
github.com/mitchellh/go-ps v1.0.0
|
||||
github.com/nakabonne/nestif v0.3.0
|
||||
github.com/nishanths/exhaustive v0.0.0-20200525081945-8e46705b6132
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/ryancurrah/gomodguard v1.1.0
|
||||
github.com/securego/gosec/v2 v2.3.0
|
||||
@ -52,7 +53,7 @@ require (
|
||||
github.com/ultraware/whitespace v0.0.4
|
||||
github.com/uudashr/gocognit v1.0.1
|
||||
github.com/valyala/quicktemplate v1.5.0
|
||||
golang.org/x/tools v0.0.0-20200502202811-ed308ab3e770
|
||||
golang.org/x/tools v0.0.0-20200519015757-0d0afa43d58a
|
||||
gopkg.in/yaml.v2 v2.3.0
|
||||
honnef.co/go/tools v0.0.1-2020.1.4
|
||||
mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed
|
||||
|
4
go.sum
4
go.sum
@ -267,6 +267,8 @@ github.com/nbutton23/zxcvbn-go v0.0.0-20180912185939-ae427f1e4c1d h1:AREM5mwr4u1
|
||||
github.com/nbutton23/zxcvbn-go v0.0.0-20180912185939-ae427f1e4c1d/go.mod h1:o96djdrsSGy3AWPyBgZMAGfxZNfgntdJG+11KU4QvbU=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||
github.com/nishanths/exhaustive v0.0.0-20200525081945-8e46705b6132 h1:NjznefjSrral0MiR4KlB41io/d3OklvhcgQUdfZTqJE=
|
||||
github.com/nishanths/exhaustive v0.0.0-20200525081945-8e46705b6132/go.mod h1:wBEpHwM2OdmeNpdCvRPUlkEbBuaFmcK4Wv8Q7FuGW3c=
|
||||
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
|
||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.12.0 h1:Iw5WCbBcaAAd0fpRb1c9r5YCylv4XDoCSigm1zLevwU=
|
||||
@ -511,6 +513,8 @@ golang.org/x/tools v0.0.0-20200502202811-ed308ab3e770 h1:M9Fif0OxNji8w+HvmhVQ8KJ
|
||||
golang.org/x/tools v0.0.0-20200502202811-ed308ab3e770 h1:M9Fif0OxNji8w+HvmhVQ8KJtiZOsjU9RgslJGhn95XE=
|
||||
golang.org/x/tools v0.0.0-20200502202811-ed308ab3e770 h1:M9Fif0OxNji8w+HvmhVQ8KJtiZOsjU9RgslJGhn95XE=
|
||||
golang.org/x/tools v0.0.0-20200502202811-ed308ab3e770/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200519015757-0d0afa43d58a h1:gILuVKC+ZPD6g/tj6zBOdnOH1ZHI0zZ86+KLMogc6/s=
|
||||
golang.org/x/tools v0.0.0-20200519015757-0d0afa43d58a/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7 h1:9zdDQZ7Thm29KFXgAX/+yaf3eVbP7djjWp/dXAppNCc=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898 h1:/atklqdjdhuosWIl6AIbOeHJjicWYPqR9bpxqxYG2pA=
|
||||
|
@ -242,6 +242,7 @@ type LintersSettings struct {
|
||||
Testpackage TestpackageSettings
|
||||
Nestif NestifSettings
|
||||
NoLintLint NoLintLintSettings
|
||||
Exhaustive ExhaustiveSettings
|
||||
|
||||
Custom map[string]CustomLinterSettings
|
||||
}
|
||||
@ -339,6 +340,10 @@ type NestifSettings struct {
|
||||
MinComplexity int `mapstructure:"min-complexity"`
|
||||
}
|
||||
|
||||
type ExhaustiveSettings struct {
|
||||
DefaultSignifiesExhaustive bool `mapstructure:"default-signifies-exhaustive"`
|
||||
}
|
||||
|
||||
var defaultLintersSettings = LintersSettings{
|
||||
Lll: LllSettings{
|
||||
LineLength: 120,
|
||||
@ -389,6 +394,9 @@ var defaultLintersSettings = LintersSettings{
|
||||
Nestif: NestifSettings{
|
||||
MinComplexity: 5,
|
||||
},
|
||||
Exhaustive: ExhaustiveSettings{
|
||||
DefaultSignifiesExhaustive: false,
|
||||
},
|
||||
}
|
||||
|
||||
type CustomLinterSettings struct {
|
||||
|
25
pkg/golinters/exhaustive.go
Normal file
25
pkg/golinters/exhaustive.go
Normal file
@ -0,0 +1,25 @@
|
||||
package golinters
|
||||
|
||||
import (
|
||||
"github.com/nishanths/exhaustive"
|
||||
"golang.org/x/tools/go/analysis"
|
||||
|
||||
"github.com/golangci/golangci-lint/pkg/config"
|
||||
"github.com/golangci/golangci-lint/pkg/golinters/goanalysis"
|
||||
)
|
||||
|
||||
func NewExhaustive(settings *config.ExhaustiveSettings) *goanalysis.Linter {
|
||||
a := exhaustive.Analyzer
|
||||
|
||||
var cfg map[string]map[string]interface{}
|
||||
if settings != nil {
|
||||
cfg = map[string]map[string]interface{}{
|
||||
a.Name: {
|
||||
exhaustive.DefaultSignifiesExhaustiveFlag: settings.DefaultSignifiesExhaustive,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
return goanalysis.NewLinter(a.Name, a.Doc, []*analysis.Analyzer{a}, cfg).
|
||||
WithLoadMode(goanalysis.LoadModeTypesInfo)
|
||||
}
|
@ -935,7 +935,8 @@ func sizeOfReflectValueTreeBytes(rv reflect.Value, visitedPtrs map[uintptr]struc
|
||||
return rv.Len()
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
|
||||
reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
|
||||
reflect.Uintptr, reflect.Bool, reflect.Float32, reflect.Float64, reflect.UnsafePointer:
|
||||
reflect.Uintptr, reflect.Bool, reflect.Float32, reflect.Float64,
|
||||
reflect.Complex64, reflect.Complex128, reflect.Func, reflect.UnsafePointer:
|
||||
return int(rv.Type().Size())
|
||||
case reflect.Invalid:
|
||||
return 0
|
||||
|
@ -87,9 +87,11 @@ func enableLinterConfigs(lcs []*linter.Config, isEnabled func(lc *linter.Config)
|
||||
func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config {
|
||||
var govetCfg *config.GovetSettings
|
||||
var testpackageCfg *config.TestpackageSettings
|
||||
var exhaustiveCfg *config.ExhaustiveSettings
|
||||
if m.cfg != nil {
|
||||
govetCfg = &m.cfg.LintersSettings.Govet
|
||||
testpackageCfg = &m.cfg.LintersSettings.Testpackage
|
||||
exhaustiveCfg = &m.cfg.LintersSettings.Exhaustive
|
||||
}
|
||||
const megacheckName = "megacheck"
|
||||
lcs := []*linter.Config{
|
||||
@ -275,6 +277,10 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config {
|
||||
linter.NewConfig(golinters.NewExportLoopRef()).
|
||||
WithPresets(linter.PresetBugs).
|
||||
WithURL("https://github.com/kyoh86/exportloopref"),
|
||||
linter.NewConfig(golinters.NewExhaustive(exhaustiveCfg)).
|
||||
WithPresets(linter.PresetBugs).
|
||||
WithLoadForGoAnalysis().
|
||||
WithURL("https://github.com/nishanths/exhaustive"),
|
||||
// nolintlint must be last because it looks at the results of all the previous linters for unused nolint directives
|
||||
linter.NewConfig(golinters.NewNoLintLint()).
|
||||
WithPresets(linter.PresetStyle).
|
||||
|
@ -17,9 +17,13 @@ import (
|
||||
|
||||
func runGoErrchk(c *exec.Cmd, files []string, t *testing.T) {
|
||||
output, err := c.CombinedOutput()
|
||||
assert.Error(t, err)
|
||||
_, ok := err.(*exec.ExitError)
|
||||
assert.True(t, ok, err)
|
||||
// The returned error will be nil if the test file does not have any issues
|
||||
// and thus the linter exits with exit code 0. So perform the additional
|
||||
// assertions only if the error is non-nil.
|
||||
if err != nil {
|
||||
_, ok := err.(*exec.ExitError)
|
||||
assert.True(t, ok, err)
|
||||
}
|
||||
|
||||
// TODO: uncomment after deprecating go1.11
|
||||
// assert.Equal(t, exitcodes.IssuesFound, exitErr.ExitCode())
|
||||
|
3
test/testdata/configs/exhaustive.yml
vendored
Normal file
3
test/testdata/configs/exhaustive.yml
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
linters-settings:
|
||||
exhaustive:
|
||||
default-signifies-exhaustive: true
|
17
test/testdata/exhaustive.go
vendored
Normal file
17
test/testdata/exhaustive.go
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
//args: -Eexhaustive
|
||||
package testdata
|
||||
|
||||
type Direction int
|
||||
|
||||
const (
|
||||
North Direction = iota
|
||||
East
|
||||
South
|
||||
West
|
||||
)
|
||||
|
||||
func processDirection(d Direction) {
|
||||
switch d { // ERROR "missing cases in switch of type Direction: East, West"
|
||||
case North, South:
|
||||
}
|
||||
}
|
19
test/testdata/exhaustive_default.go
vendored
Normal file
19
test/testdata/exhaustive_default.go
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
//args: -Eexhaustive
|
||||
//config_path: testdata/configs/exhaustive.yml
|
||||
package testdata
|
||||
|
||||
type Direction int
|
||||
|
||||
const (
|
||||
North Direction = iota
|
||||
East
|
||||
South
|
||||
West
|
||||
)
|
||||
|
||||
func processDirectionDefault(d Direction) {
|
||||
switch d {
|
||||
case North, South:
|
||||
default:
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user