1
0
mirror of https://github.com/mgechev/revive.git synced 2025-11-23 22:04:49 +02:00

refactor: enable godoclint linter in golangci-lint (#1576)

This commit is contained in:
Oleksandr Redko
2025-11-14 18:02:48 +02:00
committed by GitHub
parent ac5f398440
commit a295bebe6e
13 changed files with 61 additions and 29 deletions

View File

@@ -9,6 +9,7 @@ linters:
- dupword - dupword
- gocritic - gocritic
- godot - godot
- godoclint
- govet - govet
- ineffassign - ineffassign
- misspell - misspell
@@ -19,12 +20,32 @@ linters:
- staticcheck - staticcheck
- unused - unused
exclusions:
warn-unused: true
rules:
- path: '(.+)_test\.go'
linters:
- godoclint
- linters:
- godoclint
text: 'symbol should have a godoc \("Visit"\)'
settings: settings:
gocritic: gocritic:
enable-all: true enable-all: true
disabled-checks: disabled-checks:
- hugeParam - hugeParam
- rangeValCopy - rangeValCopy
godoclint:
default: all
options:
max-len:
length: 120
require-doc:
ignore-exported: false
ignore-unexported: true
start-with-name:
include-unexported: true
govet: govet:
enable-all: true enable-all: true
disable: disable:

View File

@@ -41,6 +41,7 @@ func ParseFileFilter(rawFilter string) (*FileFilter, error) {
return result, nil return result, nil
} }
// String returns the original raw filter definition as it appears in the configuration.
func (ff *FileFilter) String() string { return ff.raw } func (ff *FileFilter) String() string { return ff.raw }
// MatchFileName checks if the file name matches the filter. // MatchFileName checks if the file name matches the filter.

View File

