github.com/songshiyun/revive@v1.1.5-0.20220323112655-f8433a19b3c5/rule/bare-return.go (about)

     1  package rule
     2  
     3  import (
     4  	"go/ast"
     5  
     6  	"github.com/songshiyun/revive/lint"
     7  )
     8  
     9  // BareReturnRule lints given else constructs.
    10  type BareReturnRule struct{}
    11  
    12  // Apply applies the rule to given file.
    13  func (r *BareReturnRule) 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 := lintBareReturnRule{onFailure: onFailure}
    21  	ast.Walk(w, file.AST)
    22  	return failures
    23  }
    24  
    25  // Name returns the rule name.
    26  func (r *BareReturnRule) Name() string {
    27  	return "bare-return"
    28  }
    29  
    30  type lintBareReturnRule struct {
    31  	onFailure func(lint.Failure)
    32  }
    33  
    34  func (w lintBareReturnRule) Visit(node ast.Node) ast.Visitor {
    35  	switch n := node.(type) {
    36  	case *ast.FuncDecl:
    37  		w.checkFunc(n.Type.Results, n.Body)
    38  	case *ast.FuncLit: // to cope with deferred functions and go-routines
    39  		w.checkFunc(n.Type.Results, n.Body)
    40  	}
    41  
    42  	return w
    43  }
    44  
    45  // checkFunc will verify if the given function has named result and bare returns
    46  func (w lintBareReturnRule) checkFunc(results *ast.FieldList, body *ast.BlockStmt) {
    47  	hasNamedResults := results != nil && len(results.List) > 0 && results.List[0].Names != nil
    48  	if !hasNamedResults || body == nil {
    49  		return // nothing to do
    50  	}
    51  
    52  	brf := bareReturnFinder{w.onFailure}
    53  	ast.Walk(brf, body)
    54  }
    55  
    56  type bareReturnFinder struct {
    57  	onFailure func(lint.Failure)
    58  }
    59  
    60  func (w bareReturnFinder) Visit(node ast.Node) ast.Visitor {
    61  	_, ok := node.(*ast.FuncLit)
    62  	if ok {
    63  		// skip analysing function literals
    64  		// they will be analysed by the lintBareReturnRule.Visit method
    65  		return nil
    66  	}
    67  
    68  	rs, ok := node.(*ast.ReturnStmt)
    69  	if !ok {
    70  		return w
    71  	}
    72  
    73  	if len(rs.Results) > 0 {
    74  		return w
    75  	}
    76  
    77  	w.onFailure(lint.Failure{
    78  		Confidence: 1,
    79  		Node:       rs,
    80  		Failure:    "avoid using bare returns, please add return expressions",
    81  	})
    82  
    83  	return w
    84  }