From 671c55d82e238932de6e461df7bbc8b763719750 Mon Sep 17 00:00:00 2001 From: chavacava Date: Tue, 29 Mar 2022 20:25:38 +0200 Subject: [PATCH] adds rule use-any (#660) --- README.md | 1 + RULES_DESCRIPTIONS.md | 7 ++++++ config/config.go | 1 + rule/use-any.go | 54 +++++++++++++++++++++++++++++++++++++++++++ test/use-any_test.go | 11 +++++++++ testdata/use-any.go | 31 +++++++++++++++++++++++++ 6 files changed, 105 insertions(+) create mode 100644 rule/use-any.go create mode 100644 test/use-any_test.go create mode 100644 testdata/use-any.go diff --git a/README.md b/README.md index 58c908696..1268a5566 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 8f41630d2..a788e4a69 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 72865473d..388517a30 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 000000000..5e75e2f87 --- /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 +} diff --git a/test/use-any_test.go b/test/use-any_test.go new file mode 100644 index 000000000..b1183ec3a --- /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 000000000..bc6e64759 --- /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() } {}