diff --git a/pkg/analyzer/analyzer.go b/pkg/analyzer/analyzer.go index 60f3aea..2b8794d 100644 --- a/pkg/analyzer/analyzer.go +++ b/pkg/analyzer/analyzer.go @@ -61,10 +61,10 @@ func run(pass *analysis.Pass) (interface{}, error) { name := v.Name.Name if _, ok := v.Type.(*ast.ArrayType); ok { if !isValidErrorArrayTypeName(name) { - reportAboutErrorType(pass, v.Pos(), name, true) + reportAboutArrayErrorType(pass, v.Pos(), name) } } else if !isValidErrorTypeName(name) { - reportAboutErrorType(pass, v.Pos(), name, false) + reportAboutErrorType(pass, v.Pos(), name) } return false } @@ -75,7 +75,7 @@ func run(pass *analysis.Pass) (interface{}, error) { return nil, nil //nolint:nilnil } -func reportAboutErrorType(pass *analysis.Pass, typePos token.Pos, typeName string, isArrayType bool) { +func reportAboutErrorType(pass *analysis.Pass, typePos token.Pos, typeName string) { var form string if unicode.IsLower([]rune(typeName)[0]) { form = "xxxError" @@ -83,12 +83,20 @@ func reportAboutErrorType(pass *analysis.Pass, typePos token.Pos, typeName strin form = "XxxError" } - if isArrayType { - form += "s" - } pass.Reportf(typePos, "the error type name `%s` should conform to the `%s` format", typeName, form) } +func reportAboutArrayErrorType(pass *analysis.Pass, typePos token.Pos, typeName string) { + var forms string + if unicode.IsLower([]rune(typeName)[0]) { + forms = "`xxxErrors` or `xxxError`" + } else { + forms = "`XxxErrors` or `XxxError`" + } + + pass.Reportf(typePos, "the error type name `%s` should conform to the %s format", typeName, forms) +} + func reportAboutSentinelError(pass *analysis.Pass, pos token.Pos, varName string) { var form string if unicode.IsLower([]rune(varName)[0]) { diff --git a/pkg/analyzer/facts.go b/pkg/analyzer/facts.go index f02ed55..04e14fb 100644 --- a/pkg/analyzer/facts.go +++ b/pkg/analyzer/facts.go @@ -41,10 +41,12 @@ func isValidErrorArrayTypeName(s string) bool { words := split(s) wordsCnt := wordsCount(words) - if wordsCnt["errors"] != 1 { + if wordsCnt["errors"] != 1 && wordsCnt["error"] != 1 { return false } - return words[len(words)-1] == "errors" + + lastWord := words[len(words)-1] + return lastWord == "errors" || lastWord == "error" } func isValidErrorVarName(s string) bool { diff --git a/pkg/analyzer/facts_test.go b/pkg/analyzer/facts_test.go index af765f8..3997730 100644 --- a/pkg/analyzer/facts_test.go +++ b/pkg/analyzer/facts_test.go @@ -188,6 +188,8 @@ func Test_isValidErrorArrayTypeName(t *testing.T) { "validationErrors", "ERRORS", "errors", + "IncompatiblePairError", + "multiError", } { if !isValidErrorArrayTypeName(tt) { t.Errorf("%q must be valid error array type name", tt) @@ -197,6 +199,10 @@ func Test_isValidErrorArrayTypeName(t *testing.T) { for _, tt := range []string{ "ErrorsFromValidation", "errorsFromValidation", + "ErrorMulti", + "ErrorsOfProcessing", + "processingErrs", + "ValidationErr", } { if isValidErrorArrayTypeName(tt) { t.Errorf("%q must be invalid error array type name", tt) diff --git a/pkg/analyzer/testdata/src/regular/error_types_exceptions.go b/pkg/analyzer/testdata/src/regular/error_types_exceptions.go index 208df8e..7a7813f 100644 --- a/pkg/analyzer/testdata/src/regular/error_types_exceptions.go +++ b/pkg/analyzer/testdata/src/regular/error_types_exceptions.go @@ -18,14 +18,30 @@ type tenErrors [10]string func (te tenErrors) Error() string { return strings.Join(te[:], "\n") } -type MultiError []error // want "the error type name `MultiError` should conform to the `XxxErrors` format" +type MultiErr []error // want "the error type name `MultiErr` should conform to the `XxxErrors` or `XxxError` format" +func (me MultiErr) Error() string { return "" } + +type multiErr []error // want "the error type name `multiErr` should conform to the `xxxErrors` or `xxxError` format" +func (me multiErr) Error() string { return "" } + +type Twoerr [2]error // want "the error type name `Twoerr` should conform to the `XxxErrors` or `XxxError` format" +func (te Twoerr) Error() string { return te[0].Error() + "\n" + te[1].Error() } + +type twoErrorss [2]error // want "the error type name `twoErrorss` should conform to the `xxxErrors` or `xxxError` format" +func (te twoErrorss) Error() string { return te[0].Error() + "\n" + te[1].Error() } + +type MultiError []error + func (me MultiError) Error() string { return "" } -type multiError []error // want "the error type name `multiError` should conform to the `xxxErrors` format" +type multiError []error + func (me multiError) Error() string { return "" } -type TwoError [2]error // want "the error type name `TwoError` should conform to the `XxxErrors` format" +type TwoError [2]error + func (te TwoError) Error() string { return te[0].Error() + "\n" + te[1].Error() } -type twoError [2]error // want "the error type name `twoError` should conform to the `xxxErrors` format" +type twoError [2]error + func (te twoError) Error() string { return te[0].Error() + "\n" + te[1].Error() }