Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix/677 #678

Merged
merged 7 commits into from
Apr 10, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,5 @@ build:
@go build -ldflags='$(VERSION_FLAGS)'

test:
@go test -v ./...
@go test -v -race ./...

2 changes: 1 addition & 1 deletion lint/file.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down
1 change: 0 additions & 1 deletion lint/linter.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
53 changes: 39 additions & 14 deletions lint/package.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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 {
Expand All @@ -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{
Expand All @@ -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
}

Expand All @@ -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 {
Expand All @@ -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 (
Expand All @@ -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
}
}
}
Expand Down
95 changes: 52 additions & 43 deletions rule/add-constant.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"go/ast"
"strconv"
"strings"
"sync"

"github.com/mgechev/revive/lint"
)
Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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
}
}
}
}
}
21 changes: 15 additions & 6 deletions rule/argument-limit.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,19 @@ package rule
import (
"fmt"
"go/ast"
"sync"

"github.com/mgechev/revive/lint"
)

// 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())

Expand All @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion rule/atomic.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
},
Expand Down
13 changes: 11 additions & 2 deletions rule/banned-characters.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,31 @@ import (
"fmt"
"go/ast"
"strings"
"sync"

"github.com/mgechev/revive/lint"
)

// 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) {
Expand All @@ -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
}
Expand Down
13 changes: 11 additions & 2 deletions rule/cognitive-complexity.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"fmt"
"go/ast"
"go/token"
"sync"

"github.com/mgechev/revive/lint"
"golang.org/x/tools/go/ast/astutil"
Expand All @@ -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())

Expand All @@ -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,
Expand Down