1
0
mirror of https://github.com/mgechev/revive.git synced 2025-02-09 13:37:14 +02:00

Adds rule superfluous-else (an extension of indent-error-flow)

This commit is contained in:
Salvador Cavadini 2018-06-07 13:27:02 +02:00
parent abf02d70f2
commit 4150d79684
3 changed files with 166 additions and 0 deletions

View 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
View File

@ -0,0 +1,81 @@
package rule
import (
"go/ast"
"go/token"
"github.com/mgechev/revive/lint"
)
// SuperfluousElse lints given else constructs.
type SuperfluousElse struct{}
// Apply applies the rule to given file.
func (r *SuperfluousElse) 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 *SuperfluousElse) 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
}

View 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.SuperfluousElse{})
}