new-linter: ireturn (checks for function return type) (#2219)

This commit is contained in:
Oleg Butuzov 2021-09-16 12:47:56 +03:00 committed by GitHub
parent 813ba7d953
commit 2ea496f22b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 130 additions and 0 deletions

View File

@ -447,6 +447,29 @@ linters-settings:
- pkg: knative.dev/serving/pkg/apis/(\w+)/(v[\w\d]+)
alias: $1$2
ireturn:
# ireturn allows using `allow` and `reject` settings at the same time.
# Both settings are lists of the keywords and regular expressions matched to interface or package names.
# keywords:
# - `empty` for `interface{}`
# - `error` for errors
# - `stdlib` for standard library
# - `anon` for anonymous interfaces
# By default, it allows using errors, empty interfaces, anonymous interfaces,
# and interfaces provided by the standard library.
allow:
- anon
- error
- empty
- stdlib
# You can specify idiomatic endings for interface
- (or|er)$
# Reject patterns
reject:
- github.com\/user\/package\/v4\.Type
lll:
# max line length, lines longer will be reported. Default is 120.
# '\t' is counted as 1 character by default, and can be changed with the tab-width option

1
go.mod
View File

@ -13,6 +13,7 @@ require (
github.com/ashanbrown/makezero v0.0.0-20210520155254-b6261585ddde
github.com/bkielbasa/cyclop v1.2.0
github.com/bombsimon/wsl/v3 v3.3.0
github.com/butuzov/ireturn v0.1.0
github.com/charithe/durationcheck v0.0.8
github.com/daixiang0/gci v0.2.9
github.com/denis-tingajkin/go-header v0.4.2

2
go.sum generated
View File

@ -95,6 +95,8 @@ github.com/bkielbasa/cyclop v1.2.0 h1:7Jmnh0yL2DjKfw28p86YTd/B4lRGcNuu12sKE35sM7
github.com/bkielbasa/cyclop v1.2.0/go.mod h1:qOI0yy6A7dYC4Zgsa72Ppm9kONl0RoIlPbzot9mhmeI=
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.0 h1:fMNgwuKMwsV9qtPNFgI7/NUOF3+CfbdLPGX6ZhDaMgA=
github.com/butuzov/ireturn v0.1.0/go.mod h1:Wh6Zl3IMtTpaIKbmwzqi6olnM9ptYQxxVacMsOEFPoc=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=

View File

@ -110,6 +110,7 @@ type LintersSettings struct {
Gosimple StaticCheckSettings
Govet GovetSettings
Ifshort IfshortSettings
Ireturn IreturnSettings
ImportAs ImportAsSettings
Lll LllSettings
Makezero MakezeroSettings
@ -186,6 +187,11 @@ type ExhaustiveStructSettings struct {
StructPatterns []string `mapstructure:"struct-patterns"`
}
type IreturnSettings struct {
Allow []string `mapstructure:"allow"`
Reject []string `mapstructure:"reject"`
}
type ForbidigoSettings struct {
Forbid []string `mapstructure:"forbid"`
ExcludeGodocExamples bool `mapstructure:"exclude-godoc-examples"`

30
pkg/golinters/ireturn.go Normal file
View File

@ -0,0 +1,30 @@
package golinters
import (
"strings"
"github.com/golangci/golangci-lint/pkg/config"
"github.com/golangci/golangci-lint/pkg/golinters/goanalysis"
"github.com/butuzov/ireturn/analyzer"
"golang.org/x/tools/go/analysis"
)
func NewIreturn(settings *config.IreturnSettings) *goanalysis.Linter {
a := analyzer.NewAnalyzer()
cfg := map[string]map[string]interface{}{}
if settings != nil {
cfg[a.Name] = map[string]interface{}{
"allow": strings.Join(settings.Allow, ","),
"reject": strings.Join(settings.Reject, ","),
}
}
return goanalysis.NewLinter(
a.Name,
a.Doc,
[]*analysis.Analyzer{a},
cfg,
).WithLoadMode(goanalysis.LoadModeTypesInfo)
}

View File

@ -110,6 +110,7 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config {
var reviveCfg *config.ReviveSettings
var cyclopCfg *config.Cyclop
var importAsCfg *config.ImportAsSettings
var ireturnCfg *config.IreturnSettings
var goModDirectivesCfg *config.GoModDirectivesSettings
var tagliatelleCfg *config.TagliatelleSettings
var gosecCfg *config.GoSecSettings
@ -131,6 +132,7 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config {
reviveCfg = &m.cfg.LintersSettings.Revive
cyclopCfg = &m.cfg.LintersSettings.Cyclop
importAsCfg = &m.cfg.LintersSettings.ImportAs
ireturnCfg = &m.cfg.LintersSettings.Ireturn
goModDirectivesCfg = &m.cfg.LintersSettings.GoModDirectives
tagliatelleCfg = &m.cfg.LintersSettings.Tagliatelle
gosecCfg = &m.cfg.LintersSettings.Gosec
@ -506,6 +508,11 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config {
WithLoadForGoAnalysis().
WithURL("https://github.com/Antonboom/errname").
WithSince("v1.42.0"),
linter.NewConfig(golinters.NewIreturn(ireturnCfg)).
WithSince("v1.43.0").
WithPresets(linter.PresetStyle).
WithLoadForGoAnalysis().
WithURL("https://github.com/butuzov/ireturn"),
// nolintlint must be last because it looks at the results of all the previous linters for unused nolint directives
linter.NewConfig(golinters.NewNoLintLint()).

4
test/testdata/configs/ireturn.yml vendored Normal file
View File

@ -0,0 +1,4 @@
linters-settings:
ireturn:
allow:
- IreturnAllowDoer

View File

@ -0,0 +1,4 @@
linters-settings:
ireturn:
reject:
- stdlib

13
test/testdata/ireturn_allow.go vendored Normal file
View File

@ -0,0 +1,13 @@
// args: -Eireturn
// config_path: testdata/configs/ireturn.yml
package testdata
type (
IreturnAllowDoer interface{ Do() }
ireturnAllowDoer struct{}
)
func NewAllowDoer() IreturnAllowDoer { return new(ireturnAllowDoer) }
func (d *ireturnAllowDoer) Do() { /*...*/ }
func NewerAllowDoer() *ireturnAllowDoer { return new(ireturnAllowDoer) }

12
test/testdata/ireturn_default.go vendored Normal file
View File

@ -0,0 +1,12 @@
// args: -Eireturn
package testdata
type (
IreturnDoer interface{ Do() }
ireturnDoer struct{}
)
func New() IreturnDoer { return new(ireturnDoer) } // ERROR `New returns interface \(command-line-arguments.IreturnDoer\)`
func (d *ireturnDoer) Do() { /*...*/ }
func Newer() *ireturnDoer { return new(ireturnDoer) }

28
test/testdata/ireturn_reject_stdlib.go vendored Normal file
View File

@ -0,0 +1,28 @@
// args: -Eireturn
// config_path: testdata/configs/ireturn_stdlib_reject.yml
package testdata
import (
"bytes"
"io"
)
func NewWriter() io.Writer { // ERROR `NewWriter returns interface \(io.Writer\)`
var buf bytes.Buffer
return &buf
}
func TestError() error {
return nil
}
type Foo interface {
Foo()
}
type foo int
func (f foo) Foo() {}
func NewFoo() Foo {
return foo(1)
}