diff --git a/.golangci.example.yml b/.golangci.example.yml index 4c5e0fe01cb2..d1c828f9a7cb 100644 --- a/.golangci.example.yml +++ b/.golangci.example.yml @@ -392,6 +392,12 @@ linters-settings: makezero: # Allow only slices initialized with a length of zero. Default is false. always: false + forbidigo: + # Forbid the following identifiers + forbid: + - fmt.Errorf # consider errors.Errorf in github.com/pkg/errors + - fmt.Print.* # too much log noise + - ginkgo\\.F.* # these are used just for local development # The custom section can be used to define linter plugins to be loaded at runtime. See README doc # for more info. diff --git a/go.mod b/go.mod index a5c212e8dd15..ce17ac3d3e5e 100644 --- a/go.mod +++ b/go.mod @@ -6,6 +6,7 @@ require ( 4d63.com/gochecknoglobals v0.0.0-20201008074935-acfc0b28355a github.com/Djarvur/go-err113 v0.0.0-20200511133814-5174e21577d5 github.com/OpenPeeDeeP/depguard v1.0.1 + github.com/ashanbrown/forbidigo v1.0.0 github.com/ashanbrown/makezero v0.0.0-20201205152432-7b7cdbb3025a github.com/bombsimon/wsl/v3 v3.1.0 github.com/daixiang0/gci v0.2.7 diff --git a/go.sum b/go.sum index 1b4211a2bc51..9cfe7838688c 100644 --- a/go.sum +++ b/go.sum @@ -31,6 +31,8 @@ github.com/andybalholm/brotli v1.0.0/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/ashanbrown/forbidigo v1.0.0 h1:QdNXBduDUopc3GW+YVYZn8jzmIMklQiCfdN2N5+dQeE= +github.com/ashanbrown/forbidigo v1.0.0/go.mod h1:PH+zMRWE15yW69fYfe7Kn8nYR6yYyafc3ntEGh2BBAg= github.com/ashanbrown/makezero v0.0.0-20201205152432-7b7cdbb3025a h1:/U9tbJzDRof4fOR51vwzWdIBsIH6R2yU0KG1MBRM2Js= github.com/ashanbrown/makezero v0.0.0-20201205152432-7b7cdbb3025a/go.mod h1:oG9Dnez7/ESBqc4EdrdNlryeo7d0KcW1ftXHm7nU/UU= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= @@ -332,8 +334,6 @@ github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFR github.com/rogpeppe/go-internal v1.5.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.6.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/ryancurrah/gomodguard v1.1.0 h1:DWbye9KyMgytn8uYpuHkwf0RHqAYO6Ay/D0TbCpPtVU= -github.com/ryancurrah/gomodguard v1.1.0/go.mod h1:4O8tr7hBODaGE6VIhfJDHcwzh5GUccKSJBU0UMXJFVM= github.com/ryancurrah/gomodguard v1.2.0 h1:YWfhGOrXwLGiqcC/u5EqG6YeS8nh+1fw0HEc85CVZro= github.com/ryancurrah/gomodguard v1.2.0/go.mod h1:rNqbC4TOIdUDcVMSIpNNAzTbzXAZa6W5lnUepvuMMgQ= github.com/ryanrolds/sqlclosecheck v0.3.0 h1:AZx+Bixh8zdUBxUA1NxbxVAS78vTPq4rCb8OUZI9xFw= diff --git a/pkg/config/config.go b/pkg/config/config.go index 1e2c79438c31..6474a04c1106 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -269,6 +269,7 @@ type LintersSettings struct { ErrorLint ErrorLintSettings Makezero MakezeroSettings Thelper ThelperSettings + Forbidigo ForbidigoSettings Custom map[string]CustomLinterSettings } @@ -406,6 +407,10 @@ type ThelperSettings struct { } `mapstructure:"benchmark"` } +type ForbidigoSettings struct { + Forbid []string `mapstructure:"forbid"` +} + var defaultLintersSettings = LintersSettings{ Lll: LllSettings{ LineLength: 120, diff --git a/pkg/golinters/forbidigo.go b/pkg/golinters/forbidigo.go new file mode 100644 index 000000000000..1b4dc7686d7a --- /dev/null +++ b/pkg/golinters/forbidigo.go @@ -0,0 +1,66 @@ +package golinters + +import ( + "sync" + + "github.com/ashanbrown/forbidigo/forbidigo" + "github.com/pkg/errors" + "golang.org/x/tools/go/analysis" + + "github.com/golangci/golangci-lint/pkg/golinters/goanalysis" + "github.com/golangci/golangci-lint/pkg/lint/linter" + "github.com/golangci/golangci-lint/pkg/result" +) + +const forbidigoName = "forbidigo" + +func NewForbidigo() *goanalysis.Linter { + var mu sync.Mutex + var resIssues []goanalysis.Issue + + analyzer := &analysis.Analyzer{ + Name: forbidigoName, + Doc: goanalysis.TheOnlyanalyzerDoc, + } + return goanalysis.NewLinter( + forbidigoName, + "Forbids identifiers", + []*analysis.Analyzer{analyzer}, + nil, + ).WithContextSetter(func(lintCtx *linter.Context) { + s := &lintCtx.Settings().Forbidigo + + analyzer.Run = func(pass *analysis.Pass) (interface{}, error) { + var res []goanalysis.Issue + forbid, err := forbidigo.NewLinter(s.Forbid) + if err != nil { + return nil, errors.Wrapf(err, "failed to create linter %q", forbidigoName) + } + + for _, file := range pass.Files { + hints, err := forbid.Run(pass.Fset, file) + if err != nil { + return nil, errors.Wrapf(err, "forbidigo linter failed on file %q", file.Name.String()) + } + for _, hint := range hints { + res = append(res, goanalysis.NewIssue(&result.Issue{ + Pos: hint.Position(), + Text: hint.Details(), + FromLinter: makezeroName, + }, pass)) + } + } + + if len(res) == 0 { + return nil, nil + } + + mu.Lock() + resIssues = append(resIssues, res...) + mu.Unlock() + return nil, nil + } + }).WithIssuesReporter(func(*linter.Context) []goanalysis.Issue { + return resIssues + }).WithLoadMode(goanalysis.LoadModeSyntax) +} diff --git a/pkg/lint/lintersdb/manager.go b/pkg/lint/lintersdb/manager.go index f3b92a68a4e7..c9bbdb9a866b 100644 --- a/pkg/lint/lintersdb/manager.go +++ b/pkg/lint/lintersdb/manager.go @@ -337,6 +337,9 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config { linter.NewConfig(golinters.NewMakezero()). WithPresets(linter.PresetStyle, linter.PresetBugs). WithURL("https://github.com/ashanbrown/makezero"), + linter.NewConfig(golinters.NewForbidigo()). + WithPresets(linter.PresetStyle). + WithURL("https://github.com/ashanbrown/forbidigo"), // 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/configs/forbidigo.yml b/test/testdata/configs/forbidigo.yml new file mode 100644 index 000000000000..561e46d53cc4 --- /dev/null +++ b/test/testdata/configs/forbidigo.yml @@ -0,0 +1,4 @@ +linters-settings: + forbidigo: + forbid: + - fmt\.Print.* diff --git a/test/testdata/forbidigo.go b/test/testdata/forbidigo.go new file mode 100644 index 000000000000..441d21b99d1a --- /dev/null +++ b/test/testdata/forbidigo.go @@ -0,0 +1,9 @@ +//args: -Eforbidigo +//config_path: testdata/configs/forbidigo.yml +package testdata + +import "fmt" + +func Forbidigo() { + fmt.Printf("too noisy!!!") // ERROR "use of `fmt.Printf` forbidden by pattern `fmt\\.Print.*`" +}