Skip to content

Commit

Permalink
Fix/677 (mgechev#678)
Browse files Browse the repository at this point in the history
Signed-off-by: subham sarkar <subham@deepsource.io>
  • Loading branch information
chavacava authored and subham-deepsource committed Aug 5, 2022
1 parent 7bc976f commit 7b8e012
Show file tree
Hide file tree
Showing 23 changed files with 274 additions and 118 deletions.
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 @@ -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
}
Expand Down
1 change: 0 additions & 1 deletion lint/linter.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
53 changes: 39 additions & 14 deletions lint/package.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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 {
Expand All @@ -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{
Expand All @@ -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
}

Expand All @@ -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 {
Expand All @@ -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 (
Expand All @@ -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
}
}
}
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/deepsourcelabs/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/deepsourcelabs/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/deepsourcelabs/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/deepsourcelabs/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

0 comments on commit 7b8e012

Please sign in to comment.