mirror of
https://github.com/mgechev/revive.git
synced 2025-06-02 22:57:22 +02:00
wip: new rule enforce-switch-default
This commit is contained in:
parent
6becd540e4
commit
b22e68f34a
@ -104,6 +104,7 @@ var allRules = append([]lint.Rule{
|
||||
&rule.RedundantTestMainExitRule{},
|
||||
&rule.UnnecessaryFormatRule{},
|
||||
&rule.UseFmtPrintRule{},
|
||||
&rule.EnforceSwitchDefaultRule{},
|
||||
}, defaultRules...)
|
||||
|
||||
// allFormatters is a list of all available formatters to output the linting results.
|
||||
|
107
rule/enforce_switch_default.go
Normal file
107
rule/enforce_switch_default.go
Normal file
@ -0,0 +1,107 @@
|
||||
package rule
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"strings"
|
||||
|
||||
"github.com/mgechev/revive/lint"
|
||||
)
|
||||
|
||||
// EnforceSwitchDefaultRule implements a rule to enforce default clauses use and/or position.
|
||||
type EnforceSwitchDefaultRule struct {
|
||||
allowNoDefault bool // allow absence of default
|
||||
allowDefaultNotLast bool // allow default, if present, not being the last case
|
||||
}
|
||||
|
||||
// Configure validates the rule configuration, and configures the rule accordingly.
|
||||
//
|
||||
// Configuration implements the [lint.ConfigurableRule] interface.
|
||||
func (r *EnforceSwitchDefaultRule) Configure(arguments lint.Arguments) error {
|
||||
if len(arguments) < 1 {
|
||||
return nil
|
||||
}
|
||||
|
||||
for _, arg := range arguments {
|
||||
argStr, ok := arg.(string)
|
||||
if !ok {
|
||||
return fmt.Errorf("invalid argument for rule %s; expected string but got %T", r.Name(), arg)
|
||||
}
|
||||
switch strings.ToLower(argStr) {
|
||||
case "allownodefault":
|
||||
r.allowNoDefault = true
|
||||
case "allowdefaultnotlast":
|
||||
r.allowDefaultNotLast = true
|
||||
default:
|
||||
return fmt.Errorf(`invalid argument %q for rule %s; expected "allowNoDefault" or "allowDefaultNotLast"`, argStr, r.Name())
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Apply applies the rule to given file.
|
||||
func (r *EnforceSwitchDefaultRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
|
||||
var failures []lint.Failure
|
||||
astFile := file.AST
|
||||
ast.Inspect(astFile, func(n ast.Node) bool {
|
||||
switchNode, ok := n.(*ast.SwitchStmt)
|
||||
if !ok {
|
||||
return true // not a switch statement
|
||||
}
|
||||
|
||||
defaultClause, isLast := r.seekDefaultCase(switchNode.Body)
|
||||
hasDefault := defaultClause != nil
|
||||
|
||||
if !hasDefault && r.allowNoDefault {
|
||||
return true // switch without default but the rule is configured to don´t care
|
||||
}
|
||||
|
||||
if !hasDefault && !r.allowNoDefault {
|
||||
// switch without default
|
||||
failures = append(failures, lint.Failure{
|
||||
Confidence: 1,
|
||||
Node: switchNode,
|
||||
Category: lint.FailureCategoryStyle,
|
||||
Failure: "switch must have a default case clause",
|
||||
})
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// the switch has a default
|
||||
|
||||
if r.allowDefaultNotLast || isLast {
|
||||
return true
|
||||
}
|
||||
|
||||
failures = append(failures, lint.Failure{
|
||||
Confidence: 1,
|
||||
Node: defaultClause,
|
||||
Category: lint.FailureCategoryStyle,
|
||||
Failure: "default case clause must be the last one",
|
||||
})
|
||||
|
||||
return true
|
||||
})
|
||||
|
||||
return failures
|
||||
}
|
||||
|
||||
func (r *EnforceSwitchDefaultRule) seekDefaultCase(body *ast.BlockStmt) (defaultClause *ast.CaseClause, isLast bool) {
|
||||
var last *ast.CaseClause
|
||||
for _, stmt := range body.List {
|
||||
cc, _ := stmt.(*ast.CaseClause) // no need to check for ok
|
||||
last = cc
|
||||
if cc.List == nil { // a nil List means "default"
|
||||
defaultClause = cc
|
||||
}
|
||||
}
|
||||
|
||||
return defaultClause, defaultClause == last
|
||||
}
|
||||
|
||||
// Name returns the rule name.
|
||||
func (*EnforceSwitchDefaultRule) Name() string {
|
||||
return "enforce-switch-default"
|
||||
}
|
18
test/enforce_switch_default_test.go
Normal file
18
test/enforce_switch_default_test.go
Normal file
@ -0,0 +1,18 @@
|
||||
package test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/mgechev/revive/lint"
|
||||
"github.com/mgechev/revive/rule"
|
||||
)
|
||||
|
||||
func TestEnforceSwitchDefault(t *testing.T) {
|
||||
testRule(t, "enforce_switch_default", &rule.EnforceSwitchDefaultRule{})
|
||||
testRule(t, "enforce_switch_default_allow_no_default", &rule.EnforceSwitchDefaultRule{}, &lint.RuleConfig{
|
||||
Arguments: []any{"allowNoDefault"},
|
||||
})
|
||||
testRule(t, "enforce_switch_default_allow_not_last", &rule.EnforceSwitchDefaultRule{}, &lint.RuleConfig{
|
||||
Arguments: []any{"allowDefaultNotLast"},
|
||||
})
|
||||
}
|
18
testdata/enforce_switch_default.go
vendored
Normal file
18
testdata/enforce_switch_default.go
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
package fixtures
|
||||
|
||||
func enforceSwitchDefault() {
|
||||
|
||||
switch expression {
|
||||
case condition:
|
||||
default:
|
||||
}
|
||||
|
||||
switch expression {
|
||||
default: // MATCH /default case clause must be the last one/
|
||||
case condition:
|
||||
}
|
||||
|
||||
switch expression { // MATCH /switch must have a default case clause/
|
||||
case condition:
|
||||
}
|
||||
}
|
18
testdata/enforce_switch_default_allow_no_default.go
vendored
Normal file
18
testdata/enforce_switch_default_allow_no_default.go
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
package fixtures
|
||||
|
||||
func enforceSwitchDefault() {
|
||||
|
||||
switch expression {
|
||||
case condition:
|
||||
default:
|
||||
}
|
||||
|
||||
switch expression {
|
||||
default: // MATCH /default case clause must be the last one/
|
||||
case condition:
|
||||
}
|
||||
|
||||
switch expression {
|
||||
case condition:
|
||||
}
|
||||
}
|
18
testdata/enforce_switch_default_allow_not_last.go
vendored
Normal file
18
testdata/enforce_switch_default_allow_not_last.go
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
package fixtures
|
||||
|
||||
func enforceSwitchDefault() {
|
||||
|
||||
switch expression {
|
||||
case condition:
|
||||
default:
|
||||
}
|
||||
|
||||
switch expression {
|
||||
default:
|
||||
case condition:
|
||||
}
|
||||
|
||||
switch expression { // MATCH /switch must have a default case clause/
|
||||
case condition:
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user