Add go-errorlint (#1420)
* Add errorlint * Add errorlint config example
This commit is contained in:
parent
501f00c6b0
commit
796a958805
@ -331,6 +331,9 @@ linters-settings:
|
||||
# Choose whether or not to use the extra rules that are disabled
|
||||
# by default
|
||||
extra-rules: false
|
||||
errorlint:
|
||||
# Report non-wrapping error creation using fmt.Errorf
|
||||
errorf: true
|
||||
|
||||
# The custom section can be used to define linter plugins to be loaded at runtime. See README doc
|
||||
# for more info.
|
||||
|
1
go.mod
1
go.mod
@ -38,6 +38,7 @@ require (
|
||||
github.com/nakabonne/nestif v0.3.0
|
||||
github.com/nishanths/exhaustive v0.0.0-20200811152831-6cf413ae40e0
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/polyfloyd/go-errorlint v0.0.0-20201006195004-351e25ade6e3
|
||||
github.com/ryancurrah/gomodguard v1.1.0
|
||||
github.com/ryanrolds/sqlclosecheck v0.3.0
|
||||
github.com/securego/gosec/v2 v2.4.0
|
||||
|
8
go.sum
generated
8
go.sum
generated
@ -223,6 +223,7 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/kyoh86/exportloopref v0.1.7 h1:u+iHuTbkbTS2D/JP7fCuZDo/t3rBVGo3Hf58Rc+lQVY=
|
||||
github.com/kyoh86/exportloopref v0.1.7/go.mod h1:h1rDl2Kdj97+Kwh4gdz3ujE7XHmH51Q0lUiZ1z4NLj8=
|
||||
github.com/lib/pq v1.0.0 h1:X5PMW56eZitiTeO7tKzZxFCSpbFZJtkMMooicw2us9A=
|
||||
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/logrusorgru/aurora v0.0.0-20181002194514-a7b3b318ed4e/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4=
|
||||
github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4=
|
||||
@ -233,8 +234,6 @@ github.com/matoous/godox v0.0.0-20190911065817-5d6d842e92eb h1:RHba4YImhrUVQDHUC
|
||||
github.com/matoous/godox v0.0.0-20190911065817-5d6d842e92eb/go.mod h1:1BELzlh859Sh1c6+90blK8lbYy0kwQf1bYlBhBysy1s=
|
||||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
github.com/mattn/go-colorable v0.1.7 h1:bQGKb3vps/j0E9GfJQ03JyhRuxsvdAanXlT9BTw3mdw=
|
||||
github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8=
|
||||
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||
@ -242,6 +241,7 @@ github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hd
|
||||
github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
|
||||
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
|
||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/mattn/go-sqlite3 v1.9.0 h1:pDRiWfl+++eC2FEFRy6jXmQlvp4Yh3z1MJKg4UeYM/4=
|
||||
github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||
github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
@ -294,6 +294,8 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
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-20201006195004-351e25ade6e3 h1:Amgs0nbayPhBNGh1qPqqr2e7B2qNAcBgRjnBH/lmn8k=
|
||||
github.com/polyfloyd/go-errorlint v0.0.0-20201006195004-351e25ade6e3/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=
|
||||
@ -457,6 +459,7 @@ golang.org/x/net v0.0.0-20200822124328-c89045814202 h1:VvcQYSHwXgi7W+TpUR6A9g6Up
|
||||
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
@ -520,6 +523,7 @@ golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtn
|
||||
golang.org/x/tools v0.0.0-20190910044552-dd2b5c81c578/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
|
@ -249,6 +249,7 @@ type LintersSettings struct {
|
||||
NoLintLint NoLintLintSettings
|
||||
Exhaustive ExhaustiveSettings
|
||||
Gofumpt GofumptSettings
|
||||
ErrorLint ErrorLintSettings
|
||||
|
||||
Custom map[string]CustomLinterSettings
|
||||
}
|
||||
@ -360,6 +361,10 @@ type GofumptSettings struct {
|
||||
ExtraRules bool `mapstructure:"extra-rules"`
|
||||
}
|
||||
|
||||
type ErrorLintSettings struct {
|
||||
Errorf bool `mapstructure:"errorf"`
|
||||
}
|
||||
|
||||
var defaultLintersSettings = LintersSettings{
|
||||
Lll: LllSettings{
|
||||
LineLength: 120,
|
||||
@ -416,6 +421,9 @@ var defaultLintersSettings = LintersSettings{
|
||||
Gofumpt: GofumptSettings{
|
||||
ExtraRules: false,
|
||||
},
|
||||
ErrorLint: ErrorLintSettings{
|
||||
Errorf: true,
|
||||
},
|
||||
}
|
||||
|
||||
type CustomLinterSettings struct {
|
||||
|
27
pkg/golinters/errorlint.go
Normal file
27
pkg/golinters/errorlint.go
Normal file
@ -0,0 +1,27 @@
|
||||
package golinters
|
||||
|
||||
import (
|
||||
"github.com/polyfloyd/go-errorlint/errorlint"
|
||||
"golang.org/x/tools/go/analysis"
|
||||
|
||||
"github.com/golangci/golangci-lint/pkg/config"
|
||||
"github.com/golangci/golangci-lint/pkg/golinters/goanalysis"
|
||||
)
|
||||
|
||||
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,
|
||||
}
|
||||
}
|
||||
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.",
|
||||
[]*analysis.Analyzer{a},
|
||||
cfgMap,
|
||||
).WithLoadMode(goanalysis.LoadModeTypesInfo)
|
||||
}
|
@ -90,10 +90,12 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config {
|
||||
var govetCfg *config.GovetSettings
|
||||
var testpackageCfg *config.TestpackageSettings
|
||||
var exhaustiveCfg *config.ExhaustiveSettings
|
||||
var errorlintCfg *config.ErrorLintSettings
|
||||
if m.cfg != nil {
|
||||
govetCfg = &m.cfg.LintersSettings.Govet
|
||||
testpackageCfg = &m.cfg.LintersSettings.Testpackage
|
||||
exhaustiveCfg = &m.cfg.LintersSettings.Exhaustive
|
||||
errorlintCfg = &m.cfg.LintersSettings.ErrorLint
|
||||
}
|
||||
const megacheckName = "megacheck"
|
||||
lcs := []*linter.Config{
|
||||
@ -315,6 +317,10 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config {
|
||||
WithPresets(linter.PresetStyle).
|
||||
WithLoadForGoAnalysis().
|
||||
WithURL("https://github.com/moricho/tparallel"),
|
||||
linter.NewConfig(golinters.NewErrorLint(errorlintCfg)).
|
||||
WithPresets(linter.PresetBugs).
|
||||
WithLoadForGoAnalysis().
|
||||
WithURL("https://github.com/polyfloyd/go-errorlint"),
|
||||
|
||||
// nolintlint must be last because it looks at the results of all the previous linters for unused nolint directives
|
||||
linter.NewConfig(golinters.NewNoLintLint()).
|
||||
|
90
test/testdata/errorlint.go
vendored
Normal file
90
test/testdata/errorlint.go
vendored
Normal file
@ -0,0 +1,90 @@
|
||||
//args: -Eerrorlint
|
||||
package testdata
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"log"
|
||||
)
|
||||
|
||||
var errFoo = errors.New("foo")
|
||||
|
||||
func doThing() error {
|
||||
return errFoo
|
||||
}
|
||||
|
||||
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")
|
||||
}
|
||||
}
|
||||
|
||||
type myError struct{}
|
||||
|
||||
func (*myError) Error() string {
|
||||
return "foo"
|
||||
}
|
||||
|
||||
func doAnotherThing() error {
|
||||
return &myError{}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
26
test/testdata/errorlint_errorf.go
vendored
Normal file
26
test/testdata/errorlint_errorf.go
vendored
Normal file
@ -0,0 +1,26 @@
|
||||
//args: -Eerrorlint
|
||||
//config: linters-settings.errorlint.errorf=true
|
||||
package testdata
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type customError struct{}
|
||||
|
||||
func (customError) Error() string {
|
||||
return "oops"
|
||||
}
|
||||
|
||||
func wraps() {
|
||||
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"
|
||||
fmt.Errorf("%v %v", err, err) // ERROR "non-wrapping format verb for fmt.Errorf. Use `%w` to format errors"
|
||||
fmt.Errorf("error: %s", err.Error()) // ERROR "non-wrapping format verb for fmt.Errorf. Use `%w` to format errors"
|
||||
customError := customError{}
|
||||
fmt.Errorf("error: %s", customError.Error()) // ERROR "non-wrapping format verb for fmt.Errorf. Use `%w` to format errors"
|
||||
strErr := "oops"
|
||||
fmt.Errorf("%v", strErr)
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user