github.com/Johnny2210/revive@v1.0.8-0.20210625134200-febf37ccd0f5/rule/error-return.go (about)

     1  package rule
     2  
     3  import (
     4  	"go/ast"
     5  
     6  	"github.com/mgechev/revive/lint"
     7  )
     8  
     9  // ErrorReturnRule lints given else constructs.
    10  type ErrorReturnRule struct{}
    11  
    12  // Apply applies the rule to given file.
    13  func (r *ErrorReturnRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
    14  	var failures []lint.Failure
    15  
    16  	fileAst := file.AST
    17  	walker := lintErrorReturn{
    18  		file:    file,
    19  		fileAst: fileAst,
    20  		onFailure: func(failure lint.Failure) {
    21  			failures = append(failures, failure)
    22  		},
    23  	}
    24  
    25  	ast.Walk(walker, fileAst)
    26  
    27  	return failures
    28  }
    29  
    30  // Name returns the rule name.
    31  func (r *ErrorReturnRule) Name() string {
    32  	return "error-return"
    33  }
    34  
    35  type lintErrorReturn struct {
    36  	file      *lint.File
    37  	fileAst   *ast.File
    38  	onFailure func(lint.Failure)
    39  }
    40  
    41  func (w lintErrorReturn) Visit(n ast.Node) ast.Visitor {
    42  	fn, ok := n.(*ast.FuncDecl)
    43  	if !ok || fn.Type.Results == nil {
    44  		return w
    45  	}
    46  	ret := fn.Type.Results.List
    47  	if len(ret) <= 1 {
    48  		return w
    49  	}
    50  	if isIdent(ret[len(ret)-1].Type, "error") {
    51  		return nil
    52  	}
    53  	// An error return parameter should be the last parameter.
    54  	// Flag any error parameters found before the last.
    55  	for _, r := range ret[:len(ret)-1] {
    56  		if isIdent(r.Type, "error") {
    57  			w.onFailure(lint.Failure{
    58  				Category:   "arg-order",
    59  				Confidence: 0.9,
    60  				Node:       fn,
    61  				Failure:    "error should be the last type when returning multiple items",
    62  			})
    63  			break // only flag one
    64  		}
    65  	}
    66  	return w
    67  }