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

     1  package rule
     2  
     3  import (
     4  	"fmt"
     5  	"go/ast"
     6  	"go/token"
     7  	"strings"
     8  
     9  	"github.com/mgechev/revive/lint"
    10  )
    11  
    12  // ErrorNamingRule lints given else constructs.
    13  type ErrorNamingRule struct{}
    14  
    15  // Apply applies the rule to given file.
    16  func (r *ErrorNamingRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
    17  	var failures []lint.Failure
    18  
    19  	fileAst := file.AST
    20  	walker := lintErrors{
    21  		file:    file,
    22  		fileAst: fileAst,
    23  		onFailure: func(failure lint.Failure) {
    24  			failures = append(failures, failure)
    25  		},
    26  	}
    27  
    28  	ast.Walk(walker, fileAst)
    29  
    30  	return failures
    31  }
    32  
    33  // Name returns the rule name.
    34  func (r *ErrorNamingRule) Name() string {
    35  	return "error-naming"
    36  }
    37  
    38  type lintErrors struct {
    39  	file      *lint.File
    40  	fileAst   *ast.File
    41  	onFailure func(lint.Failure)
    42  }
    43  
    44  func (w lintErrors) Visit(_ ast.Node) ast.Visitor {
    45  	for _, decl := range w.fileAst.Decls {
    46  		gd, ok := decl.(*ast.GenDecl)
    47  		if !ok || gd.Tok != token.VAR {
    48  			continue
    49  		}
    50  		for _, spec := range gd.Specs {
    51  			spec := spec.(*ast.ValueSpec)
    52  			if len(spec.Names) != 1 || len(spec.Values) != 1 {
    53  				continue
    54  			}
    55  			ce, ok := spec.Values[0].(*ast.CallExpr)
    56  			if !ok {
    57  				continue
    58  			}
    59  			if !isPkgDot(ce.Fun, "errors", "New") && !isPkgDot(ce.Fun, "fmt", "Errorf") {
    60  				continue
    61  			}
    62  
    63  			id := spec.Names[0]
    64  			prefix := "err"
    65  			if id.IsExported() {
    66  				prefix = "Err"
    67  			}
    68  			if !strings.HasPrefix(id.Name, prefix) {
    69  				w.onFailure(lint.Failure{
    70  					Node:       id,
    71  					Confidence: 0.9,
    72  					Category:   "naming",
    73  					Failure:    fmt.Sprintf("error var %s should have name of the form %sFoo", id.Name, prefix),
    74  				})
    75  			}
    76  		}
    77  	}
    78  	return nil
    79  }