diff --git a/go.mod b/go.mod index c6bdb49b92cd..0ebe29a8889d 100644 --- a/go.mod +++ b/go.mod @@ -57,7 +57,7 @@ require ( github.com/nishanths/exhaustive v0.1.0 github.com/nishanths/predeclared v0.2.1 github.com/pkg/errors v0.9.1 - github.com/polyfloyd/go-errorlint v0.0.0-20201127212506-19bd8db6546f + github.com/polyfloyd/go-errorlint v0.0.0-20210418123303-74da32850375 github.com/ryancurrah/gomodguard v1.2.0 github.com/ryanrolds/sqlclosecheck v0.3.0 github.com/sanposhiho/wastedassign v0.2.0 diff --git a/go.sum b/go.sum index 187ded4a59fb..fd731e334281 100644 --- a/go.sum +++ b/go.sum @@ -495,8 +495,8 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/polyfloyd/go-errorlint v0.0.0-20201127212506-19bd8db6546f h1:xAw10KgJqG5NJDfmRqJ05Z0IFblKumjtMeyiOLxj3+4= -github.com/polyfloyd/go-errorlint v0.0.0-20201127212506-19bd8db6546f/go.mod h1:wi9BfjxjF/bwiZ701TzmfKu6UKC357IOAtNr0Td0Lvw= +github.com/polyfloyd/go-errorlint v0.0.0-20210418123303-74da32850375 h1:uuOfAQo7em74dKh41UzjlQ6dXmE9wYxjvUcfg2EHTDw= +github.com/polyfloyd/go-errorlint v0.0.0-20210418123303-74da32850375/go.mod h1:wi9BfjxjF/bwiZ701TzmfKu6UKC357IOAtNr0Td0Lvw= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= diff --git a/pkg/config/linters_settings.go b/pkg/config/linters_settings.go index 2d12c209cbcd..d8fa2bf3c2ec 100644 --- a/pkg/config/linters_settings.go +++ b/pkg/config/linters_settings.go @@ -62,7 +62,9 @@ var defaultLintersSettings = LintersSettings{ ExtraRules: false, }, ErrorLint: ErrorLintSettings{ - Errorf: true, + Errorf: true, + Asserts: true, + Comparison: true, }, Ifshort: IfshortSettings{ MaxDeclLines: 1, @@ -161,7 +163,9 @@ type ErrcheckSettings struct { } type ErrorLintSettings struct { - Errorf bool `mapstructure:"errorf"` + Errorf bool `mapstructure:"errorf"` + Asserts bool `mapstructure:"asserts"` + Comparison bool `mapstructure:"comparison"` } type ExhaustiveSettings struct { diff --git a/pkg/golinters/errorlint.go b/pkg/golinters/errorlint.go index 1c9ede203a63..dd9d901617a9 100644 --- a/pkg/golinters/errorlint.go +++ b/pkg/golinters/errorlint.go @@ -10,17 +10,21 @@ import ( func NewErrorLint(cfg *config.ErrorLintSettings) *goanalysis.Linter { a := errorlint.NewAnalyzer() + cfgMap := map[string]map[string]interface{}{} + if cfg != nil { cfgMap[a.Name] = map[string]interface{}{ - "errorf": cfg.Errorf, + "errorf": cfg.Errorf, + "asserts": cfg.Asserts, + "comparison": cfg.Comparison, } } + return goanalysis.NewLinter( - "errorlint", - "go-errorlint is a source code linter for Go software "+ - "that can be used to find code that will cause problems "+ - "with the error wrapping scheme introduced in Go 1.13.", + a.Name, + "errorlint is a linter for that can be used to find code "+ + "that will cause problems with the error wrapping scheme introduced in Go 1.13.", []*analysis.Analyzer{a}, cfgMap, ).WithLoadMode(goanalysis.LoadModeTypesInfo) diff --git a/test/testdata/configs/errorlint_asserts.yml b/test/testdata/configs/errorlint_asserts.yml new file mode 100644 index 000000000000..5e00e940930d --- /dev/null +++ b/test/testdata/configs/errorlint_asserts.yml @@ -0,0 +1,5 @@ +linters-settings: + errorlint: + errorf: false + asserts: true + comparison: false diff --git a/test/testdata/configs/errorlint_comparison.yml b/test/testdata/configs/errorlint_comparison.yml new file mode 100644 index 000000000000..8c9783d63b3c --- /dev/null +++ b/test/testdata/configs/errorlint_comparison.yml @@ -0,0 +1,5 @@ +linters-settings: + errorlint: + errorf: false + asserts: false + comparison: true diff --git a/test/testdata/configs/errorlint_errorf.yml b/test/testdata/configs/errorlint_errorf.yml new file mode 100644 index 000000000000..6d647f9230a7 --- /dev/null +++ b/test/testdata/configs/errorlint_errorf.yml @@ -0,0 +1,5 @@ +linters-settings: + errorlint: + errorf: true + asserts: false + comparison: false diff --git a/test/testdata/errorlint.go b/test/testdata/errorlint.go index a61931dc4115..7d191cae0499 100644 --- a/test/testdata/errorlint.go +++ b/test/testdata/errorlint.go @@ -3,88 +3,29 @@ package testdata import ( "errors" + "fmt" "log" ) -var errFoo = errors.New("foo") +var errLintFoo = errors.New("foo") -func doThing() error { - return errFoo -} +type errLintBar struct{} -func compare() { - err := doThing() - if errors.Is(err, errFoo) { - log.Println("ErrFoo") - } - if err == nil { - log.Println("nil") - } - if err != nil { - log.Println("nil") - } - if nil == err { - log.Println("nil") - } - if nil != err { - log.Println("nil") - } - if err == errFoo { // ERROR "comparing with == will fail on wrapped errors. Use errors.Is to check for a specific error" - log.Println("errFoo") - } - if err != errFoo { // ERROR "comparing with != will fail on wrapped errors. Use errors.Is to check for a specific error" - log.Println("not errFoo") - } - if errFoo == err { // ERROR "comparing with == will fail on wrapped errors. Use errors.Is to check for a specific error" - log.Println("errFoo") - } - if errFoo != err { // ERROR "comparing with != will fail on wrapped errors. Use errors.Is to check for a specific error" - log.Println("not errFoo") - } - switch err { // ERROR "switch on an error will fail on wrapped errors. Use errors.Is to check for specific errors" - case errFoo: - log.Println("errFoo") - } - switch doThing() { // ERROR "switch on an error will fail on wrapped errors. Use errors.Is to check for specific errors" - case errFoo: - log.Println("errFoo") - } +func (*errLintBar) Error() string { + return "bar" } -type myError struct{} - -func (*myError) Error() string { - return "foo" -} +func errorLintAll() { + err := func() error { return nil }() + if err == errLintFoo { // ERROR "comparing with == will fail on wrapped errors. Use errors.Is to check for a specific error" + log.Println("errCompare") + } -func doAnotherThing() error { - return &myError{} -} + err = errors.New("oops") + fmt.Errorf("error: %v", err) // ERROR "non-wrapping format verb for fmt.Errorf. Use `%w` to format errors" -func typeCheck() { - err := doAnotherThing() - var me *myError - if errors.As(err, &me) { - log.Println("myError") - } - _, ok := err.(*myError) // ERROR "type assertion on error will fail on wrapped errors. Use errors.As to check for specific errors" - if ok { - log.Println("myError") - } switch err.(type) { // ERROR "type switch on error will fail on wrapped errors. Use errors.As to check for specific errors" - case *myError: - log.Println("myError") - } - switch doAnotherThing().(type) { // ERROR "type switch on error will fail on wrapped errors. Use errors.As to check for specific errors" - case *myError: - log.Println("myError") - } - switch t := err.(type) { // ERROR "type switch on error will fail on wrapped errors. Use errors.As to check for specific errors" - case *myError: - log.Println("myError", t) - } - switch t := doAnotherThing().(type) { // ERROR "type switch on error will fail on wrapped errors. Use errors.As to check for specific errors" - case *myError: - log.Println("myError", t) + case *errLintBar: + log.Println("errLintBar") } } diff --git a/test/testdata/errorlint_asserts.go b/test/testdata/errorlint_asserts.go new file mode 100644 index 000000000000..31f53a59abcc --- /dev/null +++ b/test/testdata/errorlint_asserts.go @@ -0,0 +1,46 @@ +//args: -Eerrorlint +//config_path: testdata/configs/errorlint_asserts.yml +package testdata + +import ( + "errors" + "log" +) + +type myError struct{} + +func (*myError) Error() string { + return "foo" +} + +func errorLintDoAnotherThing() error { + return &myError{} +} + +func errorLintAsserts() { + err := errorLintDoAnotherThing() + var me *myError + if errors.As(err, &me) { + log.Println("myError") + } + _, ok := err.(*myError) // ERROR "type assertion on error will fail on wrapped errors. Use errors.As to check for specific errors" + if ok { + log.Println("myError") + } + switch err.(type) { // ERROR "type switch on error will fail on wrapped errors. Use errors.As to check for specific errors" + case *myError: + log.Println("myError") + } + switch errorLintDoAnotherThing().(type) { // ERROR "type switch on error will fail on wrapped errors. Use errors.As to check for specific errors" + case *myError: + log.Println("myError") + } + switch t := err.(type) { // ERROR "type switch on error will fail on wrapped errors. Use errors.As to check for specific errors" + case *myError: + log.Println("myError", t) + } + switch t := errorLintDoAnotherThing().(type) { // ERROR "type switch on error will fail on wrapped errors. Use errors.As to check for specific errors" + case *myError: + log.Println("myError", t) + } +} diff --git a/test/testdata/errorlint_comparison.go b/test/testdata/errorlint_comparison.go new file mode 100644 index 000000000000..1bef52ed2b8f --- /dev/null +++ b/test/testdata/errorlint_comparison.go @@ -0,0 +1,53 @@ +//args: -Eerrorlint +//config_path: testdata/configs/errorlint_comparison.yml +package testdata + +import ( + "errors" + "log" +) + +var errCompare = errors.New("foo") + +func errorLintDoThing() error { + return errCompare +} + +func errorLintComparison() { + err := errorLintDoThing() + if errors.Is(err, errCompare) { + log.Println("errCompare") + } + if err == nil { + log.Println("nil") + } + if err != nil { + log.Println("nil") + } + if nil == err { + log.Println("nil") + } + if nil != err { + log.Println("nil") + } + if err == errCompare { // ERROR "comparing with == will fail on wrapped errors. Use errors.Is to check for a specific error" + log.Println("errCompare") + } + if err != errCompare { // ERROR "comparing with != will fail on wrapped errors. Use errors.Is to check for a specific error" + log.Println("not errCompare") + } + if errCompare == err { // ERROR "comparing with == will fail on wrapped errors. Use errors.Is to check for a specific error" + log.Println("errCompare") + } + if errCompare != err { // ERROR "comparing with != will fail on wrapped errors. Use errors.Is to check for a specific error" + log.Println("not errCompare") + } + switch err { // ERROR "switch on an error will fail on wrapped errors. Use errors.Is to check for specific errors" + case errCompare: + log.Println("errCompare") + } + switch errorLintDoThing() { // ERROR "switch on an error will fail on wrapped errors. Use errors.Is to check for specific errors" + case errCompare: + log.Println("errCompare") + } +} diff --git a/test/testdata/errorlint_errorf.go b/test/testdata/errorlint_errorf.go index 8bd3f419f812..5d3cb85603d5 100644 --- a/test/testdata/errorlint_errorf.go +++ b/test/testdata/errorlint_errorf.go @@ -1,5 +1,5 @@ //args: -Eerrorlint -//config: linters-settings.errorlint.errorf=true +//config_path: testdata/configs/errorlint_errorf.yml package testdata import ( @@ -13,7 +13,7 @@ func (customError) Error() string { return "oops" } -func wraps() { +func errorLintErrorf() { err := errors.New("oops") fmt.Errorf("error: %w", err) fmt.Errorf("error: %v", err) // ERROR "non-wrapping format verb for fmt.Errorf. Use `%w` to format errors"