mirror of
https://github.com/mgechev/revive.git
synced 2025-06-08 23:26:29 +02:00
Adds rule superfluous-else (an extension of indent-error-flow) (#13)
* Adds rule superfluous-else (an extension of indent-error-flow) * Fix superfluous-else rule struct namming. * Adds superfuous-else rule to the rules table
This commit is contained in:
parent
5a0635ddfd
commit
cbe45ffc79
@ -167,6 +167,7 @@ List of all available rules. The rules ported from `golint` are left unchanged a
|
|||||||
| `cyclomatic` | int | Sets restriction for maximum Cyclomatic complexity. | no | no |
|
| `cyclomatic` | int | Sets restriction for maximum Cyclomatic complexity. | no | no |
|
||||||
| `max-public-structs` | int | The maximum number of public structs in a file. | no | no |
|
| `max-public-structs` | int | The maximum number of public structs in a file. | no | no |
|
||||||
| `file-header` | string | Header which each file should have. | no | no |
|
| `file-header` | string | Header which each file should have. | no | no |
|
||||||
|
| `superfluous-else` | n/a | Prevents redundant else statements (extends `indent-error-flow`) | no | no |
|
||||||
|
|
||||||
## Available Formatters
|
## Available Formatters
|
||||||
|
|
||||||
|
73
fixtures/superfluous-else.go
Normal file
73
fixtures/superfluous-else.go
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
// Test of return+else warning.
|
||||||
|
|
||||||
|
// Package pkg ...
|
||||||
|
package pkg
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
)
|
||||||
|
|
||||||
|
func h(f func() bool) string {
|
||||||
|
for {
|
||||||
|
if ok := f(); ok {
|
||||||
|
a := 1
|
||||||
|
continue
|
||||||
|
} else { // MATCH /if block ends with a continue statement, so drop this else and outdent its block (move short variable declaration to its own line if necessary)/
|
||||||
|
return "it's NOT okay!"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func i(f func() bool) string {
|
||||||
|
for {
|
||||||
|
if f() {
|
||||||
|
a := 1
|
||||||
|
continue
|
||||||
|
} else { // MATCH /if block ends with a continue statement, so drop this else and outdent its block/
|
||||||
|
log.Printf("non-positive")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return "ok"
|
||||||
|
}
|
||||||
|
|
||||||
|
func j(f func() bool) string {
|
||||||
|
for {
|
||||||
|
if f() {
|
||||||
|
break
|
||||||
|
} else { // MATCH /if block ends with a break statement, so drop this else and outdent its block/
|
||||||
|
log.Printf("non-positive")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return "ok"
|
||||||
|
}
|
||||||
|
|
||||||
|
func k() {
|
||||||
|
var a = 10
|
||||||
|
/* do loop execution */
|
||||||
|
LOOP:
|
||||||
|
for a < 20 {
|
||||||
|
if a == 15 {
|
||||||
|
a = a + 1
|
||||||
|
goto LOOP
|
||||||
|
} else { // MATCH /if block ends with a goto statement, so drop this else and outdent its block/
|
||||||
|
fmt.Printf("value of a: %d\n", a)
|
||||||
|
a++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func j(f func() bool) string {
|
||||||
|
for {
|
||||||
|
if f() {
|
||||||
|
a := 1
|
||||||
|
fallthrough
|
||||||
|
} else {
|
||||||
|
log.Printf("non-positive")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return "ok"
|
||||||
|
}
|
81
rule/superfluous-else.go
Normal file
81
rule/superfluous-else.go
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
package rule
|
||||||
|
|
||||||
|
import (
|
||||||
|
"go/ast"
|
||||||
|
"go/token"
|
||||||
|
|
||||||
|
"github.com/mgechev/revive/lint"
|
||||||
|
)
|
||||||
|
|
||||||
|
// SuperfluousElseRule lints given else constructs.
|
||||||
|
type SuperfluousElseRule struct{}
|
||||||
|
|
||||||
|
// Apply applies the rule to given file.
|
||||||
|
func (r *SuperfluousElseRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure {
|
||||||
|
var failures []lint.Failure
|
||||||
|
|
||||||
|
onFailure := func(failure lint.Failure) {
|
||||||
|
failures = append(failures, failure)
|
||||||
|
}
|
||||||
|
|
||||||
|
w := lintSuperfluousElse{make(map[*ast.IfStmt]bool), onFailure}
|
||||||
|
ast.Walk(w, file.AST)
|
||||||
|
return failures
|
||||||
|
}
|
||||||
|
|
||||||
|
// Name returns the rule name.
|
||||||
|
func (r *SuperfluousElseRule) Name() string {
|
||||||
|
return "superfluous-else"
|
||||||
|
}
|
||||||
|
|
||||||
|
type lintSuperfluousElse struct {
|
||||||
|
ignore map[*ast.IfStmt]bool
|
||||||
|
onFailure func(lint.Failure)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w lintSuperfluousElse) Visit(node ast.Node) ast.Visitor {
|
||||||
|
ifStmt, ok := node.(*ast.IfStmt)
|
||||||
|
if !ok || ifStmt.Else == nil {
|
||||||
|
return w
|
||||||
|
}
|
||||||
|
if w.ignore[ifStmt] {
|
||||||
|
return w
|
||||||
|
}
|
||||||
|
if elseif, ok := ifStmt.Else.(*ast.IfStmt); ok {
|
||||||
|
w.ignore[elseif] = true
|
||||||
|
return w
|
||||||
|
}
|
||||||
|
if _, ok := ifStmt.Else.(*ast.BlockStmt); !ok {
|
||||||
|
// only care about elses without conditions
|
||||||
|
return w
|
||||||
|
}
|
||||||
|
if len(ifStmt.Body.List) == 0 {
|
||||||
|
return w
|
||||||
|
}
|
||||||
|
shortDecl := false // does the if statement have a ":=" initialization statement?
|
||||||
|
if ifStmt.Init != nil {
|
||||||
|
if as, ok := ifStmt.Init.(*ast.AssignStmt); ok && as.Tok == token.DEFINE {
|
||||||
|
shortDecl = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
extra := ""
|
||||||
|
if shortDecl {
|
||||||
|
extra = " (move short variable declaration to its own line if necessary)"
|
||||||
|
}
|
||||||
|
|
||||||
|
lastStmt := ifStmt.Body.List[len(ifStmt.Body.List)-1]
|
||||||
|
if stmt, ok := lastStmt.(*ast.BranchStmt); ok {
|
||||||
|
token := stmt.Tok.String()
|
||||||
|
if token != "fallthrough" {
|
||||||
|
w.onFailure(lint.Failure{
|
||||||
|
Confidence: 1,
|
||||||
|
Node: ifStmt.Else,
|
||||||
|
Category: "indent",
|
||||||
|
URL: "#indent-error-flow",
|
||||||
|
Failure: "if block ends with a " + token + " statement, so drop this else and outdent its block" + extra,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return w
|
||||||
|
}
|
12
test/superfluous-else_test.go
Normal file
12
test/superfluous-else_test.go
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
package test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/mgechev/revive/rule"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TestSuperfluousElse rule.
|
||||||
|
func TestSuperfluousElse(t *testing.T) {
|
||||||
|
testRule(t, "superfluous-else", &rule.SuperfluousElseRule{})
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user