Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update errorlint to HEAD #1933

Merged
merged 1 commit into from May 1, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 5 additions & 1 deletion .golangci.example.yml
Expand Up @@ -118,8 +118,12 @@ linters-settings:
exclude: /path/to/file.txt

errorlint:
# Report non-wrapping error creation using fmt.Errorf
# Check whether fmt.Errorf uses the %w verb for formatting errors. See the readme for caveats
errorf: true
# Check for plain type assertions and type switches
asserts: true
# Check for plain error comparisons
comparison: true

exhaustive:
# check switch statements in generated files also
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions go.sum

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 6 additions & 2 deletions pkg/config/linters_settings.go
Expand Up @@ -62,7 +62,9 @@ var defaultLintersSettings = LintersSettings{
ExtraRules: false,
},
ErrorLint: ErrorLintSettings{
Errorf: true,
Errorf: true,
Asserts: true,
Comparison: true,
},
Ifshort: IfshortSettings{
MaxDeclLines: 1,
Expand Down Expand Up @@ -164,7 +166,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 {
Expand Down
14 changes: 9 additions & 5 deletions pkg/golinters/errorlint.go
Expand Up @@ -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)
Expand Down
5 changes: 5 additions & 0 deletions test/testdata/configs/errorlint_asserts.yml
@@ -0,0 +1,5 @@
linters-settings:
errorlint:
errorf: false
asserts: true
comparison: false
5 changes: 5 additions & 0 deletions test/testdata/configs/errorlint_comparison.yml
@@ -0,0 +1,5 @@
linters-settings:
errorlint:
errorf: false
asserts: false
comparison: true
5 changes: 5 additions & 0 deletions test/testdata/configs/errorlint_errorf.yml
@@ -0,0 +1,5 @@
linters-settings:
errorlint:
errorf: true
asserts: false
comparison: false
87 changes: 14 additions & 73 deletions test/testdata/errorlint.go
Expand Up @@ -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")
}
}
46 changes: 46 additions & 0 deletions 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)
}
}
53 changes: 53 additions & 0 deletions 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")
}
}
4 changes: 2 additions & 2 deletions 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 (
Expand All @@ -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"
Expand Down