diff --git a/Makefile b/Makefile index f85c21200..08d6c4d68 100644 --- a/Makefile +++ b/Makefile @@ -15,5 +15,5 @@ build: @go build -ldflags='$(VERSION_FLAGS)' test: - @go test -v ./... + @go test -v -race ./... diff --git a/lint/file.go b/lint/file.go index 6505760f5..af4bc16ae 100644 --- a/lint/file.go +++ b/lint/file.go @@ -78,7 +78,7 @@ func (f *File) IsUntypedConst(expr ast.Expr) (defType string, ok bool) { // Re-evaluate expr outside its context to see if it's untyped. // (An expr evaluated within, for example, an assignment context will get the type of the LHS.) exprStr := f.Render(expr) - tv, err := types.Eval(f.Pkg.fset, f.Pkg.TypesPkg, expr.Pos(), exprStr) + tv, err := types.Eval(f.Pkg.fset, f.Pkg.TypesPkg(), expr.Pos(), exprStr) if err != nil { return "", false } diff --git a/lint/linter.go b/lint/linter.go index 940c858b0..a88425bef 100644 --- a/lint/linter.go +++ b/lint/linter.go @@ -85,7 +85,6 @@ func (l *Linter) lintPackage(filenames []string, ruleSet []Rule, config Config, pkg := &Package{ fset: token.NewFileSet(), files: map[string]*File{}, - mu: sync.Mutex{}, } for _, filename := range filenames { content, err := l.readFile(filename) diff --git a/lint/package.go b/lint/package.go index fd858c56a..eb5c112f8 100644 --- a/lint/package.go +++ b/lint/package.go @@ -16,14 +16,14 @@ type Package struct { fset *token.FileSet files map[string]*File - TypesPkg *types.Package - TypesInfo *types.Info + typesPkg *types.Package + typesInfo *types.Info // sortable is the set of types in the package that implement sort.Interface. - Sortable map[string]bool + sortable map[string]bool // main is whether this is a "main" package. main int - mu sync.Mutex + sync.RWMutex } var newImporter = func(fset *token.FileSet) types.ImporterFrom { @@ -38,6 +38,9 @@ var ( // IsMain returns if that's the main package. func (p *Package) IsMain() bool { + p.Lock() + defer p.Unlock() + if p.main == trueValue { return true } else if p.main == falseValue { @@ -53,13 +56,35 @@ func (p *Package) IsMain() bool { return false } +// TypesPkg yields information on this package +func (p *Package) TypesPkg() *types.Package { + p.RLock() + defer p.RUnlock() + return p.typesPkg +} + +// TypesInfo yields type information of this package identifiers +func (p *Package) TypesInfo() *types.Info { + p.RLock() + defer p.RUnlock() + return p.typesInfo +} + +// Sortable yields a map of sortable types in this package +func (p *Package) Sortable() map[string]bool { + p.RLock() + defer p.RUnlock() + return p.sortable +} + // TypeCheck performs type checking for given package. func (p *Package) TypeCheck() error { - p.mu.Lock() + p.Lock() + defer p.Unlock() + // If type checking has already been performed // skip it. - if p.TypesInfo != nil || p.TypesPkg != nil { - p.mu.Unlock() + if p.typesInfo != nil || p.typesPkg != nil { return nil } config := &types.Config{ @@ -84,9 +109,9 @@ func (p *Package) TypeCheck() error { // Remember the typechecking info, even if config.Check failed, // since we will get partial information. - p.TypesPkg = typesPkg - p.TypesInfo = info - p.mu.Unlock() + p.typesPkg = typesPkg + p.typesInfo = info + return err } @@ -106,10 +131,10 @@ func check(config *types.Config, n string, fset *token.FileSet, astFiles []*ast. // TypeOf returns the type of an expression. func (p *Package) TypeOf(expr ast.Expr) types.Type { - if p.TypesInfo == nil { + if p.typesInfo == nil { return nil } - return p.TypesInfo.TypeOf(expr) + return p.typesInfo.TypeOf(expr) } type walker struct { @@ -131,7 +156,7 @@ func (w *walker) Visit(n ast.Node) ast.Visitor { } func (p *Package) scanSortable() { - p.Sortable = make(map[string]bool) + p.sortable = make(map[string]bool) // bitfield for which methods exist on each type. const ( @@ -146,7 +171,7 @@ func (p *Package) scanSortable() { } for typ, ms := range has { if ms == Len|Less|Swap { - p.Sortable[typ] = true + p.sortable[typ] = true } } } diff --git a/rule/add-constant.go b/rule/add-constant.go index f3f5f5662..f37dcc95e 100644 --- a/rule/add-constant.go +++ b/rule/add-constant.go @@ -5,6 +5,7 @@ import ( "go/ast" "strconv" "strings" + "sync" "github.com/deepsourcelabs/revive/lint" ) @@ -33,53 +34,12 @@ func (wl whiteList) add(kind, list string) { type AddConstantRule struct { whiteList whiteList strLitLimit int + sync.Mutex } // Apply applies the rule to given file. func (r *AddConstantRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure { - 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)) - } - r.strLitLimit = limit - } - } - } - } + r.configure(arguments) var failures []lint.Failure @@ -154,3 +114,52 @@ func (w lintAddConstantRule) checkNumLit(kind string, n *ast.BasicLit) { Failure: fmt.Sprintf("avoid magic numbers like '%s', create a named constant for it", n.Value), }) } + +func (r *AddConstantRule) configure(arguments lint.Arguments) { + r.Lock() + defer r.Unlock() + + 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)) + } + r.strLitLimit = limit + } + } + } + } +} diff --git a/rule/argument-limit.go b/rule/argument-limit.go index e3048111e..9a84ff5b8 100644 --- a/rule/argument-limit.go +++ b/rule/argument-limit.go @@ -3,6 +3,7 @@ package rule import ( "fmt" "go/ast" + "sync" "github.com/deepsourcelabs/revive/lint" ) @@ -10,10 +11,11 @@ import ( // ArgumentsLimitRule lints given else constructs. type ArgumentsLimitRule struct { total int + sync.Mutex } -// Apply applies the rule to given file. -func (r *ArgumentsLimitRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure { +func (r *ArgumentsLimitRule) configure(arguments lint.Arguments) { + r.Lock() if r.total == 0 { checkNumberOfArguments(1, arguments, r.Name()) @@ -23,14 +25,21 @@ func (r *ArgumentsLimitRule) Apply(file *lint.File, arguments lint.Arguments) [] } r.total = int(total) } + r.Unlock() +} + +// Apply applies the rule to given file. +func (r *ArgumentsLimitRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure { + r.configure(arguments) var failures []lint.Failure + onFailure := func(failure lint.Failure) { + failures = append(failures, failure) + } walker := lintArgsNum{ - total: r.total, - onFailure: func(failure lint.Failure) { - failures = append(failures, failure) - }, + total: r.total, + onFailure: onFailure, } ast.Walk(walker, file.AST) diff --git a/rule/atomic.go b/rule/atomic.go index 7c6be3a47..c646cd6e2 100644 --- a/rule/atomic.go +++ b/rule/atomic.go @@ -15,7 +15,7 @@ type AtomicRule struct{} func (r *AtomicRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure { var failures []lint.Failure walker := atomic{ - pkgTypesInfo: file.Pkg.TypesInfo, + pkgTypesInfo: file.Pkg.TypesInfo(), onFailure: func(failure lint.Failure) { failures = append(failures, failure) }, diff --git a/rule/banned-characters.go b/rule/banned-characters.go index 42238e528..b6ff956eb 100644 --- a/rule/banned-characters.go +++ b/rule/banned-characters.go @@ -4,6 +4,7 @@ import ( "fmt" "go/ast" "strings" + "sync" "github.com/deepsourcelabs/revive/lint" ) @@ -11,16 +12,23 @@ import ( // BannedCharsRule checks if a file contains banned characters. type BannedCharsRule struct { bannedCharList []string + sync.Mutex } const bannedCharsRuleName = "banned-characters" -// Apply applied the rule to the given file. -func (r *BannedCharsRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure { +func (r *BannedCharsRule) configure(arguments lint.Arguments) { + r.Lock() if r.bannedCharList == nil { checkNumberOfArguments(1, arguments, bannedCharsRuleName) r.bannedCharList = r.getBannedCharsList(arguments) } + r.Unlock() +} + +// Apply applied the rule to the given file. +func (r *BannedCharsRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure { + r.configure(arguments) var failures []lint.Failure onFailure := func(failure lint.Failure) { @@ -31,6 +39,7 @@ func (r *BannedCharsRule) Apply(file *lint.File, arguments lint.Arguments) []lin bannedChars: r.bannedCharList, onFailure: onFailure, } + ast.Walk(w, file.AST) return failures } diff --git a/rule/cognitive-complexity.go b/rule/cognitive-complexity.go index 9ea5c11ed..b7cdd71f9 100644 --- a/rule/cognitive-complexity.go +++ b/rule/cognitive-complexity.go @@ -4,6 +4,7 @@ import ( "fmt" "go/ast" "go/token" + "sync" "github.com/deepsourcelabs/revive/lint" "golang.org/x/tools/go/ast/astutil" @@ -12,10 +13,11 @@ import ( // CognitiveComplexityRule lints given else constructs. type CognitiveComplexityRule struct { maxComplexity int + sync.Mutex } -// Apply applies the rule to given file. -func (r *CognitiveComplexityRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure { +func (r *CognitiveComplexityRule) configure(arguments lint.Arguments) { + r.Lock() if r.maxComplexity == 0 { checkNumberOfArguments(1, arguments, r.Name()) @@ -25,8 +27,15 @@ func (r *CognitiveComplexityRule) Apply(file *lint.File, arguments lint.Argument } r.maxComplexity = int(complexity) } + r.Unlock() +} + +// Apply applies the rule to given file. +func (r *CognitiveComplexityRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure { + r.configure(arguments) var failures []lint.Failure + linter := cognitiveComplexityLinter{ file: file, maxComplexity: r.maxComplexity, diff --git a/rule/context-as-argument.go b/rule/context-as-argument.go index f062b095b..1798ee349 100644 --- a/rule/context-as-argument.go +++ b/rule/context-as-argument.go @@ -4,6 +4,7 @@ import ( "fmt" "go/ast" "strings" + "sync" "github.com/deepsourcelabs/revive/lint" ) @@ -11,21 +12,27 @@ import ( // ContextAsArgumentRule lints given else constructs. type ContextAsArgumentRule struct { allowTypesLUT map[string]struct{} + sync.Mutex } // Apply applies the rule to given file. func (r *ContextAsArgumentRule) Apply(file *lint.File, args lint.Arguments) []lint.Failure { + + r.Lock() if r.allowTypesLUT == nil { r.allowTypesLUT = getAllowTypesFromArguments(args) } + r.Unlock() var failures []lint.Failure + r.Lock() walker := lintContextArguments{ allowTypesLUT: r.allowTypesLUT, onFailure: func(failure lint.Failure) { failures = append(failures, failure) }, } + r.Unlock() ast.Walk(walker, file.AST) diff --git a/rule/context-keys-type.go b/rule/context-keys-type.go index 9c933db7e..7ff58fc34 100644 --- a/rule/context-keys-type.go +++ b/rule/context-keys-type.go @@ -68,7 +68,7 @@ func checkContextKeyType(w lintContextKeyTypes, x *ast.CallExpr) { if len(x.Args) != 3 { return } - key := f.Pkg.TypesInfo.Types[x.Args[1]] + key := f.Pkg.TypesInfo().Types[x.Args[1]] if ktyp, ok := key.Type.(*types.Basic); ok && ktyp.Kind() != types.Invalid { w.onFailure(lint.Failure{ diff --git a/rule/cyclomatic.go b/rule/cyclomatic.go index 23928a37b..904f82ac7 100644 --- a/rule/cyclomatic.go +++ b/rule/cyclomatic.go @@ -4,6 +4,7 @@ import ( "fmt" "go/ast" "go/token" + "sync" "github.com/deepsourcelabs/revive/lint" ) @@ -13,10 +14,11 @@ import ( // CyclomaticRule lints given else constructs. type CyclomaticRule struct { maxComplexity int + sync.Mutex } -// Apply applies the rule to given file. -func (r *CyclomaticRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure { +func (r *CyclomaticRule) configure(arguments lint.Arguments) { + r.Lock() if r.maxComplexity == 0 { checkNumberOfArguments(1, arguments, r.Name()) @@ -26,9 +28,16 @@ func (r *CyclomaticRule) Apply(file *lint.File, arguments lint.Arguments) []lint } r.maxComplexity = int(complexity) } + r.Unlock() +} + +// Apply applies the rule to given file. +func (r *CyclomaticRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure { + r.configure(arguments) var failures []lint.Failure fileAst := file.AST + walker := lintCyclomatic{ file: file, complexity: r.maxComplexity, diff --git a/rule/defer.go b/rule/defer.go index f6d47f5f7..68fb51060 100644 --- a/rule/defer.go +++ b/rule/defer.go @@ -3,6 +3,7 @@ package rule import ( "fmt" "go/ast" + "sync" "github.com/deepsourcelabs/revive/lint" ) @@ -10,18 +11,25 @@ import ( // DeferRule lints unused params in functions. type DeferRule struct { allow map[string]bool + sync.Mutex } -// Apply applies the rule to given file. -func (r *DeferRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure { +func (r *DeferRule) configure(arguments lint.Arguments) { + r.Lock() if r.allow == nil { r.allow = r.allowFromArgs(arguments) } + r.Unlock() +} + +// Apply applies the rule to given file. +func (r *DeferRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure { + r.configure(arguments) + var failures []lint.Failure onFailure := func(failure lint.Failure) { failures = append(failures, failure) } - w := lintDeferRule{onFailure: onFailure, allow: r.allow} ast.Walk(w, file.AST) diff --git a/rule/exported.go b/rule/exported.go index 11c4b0316..907bc5ffe 100644 --- a/rule/exported.go +++ b/rule/exported.go @@ -5,6 +5,7 @@ import ( "go/ast" "go/token" "strings" + "sync" "unicode" "unicode/utf8" @@ -17,19 +18,14 @@ type ExportedRule struct { checkPrivateReceivers bool disableStutteringCheck bool stuttersMsg string + sync.Mutex } -// Apply applies the rule to given file. -func (r *ExportedRule) Apply(file *lint.File, args lint.Arguments) []lint.Failure { - var failures []lint.Failure - - if file.IsTest() { - return failures - } - +func (r *ExportedRule) configure(arguments lint.Arguments) { + r.Lock() if !r.configured { var sayRepetitiveInsteadOfStutters bool - r.checkPrivateReceivers, r.disableStutteringCheck, sayRepetitiveInsteadOfStutters = r.getConf(args) + r.checkPrivateReceivers, r.disableStutteringCheck, sayRepetitiveInsteadOfStutters = r.getConf(arguments) r.stuttersMsg = "stutters" if sayRepetitiveInsteadOfStutters { r.stuttersMsg = "is repetitive" @@ -37,8 +33,20 @@ func (r *ExportedRule) Apply(file *lint.File, args lint.Arguments) []lint.Failur r.configured = true } + r.Unlock() +} + +// Apply applies the rule to given file. +func (r *ExportedRule) Apply(file *lint.File, args lint.Arguments) []lint.Failure { + r.configure(args) + + var failures []lint.Failure + if file.IsTest() { + return failures + } fileAst := file.AST + walker := lintExported{ file: file, fileAst: fileAst, @@ -118,7 +126,8 @@ func (w *lintExported) lintFuncDoc(fn *ast.FuncDecl) { } switch name { case "Len", "Less", "Swap": - if w.file.Pkg.Sortable[recv] { + sortables := w.file.Pkg.Sortable() + if sortables[recv] { return } } diff --git a/rule/file-header.go b/rule/file-header.go index cc21794fc..4c23aa44f 100644 --- a/rule/file-header.go +++ b/rule/file-header.go @@ -3,6 +3,7 @@ package rule import ( "fmt" "regexp" + "sync" "github.com/deepsourcelabs/revive/lint" ) @@ -10,6 +11,7 @@ import ( // FileHeaderRule lints given else constructs. type FileHeaderRule struct { header string + sync.Mutex } var ( @@ -17,8 +19,8 @@ var ( singleRegexp = regexp.MustCompile("^//") ) -// Apply applies the rule to given file. -func (r *FileHeaderRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure { +func (r *FileHeaderRule) configure(arguments lint.Arguments) { + r.Lock() if r.header == "" { checkNumberOfArguments(1, arguments, r.Name()) var ok bool @@ -27,6 +29,12 @@ func (r *FileHeaderRule) Apply(file *lint.File, arguments lint.Arguments) []lint panic(fmt.Sprintf("invalid argument for \"file-header\" rule: first argument should be a string, got %T", arguments[0])) } } + r.Unlock() +} + +// Apply applies the rule to given file. +func (r *FileHeaderRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure { + r.configure(arguments) failure := []lint.Failure{ { diff --git a/rule/function-length.go b/rule/function-length.go index c8b0e1747..2906c4ebf 100644 --- a/rule/function-length.go +++ b/rule/function-length.go @@ -4,6 +4,7 @@ import ( "fmt" "go/ast" "reflect" + "sync" "github.com/deepsourcelabs/revive/lint" ) @@ -12,15 +13,22 @@ import ( type FunctionLength struct { maxStmt int maxLines int + sync.Mutex } -// Apply applies the rule to given file. -func (r *FunctionLength) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure { +func (r *FunctionLength) configure(arguments lint.Arguments) { + r.Lock() if r.maxLines == 0 { maxStmt, maxLines := r.parseArguments(arguments) r.maxStmt = int(maxStmt) r.maxLines = int(maxLines) } + r.Unlock() +} + +// Apply applies the rule to given file. +func (r *FunctionLength) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure { + r.configure(arguments) var failures []lint.Failure diff --git a/rule/function-result-limit.go b/rule/function-result-limit.go index 4aeb5c0f4..db09eaa53 100644 --- a/rule/function-result-limit.go +++ b/rule/function-result-limit.go @@ -3,6 +3,7 @@ package rule import ( "fmt" "go/ast" + "sync" "github.com/deepsourcelabs/revive/lint" ) @@ -10,10 +11,11 @@ import ( // FunctionResultsLimitRule lints given else constructs. type FunctionResultsLimitRule struct { max int + sync.Mutex } -// Apply applies the rule to given file. -func (r *FunctionResultsLimitRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure { +func (r *FunctionResultsLimitRule) configure(arguments lint.Arguments) { + r.Lock() if r.max == 0 { checkNumberOfArguments(1, arguments, r.Name()) @@ -26,6 +28,12 @@ func (r *FunctionResultsLimitRule) Apply(file *lint.File, arguments lint.Argumen } r.max = int(max) } + r.Unlock() +} + +// Apply applies the rule to given file. +func (r *FunctionResultsLimitRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure { + r.configure(arguments) var failures []lint.Failure diff --git a/rule/imports-blacklist.go b/rule/imports-blacklist.go index 888df899d..5081db3e2 100644 --- a/rule/imports-blacklist.go +++ b/rule/imports-blacklist.go @@ -2,6 +2,7 @@ package rule import ( "fmt" + "sync" "github.com/deepsourcelabs/revive/lint" ) @@ -9,16 +10,11 @@ import ( // ImportsBlacklistRule lints given else constructs. type ImportsBlacklistRule struct { blacklist map[string]bool + sync.Mutex } -// Apply applies the rule to given file. -func (r *ImportsBlacklistRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure { - var failures []lint.Failure - - if file.IsTest() { - return failures // skip, test file - } - +func (r *ImportsBlacklistRule) configure(arguments lint.Arguments) { + r.Lock() if r.blacklist == nil { r.blacklist = make(map[string]bool, len(arguments)) @@ -34,6 +30,18 @@ func (r *ImportsBlacklistRule) Apply(file *lint.File, arguments lint.Arguments) r.blacklist[argStr] = true } } + r.Unlock() +} + +// Apply applies the rule to given file. +func (r *ImportsBlacklistRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure { + r.configure(arguments) + + var failures []lint.Failure + + if file.IsTest() { + return failures // skip, test file + } for _, is := range file.AST.Imports { path := is.Path diff --git a/rule/line-length-limit.go b/rule/line-length-limit.go index 0cab76daa..4c9259c86 100644 --- a/rule/line-length-limit.go +++ b/rule/line-length-limit.go @@ -6,6 +6,7 @@ import ( "fmt" "go/token" "strings" + "sync" "unicode/utf8" "github.com/deepsourcelabs/revive/lint" @@ -14,10 +15,11 @@ import ( // LineLengthLimitRule lints given else constructs. type LineLengthLimitRule struct { max int + sync.Mutex } -// Apply applies the rule to given file. -func (r *LineLengthLimitRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure { +func (r *LineLengthLimitRule) configure(arguments lint.Arguments) { + r.Lock() if r.max == 0 { checkNumberOfArguments(1, arguments, r.Name()) @@ -28,8 +30,15 @@ func (r *LineLengthLimitRule) Apply(file *lint.File, arguments lint.Arguments) [ r.max = int(max) } + r.Unlock() +} + +// Apply applies the rule to given file. +func (r *LineLengthLimitRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure { + r.configure(arguments) var failures []lint.Failure + checker := lintLineLengthNum{ max: r.max, file: file, diff --git a/rule/max-public-structs.go b/rule/max-public-structs.go index 4db32ab07..a2f2b86bb 100644 --- a/rule/max-public-structs.go +++ b/rule/max-public-structs.go @@ -3,6 +3,7 @@ package rule import ( "go/ast" "strings" + "sync" "github.com/deepsourcelabs/revive/lint" ) @@ -10,10 +11,11 @@ import ( // MaxPublicStructsRule lints given else constructs. type MaxPublicStructsRule struct { max int64 + sync.Mutex } -// Apply applies the rule to given file. -func (r *MaxPublicStructsRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure { +func (r *MaxPublicStructsRule) configure(arguments lint.Arguments) { + r.Lock() if r.max < 1 { checkNumberOfArguments(1, arguments, r.Name()) @@ -23,10 +25,17 @@ func (r *MaxPublicStructsRule) Apply(file *lint.File, arguments lint.Arguments) } r.max = max } + r.Unlock() +} + +// Apply applies the rule to given file. +func (r *MaxPublicStructsRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure { + r.configure(arguments) var failures []lint.Failure fileAst := file.AST + walker := &lintMaxPublicStructs{ fileAst: fileAst, onFailure: func(failure lint.Failure) { diff --git a/rule/nested-structs.go b/rule/nested-structs.go index a9403bacc..d087ffa4e 100644 --- a/rule/nested-structs.go +++ b/rule/nested-structs.go @@ -10,13 +10,9 @@ import ( type NestedStructs struct{} // Apply applies the rule to given file. -func (r *NestedStructs) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure { +func (r *NestedStructs) Apply(file *lint.File, _ lint.Arguments) []lint.Failure { var failures []lint.Failure - if len(arguments) > 0 { - panic(r.Name() + " doesn't take any arguments") - } - walker := &lintNestedStructs{ fileAST: file.AST, onFailure: func(failure lint.Failure) { diff --git a/rule/unhandled-error.go b/rule/unhandled-error.go index 62eb9e9d1..7d849a54e 100644 --- a/rule/unhandled-error.go +++ b/rule/unhandled-error.go @@ -4,6 +4,7 @@ import ( "fmt" "go/ast" "go/types" + "sync" "github.com/deepsourcelabs/revive/lint" ) @@ -11,16 +12,17 @@ import ( // UnhandledErrorRule lints given else constructs. type UnhandledErrorRule struct { ignoreList ignoreListType + sync.Mutex } type ignoreListType map[string]struct{} -// Apply applies the rule to given file. -func (r *UnhandledErrorRule) Apply(file *lint.File, args lint.Arguments) []lint.Failure { +func (r *UnhandledErrorRule) configure(arguments lint.Arguments) { + r.Lock() if r.ignoreList == nil { - r.ignoreList = make(ignoreListType, len(args)) + r.ignoreList = make(ignoreListType, len(arguments)) - for _, arg := range args { + for _, arg := range arguments { argStr, ok := arg.(string) if !ok { panic(fmt.Sprintf("Invalid argument to the unhandled-error rule. Expecting a string, got %T", arg)) @@ -29,6 +31,12 @@ func (r *UnhandledErrorRule) Apply(file *lint.File, args lint.Arguments) []lint. r.ignoreList[argStr] = struct{}{} } } + r.Unlock() +} + +// Apply applies the rule to given file. +func (r *UnhandledErrorRule) Apply(file *lint.File, args lint.Arguments) []lint.Failure { + r.configure(args) var failures []lint.Failure diff --git a/rule/var-naming.go b/rule/var-naming.go index 5ecab37c2..6e10ce624 100644 --- a/rule/var-naming.go +++ b/rule/var-naming.go @@ -5,6 +5,7 @@ import ( "go/ast" "go/token" "strings" + "sync" "github.com/deepsourcelabs/revive/lint" ) @@ -14,12 +15,11 @@ type VarNamingRule struct { configured bool whitelist []string blacklist []string + sync.Mutex } -// Apply applies the rule to given file. -func (r *VarNamingRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure { - var failures []lint.Failure - +func (r *VarNamingRule) configure(arguments lint.Arguments) { + r.Lock() if !r.configured { if len(arguments) >= 1 { r.whitelist = getList(arguments[0], "whitelist") @@ -30,8 +30,17 @@ func (r *VarNamingRule) Apply(file *lint.File, arguments lint.Arguments) []lint. } r.configured = true } + r.Unlock() +} + +// Apply applies the rule to given file. +func (r *VarNamingRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure { + r.configure(arguments) + + var failures []lint.Failure fileAst := file.AST + walker := lintNames{ file: file, fileAst: fileAst,