mirror of
				https://github.com/mgechev/revive.git
				synced 2025-10-30 23:37:49 +02:00 
			
		
		
		
	refactor: rule configuration and error management (#1185)
* refactor: avoid running rule once configuration failed * refactor: remove deep-exit in lint/linter.go
This commit is contained in:
		| @@ -149,6 +149,12 @@ func GetLintingRules(config *lint.Config, extraRules []lint.Rule) ([]lint.Rule, | ||||
| 			continue // skip disabled rules | ||||
| 		} | ||||
|  | ||||
| 		if r, ok := r.(lint.ConfigurableRule); ok { | ||||
| 			if err := r.Configure(ruleConfig.Arguments); err != nil { | ||||
| 				return nil, fmt.Errorf("cannot configure rule: %s", name) | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		lintingRules = append(lintingRules, r) | ||||
| 	} | ||||
|  | ||||
|   | ||||
| @@ -10,10 +10,10 @@ import ( | ||||
| 	"regexp" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
| 	"sync" | ||||
|  | ||||
| 	goversion "github.com/hashicorp/go-version" | ||||
| 	"golang.org/x/mod/modfile" | ||||
| 	"golang.org/x/sync/errgroup" | ||||
| ) | ||||
|  | ||||
| // ReadFile defines an abstraction for reading files. | ||||
| @@ -101,20 +101,23 @@ func (l *Linter) Lint(packages [][]string, ruleSet []Rule, config Config) (<-cha | ||||
| 		perPkgVersions[n] = v | ||||
| 	} | ||||
|  | ||||
| 	var wg sync.WaitGroup | ||||
| 	wg.Add(len(packages)) | ||||
| 	var wg errgroup.Group | ||||
| 	for n := range packages { | ||||
| 		go func(pkg []string, gover *goversion.Version) { | ||||
| 		wg.Go(func() error { | ||||
| 			pkg := packages[n] | ||||
| 			gover := perPkgVersions[n] | ||||
| 			if err := l.lintPackage(pkg, gover, ruleSet, config, failures); err != nil { | ||||
| 				fmt.Fprintln(os.Stderr, "error during linting: "+err.Error()) | ||||
| 				os.Exit(1) | ||||
| 				return fmt.Errorf("error during linting: %w", err) | ||||
| 			} | ||||
| 			wg.Done() | ||||
| 		}(packages[n], perPkgVersions[n]) | ||||
| 			return nil | ||||
| 		}) | ||||
| 	} | ||||
|  | ||||
| 	go func() { | ||||
| 		wg.Wait() | ||||
| 		err := wg.Wait() | ||||
| 		if err != nil { | ||||
| 			failures <- NewInternalFailure(err.Error()) | ||||
| 		} | ||||
| 		close(failures) | ||||
| 	}() | ||||
|  | ||||
|   | ||||
| @@ -17,6 +17,11 @@ type Rule interface { | ||||
| 	Apply(*File, Arguments) []Failure | ||||
| } | ||||
|  | ||||
| // ConfigurableRule defines an abstract configurable rule interface. | ||||
| type ConfigurableRule interface { | ||||
| 	Configure(Arguments) error | ||||
| } | ||||
|  | ||||
| // ToFailurePosition returns the failure position. | ||||
| func ToFailurePosition(start, end token.Pos, file *File) FailurePosition { | ||||
| 	return FailurePosition{ | ||||
|   | ||||
| @@ -7,7 +7,6 @@ import ( | ||||
| 	"regexp" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
| 	"sync" | ||||
|  | ||||
| 	"github.com/mgechev/revive/lint" | ||||
| ) | ||||
| @@ -37,18 +36,10 @@ type AddConstantRule struct { | ||||
| 	allowList       allowList | ||||
| 	ignoreFunctions []*regexp.Regexp | ||||
| 	strLitLimit     int | ||||
|  | ||||
| 	configureOnce sync.Once | ||||
| } | ||||
|  | ||||
| // Apply applies the rule to given file. | ||||
| func (r *AddConstantRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure { | ||||
| 	var configureErr error | ||||
| 	r.configureOnce.Do(func() { configureErr = r.configure(arguments) }) | ||||
| 	if configureErr != nil { | ||||
| 		return newInternalFailureError(configureErr) | ||||
| 	} | ||||
|  | ||||
| func (r *AddConstantRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure { | ||||
| 	var failures []lint.Failure | ||||
|  | ||||
| 	onFailure := func(failure lint.Failure) { | ||||
| @@ -206,7 +197,10 @@ func (w *lintAddConstantRule) isStructTag(n *ast.BasicLit) bool { | ||||
| 	return ok | ||||
| } | ||||
|  | ||||
| func (r *AddConstantRule) configure(arguments lint.Arguments) error { | ||||
| // Configure validates the rule configuration, and configures the rule accordingly. | ||||
| // | ||||
| // Configuration implements the [lint.ConfigurableRule] interface. | ||||
| func (r *AddConstantRule) Configure(arguments lint.Arguments) error { | ||||
| 	r.strLitLimit = defaultStrLitLimit | ||||
| 	r.allowList = newAllowList() | ||||
| 	if len(arguments) == 0 { | ||||
|   | ||||
| @@ -4,7 +4,6 @@ import ( | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"go/ast" | ||||
| 	"sync" | ||||
|  | ||||
| 	"github.com/mgechev/revive/lint" | ||||
| ) | ||||
| @@ -12,13 +11,14 @@ import ( | ||||
| // ArgumentsLimitRule lints the number of arguments a function can receive. | ||||
| type ArgumentsLimitRule struct { | ||||
| 	max int | ||||
|  | ||||
| 	configureOnce sync.Once | ||||
| } | ||||
|  | ||||
| const defaultArgumentsLimit = 8 | ||||
|  | ||||
| func (r *ArgumentsLimitRule) configure(arguments lint.Arguments) error { | ||||
| // Configure validates the rule configuration, and configures the rule accordingly. | ||||
| // | ||||
| // Configuration implements the [lint.ConfigurableRule] interface. | ||||
| func (r *ArgumentsLimitRule) Configure(arguments lint.Arguments) error { | ||||
| 	if len(arguments) < 1 { | ||||
| 		r.max = defaultArgumentsLimit | ||||
| 		return nil | ||||
| @@ -33,14 +33,7 @@ func (r *ArgumentsLimitRule) configure(arguments lint.Arguments) error { | ||||
| } | ||||
|  | ||||
| // Apply applies the rule to given file. | ||||
| func (r *ArgumentsLimitRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure { | ||||
| 	var configureErr error | ||||
| 	r.configureOnce.Do(func() { configureErr = r.configure(arguments) }) | ||||
|  | ||||
| 	if configureErr != nil { | ||||
| 		return newInternalFailureError(configureErr) | ||||
| 	} | ||||
|  | ||||
| func (r *ArgumentsLimitRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure { | ||||
| 	var failures []lint.Failure | ||||
|  | ||||
| 	for _, decl := range file.AST.Decls { | ||||
|   | ||||
| @@ -4,7 +4,6 @@ import ( | ||||
| 	"fmt" | ||||
| 	"go/ast" | ||||
| 	"strings" | ||||
| 	"sync" | ||||
|  | ||||
| 	"github.com/mgechev/revive/lint" | ||||
| ) | ||||
| @@ -12,13 +11,14 @@ import ( | ||||
| // BannedCharsRule checks if a file contains banned characters. | ||||
| type BannedCharsRule struct { | ||||
| 	bannedCharList []string | ||||
|  | ||||
| 	configureOnce sync.Once | ||||
| } | ||||
|  | ||||
| const bannedCharsRuleName = "banned-characters" | ||||
|  | ||||
| func (r *BannedCharsRule) configure(arguments lint.Arguments) error { | ||||
| // Configure validates the rule configuration, and configures the rule accordingly. | ||||
| // | ||||
| // Configuration implements the [lint.ConfigurableRule] interface. | ||||
| func (r *BannedCharsRule) Configure(arguments lint.Arguments) error { | ||||
| 	if len(arguments) > 0 { | ||||
| 		err := checkNumberOfArguments(1, arguments, bannedCharsRuleName) | ||||
| 		if err != nil { | ||||
| @@ -35,14 +35,7 @@ func (r *BannedCharsRule) configure(arguments lint.Arguments) error { | ||||
| } | ||||
|  | ||||
| // Apply applied the rule to the given file. | ||||
| func (r *BannedCharsRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure { | ||||
| 	var configureErr error | ||||
| 	r.configureOnce.Do(func() { configureErr = r.configure(arguments) }) | ||||
|  | ||||
| 	if configureErr != nil { | ||||
| 		return newInternalFailureError(configureErr) | ||||
| 	} | ||||
|  | ||||
| func (r *BannedCharsRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure { | ||||
| 	var failures []lint.Failure | ||||
| 	onFailure := func(failure lint.Failure) { | ||||
| 		failures = append(failures, failure) | ||||
|   | ||||
| @@ -4,7 +4,6 @@ import ( | ||||
| 	"fmt" | ||||
| 	"go/ast" | ||||
| 	"go/token" | ||||
| 	"sync" | ||||
|  | ||||
| 	"github.com/mgechev/revive/lint" | ||||
| 	"golang.org/x/tools/go/ast/astutil" | ||||
| @@ -13,13 +12,14 @@ import ( | ||||
| // CognitiveComplexityRule sets restriction for maximum cognitive complexity. | ||||
| type CognitiveComplexityRule struct { | ||||
| 	maxComplexity int | ||||
|  | ||||
| 	configureOnce sync.Once | ||||
| } | ||||
|  | ||||
| const defaultMaxCognitiveComplexity = 7 | ||||
|  | ||||
| func (r *CognitiveComplexityRule) configure(arguments lint.Arguments) error { | ||||
| // Configure validates the rule configuration, and configures the rule accordingly. | ||||
| // | ||||
| // Configuration implements the [lint.ConfigurableRule] interface. | ||||
| func (r *CognitiveComplexityRule) Configure(arguments lint.Arguments) error { | ||||
| 	if len(arguments) < 1 { | ||||
| 		r.maxComplexity = defaultMaxCognitiveComplexity | ||||
| 		return nil | ||||
| @@ -35,14 +35,7 @@ func (r *CognitiveComplexityRule) configure(arguments lint.Arguments) error { | ||||
| } | ||||
|  | ||||
| // Apply applies the rule to given file. | ||||
| func (r *CognitiveComplexityRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure { | ||||
| 	var configureErr error | ||||
| 	r.configureOnce.Do(func() { configureErr = r.configure(arguments) }) | ||||
|  | ||||
| 	if configureErr != nil { | ||||
| 		return newInternalFailureError(configureErr) | ||||
| 	} | ||||
|  | ||||
| func (r *CognitiveComplexityRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure { | ||||
| 	var failures []lint.Failure | ||||
|  | ||||
| 	linter := cognitiveComplexityLinter{ | ||||
|   | ||||
| @@ -3,7 +3,6 @@ package rule | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"strings" | ||||
| 	"sync" | ||||
|  | ||||
| 	"github.com/mgechev/revive/lint" | ||||
| ) | ||||
| @@ -12,11 +11,12 @@ import ( | ||||
| // the comment symbol( // ) and the start of the comment text | ||||
| type CommentSpacingsRule struct { | ||||
| 	allowList []string | ||||
|  | ||||
| 	configureOnce sync.Once | ||||
| } | ||||
|  | ||||
| func (r *CommentSpacingsRule) configure(arguments lint.Arguments) error { | ||||
| // Configure validates the rule configuration, and configures the rule accordingly. | ||||
| // | ||||
| // Configuration implements the [lint.ConfigurableRule] interface. | ||||
| func (r *CommentSpacingsRule) Configure(arguments lint.Arguments) error { | ||||
| 	r.allowList = []string{} | ||||
| 	for _, arg := range arguments { | ||||
| 		allow, ok := arg.(string) // Alt. non panicking version | ||||
| @@ -29,14 +29,7 @@ func (r *CommentSpacingsRule) configure(arguments lint.Arguments) error { | ||||
| } | ||||
|  | ||||
| // Apply the rule. | ||||
| func (r *CommentSpacingsRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure { | ||||
| 	var configureErr error | ||||
| 	r.configureOnce.Do(func() { configureErr = r.configure(arguments) }) | ||||
|  | ||||
| 	if configureErr != nil { | ||||
| 		return newInternalFailureError(configureErr) | ||||
| 	} | ||||
|  | ||||
| func (r *CommentSpacingsRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure { | ||||
| 	var failures []lint.Failure | ||||
|  | ||||
| 	for _, cg := range file.AST.Comments { | ||||
|   | ||||
| @@ -4,7 +4,6 @@ import ( | ||||
| 	"fmt" | ||||
| 	"go/ast" | ||||
| 	"strings" | ||||
| 	"sync" | ||||
|  | ||||
| 	"github.com/mgechev/revive/lint" | ||||
| ) | ||||
| @@ -12,13 +11,14 @@ import ( | ||||
| // CommentsDensityRule enforces a minimum comment / code relation. | ||||
| type CommentsDensityRule struct { | ||||
| 	minimumCommentsDensity int64 | ||||
|  | ||||
| 	configureOnce sync.Once | ||||
| } | ||||
|  | ||||
| const defaultMinimumCommentsPercentage = 0 | ||||
|  | ||||
| func (r *CommentsDensityRule) configure(arguments lint.Arguments) error { | ||||
| // Configure validates the rule configuration, and configures the rule accordingly. | ||||
| // | ||||
| // Configuration implements the [lint.ConfigurableRule] interface. | ||||
| func (r *CommentsDensityRule) Configure(arguments lint.Arguments) error { | ||||
| 	if len(arguments) < 1 { | ||||
| 		r.minimumCommentsDensity = defaultMinimumCommentsPercentage | ||||
| 		return nil | ||||
| @@ -33,14 +33,7 @@ func (r *CommentsDensityRule) configure(arguments lint.Arguments) error { | ||||
| } | ||||
|  | ||||
| // Apply applies the rule to given file. | ||||
| func (r *CommentsDensityRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure { | ||||
| 	var configureErr error | ||||
| 	r.configureOnce.Do(func() { configureErr = r.configure(arguments) }) | ||||
|  | ||||
| 	if configureErr != nil { | ||||
| 		return newInternalFailureError(configureErr) | ||||
| 	} | ||||
| 	 | ||||
| func (r *CommentsDensityRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure { | ||||
| 	commentsLines := countDocLines(file.AST.Comments) | ||||
| 	statementsCount := countStatements(file.AST) | ||||
| 	density := (float32(commentsLines) / float32(statementsCount+commentsLines)) * 100 | ||||
|   | ||||
| @@ -4,7 +4,6 @@ import ( | ||||
| 	"fmt" | ||||
| 	"go/ast" | ||||
| 	"strings" | ||||
| 	"sync" | ||||
|  | ||||
| 	"github.com/mgechev/revive/lint" | ||||
| ) | ||||
| @@ -12,19 +11,10 @@ import ( | ||||
| // ContextAsArgumentRule suggests that `context.Context` should be the first argument of a function. | ||||
| type ContextAsArgumentRule struct { | ||||
| 	allowTypes map[string]struct{} | ||||
|  | ||||
| 	configureOnce sync.Once | ||||
| } | ||||
|  | ||||
| // Apply applies the rule to given file. | ||||
| func (r *ContextAsArgumentRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure { | ||||
| 	var configureErr error | ||||
| 	r.configureOnce.Do(func() { configureErr = r.configure(arguments) }) | ||||
|  | ||||
| 	if configureErr != nil { | ||||
| 		return newInternalFailureError(configureErr) | ||||
| 	} | ||||
|  | ||||
| func (r *ContextAsArgumentRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure { | ||||
| 	var failures []lint.Failure | ||||
| 	for _, decl := range file.AST.Decls { | ||||
| 		fn, ok := decl.(*ast.FuncDecl) | ||||
| @@ -64,7 +54,10 @@ func (*ContextAsArgumentRule) Name() string { | ||||
| 	return "context-as-argument" | ||||
| } | ||||
|  | ||||
| func (r *ContextAsArgumentRule) configure(arguments lint.Arguments) error { | ||||
| // Configure validates the rule configuration, and configures the rule accordingly. | ||||
| // | ||||
| // Configuration implements the [lint.ConfigurableRule] interface. | ||||
| func (r *ContextAsArgumentRule) Configure(arguments lint.Arguments) error { | ||||
| 	types, err := r.getAllowTypesFromArguments(arguments) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
|   | ||||
| @@ -4,7 +4,6 @@ import ( | ||||
| 	"fmt" | ||||
| 	"go/ast" | ||||
| 	"go/token" | ||||
| 	"sync" | ||||
|  | ||||
| 	"github.com/mgechev/revive/lint" | ||||
| ) | ||||
| @@ -14,13 +13,14 @@ import ( | ||||
| // CyclomaticRule sets restriction for maximum cyclomatic complexity. | ||||
| type CyclomaticRule struct { | ||||
| 	maxComplexity int | ||||
|  | ||||
| 	configureOnce sync.Once | ||||
| } | ||||
|  | ||||
| const defaultMaxCyclomaticComplexity = 10 | ||||
|  | ||||
| func (r *CyclomaticRule) configure(arguments lint.Arguments) error { | ||||
| // Configure validates the rule configuration, and configures the rule accordingly. | ||||
| // | ||||
| // Configuration implements the [lint.ConfigurableRule] interface. | ||||
| func (r *CyclomaticRule) Configure(arguments lint.Arguments) error { | ||||
| 	if len(arguments) < 1 { | ||||
| 		r.maxComplexity = defaultMaxCyclomaticComplexity | ||||
| 		return nil | ||||
| @@ -35,14 +35,7 @@ func (r *CyclomaticRule) configure(arguments lint.Arguments) error { | ||||
| } | ||||
|  | ||||
| // Apply applies the rule to given file. | ||||
| func (r *CyclomaticRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure { | ||||
| 	var configureErr error | ||||
| 	r.configureOnce.Do(func() { configureErr = r.configure(arguments) }) | ||||
|  | ||||
| 	if configureErr != nil { | ||||
| 		return newInternalFailureError(configureErr) | ||||
| 	} | ||||
|  | ||||
| func (r *CyclomaticRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure { | ||||
| 	var failures []lint.Failure | ||||
| 	for _, decl := range file.AST.Decls { | ||||
| 		fn, ok := decl.(*ast.FuncDecl) | ||||
|   | ||||
| @@ -3,7 +3,6 @@ package rule | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"go/ast" | ||||
| 	"sync" | ||||
|  | ||||
| 	"github.com/mgechev/revive/lint" | ||||
| ) | ||||
| @@ -11,11 +10,12 @@ import ( | ||||
| // DeferRule lints gotchas in defer statements. | ||||
| type DeferRule struct { | ||||
| 	allow map[string]bool | ||||
|  | ||||
| 	configureOnce sync.Once | ||||
| } | ||||
|  | ||||
| func (r *DeferRule) configure(arguments lint.Arguments) error { | ||||
| // Configure validates the rule configuration, and configures the rule accordingly. | ||||
| // | ||||
| // Configuration implements the [lint.ConfigurableRule] interface. | ||||
| func (r *DeferRule) Configure(arguments lint.Arguments) error { | ||||
| 	list, err := r.allowFromArgs(arguments) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| @@ -25,14 +25,7 @@ func (r *DeferRule) configure(arguments lint.Arguments) error { | ||||
| } | ||||
|  | ||||
| // Apply applies the rule to given file. | ||||
| func (r *DeferRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure { | ||||
| 	var configureErr error | ||||
| 	r.configureOnce.Do(func() { configureErr = r.configure(arguments) }) | ||||
|  | ||||
| 	if configureErr != nil { | ||||
| 		return newInternalFailureError(configureErr) | ||||
| 	} | ||||
|  | ||||
| func (r *DeferRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure { | ||||
| 	var failures []lint.Failure | ||||
| 	onFailure := func(failure lint.Failure) { | ||||
| 		failures = append(failures, failure) | ||||
|   | ||||
| @@ -3,7 +3,6 @@ package rule | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"go/ast" | ||||
| 	"sync" | ||||
|  | ||||
| 	"github.com/mgechev/revive/lint" | ||||
| ) | ||||
| @@ -11,19 +10,10 @@ import ( | ||||
| // DotImportsRule forbids . imports. | ||||
| type DotImportsRule struct { | ||||
| 	allowedPackages allowPackages | ||||
|  | ||||
| 	configureOnce sync.Once | ||||
| } | ||||
|  | ||||
| // Apply applies the rule to given file. | ||||
| func (r *DotImportsRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure { | ||||
| 	var configureErr error | ||||
| 	r.configureOnce.Do(func() { configureErr = r.configure(arguments) }) | ||||
|  | ||||
| 	if configureErr != nil { | ||||
| 		return newInternalFailureError(configureErr) | ||||
| 	} | ||||
|  | ||||
| func (r *DotImportsRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure { | ||||
| 	var failures []lint.Failure | ||||
|  | ||||
| 	fileAst := file.AST | ||||
| @@ -46,7 +36,10 @@ func (*DotImportsRule) Name() string { | ||||
| 	return "dot-imports" | ||||
| } | ||||
|  | ||||
| func (r *DotImportsRule) configure(arguments lint.Arguments) error { | ||||
| // Configure validates the rule configuration, and configures the rule accordingly. | ||||
| // | ||||
| // Configuration implements the [lint.ConfigurableRule] interface. | ||||
| func (r *DotImportsRule) Configure(arguments lint.Arguments) error { | ||||
| 	r.allowedPackages = allowPackages{} | ||||
| 	if len(arguments) == 0 { | ||||
| 		return nil | ||||
|   | ||||
| @@ -3,7 +3,6 @@ package rule | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"go/ast" | ||||
| 	"sync" | ||||
|  | ||||
| 	"github.com/mgechev/revive/lint" | ||||
| ) | ||||
| @@ -40,11 +39,12 @@ func mapStyleFromString(s string) (enforceMapStyleType, error) { | ||||
| // EnforceMapStyleRule implements a rule to enforce `make(map[type]type)` over `map[type]type{}`. | ||||
| type EnforceMapStyleRule struct { | ||||
| 	enforceMapStyle enforceMapStyleType | ||||
|  | ||||
| 	configureOnce sync.Once | ||||
| } | ||||
|  | ||||
| func (r *EnforceMapStyleRule) configure(arguments lint.Arguments) error { | ||||
| // Configure validates the rule configuration, and configures the rule accordingly. | ||||
| // | ||||
| // Configuration implements the [lint.ConfigurableRule] interface. | ||||
| func (r *EnforceMapStyleRule) Configure(arguments lint.Arguments) error { | ||||
| 	if len(arguments) < 1 { | ||||
| 		r.enforceMapStyle = enforceMapStyleTypeAny | ||||
| 		return nil | ||||
| @@ -65,14 +65,7 @@ func (r *EnforceMapStyleRule) configure(arguments lint.Arguments) error { | ||||
| } | ||||
|  | ||||
| // Apply applies the rule to given file. | ||||
| func (r *EnforceMapStyleRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure { | ||||
| 	var configureErr error | ||||
| 	r.configureOnce.Do(func() { configureErr = r.configure(arguments) }) | ||||
|  | ||||
| 	if configureErr != nil { | ||||
| 		return newInternalFailureError(configureErr) | ||||
| 	} | ||||
|  | ||||
| func (r *EnforceMapStyleRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure { | ||||
| 	if r.enforceMapStyle == enforceMapStyleTypeAny { | ||||
| 		// this linter is not configured | ||||
| 		return nil | ||||
|   | ||||
| @@ -3,7 +3,6 @@ package rule | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"go/ast" | ||||
| 	"sync" | ||||
|  | ||||
| 	"github.com/mgechev/revive/lint" | ||||
| ) | ||||
| @@ -43,11 +42,12 @@ func repeatedArgTypeStyleFromString(s string) (enforceRepeatedArgTypeStyleType, | ||||
| type EnforceRepeatedArgTypeStyleRule struct { | ||||
| 	funcArgStyle    enforceRepeatedArgTypeStyleType | ||||
| 	funcRetValStyle enforceRepeatedArgTypeStyleType | ||||
|  | ||||
| 	configureOnce sync.Once | ||||
| } | ||||
|  | ||||
| func (r *EnforceRepeatedArgTypeStyleRule) configure(arguments lint.Arguments) error { | ||||
| // Configure validates the rule configuration, and configures the rule accordingly. | ||||
| // | ||||
| // Configuration implements the [lint.ConfigurableRule] interface. | ||||
| func (r *EnforceRepeatedArgTypeStyleRule) Configure(arguments lint.Arguments) error { | ||||
| 	r.funcArgStyle = enforceRepeatedArgTypeStyleTypeAny | ||||
| 	r.funcRetValStyle = enforceRepeatedArgTypeStyleTypeAny | ||||
|  | ||||
| @@ -101,14 +101,7 @@ func (r *EnforceRepeatedArgTypeStyleRule) configure(arguments lint.Arguments) er | ||||
| } | ||||
|  | ||||
| // Apply applies the rule to a given file. | ||||
| func (r *EnforceRepeatedArgTypeStyleRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure { | ||||
| 	var configureErr error | ||||
| 	r.configureOnce.Do(func() { configureErr = r.configure(arguments) }) | ||||
|  | ||||
| 	if configureErr != nil { | ||||
| 		return newInternalFailureError(configureErr) | ||||
| 	} | ||||
|  | ||||
| func (r *EnforceRepeatedArgTypeStyleRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure { | ||||
| 	if r.funcArgStyle == enforceRepeatedArgTypeStyleTypeAny && r.funcRetValStyle == enforceRepeatedArgTypeStyleTypeAny { | ||||
| 		// This linter is not configured, return no failures. | ||||
| 		return nil | ||||
|   | ||||
| @@ -3,7 +3,6 @@ package rule | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"go/ast" | ||||
| 	"sync" | ||||
|  | ||||
| 	"github.com/mgechev/revive/lint" | ||||
| ) | ||||
| @@ -44,11 +43,12 @@ func sliceStyleFromString(s string) (enforceSliceStyleType, error) { | ||||
| // EnforceSliceStyleRule implements a rule to enforce `make([]type)` over `[]type{}`. | ||||
| type EnforceSliceStyleRule struct { | ||||
| 	enforceSliceStyle enforceSliceStyleType | ||||
|  | ||||
| 	configureOnce sync.Once | ||||
| } | ||||
|  | ||||
| func (r *EnforceSliceStyleRule) configure(arguments lint.Arguments) error { | ||||
| // Configure validates the rule configuration, and configures the rule accordingly. | ||||
| // | ||||
| // Configuration implements the [lint.ConfigurableRule] interface. | ||||
| func (r *EnforceSliceStyleRule) Configure(arguments lint.Arguments) error { | ||||
| 	if len(arguments) < 1 { | ||||
| 		r.enforceSliceStyle = enforceSliceStyleTypeAny | ||||
| 		return nil | ||||
| @@ -68,14 +68,7 @@ func (r *EnforceSliceStyleRule) configure(arguments lint.Arguments) error { | ||||
| } | ||||
|  | ||||
| // Apply applies the rule to given file. | ||||
| func (r *EnforceSliceStyleRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure { | ||||
| 	var configureErr error | ||||
| 	r.configureOnce.Do(func() { configureErr = r.configure(arguments) }) | ||||
|  | ||||
| 	if configureErr != nil { | ||||
| 		return newInternalFailureError(configureErr) | ||||
| 	} | ||||
|  | ||||
| func (r *EnforceSliceStyleRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure { | ||||
| 	if r.enforceSliceStyle == enforceSliceStyleTypeAny { | ||||
| 		// this linter is not configured | ||||
| 		return nil | ||||
|   | ||||
| @@ -6,7 +6,6 @@ import ( | ||||
| 	"go/token" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
| 	"sync" | ||||
| 	"unicode" | ||||
| 	"unicode/utf8" | ||||
|  | ||||
| @@ -16,11 +15,12 @@ import ( | ||||
| // ErrorStringsRule lints error strings. | ||||
| type ErrorStringsRule struct { | ||||
| 	errorFunctions map[string]map[string]struct{} | ||||
|  | ||||
| 	configureOnce sync.Once | ||||
| } | ||||
|  | ||||
| func (r *ErrorStringsRule) configure(arguments lint.Arguments) error { | ||||
| // Configure validates the rule configuration, and configures the rule accordingly. | ||||
| // | ||||
| // Configuration implements the [lint.ConfigurableRule] interface. | ||||
| func (r *ErrorStringsRule) Configure(arguments lint.Arguments) error { | ||||
| 	r.errorFunctions = map[string]map[string]struct{}{ | ||||
| 		"fmt": { | ||||
| 			"Errorf": {}, | ||||
| @@ -53,14 +53,7 @@ func (r *ErrorStringsRule) configure(arguments lint.Arguments) error { | ||||
| } | ||||
|  | ||||
| // Apply applies the rule to given file. | ||||
| func (r *ErrorStringsRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure { | ||||
| 	var configureErr error | ||||
| 	r.configureOnce.Do(func() { configureErr = r.configure(arguments) }) | ||||
|  | ||||
| 	if configureErr != nil { | ||||
| 		return newInternalFailureError(configureErr) | ||||
| 	} | ||||
|  | ||||
| func (r *ErrorStringsRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure { | ||||
| 	var failures []lint.Failure | ||||
|  | ||||
| 	fileAst := file.AST | ||||
|   | ||||
| @@ -5,7 +5,6 @@ import ( | ||||
| 	"go/ast" | ||||
| 	"go/token" | ||||
| 	"strings" | ||||
| 	"sync" | ||||
| 	"unicode" | ||||
| 	"unicode/utf8" | ||||
|  | ||||
| @@ -25,9 +24,11 @@ type disabledChecks struct { | ||||
| 	Var              bool | ||||
| } | ||||
|  | ||||
| const checkNamePrivateReceivers = "privateReceivers" | ||||
| const checkNamePublicInterfaces = "publicInterfaces" | ||||
| const checkNameStuttering = "stuttering" | ||||
| const ( | ||||
| 	checkNamePrivateReceivers = "privateReceivers" | ||||
| 	checkNamePublicInterfaces = "publicInterfaces" | ||||
| 	checkNameStuttering       = "stuttering" | ||||
| ) | ||||
|  | ||||
| // isDisabled returns true if the given check is disabled, false otherwise | ||||
| func (dc *disabledChecks) isDisabled(checkName string) bool { | ||||
| @@ -66,11 +67,12 @@ var commonMethods = map[string]bool{ | ||||
| type ExportedRule struct { | ||||
| 	stuttersMsg    string | ||||
| 	disabledChecks disabledChecks | ||||
|  | ||||
| 	configureOnce sync.Once | ||||
| } | ||||
|  | ||||
| func (r *ExportedRule) configure(arguments lint.Arguments) error { | ||||
| // Configure validates the rule configuration, and configures the rule accordingly. | ||||
| // | ||||
| // Configuration implements the [lint.ConfigurableRule] interface. | ||||
| func (r *ExportedRule) Configure(arguments lint.Arguments) error { | ||||
| 	r.disabledChecks = disabledChecks{PrivateReceivers: true, PublicInterfaces: true} | ||||
| 	r.stuttersMsg = "stutters" | ||||
| 	for _, flag := range arguments { | ||||
| @@ -107,14 +109,7 @@ func (r *ExportedRule) configure(arguments lint.Arguments) error { | ||||
| } | ||||
|  | ||||
| // Apply applies the rule to given file. | ||||
| func (r *ExportedRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure { | ||||
| 	var configureErr error | ||||
| 	r.configureOnce.Do(func() { configureErr = r.configure(arguments) }) | ||||
|  | ||||
| 	if configureErr != nil { | ||||
| 		return newInternalFailureError(configureErr) | ||||
| 	} | ||||
|  | ||||
| func (r *ExportedRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure { | ||||
| 	var failures []lint.Failure | ||||
| 	if file.IsTest() { | ||||
| 		return failures | ||||
|   | ||||
| @@ -3,7 +3,6 @@ package rule | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"regexp" | ||||
| 	"sync" | ||||
|  | ||||
| 	"github.com/mgechev/revive/lint" | ||||
| ) | ||||
| @@ -11,8 +10,6 @@ import ( | ||||
| // FileHeaderRule lints the header that each file should have. | ||||
| type FileHeaderRule struct { | ||||
| 	header string | ||||
|  | ||||
| 	configureOnce sync.Once | ||||
| } | ||||
|  | ||||
| var ( | ||||
| @@ -20,7 +17,10 @@ var ( | ||||
| 	singleRegexp = regexp.MustCompile("^//") | ||||
| ) | ||||
|  | ||||
| func (r *FileHeaderRule) configure(arguments lint.Arguments) error { | ||||
| // Configure validates the rule configuration, and configures the rule accordingly. | ||||
| // | ||||
| // Configuration implements the [lint.ConfigurableRule] interface. | ||||
| func (r *FileHeaderRule) Configure(arguments lint.Arguments) error { | ||||
| 	if len(arguments) < 1 { | ||||
| 		return nil | ||||
| 	} | ||||
| @@ -34,14 +34,7 @@ func (r *FileHeaderRule) configure(arguments lint.Arguments) error { | ||||
| } | ||||
|  | ||||
| // Apply applies the rule to given file. | ||||
| func (r *FileHeaderRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure { | ||||
| 	var configureErr error | ||||
| 	r.configureOnce.Do(func() { configureErr = r.configure(arguments) }) | ||||
|  | ||||
| 	if configureErr != nil { | ||||
| 		return newInternalFailureError(configureErr) | ||||
| 	} | ||||
|  | ||||
| func (r *FileHeaderRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure { | ||||
| 	if r.header == "" { | ||||
| 		return nil | ||||
| 	} | ||||
|   | ||||
| @@ -7,7 +7,6 @@ import ( | ||||
| 	"go/ast" | ||||
| 	"go/token" | ||||
| 	"strings" | ||||
| 	"sync" | ||||
|  | ||||
| 	"github.com/mgechev/revive/lint" | ||||
| ) | ||||
| @@ -20,19 +19,10 @@ type FileLengthLimitRule struct { | ||||
| 	skipComments bool | ||||
| 	// skipBlankLines indicates whether to skip blank lines when counting lines. | ||||
| 	skipBlankLines bool | ||||
|  | ||||
| 	configureOnce sync.Once | ||||
| } | ||||
|  | ||||
| // Apply applies the rule to given file. | ||||
| func (r *FileLengthLimitRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure { | ||||
| 	var configureErr error | ||||
| 	r.configureOnce.Do(func() { configureErr = r.configure(arguments) }) | ||||
|  | ||||
| 	if configureErr != nil { | ||||
| 		return newInternalFailureError(configureErr) | ||||
| 	} | ||||
|  | ||||
| func (r *FileLengthLimitRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure { | ||||
| 	if r.max <= 0 { | ||||
| 		// when max is negative or 0 the rule is disabled | ||||
| 		return nil | ||||
| @@ -80,7 +70,10 @@ func (r *FileLengthLimitRule) Apply(file *lint.File, arguments lint.Arguments) [ | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (r *FileLengthLimitRule) configure(arguments lint.Arguments) error { | ||||
| // Configure validates the rule configuration, and configures the rule accordingly. | ||||
| // | ||||
| // Configuration implements the [lint.ConfigurableRule] interface. | ||||
| func (r *FileLengthLimitRule) Configure(arguments lint.Arguments) error { | ||||
| 	if len(arguments) < 1 { | ||||
| 		return nil // use default | ||||
| 	} | ||||
|   | ||||
| @@ -4,7 +4,6 @@ import ( | ||||
| 	"fmt" | ||||
| 	"path/filepath" | ||||
| 	"regexp" | ||||
| 	"sync" | ||||
| 	"unicode" | ||||
|  | ||||
| 	"github.com/mgechev/revive/lint" | ||||
| @@ -13,19 +12,10 @@ import ( | ||||
| // FilenameFormatRule lints source filenames according to a set of regular expressions given as arguments | ||||
| type FilenameFormatRule struct { | ||||
| 	format *regexp.Regexp | ||||
|  | ||||
| 	configureOnce sync.Once | ||||
| } | ||||
|  | ||||
| // Apply applies the rule to the given file. | ||||
| func (r *FilenameFormatRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure { | ||||
| 	var configureErr error | ||||
| 	r.configureOnce.Do(func() { configureErr = r.configure(arguments) }) | ||||
|  | ||||
| 	if configureErr != nil { | ||||
| 		return newInternalFailureError(configureErr) | ||||
| 	} | ||||
|  | ||||
| func (r *FilenameFormatRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure { | ||||
| 	filename := filepath.Base(file.Name) | ||||
| 	if r.format.MatchString(filename) { | ||||
| 		return nil | ||||
| @@ -60,7 +50,10 @@ func (*FilenameFormatRule) Name() string { | ||||
|  | ||||
| var defaultFormat = regexp.MustCompile(`^[_A-Za-z0-9][_A-Za-z0-9-]*\.go$`) | ||||
|  | ||||
| func (r *FilenameFormatRule) configure(arguments lint.Arguments) error { | ||||
| // Configure validates the rule configuration, and configures the rule accordingly. | ||||
| // | ||||
| // Configuration implements the [lint.ConfigurableRule] interface. | ||||
| func (r *FilenameFormatRule) Configure(arguments lint.Arguments) error { | ||||
| 	argsCount := len(arguments) | ||||
| 	if argsCount == 0 { | ||||
| 		r.format = defaultFormat | ||||
|   | ||||
| @@ -4,7 +4,6 @@ import ( | ||||
| 	"fmt" | ||||
| 	"go/ast" | ||||
| 	"reflect" | ||||
| 	"sync" | ||||
|  | ||||
| 	"github.com/mgechev/revive/lint" | ||||
| ) | ||||
| @@ -13,11 +12,12 @@ import ( | ||||
| type FunctionLength struct { | ||||
| 	maxStmt  int | ||||
| 	maxLines int | ||||
|  | ||||
| 	configureOnce sync.Once | ||||
| } | ||||
|  | ||||
| func (r *FunctionLength) configure(arguments lint.Arguments) error { | ||||
| // Configure validates the rule configuration, and configures the rule accordingly. | ||||
| // | ||||
| // Configuration implements the [lint.ConfigurableRule] interface. | ||||
| func (r *FunctionLength) Configure(arguments lint.Arguments) error { | ||||
| 	maxStmt, maxLines, err := r.parseArguments(arguments) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| @@ -28,14 +28,7 @@ func (r *FunctionLength) configure(arguments lint.Arguments) error { | ||||
| } | ||||
|  | ||||
| // Apply applies the rule to given file. | ||||
| func (r *FunctionLength) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure { | ||||
| 	var configureErr error | ||||
| 	r.configureOnce.Do(func() { configureErr = r.configure(arguments) }) | ||||
|  | ||||
| 	if configureErr != nil { | ||||
| 		return newInternalFailureError(configureErr) | ||||
| 	} | ||||
|  | ||||
| func (r *FunctionLength) Apply(file *lint.File, _ lint.Arguments) []lint.Failure { | ||||
| 	var failures []lint.Failure | ||||
| 	for _, decl := range file.AST.Decls { | ||||
| 		funcDecl, ok := decl.(*ast.FuncDecl) | ||||
| @@ -80,8 +73,10 @@ func (*FunctionLength) Name() string { | ||||
| 	return "function-length" | ||||
| } | ||||
|  | ||||
| const defaultFuncStmtsLimit = 50 | ||||
| const defaultFuncLinesLimit = 75 | ||||
| const ( | ||||
| 	defaultFuncStmtsLimit = 50 | ||||
| 	defaultFuncLinesLimit = 75 | ||||
| ) | ||||
|  | ||||
| func (*FunctionLength) parseArguments(arguments lint.Arguments) (maxStmt, maxLines int64, err error) { | ||||
| 	if len(arguments) == 0 { | ||||
|   | ||||
| @@ -4,7 +4,6 @@ import ( | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"go/ast" | ||||
| 	"sync" | ||||
|  | ||||
| 	"github.com/mgechev/revive/lint" | ||||
| ) | ||||
| @@ -12,19 +11,10 @@ import ( | ||||
| // FunctionResultsLimitRule limits the maximum number of results a function can return. | ||||
| type FunctionResultsLimitRule struct { | ||||
| 	max int | ||||
|  | ||||
| 	configureOnce sync.Once | ||||
| } | ||||
|  | ||||
| // Apply applies the rule to given file. | ||||
| func (r *FunctionResultsLimitRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure { | ||||
| 	var configureErr error | ||||
| 	r.configureOnce.Do(func() { configureErr = r.configure(arguments) }) | ||||
|  | ||||
| 	if configureErr != nil { | ||||
| 		return newInternalFailureError(configureErr) | ||||
| 	} | ||||
|  | ||||
| func (r *FunctionResultsLimitRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure { | ||||
| 	var failures []lint.Failure | ||||
| 	for _, decl := range file.AST.Decls { | ||||
| 		funcDecl, ok := decl.(*ast.FuncDecl) | ||||
| @@ -59,7 +49,10 @@ func (*FunctionResultsLimitRule) Name() string { | ||||
|  | ||||
| const defaultResultsLimit = 3 | ||||
|  | ||||
| func (r *FunctionResultsLimitRule) configure(arguments lint.Arguments) error { | ||||
| // Configure validates the rule configuration, and configures the rule accordingly. | ||||
| // | ||||
| // Configuration implements the [lint.ConfigurableRule] interface. | ||||
| func (r *FunctionResultsLimitRule) Configure(arguments lint.Arguments) error { | ||||
| 	if len(arguments) < 1 { | ||||
| 		r.max = defaultResultsLimit | ||||
| 		return nil | ||||
|   | ||||
| @@ -3,7 +3,6 @@ package rule | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"regexp" | ||||
| 	"sync" | ||||
|  | ||||
| 	"github.com/mgechev/revive/lint" | ||||
| ) | ||||
| @@ -12,15 +11,16 @@ import ( | ||||
| type ImportAliasNamingRule struct { | ||||
| 	allowRegexp *regexp.Regexp | ||||
| 	denyRegexp  *regexp.Regexp | ||||
|  | ||||
| 	configureOnce sync.Once | ||||
| } | ||||
|  | ||||
| const defaultImportAliasNamingAllowRule = "^[a-z][a-z0-9]{0,}$" | ||||
|  | ||||
| var defaultImportAliasNamingAllowRegexp = regexp.MustCompile(defaultImportAliasNamingAllowRule) | ||||
|  | ||||
| func (r *ImportAliasNamingRule) configure(arguments lint.Arguments) error { | ||||
| // Configure validates the rule configuration, and configures the rule accordingly. | ||||
| // | ||||
| // Configuration implements the [lint.ConfigurableRule] interface. | ||||
| func (r *ImportAliasNamingRule) Configure(arguments lint.Arguments) error { | ||||
| 	if len(arguments) == 0 { | ||||
| 		r.allowRegexp = defaultImportAliasNamingAllowRegexp | ||||
| 		return nil | ||||
| @@ -61,14 +61,7 @@ func (r *ImportAliasNamingRule) configure(arguments lint.Arguments) error { | ||||
| } | ||||
|  | ||||
| // Apply applies the rule to given file. | ||||
| func (r *ImportAliasNamingRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure { | ||||
| 	var configureErr error | ||||
| 	r.configureOnce.Do(func() { configureErr = r.configure(arguments) }) | ||||
|  | ||||
| 	if configureErr != nil { | ||||
| 		return newInternalFailureError(configureErr) | ||||
| 	} | ||||
|  | ||||
| func (r *ImportAliasNamingRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure { | ||||
| 	var failures []lint.Failure | ||||
|  | ||||
| 	for _, is := range file.AST.Imports { | ||||
|   | ||||
| @@ -3,7 +3,6 @@ package rule | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"regexp" | ||||
| 	"sync" | ||||
|  | ||||
| 	"github.com/mgechev/revive/lint" | ||||
| ) | ||||
| @@ -11,13 +10,14 @@ import ( | ||||
| // ImportsBlocklistRule disallows importing the specified packages. | ||||
| type ImportsBlocklistRule struct { | ||||
| 	blocklist []*regexp.Regexp | ||||
|  | ||||
| 	configureOnce sync.Once | ||||
| } | ||||
|  | ||||
| var replaceImportRegexp = regexp.MustCompile(`/?\*\*/?`) | ||||
|  | ||||
| func (r *ImportsBlocklistRule) configure(arguments lint.Arguments) error { | ||||
| // Configure validates the rule configuration, and configures the rule accordingly. | ||||
| // | ||||
| // Configuration implements the [lint.ConfigurableRule] interface. | ||||
| func (r *ImportsBlocklistRule) Configure(arguments lint.Arguments) error { | ||||
| 	r.blocklist = []*regexp.Regexp{} | ||||
| 	for _, arg := range arguments { | ||||
| 		argStr, ok := arg.(string) | ||||
| @@ -43,14 +43,7 @@ func (r *ImportsBlocklistRule) isBlocklisted(path string) bool { | ||||
| } | ||||
|  | ||||
| // Apply applies the rule to given file. | ||||
| func (r *ImportsBlocklistRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure { | ||||
| 	var configureErr error | ||||
| 	r.configureOnce.Do(func() { configureErr = r.configure(arguments) }) | ||||
|  | ||||
| 	if configureErr != nil { | ||||
| 		return newInternalFailureError(configureErr) | ||||
| 	} | ||||
|  | ||||
| func (r *ImportsBlocklistRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure { | ||||
| 	var failures []lint.Failure | ||||
|  | ||||
| 	for _, is := range file.AST.Imports { | ||||
|   | ||||
| @@ -7,7 +7,6 @@ import ( | ||||
| 	"fmt" | ||||
| 	"go/token" | ||||
| 	"strings" | ||||
| 	"sync" | ||||
| 	"unicode/utf8" | ||||
|  | ||||
| 	"github.com/mgechev/revive/lint" | ||||
| @@ -16,13 +15,14 @@ import ( | ||||
| // LineLengthLimitRule lints number of characters in a line. | ||||
| type LineLengthLimitRule struct { | ||||
| 	max int | ||||
|  | ||||
| 	configureOnce sync.Once | ||||
| } | ||||
|  | ||||
| const defaultLineLengthLimit = 80 | ||||
|  | ||||
| func (r *LineLengthLimitRule) configure(arguments lint.Arguments) error { | ||||
| // Configure validates the rule configuration, and configures the rule accordingly. | ||||
| // | ||||
| // Configuration implements the [lint.ConfigurableRule] interface. | ||||
| func (r *LineLengthLimitRule) Configure(arguments lint.Arguments) error { | ||||
| 	if len(arguments) < 1 { | ||||
| 		r.max = defaultLineLengthLimit | ||||
| 		return nil | ||||
| @@ -38,14 +38,7 @@ func (r *LineLengthLimitRule) configure(arguments lint.Arguments) error { | ||||
| } | ||||
|  | ||||
| // Apply applies the rule to given file. | ||||
| func (r *LineLengthLimitRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure { | ||||
| 	var configureErr error | ||||
| 	r.configureOnce.Do(func() { configureErr = r.configure(arguments) }) | ||||
|  | ||||
| 	if configureErr != nil { | ||||
| 		return newInternalFailureError(configureErr) | ||||
| 	} | ||||
|  | ||||
| func (r *LineLengthLimitRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure { | ||||
| 	var failures []lint.Failure | ||||
|  | ||||
| 	checker := lintLineLengthNum{ | ||||
|   | ||||
| @@ -4,7 +4,6 @@ import ( | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"go/ast" | ||||
| 	"sync" | ||||
|  | ||||
| 	"github.com/mgechev/revive/lint" | ||||
| ) | ||||
| @@ -12,21 +11,12 @@ import ( | ||||
| // MaxControlNestingRule sets restriction for maximum nesting of control structures. | ||||
| type MaxControlNestingRule struct { | ||||
| 	max int64 | ||||
|  | ||||
| 	configureOnce sync.Once | ||||
| } | ||||
|  | ||||
| const defaultMaxControlNesting = 5 | ||||
|  | ||||
| // Apply applies the rule to given file. | ||||
| func (r *MaxControlNestingRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure { | ||||
| 	var configureErr error | ||||
| 	r.configureOnce.Do(func() { configureErr = r.configure(arguments) }) | ||||
|  | ||||
| 	if configureErr != nil { | ||||
| 		return newInternalFailureError(configureErr) | ||||
| 	} | ||||
|  | ||||
| func (r *MaxControlNestingRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure { | ||||
| 	var failures []lint.Failure | ||||
|  | ||||
| 	fileAst := file.AST | ||||
| @@ -113,7 +103,10 @@ func (w *lintMaxControlNesting) walkControlledBlock(b ast.Node) { | ||||
| 	w.nestingLevelAcc = oldNestingLevel | ||||
| } | ||||
|  | ||||
| func (r *MaxControlNestingRule) configure(arguments lint.Arguments) error { | ||||
| // Configure validates the rule configuration, and configures the rule accordingly. | ||||
| // | ||||
| // Configuration implements the [lint.ConfigurableRule] interface. | ||||
| func (r *MaxControlNestingRule) Configure(arguments lint.Arguments) error { | ||||
| 	if len(arguments) < 1 { | ||||
| 		r.max = defaultMaxControlNesting | ||||
| 		return nil | ||||
|   | ||||
| @@ -5,7 +5,6 @@ import ( | ||||
| 	"fmt" | ||||
| 	"go/ast" | ||||
| 	"strings" | ||||
| 	"sync" | ||||
|  | ||||
| 	"github.com/mgechev/revive/lint" | ||||
| ) | ||||
| @@ -13,13 +12,14 @@ import ( | ||||
| // MaxPublicStructsRule lints the number of public structs in a file. | ||||
| type MaxPublicStructsRule struct { | ||||
| 	max int64 | ||||
|  | ||||
| 	configureOnce sync.Once | ||||
| } | ||||
|  | ||||
| const defaultMaxPublicStructs = 5 | ||||
|  | ||||
| func (r *MaxPublicStructsRule) configure(arguments lint.Arguments) error { | ||||
| // Configure validates the rule configuration, and configures the rule accordingly. | ||||
| // | ||||
| // Configuration implements the [lint.ConfigurableRule] interface. | ||||
| func (r *MaxPublicStructsRule) Configure(arguments lint.Arguments) error { | ||||
| 	if len(arguments) < 1 { | ||||
| 		r.max = defaultMaxPublicStructs | ||||
| 		return nil | ||||
| @@ -39,14 +39,7 @@ func (r *MaxPublicStructsRule) configure(arguments lint.Arguments) error { | ||||
| } | ||||
|  | ||||
| // Apply applies the rule to given file. | ||||
| func (r *MaxPublicStructsRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure { | ||||
| 	var configureErr error | ||||
| 	r.configureOnce.Do(func() { configureErr = r.configure(arguments) }) | ||||
|  | ||||
| 	if configureErr != nil { | ||||
| 		return newInternalFailureError(configureErr) | ||||
| 	} | ||||
|  | ||||
| func (r *MaxPublicStructsRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure { | ||||
| 	var failures []lint.Failure | ||||
|  | ||||
| 	if r.max < 1 { | ||||
|   | ||||
| @@ -3,7 +3,6 @@ package rule | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"go/ast" | ||||
| 	"sync" | ||||
|  | ||||
| 	"github.com/mgechev/revive/internal/typeparams" | ||||
| 	"github.com/mgechev/revive/lint" | ||||
| @@ -12,13 +11,13 @@ import ( | ||||
| // ReceiverNamingRule lints a receiver name. | ||||
| type ReceiverNamingRule struct { | ||||
| 	receiverNameMaxLength int | ||||
|  | ||||
| 	configureOnce sync.Once | ||||
| } | ||||
|  | ||||
| const defaultReceiverNameMaxLength = -1 // thus will not check | ||||
|  | ||||
| func (r *ReceiverNamingRule) configure(arguments lint.Arguments) error { | ||||
| // Configure validates the rule configuration, and configures the rule accordingly. | ||||
| // | ||||
| // Configuration implements the [lint.ConfigurableRule] interface. | ||||
| func (r *ReceiverNamingRule) Configure(arguments lint.Arguments) error { | ||||
| 	r.receiverNameMaxLength = defaultReceiverNameMaxLength | ||||
| 	if len(arguments) < 1 { | ||||
| 		return nil | ||||
| @@ -45,14 +44,7 @@ func (r *ReceiverNamingRule) configure(arguments lint.Arguments) error { | ||||
| } | ||||
|  | ||||
| // Apply applies the rule to given file. | ||||
| func (r *ReceiverNamingRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure { | ||||
| 	var configureErr error | ||||
| 	r.configureOnce.Do(func() { configureErr = r.configure(arguments) }) | ||||
|  | ||||
| 	if configureErr != nil { | ||||
| 		return newInternalFailureError(configureErr) | ||||
| 	} | ||||
|  | ||||
| func (r *ReceiverNamingRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure { | ||||
| 	typeReceiver := map[string]string{} | ||||
| 	var failures []lint.Failure | ||||
| 	for _, decl := range file.AST.Decls { | ||||
|   | ||||
| @@ -5,7 +5,6 @@ import ( | ||||
| 	"go/ast" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
| 	"sync" | ||||
|  | ||||
| 	"github.com/fatih/structtag" | ||||
| 	"github.com/mgechev/revive/lint" | ||||
| @@ -14,11 +13,12 @@ import ( | ||||
| // StructTagRule lints struct tags. | ||||
| type StructTagRule struct { | ||||
| 	userDefined map[string][]string // map: key -> []option | ||||
|  | ||||
| 	configureOnce sync.Once | ||||
| } | ||||
|  | ||||
| func (r *StructTagRule) configure(arguments lint.Arguments) error { | ||||
| // Configure validates the rule configuration, and configures the rule accordingly. | ||||
| // | ||||
| // Configuration implements the [lint.ConfigurableRule] interface. | ||||
| func (r *StructTagRule) Configure(arguments lint.Arguments) error { | ||||
| 	if len(arguments) == 0 { | ||||
| 		return nil | ||||
| 	} | ||||
| @@ -47,14 +47,7 @@ func (r *StructTagRule) configure(arguments lint.Arguments) error { | ||||
| } | ||||
|  | ||||
| // Apply applies the rule to given file. | ||||
| func (r *StructTagRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure { | ||||
| 	var configureErr error | ||||
| 	r.configureOnce.Do(func() { configureErr = r.configure(arguments) }) | ||||
|  | ||||
| 	if configureErr != nil { | ||||
| 		return newInternalFailureError(configureErr) | ||||
| 	} | ||||
|  | ||||
| func (r *StructTagRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure { | ||||
| 	var failures []lint.Failure | ||||
| 	onFailure := func(failure lint.Failure) { | ||||
| 		failures = append(failures, failure) | ||||
| @@ -102,14 +95,16 @@ func (w lintStructTagRule) Visit(node ast.Node) ast.Visitor { | ||||
| 	return w | ||||
| } | ||||
|  | ||||
| const keyASN1 = "asn1" | ||||
| const keyBSON = "bson" | ||||
| const keyDefault = "default" | ||||
| const keyJSON = "json" | ||||
| const keyProtobuf = "protobuf" | ||||
| const keyRequired = "required" | ||||
| const keyXML = "xml" | ||||
| const keyYAML = "yaml" | ||||
| const ( | ||||
| 	keyASN1     = "asn1" | ||||
| 	keyBSON     = "bson" | ||||
| 	keyDefault  = "default" | ||||
| 	keyJSON     = "json" | ||||
| 	keyProtobuf = "protobuf" | ||||
| 	keyRequired = "required" | ||||
| 	keyXML      = "xml" | ||||
| 	keyYAML     = "yaml" | ||||
| ) | ||||
|  | ||||
| func (w lintStructTagRule) checkTagNameIfNeed(tag *structtag.Tag) (string, bool) { | ||||
| 	isUnnamedTag := tag.Name == "" || tag.Name == "-" | ||||
|   | ||||
| @@ -4,7 +4,6 @@ import ( | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"go/ast" | ||||
| 	"sync" | ||||
|  | ||||
| 	"github.com/mgechev/revive/lint" | ||||
| ) | ||||
| @@ -17,11 +16,12 @@ const ( | ||||
| // UncheckedTypeAssertionRule lints missing or ignored `ok`-value in dynamic type casts. | ||||
| type UncheckedTypeAssertionRule struct { | ||||
| 	acceptIgnoredAssertionResult bool | ||||
|  | ||||
| 	configureOnce sync.Once | ||||
| } | ||||
|  | ||||
| func (r *UncheckedTypeAssertionRule) configure(arguments lint.Arguments) error { | ||||
| // Configure validates the rule configuration, and configures the rule accordingly. | ||||
| // | ||||
| // Configuration implements the [lint.ConfigurableRule] interface. | ||||
| func (r *UncheckedTypeAssertionRule) Configure(arguments lint.Arguments) error { | ||||
| 	if len(arguments) == 0 { | ||||
| 		return nil | ||||
| 	} | ||||
| @@ -46,14 +46,7 @@ func (r *UncheckedTypeAssertionRule) configure(arguments lint.Arguments) error { | ||||
| } | ||||
|  | ||||
| // Apply applies the rule to given file. | ||||
| func (r *UncheckedTypeAssertionRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure { | ||||
| 	var configureErr error | ||||
| 	r.configureOnce.Do(func() { configureErr = r.configure(arguments) }) | ||||
|  | ||||
| 	if configureErr != nil { | ||||
| 		return newInternalFailureError(configureErr) | ||||
| 	} | ||||
|  | ||||
| func (r *UncheckedTypeAssertionRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure { | ||||
| 	var failures []lint.Failure | ||||
|  | ||||
| 	walker := &lintUncheckedTypeAssertion{ | ||||
|   | ||||
| @@ -7,7 +7,6 @@ import ( | ||||
| 	"go/types" | ||||
| 	"regexp" | ||||
| 	"strings" | ||||
| 	"sync" | ||||
|  | ||||
| 	"github.com/mgechev/revive/lint" | ||||
| ) | ||||
| @@ -15,11 +14,12 @@ import ( | ||||
| // UnhandledErrorRule warns on unhandled errors returned by function calls. | ||||
| type UnhandledErrorRule struct { | ||||
| 	ignoreList []*regexp.Regexp | ||||
|  | ||||
| 	configureOnce sync.Once | ||||
| } | ||||
|  | ||||
| func (r *UnhandledErrorRule) configure(arguments lint.Arguments) error { | ||||
| // Configure validates the rule configuration, and configures the rule accordingly. | ||||
| // | ||||
| // Configuration implements the [lint.ConfigurableRule] interface. | ||||
| func (r *UnhandledErrorRule) Configure(arguments lint.Arguments) error { | ||||
| 	for _, arg := range arguments { | ||||
| 		argStr, ok := arg.(string) | ||||
| 		if !ok { | ||||
| @@ -42,14 +42,7 @@ func (r *UnhandledErrorRule) configure(arguments lint.Arguments) error { | ||||
| } | ||||
|  | ||||
| // Apply applies the rule to given file. | ||||
| func (r *UnhandledErrorRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure { | ||||
| 	var configureErr error | ||||
| 	r.configureOnce.Do(func() { configureErr = r.configure(arguments) }) | ||||
|  | ||||
| 	if configureErr != nil { | ||||
| 		return newInternalFailureError(configureErr) | ||||
| 	} | ||||
|  | ||||
| func (r *UnhandledErrorRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure { | ||||
| 	var failures []lint.Failure | ||||
|  | ||||
| 	walker := &lintUnhandledErrors{ | ||||
|   | ||||
| @@ -4,7 +4,6 @@ import ( | ||||
| 	"fmt" | ||||
| 	"go/ast" | ||||
| 	"regexp" | ||||
| 	"sync" | ||||
|  | ||||
| 	"github.com/mgechev/revive/lint" | ||||
| ) | ||||
| @@ -16,11 +15,12 @@ type UnusedParamRule struct { | ||||
| 	// regex to check if some name is valid for unused parameter, "^_$" by default | ||||
| 	allowRegex *regexp.Regexp | ||||
| 	failureMsg string | ||||
|  | ||||
| 	configureOnce sync.Once | ||||
| } | ||||
|  | ||||
| func (r *UnusedParamRule) configure(args lint.Arguments) error { | ||||
| // Configure validates the rule configuration, and configures the rule accordingly. | ||||
| // | ||||
| // Configuration implements the [lint.ConfigurableRule] interface. | ||||
| func (r *UnusedParamRule) Configure(args lint.Arguments) error { | ||||
| 	// while by default args is an array, i think it's good to provide structures inside it by default, not arrays or primitives | ||||
| 	// it's more compatible to JSON nature of configurations | ||||
| 	r.allowRegex = allowBlankIdentifierRegex | ||||
| @@ -50,14 +50,7 @@ func (r *UnusedParamRule) configure(args lint.Arguments) error { | ||||
| } | ||||
|  | ||||
| // Apply applies the rule to given file. | ||||
| func (r *UnusedParamRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure { | ||||
| 	var configureErr error | ||||
| 	r.configureOnce.Do(func() { configureErr = r.configure(arguments) }) | ||||
|  | ||||
| 	if configureErr != nil { | ||||
| 		return newInternalFailureError(configureErr) | ||||
| 	} | ||||
|  | ||||
| func (r *UnusedParamRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure { | ||||
| 	var failures []lint.Failure | ||||
|  | ||||
| 	onFailure := func(failure lint.Failure) { | ||||
|   | ||||
| @@ -4,7 +4,6 @@ import ( | ||||
| 	"fmt" | ||||
| 	"go/ast" | ||||
| 	"regexp" | ||||
| 	"sync" | ||||
|  | ||||
| 	"github.com/mgechev/revive/lint" | ||||
| ) | ||||
| @@ -14,11 +13,12 @@ type UnusedReceiverRule struct { | ||||
| 	// regex to check if some name is valid for unused parameter, "^_$" by default | ||||
| 	allowRegex *regexp.Regexp | ||||
| 	failureMsg string | ||||
|  | ||||
| 	configureOnce sync.Once | ||||
| } | ||||
|  | ||||
| func (r *UnusedReceiverRule) configure(args lint.Arguments) error { | ||||
| // Configure validates the rule configuration, and configures the rule accordingly. | ||||
| // | ||||
| // Configuration implements the [lint.ConfigurableRule] interface. | ||||
| func (r *UnusedReceiverRule) Configure(args lint.Arguments) error { | ||||
| 	// while by default args is an array, i think it's good to provide structures inside it by default, not arrays or primitives | ||||
| 	// it's more compatible to JSON nature of configurations | ||||
| 	r.allowRegex = allowBlankIdentifierRegex | ||||
| @@ -48,14 +48,7 @@ func (r *UnusedReceiverRule) configure(args lint.Arguments) error { | ||||
| } | ||||
|  | ||||
| // Apply applies the rule to given file. | ||||
| func (r *UnusedReceiverRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure { | ||||
| 	var configureErr error | ||||
| 	r.configureOnce.Do(func() { configureErr = r.configure(arguments) }) | ||||
|  | ||||
| 	if configureErr != nil { | ||||
| 		return newInternalFailureError(configureErr) | ||||
| 	} | ||||
|  | ||||
| func (r *UnusedReceiverRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure { | ||||
| 	var failures []lint.Failure | ||||
|  | ||||
| 	for _, decl := range file.AST.Decls { | ||||
|   | ||||
| @@ -6,7 +6,6 @@ import ( | ||||
| 	"go/token" | ||||
| 	"regexp" | ||||
| 	"strings" | ||||
| 	"sync" | ||||
|  | ||||
| 	"github.com/mgechev/revive/lint" | ||||
| ) | ||||
| @@ -29,11 +28,12 @@ type VarNamingRule struct { | ||||
| 	blockList             []string | ||||
| 	allowUpperCaseConst   bool // if true - allows to use UPPER_SOME_NAMES for constants | ||||
| 	skipPackageNameChecks bool | ||||
|  | ||||
| 	configureOnce sync.Once | ||||
| } | ||||
|  | ||||
| func (r *VarNamingRule) configure(arguments lint.Arguments) error { | ||||
| // Configure validates the rule configuration, and configures the rule accordingly. | ||||
| // | ||||
| // Configuration implements the [lint.ConfigurableRule] interface. | ||||
| func (r *VarNamingRule) Configure(arguments lint.Arguments) error { | ||||
| 	if len(arguments) >= 1 { | ||||
| 		list, err := getList(arguments[0], "allowlist") | ||||
| 		if err != nil { | ||||
| @@ -91,14 +91,7 @@ func (*VarNamingRule) applyPackageCheckRules(walker *lintNames) { | ||||
| } | ||||
|  | ||||
| // Apply applies the rule to given file. | ||||
| func (r *VarNamingRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure { | ||||
| 	var configureErr error | ||||
| 	r.configureOnce.Do(func() { configureErr = r.configure(arguments) }) | ||||
|  | ||||
| 	if configureErr != nil { | ||||
| 		return newInternalFailureError(configureErr) | ||||
| 	} | ||||
|  | ||||
| func (r *VarNamingRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure { | ||||
| 	var failures []lint.Failure | ||||
|  | ||||
| 	fileAst := file.AST | ||||
|   | ||||
| @@ -36,6 +36,10 @@ var rules = []lint.Rule{ | ||||
| func TestAll(t *testing.T) { | ||||
| 	baseDir := "../testdata/golint/" | ||||
|  | ||||
| 	for _, r := range rules { | ||||
| 		configureRule(t, r, nil) | ||||
| 	} | ||||
|  | ||||
| 	rx, err := regexp.Compile(*lintMatch) | ||||
| 	if err != nil { | ||||
| 		t.Fatalf("Bad -lint.match value %q: %v", *lintMatch, err) | ||||
|   | ||||
| @@ -16,6 +16,22 @@ import ( | ||||
| 	"github.com/mgechev/revive/lint" | ||||
| ) | ||||
|  | ||||
| // configureRule configures the given rule with the given configuration | ||||
| // if the rule implements the ConfigurableRule interface | ||||
| func configureRule(t *testing.T, rule lint.Rule, arguments lint.Arguments) { | ||||
| 	t.Helper() | ||||
|  | ||||
| 	cr, ok := rule.(lint.ConfigurableRule) | ||||
| 	if !ok { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	err := cr.Configure(arguments) | ||||
| 	if err != nil { | ||||
| 		t.Fatalf("Cannot configure rule %s: %v", rule.Name(), err) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func testRule(t *testing.T, filename string, rule lint.Rule, config ...*lint.RuleConfig) { | ||||
| 	t.Helper() | ||||
|  | ||||
| @@ -30,10 +46,14 @@ func testRule(t *testing.T, filename string, rule lint.Rule, config ...*lint.Rul | ||||
| 	if err != nil { | ||||
| 		t.Fatalf("Cannot get file info for %s: %v", rule.Name(), err) | ||||
| 	} | ||||
| 	var ruleConfig lint.RuleConfig | ||||
| 	c := map[string]lint.RuleConfig{} | ||||
| 	if config != nil { | ||||
| 		c[rule.Name()] = *config[0] | ||||
| 	if len(config) > 0 { | ||||
| 		ruleConfig = *config[0] | ||||
| 		c[rule.Name()] = ruleConfig | ||||
| 	} | ||||
| 	configureRule(t, rule, ruleConfig.Arguments) | ||||
|  | ||||
| 	if parseInstructions(t, fullFilePath, src) == nil { | ||||
| 		assertSuccess(t, baseDir, stat, []lint.Rule{rule}, c) | ||||
| 		return | ||||
|   | ||||
		Reference in New Issue
	
	Block a user