Skip to content

Commit

Permalink
new-linter: ireturn (checks for function return type) (golangci#2219)
Browse files Browse the repository at this point in the history
  • Loading branch information
butuzov authored Sep 16, 2021
1 parent 813ba7d commit 2ea496f
Show file tree
Hide file tree
Showing 11 changed files with 130 additions and 0 deletions.
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)
}

0 comments on commit 2ea496f

Please sign in to comment.