mirror of
				https://github.com/mgechev/revive.git
				synced 2025-10-30 23:37:49 +02:00 
			
		
		
		
	Fix/677 (#678)
This commit is contained in:
		
							
								
								
									
										2
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								Makefile
									
									
									
									
									
								
							| @@ -15,5 +15,5 @@ build: | ||||
| 	@go build -ldflags='$(VERSION_FLAGS)' | ||||
|  | ||||
| test: | ||||
| 	@go test -v ./... | ||||
| 	@go test -v -race ./... | ||||
|  | ||||
|   | ||||
| @@ -77,7 +77,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 | ||||
| 	} | ||||
|   | ||||
| @@ -81,7 +81,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) | ||||
|   | ||||
| @@ -14,14 +14,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 { | ||||
| @@ -36,6 +36,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 { | ||||
| @@ -51,13 +54,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{ | ||||
| @@ -82,9 +107,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 | ||||
| } | ||||
|  | ||||
| @@ -104,10 +129,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 { | ||||
| @@ -129,7 +154,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 ( | ||||
| @@ -144,7 +169,7 @@ func (p *Package) scanSortable() { | ||||
| 	} | ||||
| 	for typ, ms := range has { | ||||
| 		if ms == Len|Less|Swap { | ||||
| 			p.Sortable[typ] = true | ||||
| 			p.sortable[typ] = true | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -5,6 +5,7 @@ import ( | ||||
| 	"go/ast" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
| 	"sync" | ||||
|  | ||||
| 	"github.com/mgechev/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 | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -3,6 +3,7 @@ package rule | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"go/ast" | ||||
| 	"sync" | ||||
|  | ||||
| 	"github.com/mgechev/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) | ||||
|   | ||||
| @@ -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) | ||||
| 		}, | ||||
|   | ||||
| @@ -4,6 +4,7 @@ import ( | ||||
| 	"fmt" | ||||
| 	"go/ast" | ||||
| 	"strings" | ||||
| 	"sync" | ||||
|  | ||||
| 	"github.com/mgechev/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 | ||||
| } | ||||
|   | ||||
| @@ -4,6 +4,7 @@ import ( | ||||
| 	"fmt" | ||||
| 	"go/ast" | ||||
| 	"go/token" | ||||
| 	"sync" | ||||
|  | ||||
| 	"github.com/mgechev/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, | ||||
|   | ||||
| @@ -4,6 +4,7 @@ import ( | ||||
| 	"fmt" | ||||
| 	"go/ast" | ||||
| 	"strings" | ||||
| 	"sync" | ||||
|  | ||||
| 	"github.com/mgechev/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) | ||||
|  | ||||
|   | ||||
| @@ -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{ | ||||
|   | ||||
| @@ -4,6 +4,7 @@ import ( | ||||
| 	"fmt" | ||||
| 	"go/ast" | ||||
| 	"go/token" | ||||
| 	"sync" | ||||
|  | ||||
| 	"github.com/mgechev/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, | ||||
|   | ||||
| @@ -3,6 +3,7 @@ package rule | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"go/ast" | ||||
| 	"sync" | ||||
|  | ||||
| 	"github.com/mgechev/revive/lint" | ||||
| ) | ||||
| @@ -10,18 +11,25 @@ import ( | ||||
| // DeferRule lints unused params in functions. | ||||
| type DeferRule struct { | ||||
| 	allow map[string]bool | ||||
| 	sync.Mutex | ||||
| } | ||||
|  | ||||
| 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 { | ||||
| 	if r.allow == nil { | ||||
| 		r.allow = r.allowFromArgs(arguments) | ||||
| 	} | ||||
| 	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) | ||||
|   | ||||
| @@ -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 | ||||
| 			} | ||||
| 		} | ||||
|   | ||||
| @@ -3,6 +3,7 @@ package rule | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"regexp" | ||||
| 	"sync" | ||||
|  | ||||
| 	"github.com/mgechev/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{ | ||||
| 		{ | ||||
|   | ||||
| @@ -4,6 +4,7 @@ import ( | ||||
| 	"fmt" | ||||
| 	"go/ast" | ||||
| 	"reflect" | ||||
| 	"sync" | ||||
|  | ||||
| 	"github.com/mgechev/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 | ||||
|  | ||||
|   | ||||
| @@ -3,6 +3,7 @@ package rule | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"go/ast" | ||||
| 	"sync" | ||||
|  | ||||
| 	"github.com/mgechev/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 | ||||
|  | ||||
|   | ||||
| @@ -2,6 +2,7 @@ package rule | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"sync" | ||||
|  | ||||
| 	"github.com/mgechev/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 | ||||
|   | ||||
| @@ -6,6 +6,7 @@ import ( | ||||
| 	"fmt" | ||||
| 	"go/token" | ||||
| 	"strings" | ||||
| 	"sync" | ||||
| 	"unicode/utf8" | ||||
|  | ||||
| 	"github.com/mgechev/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, | ||||
|   | ||||
| @@ -3,6 +3,7 @@ package rule | ||||
| import ( | ||||
| 	"go/ast" | ||||
| 	"strings" | ||||
| 	"sync" | ||||
|  | ||||
| 	"github.com/mgechev/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) { | ||||
|   | ||||
| @@ -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) { | ||||
|   | ||||
| @@ -4,6 +4,7 @@ import ( | ||||
| 	"fmt" | ||||
| 	"go/ast" | ||||
| 	"go/types" | ||||
| 	"sync" | ||||
|  | ||||
| 	"github.com/mgechev/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 | ||||
|  | ||||
|   | ||||
| @@ -5,6 +5,7 @@ import ( | ||||
| 	"go/ast" | ||||
| 	"go/token" | ||||
| 	"strings" | ||||
| 	"sync" | ||||
|  | ||||
| 	"github.com/mgechev/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, | ||||
|   | ||||
		Reference in New Issue
	
	Block a user