github.com/Johnny2210/revive@v1.0.8-0.20210625134200-febf37ccd0f5/rule/early-return.go (about) 1 package rule 2 3 import ( 4 "go/ast" 5 6 "github.com/mgechev/revive/lint" 7 ) 8 9 // EarlyReturnRule lints given else constructs. 10 type EarlyReturnRule struct{} 11 12 // Apply applies the rule to given file. 13 func (r *EarlyReturnRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure { 14 var failures []lint.Failure 15 16 onFailure := func(failure lint.Failure) { 17 failures = append(failures, failure) 18 } 19 20 w := lintEarlyReturnRule{onFailure: onFailure} 21 ast.Walk(w, file.AST) 22 return failures 23 } 24 25 // Name returns the rule name. 26 func (r *EarlyReturnRule) Name() string { 27 return "early-return" 28 } 29 30 type lintEarlyReturnRule struct { 31 onFailure func(lint.Failure) 32 } 33 34 func (w lintEarlyReturnRule) Visit(node ast.Node) ast.Visitor { 35 switch n := node.(type) { 36 case *ast.IfStmt: 37 if n.Else == nil { 38 // no else branch 39 return w 40 } 41 42 elseBlock, ok := n.Else.(*ast.BlockStmt) 43 if !ok { 44 // is if-else-if 45 return w 46 } 47 48 lenElseBlock := len(elseBlock.List) 49 if lenElseBlock < 1 { 50 // empty else block, continue (there is another rule that warns on empty blocks) 51 return w 52 } 53 54 lenThenBlock := len(n.Body.List) 55 if lenThenBlock < 1 { 56 // then block is empty thus the stmt can be simplified 57 w.onFailure(lint.Failure{ 58 Confidence: 1, 59 Node: n, 60 Failure: "if c { } else {... return} can be simplified to if !c { ... return }", 61 }) 62 63 return w 64 } 65 66 _, lastThenStmtIsReturn := n.Body.List[lenThenBlock-1].(*ast.ReturnStmt) 67 _, lastElseStmtIsReturn := elseBlock.List[lenElseBlock-1].(*ast.ReturnStmt) 68 if lastElseStmtIsReturn && !lastThenStmtIsReturn { 69 w.onFailure(lint.Failure{ 70 Confidence: 1, 71 Node: n, 72 Failure: "if c {...} else {... return } can be simplified to if !c { ... return } ...", 73 }) 74 } 75 } 76 77 return w 78 }