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

adds rule use-any #660

Merged
merged 1 commit into from Mar 29, 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
1 change: 1 addition & 0 deletions README.md
Expand Up @@ -481,6 +481,7 @@ List of all available rules. The rules ported from `golint` are left unchanged a
| [`useless-break`](./RULES_DESCRIPTIONS.md#useless-break) | n/a | Warns on useless `break` statements in case clauses | no | no |
| [`banned-characters`](./RULES_DESCRIPTIONS.md#banned-characters) | n/a | Checks banned characters in identifiers | no | no |
| [`optimize-operands-order`](./RULES_DESCRIPTIONS.md#optimize-operands-order) | n/a | Checks inefficient conditional expressions | no | no |
| [`use-any`](./RULES_DESCRIPTIONS.md#use-any) | n/a | Proposes to replace `interface{}` with its alias `any` | no | no |

## Configurable rules

Expand Down
7 changes: 7 additions & 0 deletions RULES_DESCRIPTIONS.md
Expand Up @@ -70,6 +70,7 @@ List of all available rules.
- [unreachable-code](#unreachable-code)
- [unused-parameter](#unused-parameter)
- [unused-receiver](#unused-receiver)
- [use-any](#use-any)
- [useless-break](#useless-break)
- [waitgroup-by-value](#waitgroup-by-value)

Expand Down Expand Up @@ -670,6 +671,12 @@ _Description_: This rule warns on unused method receivers. Methods with unused r

_Configuration_: N/A

## use-any

_Description_: Since GO 1.18, `interface{}` has an alias: `any`. This rule proposes to replace instances of `interface{}` with `any`.

_Configuration_: N/A

## useless-break

_Description_: This rule warns on useless `break` statements in case clauses of switch and select statements. GO, unlike other programming languages like C, only executes statements of the selected case while ignoring the subsequent case clauses.
Expand Down
1 change: 1 addition & 0 deletions config/config.go
Expand Up @@ -84,6 +84,7 @@ var allRules = append([]lint.Rule{
&rule.TimeEqualRule{},
&rule.BannedCharsRule{},
&rule.OptimizeOperandsOrderRule{},
&rule.UseAnyRule{},
}, defaultRules...)

var allFormatters = []lint.Formatter{
Expand Down
54 changes: 54 additions & 0 deletions rule/use-any.go
@@ -0,0 +1,54 @@
package rule

import (
"go/ast"

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

// UseAnyRule lints given else constructs.
type UseAnyRule struct{}

// Apply applies the rule to given file.
func (r *UseAnyRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
var failures []lint.Failure

walker := lintUseAny{
onFailure: func(failure lint.Failure) {
failures = append(failures, failure)
},
}
fileAst := file.AST
ast.Walk(walker, fileAst)

return failures
}

// Name returns the rule name.
func (r *UseAnyRule) Name() string {
return "use-any"
}

type lintUseAny struct {
onFailure func(lint.Failure)
}

func (w lintUseAny) Visit(n ast.Node) ast.Visitor {
it, ok := n.(*ast.InterfaceType)
if !ok {
return w
}

if len(it.Methods.List) != 0 {
return w // it is not and empty interface
}

w.onFailure(lint.Failure{
Node: n,
Confidence: 1,
Category: "naming",
Failure: "since GO 1.18 'interface{}' can be replaced by 'any'",
})

return w
}
11 changes: 11 additions & 0 deletions test/use-any_test.go
@@ -0,0 +1,11 @@
package test

import (
"testing"

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

func TestUseAny(t *testing.T) {
testRule(t, "use-any", &rule.UseAnyRule{})
}
31 changes: 31 additions & 0 deletions testdata/use-any.go
@@ -0,0 +1,31 @@
package pkg

var i interface{} // MATCH /since GO 1.18 'interface{}' can be replaced by 'any'/

type t interface{} // MATCH /since GO 1.18 'interface{}' can be replaced by 'any'/
type a = interface{} // MATCH /since GO 1.18 'interface{}' can be replaced by 'any'/

func any1(a interface{}) { // MATCH /since GO 1.18 'interface{}' can be replaced by 'any'/
m1 := map[interface{}]string{} // MATCH /since GO 1.18 'interface{}' can be replaced by 'any'/
m2 := map[int]interface{}{} // MATCH /since GO 1.18 'interface{}' can be replaced by 'any'/
a := []interface{}{} // MATCH /since GO 1.18 'interface{}' can be replaced by 'any'/
m3 := make(map[int]interface{}, 1) // MATCH /since GO 1.18 'interface{}' can be replaced by 'any'/
a2 := make([]interface{}, 2) // MATCH /since GO 1.18 'interface{}' can be replaced by 'any'/
}

func any2(a int) interface{} {} // MATCH /since GO 1.18 'interface{}' can be replaced by 'any'/

var ni interface{ Close() }

type nt interface{ Close() }
type na = interface{ Close() }

func nany1(a interface{ Close() }) {
nm1 := map[interface{ Close() }]string{}
nm2 := map[int]interface{ Close() }{}
na := []interface{ Close() }{}
nm3 := make(map[int]interface{ Close() }, 1)
na2 := make([]interface{ Close() }, 2)
}

func nany2(a int) interface{ Close() } {}