mirror of
https://github.com/scratchfoundation/golangci-lint.git
synced 2025-08-28 22:28:43 -04:00
Fix #324, relates #314 1. Update gocritic to the latest version 2. Use proper gocritic checkers repo, old repo was archived 3. Get enabled by default gocritic checks in sync with go-critic: don't enable performance, experimental and opinionated checks by default 4. Support of `enabled-tags` options for gocritic 5. Enable almost all gocritic checks for the project 6. Make rich debugging for gocritic 7. Meticulously validate gocritic checks config
99 lines
1.9 KiB
Go
99 lines
1.9 KiB
Go
package checkers
|
|
|
|
import (
|
|
"go/ast"
|
|
|
|
"github.com/go-lintpack/lintpack"
|
|
"github.com/go-lintpack/lintpack/astwalk"
|
|
)
|
|
|
|
func init() {
|
|
var info lintpack.CheckerInfo
|
|
info.Name = "ifElseChain"
|
|
info.Tags = []string{"style"}
|
|
info.Summary = "Detects repeated if-else statements and suggests to replace them with switch statement"
|
|
info.Before = `
|
|
if cond1 {
|
|
// Code A.
|
|
} else if cond2 {
|
|
// Code B.
|
|
} else {
|
|
// Code C.
|
|
}`
|
|
info.After = `
|
|
switch {
|
|
case cond1:
|
|
// Code A.
|
|
case cond2:
|
|
// Code B.
|
|
default:
|
|
// Code C.
|
|
}`
|
|
info.Note = `
|
|
Permits single else or else-if; repeated else-if or else + else-if
|
|
will trigger suggestion to use switch statement.
|
|
See [EffectiveGo#switch](https://golang.org/doc/effective_go.html#switch).`
|
|
|
|
collection.AddChecker(&info, func(ctx *lintpack.CheckerContext) lintpack.FileWalker {
|
|
return astwalk.WalkerForStmt(&ifElseChainChecker{ctx: ctx})
|
|
})
|
|
}
|
|
|
|
type ifElseChainChecker struct {
|
|
astwalk.WalkHandler
|
|
ctx *lintpack.CheckerContext
|
|
|
|
cause *ast.IfStmt
|
|
visited map[*ast.IfStmt]bool
|
|
}
|
|
|
|
func (c *ifElseChainChecker) EnterFunc(fn *ast.FuncDecl) bool {
|
|
if fn.Body == nil {
|
|
return false
|
|
}
|
|
c.visited = make(map[*ast.IfStmt]bool)
|
|
return true
|
|
}
|
|
|
|
func (c *ifElseChainChecker) VisitStmt(stmt ast.Stmt) {
|
|
if stmt, ok := stmt.(*ast.IfStmt); ok {
|
|
if c.visited[stmt] {
|
|
return
|
|
}
|
|
c.cause = stmt
|
|
c.checkIfStmt(stmt)
|
|
}
|
|
}
|
|
|
|
func (c *ifElseChainChecker) checkIfStmt(stmt *ast.IfStmt) {
|
|
const minThreshold = 2
|
|
if c.countIfelseLen(stmt) >= minThreshold {
|
|
c.warn()
|
|
}
|
|
}
|
|
|
|
func (c *ifElseChainChecker) countIfelseLen(stmt *ast.IfStmt) int {
|
|
count := 0
|
|
for {
|
|
switch e := stmt.Else.(type) {
|
|
case *ast.IfStmt:
|
|
if e.Init != nil {
|
|
return 0 // Give up
|
|
}
|
|
// Else if.
|
|
stmt = e
|
|
count++
|
|
c.visited[e] = true
|
|
case *ast.BlockStmt:
|
|
// Else branch.
|
|
return count + 1
|
|
default:
|
|
// No else or else if.
|
|
return count
|
|
}
|
|
}
|
|
}
|
|
|
|
func (c *ifElseChainChecker) warn() {
|
|
c.ctx.Warn(c.cause, "rewrite if-else to switch statement")
|
|
}
|