diff --git a/.golangci.example.yml b/.golangci.example.yml index 836947d5631a..6de50ae8438d 100644 --- a/.golangci.example.yml +++ b/.golangci.example.yml @@ -645,6 +645,21 @@ linters-settings: # Select the Go version to target. The default is '1.13'. go: "1.15" + varnamelen: + # The longest distance, in source lines, that is being considered a "small scope." (defaults to 5) + # Variables used in at most this many lines will be ignored. + max-distance: 5 + # The minimum length of a variable's name that is considered "long." (defaults to 3) + # Variable names that are at least this long will be ignored. + min-name-length: 3 + # Check method receiver names. (defaults to false) + check-receiver: false + # Check named return values. (defaults to false) + check-return: false + # Optional list of variable names that should be ignored completely. (defaults to empty list) + ignore-names: + - err + whitespace: multi-if: false # Enforces newlines (or comments) after every multi-line if statement multi-func: false # Enforces newlines (or comments) after every multi-line function signature diff --git a/go.mod b/go.mod index a0b26c5e7071..89365ab620c7 100644 --- a/go.mod +++ b/go.mod @@ -13,6 +13,7 @@ require ( github.com/ashanbrown/forbidigo v1.2.0 github.com/ashanbrown/makezero v0.0.0-20210520155254-b6261585ddde github.com/bkielbasa/cyclop v1.2.0 + github.com/blizzy78/varnamelen v0.3.0 github.com/bombsimon/wsl/v3 v3.3.0 github.com/butuzov/ireturn v0.1.1 github.com/charithe/durationcheck v0.0.9 diff --git a/go.sum b/go.sum index 3c48991d2d76..8c26c7e6bfbb 100644 --- a/go.sum +++ b/go.sum @@ -102,6 +102,8 @@ github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kB github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM= github.com/bkielbasa/cyclop v1.2.0 h1:7Jmnh0yL2DjKfw28p86YTd/B4lRGcNuu12sKE35sM7A= github.com/bkielbasa/cyclop v1.2.0/go.mod h1:qOI0yy6A7dYC4Zgsa72Ppm9kONl0RoIlPbzot9mhmeI= +github.com/blizzy78/varnamelen v0.3.0 h1:80mYO7Y5ppeEefg1Jzu+NBg16iwToOQVnDnNIoWSShs= +github.com/blizzy78/varnamelen v0.3.0/go.mod h1:hbwRdBvoBqxk34XyQ6HA0UH3G0/1TKuv5AC4eaBT0Ec= github.com/bombsimon/wsl/v3 v3.3.0 h1:Mka/+kRLoQJq7g2rggtgQsjuI/K5Efd87WX96EWFxjM= github.com/bombsimon/wsl/v3 v3.3.0/go.mod h1:st10JtZYLE4D5sC7b8xV4zTKZwAQjCH/Hy2Pm1FNZIc= github.com/butuzov/ireturn v0.1.1 h1:QvrO2QF2+/Cx1WA/vETCIYBKtRjc30vesdoPUNo1EbY= @@ -470,6 +472,8 @@ github.com/maratori/testpackage v1.0.1 h1:QtJ5ZjqapShm0w5DosRjg0PRlSdAdlx+W6cCKo github.com/maratori/testpackage v1.0.1/go.mod h1:ddKdw+XG0Phzhx8BFDTKgpWP4i7MpApTE5fXSKAqwDU= github.com/matoous/godox v0.0.0-20210227103229-6504466cf951 h1:pWxk9e//NbPwfxat7RXkts09K+dEBJWakUWwICVqYbA= github.com/matoous/godox v0.0.0-20210227103229-6504466cf951/go.mod h1:1BELzlh859Sh1c6+90blK8lbYy0kwQf1bYlBhBysy1s= +github.com/matryer/is v1.4.0 h1:sosSmIWwkYITGrxZ25ULNDeKiMNzFSr4V/eqBQP0PeE= +github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= @@ -992,6 +996,7 @@ golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210816074244-15123e1e1f71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210915083310-ed5796bab164/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210917161153-d61c044b1678/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6 h1:foEbQz/B0Oz6YIqu/69kfXPYeFQAuuMYFkjaqXzl5Wo= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= @@ -1112,6 +1117,7 @@ golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.6/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= golang.org/x/tools v0.1.7 h1:6j8CgantCy3yc8JGBqkDLMKWqZ0RDU2g1HVgacojGWQ= golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/pkg/config/linters_settings.go b/pkg/config/linters_settings.go index 04ddb054521e..8950cee4a309 100644 --- a/pkg/config/linters_settings.go +++ b/pkg/config/linters_settings.go @@ -136,6 +136,7 @@ type LintersSettings struct { Unparam UnparamSettings Unused StaticCheckSettings Varcheck VarCheckSettings + Varnamelen VarnamelenSettings Whitespace WhitespaceSettings Wrapcheck WrapcheckSettings WSL WSLSettings @@ -478,6 +479,14 @@ type VarCheckSettings struct { CheckExportedFields bool `mapstructure:"exported-fields"` } +type VarnamelenSettings struct { + MaxDistance int `mapstructure:"max-distance"` + MinNameLength int `mapstructure:"min-name-length"` + CheckReceiver bool `mapstructure:"check-receiver"` + CheckReturn bool `mapstructure:"check-return"` + IgnoreNames []string `mapstructure:"ignore-names"` +} + type WhitespaceSettings struct { MultiIf bool `mapstructure:"multi-if"` MultiFunc bool `mapstructure:"multi-func"` diff --git a/pkg/golinters/varnamelen.go b/pkg/golinters/varnamelen.go new file mode 100644 index 000000000000..168c881c4bb3 --- /dev/null +++ b/pkg/golinters/varnamelen.go @@ -0,0 +1,41 @@ +package golinters + +import ( + "strconv" + "strings" + + "github.com/blizzy78/varnamelen" + "golang.org/x/tools/go/analysis" + + "github.com/golangci/golangci-lint/pkg/config" + "github.com/golangci/golangci-lint/pkg/golinters/goanalysis" +) + +func NewVarnamelen(settings *config.VarnamelenSettings) *goanalysis.Linter { + a := varnamelen.NewAnalyzer() + + cfg := map[string]map[string]interface{}{} + if settings != nil { + vnlCfg := map[string]interface{}{ + "checkReceiver": strconv.FormatBool(settings.CheckReceiver), + "checkReturn": strconv.FormatBool(settings.CheckReturn), + "ignoreNames": strings.Join(settings.IgnoreNames, ","), + } + + if settings.MaxDistance > 0 { + vnlCfg["maxDistance"] = strconv.Itoa(settings.MaxDistance) + } + if settings.MinNameLength > 0 { + vnlCfg["minNameLength"] = strconv.Itoa(settings.MinNameLength) + } + + cfg[a.Name] = vnlCfg + } + + return goanalysis.NewLinter( + a.Name, + "checks that the length of a variable's name matches its scope", + []*analysis.Analyzer{a}, + cfg, + ).WithLoadMode(goanalysis.LoadModeSyntax) +} diff --git a/pkg/lint/lintersdb/manager.go b/pkg/lint/lintersdb/manager.go index ce5583ab798a..737548cf1543 100644 --- a/pkg/lint/lintersdb/manager.go +++ b/pkg/lint/lintersdb/manager.go @@ -121,6 +121,7 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config { var testpackageCfg *config.TestpackageSettings var thelperCfg *config.ThelperSettings var unusedCfg *config.StaticCheckSettings + var varnamelenCfg *config.VarnamelenSettings var wrapcheckCfg *config.WrapcheckSettings var nlreturnCfg *config.NlreturnSettings @@ -146,6 +147,7 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config { testpackageCfg = &m.cfg.LintersSettings.Testpackage thelperCfg = &m.cfg.LintersSettings.Thelper unusedCfg = &m.cfg.LintersSettings.Unused + varnamelenCfg = &m.cfg.LintersSettings.Varnamelen wrapcheckCfg = &m.cfg.LintersSettings.Wrapcheck nlreturnCfg = &m.cfg.LintersSettings.Nlreturn } @@ -511,30 +513,35 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config { WithPresets(linter.PresetStyle). WithURL("https://github.com/ldez/tagliatelle"), linter.NewConfig(golinters.NewErrName()). + WithSince("v1.42.0"). WithPresets(linter.PresetStyle). WithLoadForGoAnalysis(). - WithURL("https://github.com/Antonboom/errname"). - WithSince("v1.42.0"), + WithURL("https://github.com/Antonboom/errname"), linter.NewConfig(golinters.NewIreturn(ireturnCfg)). WithSince("v1.43.0"). WithPresets(linter.PresetStyle). WithLoadForGoAnalysis(). WithURL("https://github.com/butuzov/ireturn"), linter.NewConfig(golinters.NewNilNil(nilNilCfg)). + WithSince("v1.43.0"). WithPresets(linter.PresetStyle). WithLoadForGoAnalysis(). - WithURL("https://github.com/Antonboom/nilnil"). - WithSince("v1.43.0"), + WithURL("https://github.com/Antonboom/nilnil"), linter.NewConfig(golinters.NewTenv(tenvCfg)). WithSince("v1.43.0"). WithPresets(linter.PresetStyle). WithLoadForGoAnalysis(). WithURL("https://github.com/sivchari/tenv"), linter.NewConfig(golinters.NewContextCheck()). + WithSince("v1.43.0"). WithPresets(linter.PresetBugs). WithLoadForGoAnalysis(). - WithURL("https://github.com/sylvia7788/contextcheck"). - WithSince("v1.43.0"), + WithURL("https://github.com/sylvia7788/contextcheck"), + linter.NewConfig(golinters.NewVarnamelen(varnamelenCfg)). + WithSince("v1.43.0"). + WithPresets(linter.PresetStyle). + WithLoadForGoAnalysis(). + WithURL("https://github.com/blizzy78/varnamelen"), // nolintlint must be last because it looks at the results of all the previous linters for unused nolint directives linter.NewConfig(golinters.NewNoLintLint()). diff --git a/test/testdata/varnamelen.go b/test/testdata/varnamelen.go new file mode 100644 index 000000000000..3a49c396d798 --- /dev/null +++ b/test/testdata/varnamelen.go @@ -0,0 +1,17 @@ +//args: -Evarnamelen +package testdata + +import "math" + +func varnamelen() { + x := math.MinInt8 // ERROR "variable name 'x' is too short for the scope of its usage" + x++ + x++ + x++ + x++ + x++ + x++ + x++ + x++ + x++ +}