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
|
# path to a file containing a list of functions to exclude from checking
|
||||||
# see https://github.com/kisielk/errcheck#excluding-functions for details
|
# see https://github.com/kisielk/errcheck#excluding-functions for details
|
||||||
exclude: /path/to/file.txt
|
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:
|
funlen:
|
||||||
lines: 60
|
lines: 60
|
||||||
statements: 40
|
statements: 40
|
||||||
@ -174,7 +179,7 @@ linters-settings:
|
|||||||
modules: # List of blocked modules
|
modules: # List of blocked modules
|
||||||
# - github.com/uudashr/go-module: # Blocked module
|
# - github.com/uudashr/go-module: # Blocked module
|
||||||
# recommendations: # Recommended modules that should be used instead (Optional)
|
# recommendations: # Recommended modules that should be used instead (Optional)
|
||||||
# - golang.org/x/mod
|
# - golang.org/x/mod
|
||||||
# reason: "`mod` is the official go.mod parser library." # Reason why the recommended module should be used (Optional)
|
# reason: "`mod` is the official go.mod parser library." # Reason why the recommended module should be used (Optional)
|
||||||
versions: # List of blocked module version constraints
|
versions: # List of blocked module version constraints
|
||||||
# - github.com/mitchellh/go-homedir: # Blocked module with version constraint
|
# - github.com/mitchellh/go-homedir: # Blocked module with version constraint
|
||||||
|
@ -9,6 +9,8 @@ linters-settings:
|
|||||||
- github.com/sirupsen/logrus: "logging is allowed only by logutils.Log"
|
- github.com/sirupsen/logrus: "logging is allowed only by logutils.Log"
|
||||||
dupl:
|
dupl:
|
||||||
threshold: 100
|
threshold: 100
|
||||||
|
exhaustive:
|
||||||
|
default-signifies-exhaustive: false
|
||||||
funlen:
|
funlen:
|
||||||
lines: 100
|
lines: 100
|
||||||
statements: 50
|
statements: 50
|
||||||
@ -104,6 +106,7 @@ linters:
|
|||||||
|
|
||||||
# don't enable:
|
# don't enable:
|
||||||
# - asciicheck
|
# - asciicheck
|
||||||
|
# - exhaustive (TODO: enable after next release; current release at time of writing is v1.27)
|
||||||
# - gochecknoglobals
|
# - gochecknoglobals
|
||||||
# - gocognit
|
# - gocognit
|
||||||
# - godot
|
# - godot
|
||||||
|
3
go.mod
3
go.mod
@ -34,6 +34,7 @@ require (
|
|||||||
github.com/mitchellh/go-homedir v1.1.0
|
github.com/mitchellh/go-homedir v1.1.0
|
||||||
github.com/mitchellh/go-ps v1.0.0
|
github.com/mitchellh/go-ps v1.0.0
|
||||||
github.com/nakabonne/nestif v0.3.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/pkg/errors v0.9.1
|
||||||
github.com/ryancurrah/gomodguard v1.1.0
|
github.com/ryancurrah/gomodguard v1.1.0
|
||||||
github.com/securego/gosec/v2 v2.3.0
|
github.com/securego/gosec/v2 v2.3.0
|
||||||
@ -52,7 +53,7 @@ require (
|
|||||||
github.com/ultraware/whitespace v0.0.4
|
github.com/ultraware/whitespace v0.0.4
|
||||||
github.com/uudashr/gocognit v1.0.1
|
github.com/uudashr/gocognit v1.0.1
|
||||||
github.com/valyala/quicktemplate v1.5.0
|
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
|
gopkg.in/yaml.v2 v2.3.0
|
||||||
honnef.co/go/tools v0.0.1-2020.1.4
|
honnef.co/go/tools v0.0.1-2020.1.4
|
||||||
mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed
|
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/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 h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
|
||||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
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/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.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||||
github.com/onsi/ginkgo v1.12.0 h1:Iw5WCbBcaAAd0fpRb1c9r5YCylv4XDoCSigm1zLevwU=
|
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 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-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 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-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898 h1:/atklqdjdhuosWIl6AIbOeHJjicWYPqR9bpxqxYG2pA=
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898 h1:/atklqdjdhuosWIl6AIbOeHJjicWYPqR9bpxqxYG2pA=
|
||||||
|
@ -242,6 +242,7 @@ type LintersSettings struct {
|
|||||||
Testpackage TestpackageSettings
|
Testpackage TestpackageSettings
|
||||||
Nestif NestifSettings
|
Nestif NestifSettings
|
||||||
NoLintLint NoLintLintSettings
|
NoLintLint NoLintLintSettings
|
||||||
|
Exhaustive ExhaustiveSettings
|
||||||
|
|
||||||
Custom map[string]CustomLinterSettings
|
Custom map[string]CustomLinterSettings
|
||||||
}
|
}
|
||||||
@ -339,6 +340,10 @@ type NestifSettings struct {
|
|||||||
MinComplexity int `mapstructure:"min-complexity"`
|
MinComplexity int `mapstructure:"min-complexity"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ExhaustiveSettings struct {
|
||||||
|
DefaultSignifiesExhaustive bool `mapstructure:"default-signifies-exhaustive"`
|
||||||
|
}
|
||||||
|
|
||||||
var defaultLintersSettings = LintersSettings{
|
var defaultLintersSettings = LintersSettings{
|
||||||
Lll: LllSettings{
|
Lll: LllSettings{
|
||||||
LineLength: 120,
|
LineLength: 120,
|
||||||
@ -389,6 +394,9 @@ var defaultLintersSettings = LintersSettings{
|
|||||||
Nestif: NestifSettings{
|
Nestif: NestifSettings{
|
||||||
MinComplexity: 5,
|
MinComplexity: 5,
|
||||||
},
|
},
|
||||||
|
Exhaustive: ExhaustiveSettings{
|
||||||
|
DefaultSignifiesExhaustive: false,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
type CustomLinterSettings struct {
|
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()
|
return rv.Len()
|
||||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
|
||||||
reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
|
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())
|
return int(rv.Type().Size())
|
||||||
case reflect.Invalid:
|
case reflect.Invalid:
|
||||||
return 0
|
return 0
|
||||||
|
@ -87,9 +87,11 @@ func enableLinterConfigs(lcs []*linter.Config, isEnabled func(lc *linter.Config)
|
|||||||
func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config {
|
func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config {
|
||||||
var govetCfg *config.GovetSettings
|
var govetCfg *config.GovetSettings
|
||||||
var testpackageCfg *config.TestpackageSettings
|
var testpackageCfg *config.TestpackageSettings
|
||||||
|
var exhaustiveCfg *config.ExhaustiveSettings
|
||||||
if m.cfg != nil {
|
if m.cfg != nil {
|
||||||
govetCfg = &m.cfg.LintersSettings.Govet
|
govetCfg = &m.cfg.LintersSettings.Govet
|
||||||
testpackageCfg = &m.cfg.LintersSettings.Testpackage
|
testpackageCfg = &m.cfg.LintersSettings.Testpackage
|
||||||
|
exhaustiveCfg = &m.cfg.LintersSettings.Exhaustive
|
||||||
}
|
}
|
||||||
const megacheckName = "megacheck"
|
const megacheckName = "megacheck"
|
||||||
lcs := []*linter.Config{
|
lcs := []*linter.Config{
|
||||||
@ -275,6 +277,10 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config {
|
|||||||
linter.NewConfig(golinters.NewExportLoopRef()).
|
linter.NewConfig(golinters.NewExportLoopRef()).
|
||||||
WithPresets(linter.PresetBugs).
|
WithPresets(linter.PresetBugs).
|
||||||
WithURL("https://github.com/kyoh86/exportloopref"),
|
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
|
// nolintlint must be last because it looks at the results of all the previous linters for unused nolint directives
|
||||||
linter.NewConfig(golinters.NewNoLintLint()).
|
linter.NewConfig(golinters.NewNoLintLint()).
|
||||||
WithPresets(linter.PresetStyle).
|
WithPresets(linter.PresetStyle).
|
||||||
|
@ -17,9 +17,13 @@ import (
|
|||||||
|
|
||||||
func runGoErrchk(c *exec.Cmd, files []string, t *testing.T) {
|
func runGoErrchk(c *exec.Cmd, files []string, t *testing.T) {
|
||||||
output, err := c.CombinedOutput()
|
output, err := c.CombinedOutput()
|
||||||
assert.Error(t, err)
|
// The returned error will be nil if the test file does not have any issues
|
||||||
_, ok := err.(*exec.ExitError)
|
// and thus the linter exits with exit code 0. So perform the additional
|
||||||
assert.True(t, ok, err)
|
// 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
|
// TODO: uncomment after deprecating go1.11
|
||||||
// assert.Equal(t, exitcodes.IssuesFound, exitErr.ExitCode())
|
// 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