1
0
mirror of https://github.com/mgechev/revive.git synced 2025-02-01 13:07:44 +02:00

Memoization of rule arguments (#595)

This commit is contained in:
SalvadorC 2021-10-17 20:34:48 +02:00 committed by GitHub
parent b7d1908051
commit 76b8c57329
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 213 additions and 141 deletions

View File

@ -30,48 +30,53 @@ func (wl whiteList) add(kind string, list string) {
}
// AddConstantRule lints unused params in functions.
type AddConstantRule struct{}
type AddConstantRule struct {
whiteList whiteList
strLitLimit int
}
// Apply applies the rule to given file.
func (r *AddConstantRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure {
strLitLimit := defaultStrLitLimit
var whiteList = newWhiteList()
if len(arguments) > 0 {
args, ok := arguments[0].(map[string]interface{})
if !ok {
panic(fmt.Sprintf("Invalid argument to the add-constant rule. Expecting a k,v map, got %T", arguments[0]))
}
for k, v := range args {
kind := ""
switch k {
case "allowFloats":
kind = kindFLOAT
fallthrough
case "allowInts":
if kind == "" {
kind = kindINT
}
fallthrough
case "allowStrs":
if kind == "" {
kind = kindSTRING
}
list, ok := v.(string)
if !ok {
panic(fmt.Sprintf("Invalid argument to the add-constant rule, string expected. Got '%v' (%T)", v, v))
}
whiteList.add(kind, list)
case "maxLitCount":
sl, ok := v.(string)
if !ok {
panic(fmt.Sprintf("Invalid argument to the add-constant rule, expecting string representation of an integer. Got '%v' (%T)", v, v))
}
if r.whiteList == nil {
r.strLitLimit = defaultStrLitLimit
r.whiteList = newWhiteList()
if len(arguments) > 0 {
args, ok := arguments[0].(map[string]interface{})
if !ok {
panic(fmt.Sprintf("Invalid argument to the add-constant rule. Expecting a k,v map, got %T", arguments[0]))
}
for k, v := range args {
kind := ""
switch k {
case "allowFloats":
kind = kindFLOAT
fallthrough
case "allowInts":
if kind == "" {
kind = kindINT
}
fallthrough
case "allowStrs":
if kind == "" {
kind = kindSTRING
}
list, ok := v.(string)
if !ok {
panic(fmt.Sprintf("Invalid argument to the add-constant rule, string expected. Got '%v' (%T)", v, v))
}
r.whiteList.add(kind, list)
case "maxLitCount":
sl, ok := v.(string)
if !ok {
panic(fmt.Sprintf("Invalid argument to the add-constant rule, expecting string representation of an integer. Got '%v' (%T)", v, v))
}
limit, err := strconv.Atoi(sl)
if err != nil {
panic(fmt.Sprintf("Invalid argument to the add-constant rule, expecting string representation of an integer. Got '%v'", v))
limit, err := strconv.Atoi(sl)
if err != nil {
panic(fmt.Sprintf("Invalid argument to the add-constant rule, expecting string representation of an integer. Got '%v'", v))
}
r.strLitLimit = limit
}
strLitLimit = limit
}
}
}
@ -82,7 +87,7 @@ func (r *AddConstantRule) Apply(file *lint.File, arguments lint.Arguments) []lin
failures = append(failures, failure)
}
w := lintAddConstantRule{onFailure: onFailure, strLits: make(map[string]int), strLitLimit: strLitLimit, whiteLst: whiteList}
w := lintAddConstantRule{onFailure: onFailure, strLits: make(map[string]int), strLitLimit: r.strLitLimit, whiteLst: r.whiteList}
ast.Walk(w, file.AST)

View File

@ -8,21 +8,26 @@ import (
)
// ArgumentsLimitRule lints given else constructs.
type ArgumentsLimitRule struct{}
type ArgumentsLimitRule struct {
total int
}
// Apply applies the rule to given file.
func (r *ArgumentsLimitRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure {
checkNumberOfArguments(1, arguments, r.Name())
if r.total == 0 {
checkNumberOfArguments(1, arguments, r.Name())
total, ok := arguments[0].(int64) // Alt. non panicking version
if !ok {
panic(`invalid value passed as argument number to the "argument-list" rule`)
total, ok := arguments[0].(int64) // Alt. non panicking version
if !ok {
panic(`invalid value passed as argument number to the "argument-list" rule`)
}
r.total = int(total)
}
var failures []lint.Failure
walker := lintArgsNum{
total: int(total),
total: r.total,
onFailure: func(failure lint.Failure) {
failures = append(failures, failure)
},

View File

@ -9,23 +9,26 @@ import (
)
// BannedCharsRule checks if a file contains banned characters.
type BannedCharsRule struct{}
type BannedCharsRule struct {
bannedCharList []string
}
const bannedCharsRuleName = "banned-characters"
// Apply applied the rule to the given file.
func (r *BannedCharsRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure {
if r.bannedCharList == nil {
checkNumberOfArguments(1, arguments, bannedCharsRuleName)
r.bannedCharList = r.getBannedCharsList(arguments)
}
var failures []lint.Failure
checkNumberOfArguments(1, arguments, bannedCharsRuleName)
bannedCharList := r.getBannedCharsList(arguments)
onFailure := func(failure lint.Failure) {
failures = append(failures, failure)
}
w := lintBannedCharsRule{
bannedChars: bannedCharList,
bannedChars: r.bannedCharList,
onFailure: onFailure,
}
ast.Walk(w, file.AST)

View File

@ -10,22 +10,26 @@ import (
)
// CognitiveComplexityRule lints given else constructs.
type CognitiveComplexityRule struct{}
type CognitiveComplexityRule struct {
maxComplexity int
}
// Apply applies the rule to given file.
func (r *CognitiveComplexityRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure {
checkNumberOfArguments(1, arguments, r.Name())
if r.maxComplexity == 0 {
checkNumberOfArguments(1, arguments, r.Name())
complexity, ok := arguments[0].(int64)
if !ok {
panic(fmt.Sprintf("invalid argument type for cognitive-complexity, expected int64, got %T", arguments[0]))
complexity, ok := arguments[0].(int64)
if !ok {
panic(fmt.Sprintf("invalid argument type for cognitive-complexity, expected int64, got %T", arguments[0]))
}
r.maxComplexity = int(complexity)
}
var failures []lint.Failure
linter := cognitiveComplexityLinter{
file: file,
maxComplexity: int(complexity),
maxComplexity: r.maxComplexity,
onFailure: func(failure lint.Failure) {
failures = append(failures, failure)
},

View File

@ -11,23 +11,27 @@ import (
// Based on https://github.com/fzipp/gocyclo
// CyclomaticRule lints given else constructs.
type CyclomaticRule struct{}
type CyclomaticRule struct {
maxComplexity int
}
// Apply applies the rule to given file.
func (r *CyclomaticRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure {
checkNumberOfArguments(1, arguments, r.Name())
if r.maxComplexity == 0 {
checkNumberOfArguments(1, arguments, r.Name())
complexity, ok := arguments[0].(int64) // Alt. non panicking version
if !ok {
panic("invalid argument for cyclomatic complexity")
complexity, ok := arguments[0].(int64) // Alt. non panicking version
if !ok {
panic(fmt.Sprintf("invalid argument for cyclomatic complexity; expected int but got %T", arguments[0]))
}
r.maxComplexity = int(complexity)
}
var failures []lint.Failure
fileAst := file.AST
walker := lintCyclomatic{
file: file,
complexity: int(complexity),
complexity: r.maxComplexity,
onFailure: func(failure lint.Failure) {
failures = append(failures, failure)
},

View File

@ -8,18 +8,21 @@ import (
)
// DeferRule lints unused params in functions.
type DeferRule struct{}
type DeferRule struct {
allow map[string]bool
}
// Apply applies the rule to given file.
func (r *DeferRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure {
allow := r.allowFromArgs(arguments)
if r.allow == nil {
r.allow = r.allowFromArgs(arguments)
}
var failures []lint.Failure
onFailure := func(failure lint.Failure) {
failures = append(failures, failure)
}
w := lintDeferRule{onFailure: onFailure, allow: allow}
w := lintDeferRule{onFailure: onFailure, allow: r.allow}
ast.Walk(w, file.AST)

View File

@ -12,7 +12,12 @@ import (
)
// ExportedRule lints given else constructs.
type ExportedRule struct{}
type ExportedRule struct {
configured bool
checkPrivateReceivers bool
disableStutteringCheck bool
stuttersMsg string
}
// Apply applies the rule to given file.
func (r *ExportedRule) Apply(file *lint.File, args lint.Arguments) []lint.Failure {
@ -22,11 +27,15 @@ func (r *ExportedRule) Apply(file *lint.File, args lint.Arguments) []lint.Failur
return failures
}
checkPrivateReceivers, disableStutteringCheck, sayRepetitiveInsteadOfStutters := r.getConf(args)
if !r.configured {
var sayRepetitiveInsteadOfStutters bool
r.checkPrivateReceivers, r.disableStutteringCheck, sayRepetitiveInsteadOfStutters = r.getConf(args)
r.stuttersMsg = "stutters"
if sayRepetitiveInsteadOfStutters {
r.stuttersMsg = "is repetitive"
}
stuttersMsg := "stutters"
if sayRepetitiveInsteadOfStutters {
stuttersMsg = "is repetitive"
r.configured = true
}
fileAst := file.AST
@ -37,9 +46,9 @@ func (r *ExportedRule) Apply(file *lint.File, args lint.Arguments) []lint.Failur
failures = append(failures, failure)
},
genDeclMissingComments: make(map[*ast.GenDecl]bool),
checkPrivateReceivers: checkPrivateReceivers,
disableStutteringCheck: disableStutteringCheck,
stuttersMsg: stuttersMsg,
checkPrivateReceivers: r.checkPrivateReceivers,
disableStutteringCheck: r.disableStutteringCheck,
stuttersMsg: r.stuttersMsg,
}
ast.Walk(&walker, fileAst)

View File

@ -7,7 +7,9 @@ import (
)
// FileHeaderRule lints given else constructs.
type FileHeaderRule struct{}
type FileHeaderRule struct {
header string
}
var (
multiRegexp = regexp.MustCompile("^/\\*")
@ -16,11 +18,13 @@ var (
// Apply applies the rule to given file.
func (r *FileHeaderRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure {
checkNumberOfArguments(1, arguments, r.Name())
header, ok := arguments[0].(string)
if !ok {
panic(`invalid argument for "file-header" rule: first argument should be a string`)
if r.header == "" {
checkNumberOfArguments(1, arguments, r.Name())
var ok bool
r.header, ok = arguments[0].(string)
if !ok {
panic(fmt.Sprintf("invalid argument for \"file-header\" rule: first argument should be a string, got %T", arguments[0]))
}
}
failure := []lint.Failure{
@ -50,7 +54,7 @@ func (r *FileHeaderRule) Apply(file *lint.File, arguments lint.Arguments) []lint
comment += text
}
regex, err := regexp.Compile(header)
regex, err := regexp.Compile(r.header)
if err != nil {
panic(err.Error())
}

View File

@ -9,18 +9,25 @@ import (
)
// FunctionLength lint.
type FunctionLength struct{}
type FunctionLength struct {
maxStmt int
maxLines int
}
// Apply applies the rule to given file.
func (r *FunctionLength) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure {
maxStmt, maxLines := r.parseArguments(arguments)
if r.maxLines == 0 {
maxStmt, maxLines := r.parseArguments(arguments)
r.maxStmt = int(maxStmt)
r.maxLines = int(maxLines)
}
var failures []lint.Failure
walker := lintFuncLength{
file: file,
maxStmt: int(maxStmt),
maxLines: int(maxLines),
maxStmt: r.maxStmt,
maxLines: r.maxLines,
onFailure: func(failure lint.Failure) {
failures = append(failures, failure)
},

View File

@ -8,24 +8,29 @@ import (
)
// FunctionResultsLimitRule lints given else constructs.
type FunctionResultsLimitRule struct{}
type FunctionResultsLimitRule struct {
max int
}
// Apply applies the rule to given file.
func (r *FunctionResultsLimitRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure {
checkNumberOfArguments(1, arguments, r.Name())
if r.max == 0 {
checkNumberOfArguments(1, arguments, r.Name())
max, ok := arguments[0].(int64) // Alt. non panicking version
if !ok {
panic(fmt.Sprintf(`invalid value passed as return results number to the "function-result-limit" rule; need int64 but got %T`, arguments[0]))
}
if max < 0 {
panic(`the value passed as return results number to the "function-result-limit" rule cannot be negative`)
max, ok := arguments[0].(int64) // Alt. non panicking version
if !ok {
panic(fmt.Sprintf(`invalid value passed as return results number to the "function-result-limit" rule; need int64 but got %T`, arguments[0]))
}
if max < 0 {
panic(`the value passed as return results number to the "function-result-limit" rule cannot be negative`)
}
r.max = int(max)
}
var failures []lint.Failure
walker := lintFunctionResultsNum{
max: int(max),
max: r.max,
onFailure: func(failure lint.Failure) {
failures = append(failures, failure)
},

View File

@ -7,7 +7,9 @@ import (
)
// ImportsBlacklistRule lints given else constructs.
type ImportsBlacklistRule struct{}
type ImportsBlacklistRule struct {
blacklist map[string]bool
}
// Apply applies the rule to given file.
func (r *ImportsBlacklistRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure {
@ -17,23 +19,25 @@ func (r *ImportsBlacklistRule) Apply(file *lint.File, arguments lint.Arguments)
return failures // skip, test file
}
blacklist := make(map[string]bool, len(arguments))
if r.blacklist == nil {
r.blacklist = make(map[string]bool, len(arguments))
for _, arg := range arguments {
argStr, ok := arg.(string)
if !ok {
panic(fmt.Sprintf("Invalid argument to the imports-blacklist rule. Expecting a string, got %T", arg))
for _, arg := range arguments {
argStr, ok := arg.(string)
if !ok {
panic(fmt.Sprintf("Invalid argument to the imports-blacklist rule. Expecting a string, got %T", arg))
}
// we add quotes if not present, because when parsed, the value of the AST node, will be quoted
if len(argStr) > 2 && argStr[0] != '"' && argStr[len(argStr)-1] != '"' {
argStr = fmt.Sprintf(`"%s"`, argStr)
}
r.blacklist[argStr] = true
}
// we add quotes if not present, because when parsed, the value of the AST node, will be quoted
if len(argStr) > 2 && argStr[0] != '"' && argStr[len(argStr)-1] != '"' {
argStr = fmt.Sprintf(`"%s"`, argStr)
}
blacklist[argStr] = true
}
for _, is := range file.AST.Imports {
path := is.Path
if path != nil && blacklist[path.Value] {
if path != nil && r.blacklist[path.Value] {
failures = append(failures, lint.Failure{
Confidence: 1,
Failure: "should not use the following blacklisted import: " + path.Value,

View File

@ -12,20 +12,26 @@ import (
)
// LineLengthLimitRule lints given else constructs.
type LineLengthLimitRule struct{}
type LineLengthLimitRule struct {
max int
}
// Apply applies the rule to given file.
func (r *LineLengthLimitRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure {
checkNumberOfArguments(1, arguments, r.Name())
if r.max == 0 {
checkNumberOfArguments(1, arguments, r.Name())
max, ok := arguments[0].(int64) // Alt. non panicking version
if !ok || max < 0 {
panic(`invalid value passed as argument number to the "line-length-limit" rule`)
max, ok := arguments[0].(int64) // Alt. non panicking version
if !ok || max < 0 {
panic(`invalid value passed as argument number to the "line-length-limit" rule`)
}
r.max = int(max)
}
var failures []lint.Failure
checker := lintLineLengthNum{
max: int(max),
max: r.max,
file: file,
onFailure: func(failure lint.Failure) {
failures = append(failures, failure)

View File

@ -9,15 +9,20 @@ import (
)
// MaxPublicStructsRule lints given else constructs.
type MaxPublicStructsRule struct{}
type MaxPublicStructsRule struct {
max int64
}
// Apply applies the rule to given file.
func (r *MaxPublicStructsRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure {
checkNumberOfArguments(1, arguments, r.Name())
if r.max < 1 {
checkNumberOfArguments(1, arguments, r.Name())
max, ok := arguments[0].(int64) // Alt. non panicking version
if !ok {
panic(`invalid value passed as argument number to the "max-public-structs" rule`)
max, ok := arguments[0].(int64) // Alt. non panicking version
if !ok {
panic(`invalid value passed as argument number to the "max-public-structs" rule`)
}
r.max = max
}
var failures []lint.Failure
@ -32,7 +37,7 @@ func (r *MaxPublicStructsRule) Apply(file *lint.File, arguments lint.Arguments)
ast.Walk(walker, fileAst)
if walker.current > max {
if walker.current > r.max {
walker.onFailure(lint.Failure{
Failure: "you have exceeded the maximum number of public struct declarations",
Confidence: 1,

View File

@ -9,27 +9,31 @@ import (
)
// UnhandledErrorRule lints given else constructs.
type UnhandledErrorRule struct{}
type UnhandledErrorRule struct {
ignoreList ignoreListType
}
type ignoreListType map[string]struct{}
// Apply applies the rule to given file.
func (r *UnhandledErrorRule) Apply(file *lint.File, args lint.Arguments) []lint.Failure {
var failures []lint.Failure
if r.ignoreList == nil {
r.ignoreList = make(ignoreListType, len(args))
ignoreList := make(ignoreListType, len(args))
for _, arg := range args {
argStr, ok := arg.(string)
if !ok {
panic(fmt.Sprintf("Invalid argument to the unhandled-error rule. Expecting a string, got %T", arg))
}
for _, arg := range args {
argStr, ok := arg.(string)
if !ok {
panic(fmt.Sprintf("Invalid argument to the unhandled-error rule. Expecting a string, got %T", arg))
r.ignoreList[argStr] = struct{}{}
}
ignoreList[argStr] = struct{}{}
}
var failures []lint.Failure
walker := &lintUnhandledErrors{
ignoreList: ignoreList,
ignoreList: r.ignoreList,
pkg: file.Pkg,
onFailure: func(failure lint.Failure) {
failures = append(failures, failure)

View File

@ -10,29 +10,33 @@ import (
)
// VarNamingRule lints given else constructs.
type VarNamingRule struct{}
type VarNamingRule struct {
configured bool
whitelist []string
blacklist []string
}
// Apply applies the rule to given file.
func (r *VarNamingRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure {
var failures []lint.Failure
var whitelist []string
var blacklist []string
if !r.configured {
if len(arguments) >= 1 {
r.whitelist = getList(arguments[0], "whitelist")
}
if len(arguments) >= 1 {
whitelist = getList(arguments[0], "whitelist")
}
if len(arguments) >= 2 {
blacklist = getList(arguments[1], "blacklist")
if len(arguments) >= 2 {
r.blacklist = getList(arguments[1], "blacklist")
}
r.configured = true
}
fileAst := file.AST
walker := lintNames{
file: file,
fileAst: fileAst,
whitelist: whitelist,
blacklist: blacklist,
whitelist: r.whitelist,
blacklist: r.blacklist,
onFailure: func(failure lint.Failure) {
failures = append(failures, failure)
},