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 }