Skip to content

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

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 12 commits into from
Sep 16, 2021
23 changes: 23 additions & 0 deletions .golangci.example.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions go.sum

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions pkg/config/linters_settings.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ type LintersSettings struct {
Gosimple StaticCheckSettings
Govet GovetSettings
Ifshort IfshortSettings
Ireturn IreturnSettings
ImportAs ImportAsSettings
Lll LllSettings
Makezero MakezeroSettings
Expand Down Expand Up @@ -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"`
Expand Down
30 changes: 30 additions & 0 deletions pkg/golinters/ireturn.go
Original file line number Diff line number Diff line change
@@ -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)
}
7 changes: 7 additions & 0 deletions pkg/lint/lintersdb/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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()).
Expand Down
4 changes: 4 additions & 0 deletions test/testdata/configs/ireturn.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
linters-settings:
ireturn:
allow:
- IreturnAllowDoer
4 changes: 4 additions & 0 deletions test/testdata/configs/ireturn_stdlib_reject.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
linters-settings:
ireturn:
reject:
- stdlib
13 changes: 13 additions & 0 deletions test/testdata/ireturn_allow.go
Original file line number Diff line number Diff line change
@@ -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 changes: 12 additions & 0 deletions test/testdata/ireturn_default.go
Original file line number Diff line number Diff line change
@@ -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 changes: 28 additions & 0 deletions test/testdata/ireturn_reject_stdlib.go
Original file line number Diff line number Diff line change
@@ -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)
}