From 652bd912afef757a098da3219e83e1711e711dfb Mon Sep 17 00:00:00 2001 From: Anton Telyshev Date: Thu, 5 Aug 2021 01:19:58 +0300 Subject: [PATCH] Add errname linter (#2129) * Add errname linter * bump errname version --- go.mod | 1 + go.sum | 4 +++ pkg/golinters/errname.go | 21 +++++++++++++ pkg/lint/lintersdb/manager.go | 5 ++++ test/testdata/errname.go | 55 +++++++++++++++++++++++++++++++++++ 5 files changed, 86 insertions(+) create mode 100644 pkg/golinters/errname.go create mode 100644 test/testdata/errname.go diff --git a/go.mod b/go.mod index 51aa8259..2388c8e2 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,7 @@ go 1.15 require ( 4d63.com/gochecknoglobals v0.0.0-20201008074935-acfc0b28355a + github.com/Antonboom/errname v0.1.3 github.com/BurntSushi/toml v0.3.1 github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24 github.com/OpenPeeDeeP/depguard v1.0.1 diff --git a/go.sum b/go.sum index 0ac05a3c..a5f07335 100644 --- a/go.sum +++ b/go.sum @@ -44,6 +44,10 @@ cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RX cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= contrib.go.opencensus.io/exporter/stackdriver v0.13.4/go.mod h1:aXENhDJ1Y4lIg4EUaVTwzvYETVNZk10Pu26tevFKLUc= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/Antonboom/errname v0.1.2 h1:Lg1R0kXPC57BhcK8P8dDjMC4xee7BBBwVxe9M0yOF2A= +github.com/Antonboom/errname v0.1.2/go.mod h1:jRXo3m0E0EuCnK3wbsSVH3X55Z4iTDLl6ZfCxwFj4TM= +github.com/Antonboom/errname v0.1.3 h1:qKV8gSzPzBqrG/q0dgraZXJCymWt6KuD9+Y7K7xtzN8= +github.com/Antonboom/errname v0.1.3/go.mod h1:jRXo3m0E0EuCnK3wbsSVH3X55Z4iTDLl6ZfCxwFj4TM= github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= diff --git a/pkg/golinters/errname.go b/pkg/golinters/errname.go new file mode 100644 index 00000000..7ee81134 --- /dev/null +++ b/pkg/golinters/errname.go @@ -0,0 +1,21 @@ +package golinters + +import ( + "github.com/Antonboom/errname/pkg/analyzer" + "golang.org/x/tools/go/analysis" + + "github.com/golangci/golangci-lint/pkg/golinters/goanalysis" +) + +func NewErrName() *goanalysis.Linter { + analyzers := []*analysis.Analyzer{ + analyzer.New(), + } + + return goanalysis.NewLinter( + "errname", + "Checks that sentinel errors are prefixed with the `Err` and error types are suffixed with the `Error`.", + analyzers, + nil, + ).WithLoadMode(goanalysis.LoadModeTypesInfo) +} diff --git a/pkg/lint/lintersdb/manager.go b/pkg/lint/lintersdb/manager.go index fc760dc3..a69a6ec3 100644 --- a/pkg/lint/lintersdb/manager.go +++ b/pkg/lint/lintersdb/manager.go @@ -501,6 +501,11 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config { WithSince("v1.40.0"). WithPresets(linter.PresetStyle). WithURL("https://github.com/ldez/tagliatelle"), + linter.NewConfig(golinters.NewErrName()). + WithPresets(linter.PresetStyle). + WithLoadForGoAnalysis(). + WithURL("https://github.com/Antonboom/errname"). + WithSince("v1.42.0"), // 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/errname.go b/test/testdata/errname.go new file mode 100644 index 00000000..8b44e0b7 --- /dev/null +++ b/test/testdata/errname.go @@ -0,0 +1,55 @@ +//args: -Eerrname +package testdata + +import ( + "errors" + "fmt" +) + +var ( + EOF = errors.New("end of file") + ErrEndOfFile = errors.New("end of file") + errEndOfFile = errors.New("end of file") + + EndOfFileError = errors.New("end of file") // ERROR "the variable name `EndOfFileError` should conform to the `ErrXxx` format" + ErrorEndOfFile = errors.New("end of file") // ERROR "the variable name `ErrorEndOfFile` should conform to the `ErrXxx` format" + EndOfFileErr = errors.New("end of file") // ERROR "the variable name `EndOfFileErr` should conform to the `ErrXxx` format" + endOfFileError = errors.New("end of file") // ERROR "the variable name `endOfFileError` should conform to the `errXxx` format" + errorEndOfFile = errors.New("end of file") // ERROR "the variable name `errorEndOfFile` should conform to the `errXxx` format" +) + +const maxSize = 256 + +var ( + ErrOutOfSize = fmt.Errorf("out of size (max %d)", maxSize) + errOutOfSize = fmt.Errorf("out of size (max %d)", maxSize) + + OutOfSizeError = fmt.Errorf("out of size (max %d)", maxSize) // ERROR "the variable name `OutOfSizeError` should conform to the `ErrXxx` format" + outOfSizeError = fmt.Errorf("out of size (max %d)", maxSize) // ERROR "the variable name `outOfSizeError` should conform to the `errXxx` format" +) + +func errInsideFuncIsNotSentinel() error { + var lastErr error + return lastErr +} + +type NotErrorType struct{} + +func (t NotErrorType) Set() {} +func (t NotErrorType) Get() {} + +type DNSConfigError struct{} + +func (D DNSConfigError) Error() string { return "DNS config error" } + +type someTypeWithoutPtr struct{} // ERROR "the type name `someTypeWithoutPtr` should conform to the `xxxError` format" +func (s someTypeWithoutPtr) Error() string { return "someTypeWithoutPtr" } + +type SomeTypeWithoutPtr struct{} // ERROR "the type name `SomeTypeWithoutPtr` should conform to the `XxxError` format" +func (s SomeTypeWithoutPtr) Error() string { return "SomeTypeWithoutPtr" } + +type someTypeWithPtr struct{} // ERROR "the type name `someTypeWithPtr` should conform to the `xxxError` format" +func (s *someTypeWithPtr) Error() string { return "someTypeWithPtr" } + +type SomeTypeWithPtr struct{} // ERROR "the type name `SomeTypeWithPtr` should conform to the `XxxError` format" +func (s *SomeTypeWithPtr) Error() string { return "SomeTypeWithPtr" }