1
0
mirror of https://github.com/mgechev/revive.git synced 2025-10-30 23:37:49 +02:00

refactor: replace failure Category raw string with constant (#1196)

* refactor: replace Category raw strings with constants

* Add type FailureCategory; add comments for constants
This commit is contained in:
Oleksandr Redko
2025-01-18 13:16:19 +02:00
committed by GitHub
parent 57fe5b63d4
commit 395f7902d3
63 changed files with 151 additions and 107 deletions

View File

@@ -5,6 +5,53 @@ import (
"go/token"
)
const (
// FailureCategoryArgOrder indicates argument order issues.
FailureCategoryArgOrder FailureCategory = "arg-order"
// FailureCategoryBadPractice indicates bad practice issues.
FailureCategoryBadPractice FailureCategory = "bad practice"
// FailureCategoryCodeStyle indicates code style issues.
FailureCategoryCodeStyle FailureCategory = "code-style"
// FailureCategoryComments indicates comment issues.
FailureCategoryComments FailureCategory = "comments"
// FailureCategoryComplexity indicates complexity issues.
FailureCategoryComplexity FailureCategory = "complexity"
// FailureCategoryContent indicates content issues.
FailureCategoryContent FailureCategory = "content"
// FailureCategoryErrors indicates error handling issues.
FailureCategoryErrors FailureCategory = "errors"
// FailureCategoryImports indicates import issues.
FailureCategoryImports FailureCategory = "imports"
// FailureCategoryLogic indicates logic issues.
FailureCategoryLogic FailureCategory = "logic"
// FailureCategoryMaintenance indicates maintenance issues.
FailureCategoryMaintenance FailureCategory = "maintenance"
// FailureCategoryNaming indicates naming issues.
FailureCategoryNaming FailureCategory = "naming"
// FailureCategoryOptimization indicates optimization issues.
FailureCategoryOptimization FailureCategory = "optimization"
// FailureCategoryStyle indicates style issues.
FailureCategoryStyle FailureCategory = "style"
// FailureCategoryTime indicates time-related issues.
FailureCategoryTime FailureCategory = "time"
// FailureCategoryTypeInference indicates type inference issues.
FailureCategoryTypeInference FailureCategory = "type-inference"
// FailureCategoryUnaryOp indicates unary operation issues.
FailureCategoryUnaryOp FailureCategory = "unary-op"
// FailureCategoryUnexportedTypeInAPI indicates unexported type in API issues.
FailureCategoryUnexportedTypeInAPI FailureCategory = "unexported-type-in-api"
// FailureCategoryZeroValue indicates zero value issues.
FailureCategoryZeroValue FailureCategory = "zero-value"
// failureCategoryInternal indicates internal failures.
failureCategoryInternal FailureCategory = "REVIVE_INTERNAL"
// failureCategoryValidity indicates validity issues.
failureCategoryValidity FailureCategory = "validity"
)
// FailureCategory is the type for the failure categories.
type FailureCategory string
const (
// SeverityWarning declares failures of type warning
SeverityWarning = "warning"
@@ -25,7 +72,7 @@ type FailurePosition struct {
type Failure struct {
Failure string
RuleName string
Category string
Category FailureCategory
Position FailurePosition
Node ast.Node `json:"-"`
Confidence float64
@@ -38,17 +85,15 @@ func (f *Failure) GetFilename() string {
return f.Position.Start.Filename
}
const internalFailure = "REVIVE_INTERNAL"
// IsInternal returns true if this failure is internal, false otherwise.
func (f *Failure) IsInternal() bool {
return f.Category == internalFailure
return f.Category == failureCategoryInternal
}
// NewInternalFailure yields an internal failure with the given message as failure message.
func NewInternalFailure(message string) Failure {
return Failure{
Category: internalFailure,
Category: failureCategoryInternal,
Failure: message,
}
}

View File

@@ -223,7 +223,7 @@ func addInvalidFileFailure(filename, errStr string, failures chan Failure) {
failures <- Failure{
Confidence: 1,
Failure: fmt.Sprintf("invalid file %s: %v", filename, errStr),
Category: "validity",
Category: failureCategoryValidity,
Position: position,
}
}

View File

@@ -171,7 +171,7 @@ func (w *lintAddConstantRule) checkStrLit(n *ast.BasicLit) {
w.onFailure(lint.Failure{
Confidence: 1,
Node: n,
Category: "style",
Category: lint.FailureCategoryStyle,
Failure: fmt.Sprintf("string literal %s appears, at least, %d times, create a named constant for it", n.Value, w.strLits[n.Value]),
})
w.strLits[n.Value] = -1 // mark it to avoid failing again on the same literal
@@ -187,7 +187,7 @@ func (w *lintAddConstantRule) checkNumLit(kind string, n *ast.BasicLit) {
w.onFailure(lint.Failure{
Confidence: 1,
Node: n,
Category: "style",
Category: lint.FailureCategoryStyle,
Failure: fmt.Sprintf("avoid magic numbers like '%s', create a named constant for it", n.Value),
})
}

View File

@@ -23,7 +23,6 @@ func (r *BlankImportsRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failu
const (
message = "a blank import should be only in a main or test package, or have a comment justifying it"
category = "imports"
embedImportPath = `"embed"`
)
@@ -55,7 +54,7 @@ func (r *BlankImportsRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failu
// This is the first blank import of a group.
if imp.Doc == nil && imp.Comment == nil {
failures = append(failures, lint.Failure{Failure: message, Category: category, Node: imp, Confidence: 1})
failures = append(failures, lint.Failure{Failure: message, Category: lint.FailureCategoryImports, Node: imp, Confidence: 1})
}
}

View File

@@ -53,16 +53,16 @@ func (w *lintBoolLiteral) Visit(node ast.Node) ast.Visitor {
isConstant := (n.Op == token.LAND && lexeme == "false") || (n.Op == token.LOR && lexeme == "true")
if isConstant {
w.addFailure(n, "Boolean expression seems to always evaluate to "+lexeme, "logic")
w.addFailure(n, "Boolean expression seems to always evaluate to "+lexeme, lint.FailureCategoryLogic)
} else {
w.addFailure(n, "omit Boolean literal in expression", "style")
w.addFailure(n, "omit Boolean literal in expression", lint.FailureCategoryStyle)
}
}
return w
}
func (w lintBoolLiteral) addFailure(node ast.Node, msg, cat string) {
func (w lintBoolLiteral) addFailure(node ast.Node, msg string, cat lint.FailureCategory) {
w.onFailure(lint.Failure{
Confidence: 1,
Node: node,

View File

@@ -62,7 +62,7 @@ func (w lintCallToGC) Visit(node ast.Node) ast.Visitor {
w.onFailure(lint.Failure{
Confidence: 1,
Node: node,
Category: "bad practice",
Category: lint.FailureCategoryBadPractice,
Failure: "explicit call to the garbage collector",
})

View File

@@ -73,7 +73,7 @@ func (w cognitiveComplexityLinter) lintCognitiveComplexity() {
if c > w.maxComplexity {
w.onFailure(lint.Failure{
Confidence: 1,
Category: "maintenance",
Category: lint.FailureCategoryMaintenance,
Failure: fmt.Sprintf("function %s has cognitive complexity %d (> max enabled %d)", funcName(fn), c, w.maxComplexity),
Node: fn,
})

View File

@@ -57,7 +57,7 @@ func (r *CommentSpacingsRule) Apply(file *lint.File, _ lint.Arguments) []lint.Fa
failures = append(failures, lint.Failure{
Node: comment,
Confidence: 1,
Category: "style",
Category: lint.FailureCategoryStyle,
Failure: "no space between comment delimiter and comment text",
})
}

View File

@@ -102,7 +102,7 @@ func checkMethodName(holder string, id *ast.Ident, w *lintConfusingNames) {
Failure: fmt.Sprintf("Method '%s' differs only by capitalization to %s '%s' in %s", id.Name, kind, refMethod.id.Name, fileName),
Confidence: 1,
Node: id,
Category: "naming",
Category: lint.FailureCategoryNaming,
})
return
@@ -176,7 +176,7 @@ func checkStructFields(fields *ast.FieldList, structName string, w *lintConfusin
Failure: fmt.Sprintf("Field '%s' differs only by capitalization to other field in the struct type %s", id.Name, structName),
Confidence: 1,
Node: id,
Category: "naming",
Category: lint.FailureCategoryNaming,
})
} else {
bl[normName] = true

View File

@@ -34,7 +34,7 @@ func (*ConfusingResultsRule) Apply(file *lint.File, _ lint.Arguments) []lint.Fai
failures = append(failures, lint.Failure{
Node: result,
Confidence: 1,
Category: "naming",
Category: lint.FailureCategoryNaming,
Failure: "unnamed results of the same type may be confusing, consider using named results",
})

View File

@@ -95,7 +95,7 @@ func (w *lintConstantLogicalExpr) newFailure(node ast.Node, msg string) {
w.onFailure(lint.Failure{
Confidence: 1,
Node: node,
Category: "logic",
Category: lint.FailureCategoryLogic,
Failure: msg,
})
}

View File

@@ -32,7 +32,7 @@ func (r *ContextAsArgumentRule) Apply(file *lint.File, _ lint.Arguments) []lint.
if argIsCtx && !isCtxStillAllowed {
failures = append(failures, lint.Failure{
Node: arg,
Category: "arg-order",
Category: lint.FailureCategoryArgOrder,
Failure: "context.Context should be the first parameter of a function",
Confidence: 0.9,
})

View File

@@ -74,7 +74,7 @@ func checkContextKeyType(w lintContextKeyTypes, x *ast.CallExpr) {
w.onFailure(lint.Failure{
Confidence: 1,
Node: x,
Category: "content",
Category: lint.FailureCategoryContent,
Failure: fmt.Sprintf("should not use basic type %s as key in context.WithValue", key.Type),
})
}

View File

@@ -47,7 +47,7 @@ func (r *CyclomaticRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure
if c > r.maxComplexity {
failures = append(failures, lint.Failure{
Confidence: 1,
Category: "maintenance",
Category: lint.FailureCategoryMaintenance,
Failure: fmt.Sprintf("function %s has cyclomatic complexity %d (> max enabled %d)",
funcName(fn), c, r.maxComplexity),
Node: fn,

View File

@@ -122,14 +122,14 @@ func (w lintFunctionForDataRaces) Visit(node ast.Node) ast.Visitor {
w.onFailure(lint.Failure{
Confidence: 1,
Node: id,
Category: "logic",
Category: lint.FailureCategoryLogic,
Failure: fmt.Sprintf("datarace: range value %s is captured (by-reference) in goroutine", id.Name),
})
case isReturnID:
w.onFailure(lint.Failure{
Confidence: 0.8,
Node: id,
Category: "logic",
Category: lint.FailureCategoryLogic,
Failure: fmt.Sprintf("potential datarace: return value %s is captured (by-reference) in goroutine", id.Name),
})
}

View File

@@ -68,7 +68,7 @@ func (w *lintDeepExit) Visit(node ast.Node) ast.Visitor {
w.onFailure(lint.Failure{
Confidence: 1,
Node: ce,
Category: "bad practice",
Category: lint.FailureCategoryBadPractice,
Failure: fmt.Sprintf("calls to %s.%s only in main() or init() functions", pkg, fn),
})
}

View File

@@ -94,7 +94,7 @@ func (w lintDeferRule) Visit(node ast.Node) ast.Visitor {
return nil
case *ast.ReturnStmt:
if len(n.Results) != 0 && w.inADefer && w.inAFuncLit {
w.newFailure("return in a defer function has no effect", n, 1.0, "logic", "return")
w.newFailure("return in a defer function has no effect", n, 1.0, lint.FailureCategoryLogic, "return")
}
case *ast.CallExpr:
isCallToRecover := isIdent(n.Fun, "recover")
@@ -103,13 +103,13 @@ func (w lintDeferRule) Visit(node ast.Node) ast.Visitor {
// func fn() { recover() }
//
// confidence is not 1 because recover can be in a function that is deferred elsewhere
w.newFailure("recover must be called inside a deferred function", n, 0.8, "logic", "recover")
w.newFailure("recover must be called inside a deferred function", n, 0.8, lint.FailureCategoryLogic, "recover")
case w.inADefer && !w.inAFuncLit && isCallToRecover:
// defer helper(recover())
//
// confidence is not truly 1 because this could be in a correctly-deferred func,
// but it is very likely to be a misunderstanding of defer's behavior around arguments.
w.newFailure("recover must be called inside a deferred function, this is executing recover immediately", n, 1, "logic", "immediate-recover")
w.newFailure("recover must be called inside a deferred function, this is executing recover immediately", n, 1, lint.FailureCategoryLogic, "immediate-recover")
}
return nil // no need to analyze the arguments of the function call
case *ast.DeferStmt:
@@ -118,7 +118,7 @@ func (w lintDeferRule) Visit(node ast.Node) ast.Visitor {
//
// confidence is not truly 1 because this could be in a correctly-deferred func,
// but normally this doesn't suppress a panic, and even if it did it would silently discard the value.
w.newFailure("recover must be called inside a deferred function, this is executing recover immediately", n, 1, "logic", "immediate-recover")
w.newFailure("recover must be called inside a deferred function, this is executing recover immediately", n, 1, lint.FailureCategoryLogic, "immediate-recover")
}
w.visitSubtree(n.Call.Fun, true, false, false)
for _, a := range n.Call.Args {
@@ -131,17 +131,17 @@ func (w lintDeferRule) Visit(node ast.Node) ast.Visitor {
}
if w.inALoop {
w.newFailure("prefer not to defer inside loops", n, 1.0, "bad practice", "loop")
w.newFailure("prefer not to defer inside loops", n, 1.0, lint.FailureCategoryBadPractice, "loop")
}
switch fn := n.Call.Fun.(type) {
case *ast.CallExpr:
w.newFailure("prefer not to defer chains of function calls", fn, 1.0, "bad practice", "call-chain")
w.newFailure("prefer not to defer chains of function calls", fn, 1.0, lint.FailureCategoryBadPractice, "call-chain")
case *ast.SelectorExpr:
if id, ok := fn.X.(*ast.Ident); ok {
isMethodCall := id != nil && id.Obj != nil && id.Obj.Kind == ast.Typ
if isMethodCall {
w.newFailure("be careful when deferring calls to methods without pointer receiver", fn, 0.8, "bad practice", "method-call")
w.newFailure("be careful when deferring calls to methods without pointer receiver", fn, 0.8, lint.FailureCategoryBadPractice, "method-call")
}
}
}
@@ -163,7 +163,7 @@ func (w lintDeferRule) visitSubtree(n ast.Node, inADefer, inALoop, inAFuncLit bo
ast.Walk(nw, n)
}
func (w lintDeferRule) newFailure(msg string, node ast.Node, confidence float64, cat, subcase string) {
func (w lintDeferRule) newFailure(msg string, node ast.Node, confidence float64, cat lint.FailureCategory, subcase string) {
if !w.allow[subcase] {
return
}

View File

@@ -81,7 +81,7 @@ func (w lintImports) Visit(_ ast.Node) ast.Visitor {
Confidence: 1,
Failure: "should not use dot imports",
Node: importSpec,
Category: "imports",
Category: lint.FailureCategoryImports,
})
}
}

View File

@@ -22,7 +22,7 @@ func (*DuplicatedImportsRule) Apply(file *lint.File, _ lint.Arguments) []lint.Fa
Confidence: 1,
Failure: fmt.Sprintf("Package %s already imported", path),
Node: imp,
Category: "imports",
Category: lint.FailureCategoryImports,
})
continue
}

View File

@@ -55,7 +55,7 @@ func (w lintEmptyBlock) Visit(node ast.Node) ast.Visitor {
w.onFailure(lint.Failure{
Confidence: 0.9,
Node: n,
Category: "logic",
Category: lint.FailureCategoryLogic,
Failure: "this block is empty, you can remove it",
})
return nil // skip visiting the range subtree (it will produce a duplicated failure)
@@ -65,7 +65,7 @@ func (w lintEmptyBlock) Visit(node ast.Node) ast.Visitor {
w.onFailure(lint.Failure{
Confidence: 1,
Node: n,
Category: "logic",
Category: lint.FailureCategoryLogic,
Failure: "this block is empty, you can remove it",
})
}

View File

@@ -60,7 +60,7 @@ func (w lintEmptyLines) checkStart(block *ast.BlockStmt) {
w.onFailure(lint.Failure{
Confidence: 1,
Node: block,
Category: "style",
Category: lint.FailureCategoryStyle,
Failure: "extra empty line at the start of a block",
})
}
@@ -79,7 +79,7 @@ func (w lintEmptyLines) checkEnd(block *ast.BlockStmt) {
w.onFailure(lint.Failure{
Confidence: 1,
Node: block,
Category: "style",
Category: lint.FailureCategoryStyle,
Failure: "extra empty line at the end of a block",
})
}

View File

@@ -91,7 +91,7 @@ func (r *EnforceMapStyleRule) Apply(file *lint.File, _ lint.Arguments) []lint.Fa
failures = append(failures, lint.Failure{
Confidence: 1,
Node: v,
Category: "style",
Category: lint.FailureCategoryStyle,
Failure: "use make(map[type]type) instead of map[type]type{}",
})
case *ast.CallExpr:
@@ -119,7 +119,7 @@ func (r *EnforceMapStyleRule) Apply(file *lint.File, _ lint.Arguments) []lint.Fa
failures = append(failures, lint.Failure{
Confidence: 1,
Node: v.Args[0],
Category: "style",
Category: lint.FailureCategoryStyle,
Failure: "use map[type]type{} instead of make(map[type]type)",
})
}

View File

@@ -121,7 +121,7 @@ func (r *EnforceRepeatedArgTypeStyleRule) Apply(file *lint.File, _ lint.Argument
failures = append(failures, lint.Failure{
Confidence: 1,
Node: field,
Category: "style",
Category: lint.FailureCategoryStyle,
Failure: "argument types should not be omitted",
})
}
@@ -137,7 +137,7 @@ func (r *EnforceRepeatedArgTypeStyleRule) Apply(file *lint.File, _ lint.Argument
failures = append(failures, lint.Failure{
Confidence: 1,
Node: prevType,
Category: "style",
Category: lint.FailureCategoryStyle,
Failure: fmt.Sprintf("repeated argument type %q can be omitted", prevTypeStr),
})
}
@@ -154,7 +154,7 @@ func (r *EnforceRepeatedArgTypeStyleRule) Apply(file *lint.File, _ lint.Argument
failures = append(failures, lint.Failure{
Confidence: 1,
Node: field,
Category: "style",
Category: lint.FailureCategoryStyle,
Failure: "return types should not be omitted",
})
}
@@ -170,7 +170,7 @@ func (r *EnforceRepeatedArgTypeStyleRule) Apply(file *lint.File, _ lint.Argument
failures = append(failures, lint.Failure{
Confidence: 1,
Node: prevType,
Category: "style",
Category: lint.FailureCategoryStyle,
Failure: fmt.Sprintf("repeated return type %q can be omitted", prevTypeStr),
})
}

View File

@@ -105,7 +105,7 @@ func (r *EnforceSliceStyleRule) Apply(file *lint.File, _ lint.Arguments) []lint.
failures = append(failures, lint.Failure{
Confidence: 1,
Node: v,
Category: "style",
Category: lint.FailureCategoryStyle,
Failure: failureMessage,
})
case *ast.CallExpr:
@@ -165,7 +165,7 @@ func (r *EnforceSliceStyleRule) Apply(file *lint.File, _ lint.Arguments) []lint.
failures = append(failures, lint.Failure{
Confidence: 1,
Node: v.Args[0],
Category: "style",
Category: lint.FailureCategoryStyle,
Failure: failureMessage,
})
}

View File

@@ -69,7 +69,7 @@ func (w lintErrors) Visit(_ ast.Node) ast.Visitor {
w.onFailure(lint.Failure{
Node: id,
Confidence: 0.9,
Category: "naming",
Category: lint.FailureCategoryNaming,
Failure: fmt.Sprintf("error var %s should have name of the form %sFoo", id.Name, prefix),
})
}

View File

@@ -31,7 +31,7 @@ func (*ErrorReturnRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure
for _, r := range funcResults[:len(funcResults)-1] {
if isIdent(r.Type, "error") {
failures = append(failures, lint.Failure{
Category: "style",
Category: lint.FailureCategoryStyle,
Confidence: 0.9,
Node: funcDecl,
Failure: "error should be the last type when returning multiple items",

View File

@@ -115,7 +115,7 @@ func (w lintErrorStrings) Visit(n ast.Node) ast.Visitor {
w.onFailure(lint.Failure{
Node: str,
Confidence: conf,
Category: "errors",
Category: lint.FailureCategoryErrors,
Failure: "error strings should not be capitalized or end with punctuation or a newline",
})
return w

View File

@@ -69,7 +69,7 @@ func (w lintErrorf) Visit(n ast.Node) ast.Visitor {
}
failure := lint.Failure{
Category: "errors",
Category: lint.FailureCategoryErrors,
Node: n,
Confidence: 1,
Failure: fmt.Sprintf("should replace %s(fmt.Sprintf(...)) with %s.Errorf(...)", w.file.Render(se), errorfPrefix),

View File

@@ -186,7 +186,7 @@ func (w *lintExported) lintFuncDoc(fn *ast.FuncDecl) {
w.onFailure(lint.Failure{
Node: fn,
Confidence: 1,
Category: "comments",
Category: lint.FailureCategoryComments,
Failure: fmt.Sprintf("exported %s %s should have comment or be unexported", kind, name),
})
return
@@ -198,7 +198,7 @@ func (w *lintExported) lintFuncDoc(fn *ast.FuncDecl) {
w.onFailure(lint.Failure{
Node: fn.Doc,
Confidence: 0.8,
Category: "comments",
Category: lint.FailureCategoryComments,
Failure: fmt.Sprintf(`comment on exported %s %s should be of the form "%s..."`, kind, name, prefix),
})
}
@@ -232,7 +232,7 @@ func (w *lintExported) checkStutter(id *ast.Ident, thing string) {
w.onFailure(lint.Failure{
Node: id,
Confidence: 0.8,
Category: "naming",
Category: lint.FailureCategoryNaming,
Failure: fmt.Sprintf("%s name will be used as %s.%s by other packages, and that %s; consider calling this %s", thing, pkg, name, w.stuttersMsg, rem),
})
}
@@ -251,7 +251,7 @@ func (w *lintExported) lintTypeDoc(t *ast.TypeSpec, doc *ast.CommentGroup) {
w.onFailure(lint.Failure{
Node: t,
Confidence: 1,
Category: "comments",
Category: lint.FailureCategoryComments,
Failure: fmt.Sprintf("exported type %v should have comment or be unexported", t.Name),
})
return
@@ -278,7 +278,7 @@ func (w *lintExported) lintTypeDoc(t *ast.TypeSpec, doc *ast.CommentGroup) {
w.onFailure(lint.Failure{
Node: doc,
Confidence: 1,
Category: "comments",
Category: lint.FailureCategoryComments,
Failure: fmt.Sprintf(`comment on exported type %v should be of the form "%s..." (with optional leading article)`, t.Name, expectedPrefix),
})
}
@@ -298,7 +298,7 @@ func (w *lintExported) lintValueSpecDoc(vs *ast.ValueSpec, gd *ast.GenDecl, genD
for _, n := range vs.Names[1:] {
if ast.IsExported(n.Name) {
w.onFailure(lint.Failure{
Category: "comments",
Category: lint.FailureCategoryComments,
Confidence: 1,
Failure: fmt.Sprintf("exported %s %s should have its own declaration", kind, n.Name),
Node: vs,
@@ -325,7 +325,7 @@ func (w *lintExported) lintValueSpecDoc(vs *ast.ValueSpec, gd *ast.GenDecl, genD
w.onFailure(lint.Failure{
Confidence: 1,
Node: vs,
Category: "comments",
Category: lint.FailureCategoryComments,
Failure: fmt.Sprintf("exported %s %s should have comment%s or be unexported", kind, name, block),
})
genDeclMissingComments[gd] = true
@@ -353,7 +353,7 @@ func (w *lintExported) lintValueSpecDoc(vs *ast.ValueSpec, gd *ast.GenDecl, genD
w.onFailure(lint.Failure{
Confidence: 1,
Node: doc,
Category: "comments",
Category: lint.FailureCategoryComments,
Failure: fmt.Sprintf(`comment on exported %s %s should be of the form "%s..."`, kind, name, prefix),
})
}
@@ -428,7 +428,7 @@ func (w *lintExported) lintInterfaceMethod(typeName string, m *ast.Field) {
w.onFailure(lint.Failure{
Node: m,
Confidence: 1,
Category: "comments",
Category: lint.FailureCategoryComments,
Failure: fmt.Sprintf("public interface method %s.%s should be commented", typeName, name),
})
return
@@ -439,7 +439,7 @@ func (w *lintExported) lintInterfaceMethod(typeName string, m *ast.Field) {
w.onFailure(lint.Failure{
Node: m.Doc,
Confidence: 0.8,
Category: "comments",
Category: lint.FailureCategoryComments,
Failure: fmt.Sprintf(`comment on exported interface method %s.%s should be of the form "%s..."`, typeName, name, expectedPrefix),
})
}

View File

@@ -57,7 +57,7 @@ func (r *FileLengthLimitRule) Apply(file *lint.File, _ lint.Arguments) []lint.Fa
return []lint.Failure{
{
Category: "code-style",
Category: lint.FailureCategoryCodeStyle,
Confidence: 1,
Position: lint.FailurePosition{
Start: token.Position{

View File

@@ -81,7 +81,7 @@ func (w conditionVisitor) Visit(node ast.Node) ast.Visitor {
w.onFailure(lint.Failure{
Confidence: 1,
Node: w.fd.Type.Params,
Category: "bad practice",
Category: lint.FailureCategoryBadPractice,
Failure: fmt.Sprintf("parameter '%s' seems to be a control flag, avoid control coupling", uses[0]),
})

View File

@@ -32,7 +32,7 @@ func (*GetReturnRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
failures = append(failures, lint.Failure{
Confidence: 0.8,
Node: fd,
Category: "logic",
Category: lint.FailureCategoryLogic,
Failure: fmt.Sprintf("function '%s' seems to be a getter but it does not return any result", fd.Name.Name),
})
}

View File

@@ -81,7 +81,7 @@ func (w *lintIdenticalBranches) newFailure(node ast.Node, msg string) {
w.onFailure(lint.Failure{
Confidence: 1,
Node: node,
Category: "logic",
Category: lint.FailureCategoryLogic,
Failure: msg,
})
}

View File

@@ -80,7 +80,7 @@ func (r *ImportAliasNamingRule) Apply(file *lint.File, _ lint.Arguments) []lint.
Confidence: 1,
Failure: fmt.Sprintf("import name (%s) must match the regular expression: %s", alias.Name, r.allowRegexp.String()),
Node: alias,
Category: "imports",
Category: lint.FailureCategoryImports,
})
}
@@ -89,7 +89,7 @@ func (r *ImportAliasNamingRule) Apply(file *lint.File, _ lint.Arguments) []lint.
Confidence: 1,
Failure: fmt.Sprintf("import name (%s) must NOT match the regular expression: %s", alias.Name, r.denyRegexp.String()),
Node: alias,
Category: "imports",
Category: lint.FailureCategoryImports,
})
}
}

View File

@@ -103,7 +103,7 @@ func (w importShadowing) Visit(n ast.Node) ast.Visitor {
w.onFailure(lint.Failure{
Confidence: 1,
Node: n,
Category: "naming",
Category: lint.FailureCategoryNaming,
Failure: fmt.Sprintf("The name '%s' shadows an import name", id),
})

View File

@@ -53,7 +53,7 @@ func (r *ImportsBlocklistRule) Apply(file *lint.File, _ lint.Arguments) []lint.F
Confidence: 1,
Failure: "should not use the following blocklisted import: " + path.Value,
Node: is,
Category: "imports",
Category: lint.FailureCategoryImports,
})
}
}

View File

@@ -61,7 +61,7 @@ func (w lintIncrementDecrement) Visit(n ast.Node) ast.Visitor {
w.onFailure(lint.Failure{
Confidence: 0.8,
Node: as,
Category: "unary-op",
Category: lint.FailureCategoryUnaryOp,
Failure: fmt.Sprintf("should replace %s with %s%s", w.file.Render(as), w.file.Render(as.Lhs[0]), suffix),
})
return w

View File

@@ -76,7 +76,7 @@ func (r lintLineLengthNum) check() {
c := utf8.RuneCountInString(t)
if c > r.max {
r.onFailure(lint.Failure{
Category: "code-style",
Category: lint.FailureCategoryCodeStyle,
Position: lint.FailurePosition{
// Offset not set; it is non-trivial, and doesn't appear to be needed.
Start: token.Position{

View File

@@ -51,7 +51,7 @@ func (w *lintMaxControlNesting) Visit(n ast.Node) ast.Visitor {
Failure: fmt.Sprintf("control flow nesting exceeds %d", w.max),
Confidence: 1,
Node: w.lastCtrlStmt,
Category: "complexity",
Category: lint.FailureCategoryComplexity,
})
return nil // stop visiting deeper
}

View File

@@ -62,7 +62,7 @@ func (r *MaxPublicStructsRule) Apply(file *lint.File, _ lint.Arguments) []lint.F
Failure: fmt.Sprintf("you have exceeded the maximum number (%d) of public struct declarations", r.max),
Confidence: 1,
Node: fileAst,
Category: "style",
Category: lint.FailureCategoryStyle,
})
}

View File

@@ -73,7 +73,7 @@ func checkParam(id *ast.Ident, w *lintModifiesParamRule) {
w.onFailure(lint.Failure{
Confidence: 0.5, // confidence is low because of shadow variables
Node: id,
Category: "bad practice",
Category: lint.FailureCategoryBadPractice,
Failure: fmt.Sprintf("parameter '%s' seems to be modified", id),
})
}

View File

@@ -68,7 +68,7 @@ func (l *lintStruct) Visit(n ast.Node) ast.Visitor {
func (l *lintStruct) fail(n ast.Node) {
l.onFailure(lint.Failure{
Failure: "no nested structs are allowed",
Category: "style",
Category: lint.FailureCategoryStyle,
Node: n,
Confidence: 1,
})

View File

@@ -78,7 +78,7 @@ func (w lintOptimizeOperandsOrderlExpr) Visit(node ast.Node) ast.Visitor {
w.onFailure(lint.Failure{
Failure: fmt.Sprintf("for better performance '%v' might be rewritten as '%v'", gofmt(binExpr), gofmt(&newExpr)),
Node: node,
Category: "optimization",
Category: lint.FailureCategoryOptimization,
Confidence: 0.3,
})

View File

@@ -88,7 +88,7 @@ func (l *lintPackageComments) checkPackageComment() []lint.Failure {
if docFile != nil {
pkgFile := l.file.Pkg.Files()[fileSource]
return []lint.Failure{{
Category: "comments",
Category: lint.FailureCategoryComments,
Position: lint.FailurePosition{
Start: pkgFile.ToPosition(docFile.Pos()),
End: pkgFile.ToPosition(docFile.Name.End()),
@@ -131,7 +131,7 @@ func (l *lintPackageComments) Visit(_ ast.Node) ast.Visitor {
Column: 1,
}
l.onFailure(lint.Failure{
Category: "comments",
Category: lint.FailureCategoryComments,
Position: lint.FailurePosition{
Start: pos,
End: pos,
@@ -154,7 +154,7 @@ func (l *lintPackageComments) Visit(_ ast.Node) ast.Visitor {
// Only non-main packages need to keep to this form.
if !l.file.Pkg.IsMain() && !strings.HasPrefix(s, prefix) && !isDirectiveComment(s) {
l.onFailure(lint.Failure{
Category: "comments",
Category: lint.FailureCategoryComments,
Node: l.fileAst.Doc,
Confidence: 1,
Failure: fmt.Sprintf(`package comment should be of the form "%s..."`, prefix),

View File

@@ -63,7 +63,7 @@ func (r *ReceiverNamingRule) Apply(file *lint.File, _ lint.Arguments) []lint.Fai
failures = append(failures, lint.Failure{
Node: decl,
Confidence: 1,
Category: "naming",
Category: lint.FailureCategoryNaming,
Failure: "receiver name should not be an underscore, omit the name if it is unused",
})
continue
@@ -73,7 +73,7 @@ func (r *ReceiverNamingRule) Apply(file *lint.File, _ lint.Arguments) []lint.Fai
failures = append(failures, lint.Failure{
Node: decl,
Confidence: 1,
Category: "naming",
Category: lint.FailureCategoryNaming,
Failure: `receiver name should be a reflection of its identity; don't use generic names such as "this" or "self"`,
})
continue
@@ -83,7 +83,7 @@ func (r *ReceiverNamingRule) Apply(file *lint.File, _ lint.Arguments) []lint.Fai
failures = append(failures, lint.Failure{
Node: decl,
Confidence: 1,
Category: "naming",
Category: lint.FailureCategoryNaming,
Failure: fmt.Sprintf("receiver name %s is longer than %d characters", name, r.receiverNameMaxLength),
})
continue
@@ -94,7 +94,7 @@ func (r *ReceiverNamingRule) Apply(file *lint.File, _ lint.Arguments) []lint.Fai
failures = append(failures, lint.Failure{
Node: decl,
Confidence: 1,
Category: "naming",
Category: lint.FailureCategoryNaming,
Failure: fmt.Sprintf("receiver name %s should be consistent with previous receiver name %s for %s", name, prev, recv),
})
continue

View File

@@ -202,7 +202,7 @@ func (w *lintRedefinesBuiltinID) addFailure(node ast.Node, msg string) {
w.onFailure(lint.Failure{
Confidence: 1,
Node: node,
Category: "logic",
Category: lint.FailureCategoryLogic,
Failure: msg,
})
}

View File

@@ -23,7 +23,7 @@ func (*RedundantBuildTagRule) Apply(file *lint.File, _ lint.Arguments) []lint.Fa
if hasGoBuild && strings.HasPrefix(comment.Text, "// +build ") {
return []lint.Failure{{
Category: "style",
Category: lint.FailureCategoryStyle,
Confidence: 1,
Node: comment,
Failure: `The build tag "// +build" is redundant since Go 1.17 and can be removed`,

View File

@@ -25,7 +25,7 @@ func (*RedundantImportAlias) Apply(file *lint.File, _ lint.Arguments) []lint.Fai
Confidence: 1,
Failure: fmt.Sprintf("Import alias \"%s\" is redundant", imp.Name.Name),
Node: imp,
Category: "imports",
Category: lint.FailureCategoryImports,
})
}
}

View File

@@ -63,7 +63,7 @@ func (l *lintTimeEqual) Visit(node ast.Node) ast.Visitor {
}
l.onFailure(lint.Failure{
Category: "time",
Category: lint.FailureCategoryTime,
Confidence: 1,
Node: node,
Failure: fmt.Sprintf("use %s%s.Equal(%s) instead of %q operator", negateStr, gofmt(expr.X), gofmt(expr.Y), expr.Op),

View File

@@ -64,7 +64,7 @@ func (w *lintTimeNames) Visit(node ast.Node) ast.Visitor {
continue
}
w.onFailure(lint.Failure{
Category: "time",
Category: lint.FailureCategoryTime,
Confidence: 0.9,
Node: v,
Failure: fmt.Sprintf("var %s is of type %v; don't use unit-specific suffix %q", name.Name, origTyp, suffix),

View File

@@ -181,7 +181,7 @@ func (w *lintUncheckedTypeAssertion) Visit(node ast.Node) ast.Visitor {
func (w *lintUncheckedTypeAssertion) addFailure(n *ast.TypeAssertExpr, why string) {
s := fmt.Sprintf("type cast result is unchecked in %v - %s", gofmt(n), why)
w.onFailure(lint.Failure{
Category: "bad practice",
Category: lint.FailureCategoryBadPractice,
Confidence: 1,
Node: n,
Failure: s,

View File

@@ -100,7 +100,7 @@ func (w *lintUnconditionalRecursionRule) Visit(node ast.Node) ast.Visitor {
!w.currentFunc.seenConditionalExit && // there is a conditional exit in the function
w.currentFunc.funcDesc.equal(&funcDesc{selector, funcID}) {
w.onFailure(lint.Failure{
Category: "logic",
Category: lint.FailureCategoryLogic,
Confidence: 0.8,
Node: n,
Failure: "unconditional recursive call",

View File

@@ -107,7 +107,7 @@ func (unl unexportablenamingLinter) lintIDs(ids []*ast.Ident) {
unl.onFailure(lint.Failure{
Node: id,
Confidence: 1,
Category: "naming",
Category: lint.FailureCategoryNaming,
Failure: fmt.Sprintf("the symbol %s is local, its name should start with a lowercase letter", id.String()),
})
}

View File

@@ -47,7 +47,7 @@ func (*UnexportedReturnRule) Apply(file *lint.File, _ lint.Arguments) []lint.Fai
}
failures = append(failures, lint.Failure{
Category: "unexported-type-in-api",
Category: lint.FailureCategoryUnexportedTypeInAPI,
Node: ret.Type,
Confidence: 0.8,
Failure: fmt.Sprintf("exported %s %s returns unexported type %s, which can be annoying to use",

View File

@@ -113,7 +113,7 @@ func (w *lintUnhandledErrors) addFailure(n *ast.CallExpr) {
}
w.onFailure(lint.Failure{
Category: "bad practice",
Category: lint.FailureCategoryBadPractice,
Confidence: 1,
Node: n,
Failure: fmt.Sprintf("Unhandled error in call to function %v", name),

View File

@@ -101,7 +101,7 @@ func (w lintUnnecessaryStmtRule) newFailure(node ast.Node, msg string) {
w.onFailure(lint.Failure{
Confidence: 1,
Node: node,
Category: "style",
Category: lint.FailureCategoryStyle,
Failure: msg,
})
}

View File

@@ -115,7 +115,7 @@ func newUnreachableCodeFailure(node ast.Node) lint.Failure {
return lint.Failure{
Confidence: 1,
Node: node,
Category: "logic",
Category: lint.FailureCategoryLogic,
Failure: "unreachable code after this statement",
}
}

View File

@@ -129,7 +129,7 @@ func (w lintUnusedParamRule) Visit(node ast.Node) ast.Visitor {
w.onFailure(lint.Failure{
Confidence: 1,
Node: n,
Category: "bad practice",
Category: lint.FailureCategoryBadPractice,
Failure: fmt.Sprintf(w.failureMsg, n.Name),
})
}

View File

@@ -87,7 +87,7 @@ func (r *UnusedReceiverRule) Apply(file *lint.File, _ lint.Arguments) []lint.Fai
failures = append(failures, lint.Failure{
Confidence: 1,
Node: recID,
Category: "bad practice",
Category: lint.FailureCategoryBadPractice,
Failure: fmt.Sprintf(r.failureMsg, recID.Name),
})
}

View File

@@ -46,7 +46,7 @@ func (w lintUseAny) Visit(n ast.Node) ast.Visitor {
w.onFailure(lint.Failure{
Node: n,
Confidence: 1,
Category: "naming",
Category: lint.FailureCategoryNaming,
Failure: "since Go 1.18 'interface{}' can be replaced by 'any'",
})

View File

@@ -50,7 +50,7 @@ func (w lintFmtErrorf) Visit(n ast.Node) ast.Visitor {
// the call is of the form fmt.Errorf("...")
w.onFailure(lint.Failure{
Category: "errors",
Category: lint.FailureCategoryErrors,
Node: n,
Confidence: 1,
Failure: "replace fmt.Errorf by errors.New",

View File

@@ -93,7 +93,7 @@ func (w *lintVarDeclarations) Visit(node ast.Node) ast.Visitor {
w.onFailure(lint.Failure{
Confidence: 0.9,
Node: rhs,
Category: "zero-value",
Category: lint.FailureCategoryZeroValue,
Failure: fmt.Sprintf("should drop = %s from declaration of var %s; it is the zero value", w.file.Render(rhs), v.Names[0]),
})
return nil
@@ -127,7 +127,7 @@ func (w *lintVarDeclarations) Visit(node ast.Node) ast.Visitor {
}
w.onFailure(lint.Failure{
Category: "type-inference",
Category: lint.FailureCategoryTypeInference,
Confidence: 0.8,
Node: v.Type,
Failure: fmt.Sprintf("should omit type %s from declaration of var %s; it will be inferred from the right-hand side", w.file.Render(v.Type), v.Names[0]),

View File

@@ -77,7 +77,7 @@ func (*VarNamingRule) applyPackageCheckRules(walker *lintNames) {
Failure: "don't use an underscore in package name",
Confidence: 1,
Node: walker.fileAst.Name,
Category: "naming",
Category: lint.FailureCategoryNaming,
})
}
if anyCapsRE.MatchString(walker.fileAst.Name.Name) {
@@ -85,7 +85,7 @@ func (*VarNamingRule) applyPackageCheckRules(walker *lintNames) {
Failure: fmt.Sprintf("don't use MixedCaps in package name; %s should be %s", walker.fileAst.Name.Name, strings.ToLower(walker.fileAst.Name.Name)),
Confidence: 1,
Node: walker.fileAst.Name,
Category: "naming",
Category: lint.FailureCategoryNaming,
})
}
}
@@ -152,7 +152,7 @@ func (w *lintNames) check(id *ast.Ident, thing string) {
Failure: "don't use ALL_CAPS in Go names; use CamelCase",
Confidence: 0.8,
Node: id,
Category: "naming",
Category: lint.FailureCategoryNaming,
})
return
}
@@ -167,7 +167,7 @@ func (w *lintNames) check(id *ast.Ident, thing string) {
Failure: fmt.Sprintf("don't use underscores in Go names; %s %s should be %s", thing, id.Name, should),
Confidence: 0.9,
Node: id,
Category: "naming",
Category: lint.FailureCategoryNaming,
})
return
}
@@ -175,7 +175,7 @@ func (w *lintNames) check(id *ast.Ident, thing string) {
Failure: fmt.Sprintf("%s %s should be %s", thing, id.Name, should),
Confidence: 0.8,
Node: id,
Category: "naming",
Category: lint.FailureCategoryNaming,
})
}