mirror of
https://github.com/mgechev/revive.git
synced 2025-03-23 21:19:26 +02:00
116 lines
2.4 KiB
Go
116 lines
2.4 KiB
Go
package ifelse
|
|
|
|
import (
|
|
"fmt"
|
|
"go/ast"
|
|
"go/token"
|
|
)
|
|
|
|
// Branch contains information about a branch within an if-else chain.
|
|
type Branch struct {
|
|
BranchKind
|
|
Call // The function called at the end for kind Panic or Exit.
|
|
block []ast.Stmt
|
|
}
|
|
|
|
// BlockBranch gets the Branch of an ast.BlockStmt.
|
|
func BlockBranch(block *ast.BlockStmt) Branch {
|
|
blockLen := len(block.List)
|
|
if blockLen == 0 {
|
|
return Empty.Branch()
|
|
}
|
|
|
|
branch := StmtBranch(block.List[blockLen-1])
|
|
branch.block = block.List
|
|
return branch
|
|
}
|
|
|
|
// StmtBranch gets the Branch of an ast.Stmt.
|
|
func StmtBranch(stmt ast.Stmt) Branch {
|
|
switch stmt := stmt.(type) {
|
|
case *ast.ReturnStmt:
|
|
return Return.Branch()
|
|
case *ast.BlockStmt:
|
|
return BlockBranch(stmt)
|
|
case *ast.BranchStmt:
|
|
switch stmt.Tok {
|
|
case token.BREAK:
|
|
return Break.Branch()
|
|
case token.CONTINUE:
|
|
return Continue.Branch()
|
|
case token.GOTO:
|
|
return Goto.Branch()
|
|
}
|
|
case *ast.ExprStmt:
|
|
fn, ok := ExprCall(stmt)
|
|
if !ok {
|
|
break
|
|
}
|
|
kind, ok := DeviatingFuncs[fn]
|
|
if ok {
|
|
return Branch{BranchKind: kind, Call: fn}
|
|
}
|
|
case *ast.EmptyStmt:
|
|
return Empty.Branch()
|
|
case *ast.LabeledStmt:
|
|
return StmtBranch(stmt.Stmt)
|
|
}
|
|
return Regular.Branch()
|
|
}
|
|
|
|
// String returns a brief string representation
|
|
func (b Branch) String() string {
|
|
switch b.BranchKind {
|
|
case Empty:
|
|
return "{ }"
|
|
case Regular:
|
|
return "{ ... }"
|
|
case Panic, Exit:
|
|
return fmt.Sprintf("{ ... %v() }", b.Call)
|
|
}
|
|
return fmt.Sprintf("{ ... %v }", b.BranchKind)
|
|
}
|
|
|
|
// LongString returns a longer form string representation
|
|
func (b Branch) LongString() string {
|
|
switch b.BranchKind {
|
|
case Panic, Exit:
|
|
return fmt.Sprintf("call to %v function", b.Call)
|
|
}
|
|
return b.BranchKind.LongString()
|
|
}
|
|
|
|
// HasDecls returns whether the branch has any top-level declarations
|
|
func (b Branch) HasDecls() bool {
|
|
for _, stmt := range b.block {
|
|
switch stmt := stmt.(type) {
|
|
case *ast.DeclStmt:
|
|
return true
|
|
case *ast.AssignStmt:
|
|
if stmt.Tok == token.DEFINE {
|
|
return true
|
|
}
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
// IsShort returns whether the branch is empty or consists of a single statement
|
|
func (b Branch) IsShort() bool {
|
|
switch len(b.block) {
|
|
case 0:
|
|
return true
|
|
case 1:
|
|
return isShortStmt(b.block[0])
|
|
}
|
|
return false
|
|
}
|
|
|
|
func isShortStmt(stmt ast.Stmt) bool {
|
|
switch stmt.(type) {
|
|
case *ast.BlockStmt, *ast.IfStmt, *ast.SwitchStmt, *ast.TypeSwitchStmt, *ast.SelectStmt, *ast.ForStmt, *ast.RangeStmt:
|
|
return false
|
|
}
|
|
return true
|
|
}
|