@@ -198,6 +198,7 @@ func normalizeSplit(strs []string) []string {
// ArrayFlags type for string list. // ArrayFlags type for string list.
type ArrayFlags []string type ArrayFlags []string
// String returns the space-separated representation of the ArrayFlags.
func (i *ArrayFlags) String() string { func (i *ArrayFlags) String() string {
return strings.Join([]string(*i), " ") return strings.Join([]string(*i), " ")
} }

View File

@@ -70,7 +70,8 @@ func (*ConfusingNamingRule) Name() string {
return "confusing-naming" return "confusing-naming"
} }
// checkMethodName checks if a given method/function name is similar (just case differences) to other method/function of the same struct/file. // checkMethodName checks if a given method/function name is similar (just case differences) to other method/function
// of the same struct/file.
func checkMethodName(holder string, id *ast.Ident, w *lintConfusingNames) { func checkMethodName(holder string, id *ast.Ident, w *lintConfusingNames) {
if id.Name == "init" && holder == defaultStructName { if id.Name == "init" && holder == defaultStructName {
// ignore init functions // ignore init functions

View File

@@ -170,15 +170,15 @@ func (w *lintExported) lintFuncDoc(fn *ast.FuncDecl) {
case exportedGoDocStatusOK: case exportedGoDocStatusOK:
return // comment is fine return // comment is fine
case exportedGoDocStatusMissing: case exportedGoDocStatusMissing:
w.addFailuref(fn, status.Confidence(), lint.FailureCategoryComments, w.addFailuref(fn, status.confidence(), lint.FailureCategoryComments,
"exported %s %s should have comment or be unexported", kind, name, "exported %s %s should have comment or be unexported", kind, name,
) )
return return
} }
firstCommentLine := w.firstCommentLine(fn.Doc) firstCommentLine := w.firstCommentLine(fn.Doc)
w.addFailuref(fn.Doc, status.Confidence(), lint.FailureCategoryComments, w.addFailuref(fn.Doc, status.confidence(), lint.FailureCategoryComments,
`comment on exported %s %s should be of the form "%s ..."%s`, kind, name, fn.Name.Name, status.CorrectionHint(firstCommentLine), `comment on exported %s %s should be of the form "%s ..."%s`, kind, name, fn.Name.Name, status.correctionHint(firstCommentLine),
) )
} }
@@ -264,8 +264,8 @@ func (w *lintExported) lintTypeDoc(t *ast.TypeSpec, doc *ast.CommentGroup, first
if status == exportedGoDocStatusOK { if status == exportedGoDocStatusOK {
return return
} }
w.addFailuref(doc, status.Confidence(), lint.FailureCategoryComments, w.addFailuref(doc, status.confidence(), lint.FailureCategoryComments,
`comment on exported type %v should be of the form "%s ..." (with optional leading article)%s`, t.Name, typeName, status.CorrectionHint(firstCommentLine), `comment on exported type %v should be of the form "%s ..." (with optional leading article)%s`, t.Name, typeName, status.correctionHint(firstCommentLine),
) )
} }
@@ -347,8 +347,8 @@ func (w *lintExported) lintValueSpecDoc(vs *ast.ValueSpec, gd *ast.GenDecl, genD
if status == exportedGoDocStatusOK { if status == exportedGoDocStatusOK {
return return
} }
w.addFailuref(doc, status.Confidence(), lint.FailureCategoryComments, w.addFailuref(doc, status.confidence(), lint.FailureCategoryComments,
`comment on exported %s %s should be of the form "%s ..."%s`, kind, name, name, status.CorrectionHint(firstCommentLine), `comment on exported %s %s should be of the form "%s ..."%s`, kind, name, name, status.correctionHint(firstCommentLine),
) )
} }
@@ -362,14 +362,14 @@ const (
exportedGoDocStatusUnexpected exportedGoDocStatusUnexpected
) )
func (gds exportedGoDocStatus) Confidence() float64 { func (gds exportedGoDocStatus) confidence() float64 {
if gds == exportedGoDocStatusUnexpected { if gds == exportedGoDocStatusUnexpected {
return 0.8 return 0.8
} }
return 1 return 1
} }
func (gds exportedGoDocStatus) CorrectionHint(firstCommentLine string) string { func (gds exportedGoDocStatus) correctionHint(firstCommentLine string) string {
firstWord := strings.Split(firstCommentLine, " ")[0] firstWord := strings.Split(firstCommentLine, " ")[0]
switch gds { switch gds {
case exportedGoDocStatusCaseMismatch: case exportedGoDocStatusCaseMismatch:
@@ -501,15 +501,15 @@ func (w *lintExported) lintInterfaceMethod(typeName string, m *ast.Field) {
case exportedGoDocStatusOK: case exportedGoDocStatusOK:
return // comment is fine return // comment is fine
case exportedGoDocStatusMissing: case exportedGoDocStatusMissing:
w.addFailuref(m, status.Confidence(), lint.FailureCategoryComments, w.addFailuref(m, status.confidence(), lint.FailureCategoryComments,
"public interface method %s.%s should be commented", typeName, name, "public interface method %s.%s should be commented", typeName, name,
) )
return return
} }
firstCommentLine := w.firstCommentLine(m.Doc) firstCommentLine := w.firstCommentLine(m.Doc)
w.addFailuref(m.Doc, status.Confidence(), lint.FailureCategoryComments, w.addFailuref(m.Doc, status.confidence(), lint.FailureCategoryComments,
`comment on exported interface method %s.%s should be of the form "%s ..."%s`, typeName, name, name, status.CorrectionHint(firstCommentLine), `comment on exported interface method %s.%s should be of the form "%s ..."%s`, typeName, name, name, status.correctionHint(firstCommentLine),
) )
} }

View File

@@ -81,7 +81,7 @@ type stringFormatSubruleScope struct {
field string // (optional) If the argument to be checked is a struct, which member of the struct is checked against the rule (top level members only) field string // (optional) If the argument to be checked is a struct, which member of the struct is checked against the rule (top level members only)
} }
// Regex inserted to match valid function/struct field identifiers. // identRegex matches valid function/struct field identifiers.
const identRegex = "[_A-Za-z][_A-Za-z0-9]*" const identRegex = "[_A-Za-z][_A-Za-z0-9]*"
var parseStringFormatScope = regexp.MustCompile( var parseStringFormatScope = regexp.MustCompile(
@@ -165,17 +165,18 @@ func (r *StringFormatRule) parseArgument(argument any, ruleNum int) (scopes stri
return scopes, regex, negated, errorMessage, nil return scopes, regex, negated, errorMessage, nil
} }
// Report an invalid config, this is specifically the user's fault. // configError reports an invalid config, this is specifically the user's fault.
func (*StringFormatRule) configError(msg string, ruleNum, option int) error { func (*StringFormatRule) configError(msg string, ruleNum, option int) error {
return fmt.Errorf("invalid configuration for string-format: %s [argument %d, option %d]", msg, ruleNum, option) return fmt.Errorf("invalid configuration for string-format: %s [argument %d, option %d]", msg, ruleNum, option)
} }
// Report a general config parsing failure, this may be the user's fault, but it isn't known for certain. // parseError reports a general config parsing failure, this may be the user's fault, but it isn't known for certain.
func (*StringFormatRule) parseError(msg string, ruleNum, option int) error { func (*StringFormatRule) parseError(msg string, ruleNum, option int) error {
return fmt.Errorf("failed to parse configuration for string-format: %s [argument %d, option %d]", msg, ruleNum, option) return fmt.Errorf("failed to parse configuration for string-format: %s [argument %d, option %d]", msg, ruleNum, option)
} }
// Report a general scope config parsing failure, this may be the user's fault, but it isn't known for certain. // parseScopeError reports a general scope config parsing failure, this may be the user's fault,
// but it isn't known for certain.
func (*StringFormatRule) parseScopeError(msg string, ruleNum, option, scopeNum int) error { func (*StringFormatRule) parseScopeError(msg string, ruleNum, option, scopeNum int) error {
return fmt.Errorf("failed to parse configuration for string-format: %s [argument %d, option %d, scope index %d]", msg, ruleNum, option, scopeNum) return fmt.Errorf("failed to parse configuration for string-format: %s [argument %d, option %d, scope index %d]", msg, ruleNum, option, scopeNum)
} }
@@ -204,7 +205,7 @@ func (w *lintStringFormatRule) Visit(node ast.Node) ast.Visitor {
return w return w
} }
// Return the name of a call expression in the form of package.Func or Func. // getCallName returns the name of a call expression in the form of package.Func or Func.
func (*lintStringFormatRule) getCallName(call *ast.CallExpr) (callName string, ok bool) { func (*lintStringFormatRule) getCallName(call *ast.CallExpr) (callName string, ok bool) {
if ident, ok := call.Fun.(*ast.Ident); ok { if ident, ok := call.Fun.(*ast.Ident); ok {
// Local function call // Local function call
@@ -227,7 +228,8 @@ func (*lintStringFormatRule) getCallName(call *ast.CallExpr) (callName string, o
return "", false return "", false
} }
// apply a single format rule to a call expression (should be done after verifying the that the call expression matches the rule's scope). // apply a single format rule to a call expression
// (should be done after verifying the that the call expression matches the rule's scope).
func (r *stringFormatSubrule) apply(call *ast.CallExpr, scope *stringFormatSubruleScope) { func (r *stringFormatSubrule) apply(call *ast.CallExpr, scope *stringFormatSubruleScope) {
if len(call.Args) <= scope.argument { if len(call.Args) <= scope.argument {
return return

View File

@@ -1003,7 +1003,7 @@ var validateSingleOptions = map[string]struct{}{
"validateFn": {}, "validateFn": {},
} }
// These are options that are used in expressions of the form: // validateLHS are options that are used in expressions of the form:
// //
// <option> = <RHS> // <option> = <RHS>
var validateLHS = map[string]struct{}{ var validateLHS = map[string]struct{}{

View File

@@ -136,7 +136,8 @@ func (w *lintUncheckedTypeAssertion) handleAssignment(n *ast.AssignStmt) {
} }
} }
// handles "return foo(.*bar)" - one of them is enough to fail as golang does not forward the type cast tuples in return statements. // handleReturn handles "return foo(.*bar)" - one of them is enough to fail
// as Go does not forward the type cast tuples in return statements.
func (w *lintUncheckedTypeAssertion) handleReturn(n *ast.ReturnStmt) { func (w *lintUncheckedTypeAssertion) handleReturn(n *ast.ReturnStmt) {
for _, r := range n.Results { for _, r := range n.Results {
w.requireNoTypeAssert(r) w.requireNoTypeAssert(r)

View File

@@ -79,11 +79,14 @@ type lintUnconditionalRecursionRule struct {
} }
// Visit will traverse function's body we search for calls to the function itself. // Visit will traverse function's body we search for calls to the function itself.
// We do not search inside conditional control structures (if, for, switch, ...) because any recursive call inside them is conditioned. // We do not search inside conditional control structures (if, for, switch, ...)
// We do search inside conditional control structures are statements that will take the control out of the function (return, exit, panic). // because any recursive call inside them is conditioned.
// We do search inside conditional control structures are statements
// that will take the control out of the function (return, exit, panic).
// If we find conditional control exits, it means the function is NOT unconditionally-recursive. // If we find conditional control exits, it means the function is NOT unconditionally-recursive.
// If we find a recursive call before finding any conditional exit, a failure is generated. // If we find a recursive call before finding any conditional exit, a failure is generated.
// In resume: if we found a recursive call control-dependent from the entry point of the function then we raise a failure. // In resume: if we found a recursive call control-dependent from the entry point of
// the function then we raise a failure.
func (w *lintUnconditionalRecursionRule) Visit(node ast.Node) ast.Visitor { func (w *lintUnconditionalRecursionRule) Visit(node ast.Node) ast.Visitor {
switch n := node.(type) { switch n := node.(type) {
case *ast.CallExpr: case *ast.CallExpr:

View File

@@ -10,7 +10,8 @@ import (
"github.com/mgechev/revive/lint" "github.com/mgechev/revive/lint"
) )
// UnsecureURLSchemeRule checks if a file contains string literals with unsecure URL schemes (for example: http://... in place of https://...). // UnsecureURLSchemeRule checks if a file contains string literals with unsecure URL schemes.
// For example: http://... in place of https://....
type UnsecureURLSchemeRule struct{} type UnsecureURLSchemeRule struct{}
// Apply applied the rule to the given file. // Apply applied the rule to the given file.

View File

@@ -150,7 +150,7 @@ func (*lintUseWaitGroupGo) isCallToWgAdd(stmt ast.Stmt) bool {
return ok && astutils.IsPkgDotName(call.Fun, "wg", "Add") return ok && astutils.IsPkgDotName(call.Fun, "wg", "Add")
} }
// function used when calling astutils.SeekNode that search for calls to wg.Done. // wgDonePicker is used when calling astutils.SeekNode that search for calls to wg.Done.
func wgDonePicker(n ast.Node) bool { func wgDonePicker(n ast.Node) bool {
call, ok := n.(*ast.CallExpr) call, ok := n.(*ast.CallExpr)
result := ok && astutils.IsPkgDotName(call.Fun, "wg", "Done") result := ok && astutils.IsPkgDotName(call.Fun, "wg", "Done")

View File

@@ -11,7 +11,7 @@ import (
"github.com/mgechev/revive/lint" "github.com/mgechev/revive/lint"
) )
// exitChecker is a function type that checks whether a function call is an exit function. // exitFuncChecker is a function type that checks whether a function call is an exit function.
type exitFuncChecker func(args []ast.Expr) bool type exitFuncChecker func(args []ast.Expr) bool
var alwaysTrue exitFuncChecker = func([]ast.Expr) bool { return true } var alwaysTrue exitFuncChecker = func([]ast.Expr) bool { return true }

View File

@@ -372,7 +372,8 @@ func (w *lintNames) Visit(n ast.Node) ast.Visitor {
return w return w
} }
// isUpperCaseConst checks if a string is in constant name format like `SOME_CONST`, `SOME_CONST_2`, `X123_3`, `_SOME_PRIVATE_CONST`. // isUpperCaseConst checks if a string is in constant name format like `SOME_CONST`, `SOME_CONST_2`,
// `X123_3`, `_SOME_PRIVATE_CONST`.
// See #851, #865. // See #851, #865.
func isUpperCaseConst(s string) bool { func isUpperCaseConst(s string) bool {
if s == "" { if s == "" {
@@ -418,7 +419,7 @@ func isUpperOrDigit(r rune) bool {
return isUpper(r) || isDigit(r) return isUpper(r) || isDigit(r)
} }
// isUpper checks if rune is a simple digit. // isDigit checks if rune is a simple digit.
// //
// We don't use unicode.IsDigit as it returns true for a large variety of digits that are not 0-9. // We don't use unicode.IsDigit as it returns true for a large variety of digits that are not 0-9.
func isDigit(r rune) bool { func isDigit(r rune) bool {