78 lines
1.7 KiB
Go
Vendored
78 lines
1.7 KiB
Go
Vendored
package rule
|
|
|
|
import (
|
|
"go/ast"
|
|
|
|
"github.com/mgechev/revive/lint"
|
|
)
|
|
|
|
// EarlyReturnRule lints given else constructs.
|
|
type EarlyReturnRule struct{}
|
|
|
|
// Apply applies the rule to given file.
|
|
func (r *EarlyReturnRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
|
|
var failures []lint.Failure
|
|
|
|
onFailure := func(failure lint.Failure) {
|
|
failures = append(failures, failure)
|
|
}
|
|
|
|
w := lintEarlyReturnRule{onFailure: onFailure}
|
|
ast.Walk(w, file.AST)
|
|
return failures
|
|
}
|
|
|
|
// Name returns the rule name.
|
|
func (r *EarlyReturnRule) Name() string {
|
|
return "early-return"
|
|
}
|
|
|
|
type lintEarlyReturnRule struct {
|
|
onFailure func(lint.Failure)
|
|
}
|
|
|
|
func (w lintEarlyReturnRule) Visit(node ast.Node) ast.Visitor {
|
|
switch n := node.(type) {
|
|
case *ast.IfStmt:
|
|
if n.Else == nil {
|
|
// no else branch
|
|
return w
|
|
}
|
|
|
|
elseBlock, ok := n.Else.(*ast.BlockStmt)
|
|
if !ok {
|
|
// is if-else-if
|
|
return w
|
|
}
|
|
|
|
lenElseBlock := len(elseBlock.List)
|
|
if lenElseBlock < 1 {
|
|
// empty else block, continue (there is another rule that warns on empty blocks)
|
|
return w
|
|
}
|
|
|
|
lenThenBlock := len(n.Body.List)
|
|
if lenThenBlock < 1 {
|
|
// then block is empty thus the stmt can be simplified
|
|
w.onFailure(lint.Failure{
|
|
Confidence: 1,
|
|
Node: n,
|
|
Failure: "if c { } else {... return} can be simplified to if !c { ... return }",
|
|
})
|
|
|
|
return w
|
|
}
|
|
|
|
_, lastThenStmtIsReturn := n.Body.List[lenThenBlock-1].(*ast.ReturnStmt)
|
|
_, lastElseStmtIsReturn := elseBlock.List[lenElseBlock-1].(*ast.ReturnStmt)
|
|
if lastElseStmtIsReturn && !lastThenStmtIsReturn {
|
|
w.onFailure(lint.Failure{
|
|
Confidence: 1,
|
|
Node: n,
|
|
Failure: "if c {...} else {... return } can be simplified to if !c { ... return } ...",
|
|
})
|
|
}
|
|
}
|
|
|
|
return w
|
|
}
|