Repository: mgechev/revive
Pull request #660 (2022-03-29 17:01:58)

adds rule use-any
GO 1.18 includes a type alias for `interface{}`: `any`.

Now, the whole codebase of GO uses `any` in place of `interface{}`
This rule spots instances of `interface{}` and proposes to change it into `any`

Refs: [GO 1.18 release note](https://tip.golang.org/doc/go1.18) and [GO codebase commit replacing ìnterface` by `any`](https://github.com/golang/go/commit/2580d0e08d5e9f979b943758d3c49877fb2324cb)


Patch:
diff --git a/README.md b/README.md
index 58c9086..1268a55 100644
--- a/README.md
+++ b/README.md
@@ -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
 
diff --git a/RULES_DESCRIPTIONS.md b/RULES_DESCRIPTIONS.md
index 8f41630..a788e4a 100644
--- a/RULES_DESCRIPTIONS.md
+++ b/RULES_DESCRIPTIONS.md
@@ -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)
 
@@ -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.
diff --git a/config/config.go b/config/config.go
index 7286547..388517a 100644
--- a/config/config.go
+++ b/config/config.go
@@ -84,6 +84,7 @@ var allRules = append([]lint.Rule{
 	&rule.TimeEqualRule{},
 	&rule.BannedCharsRule{},
 	&rule.OptimizeOperandsOrderRule{},
+	&rule.UseAnyRule{},
 }, defaultRules...)
 
 var allFormatters = []lint.Formatter{
diff --git a/rule/use-any.go b/rule/use-any.go
new file mode 100644
index 0000000..5e75e2f
--- /dev/null
+++ b/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
+}


Test patch:
diff --git a/test/use-any_test.go b/test/use-any_test.go
new file mode 100644
index 0000000..b1183ec
--- /dev/null
+++ b/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{})
+}
diff --git a/testdata/use-any.go b/testdata/use-any.go
new file mode 100644
index 0000000..bc6e647
--- /dev/null
+++ b/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() } {}