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  }