github.com/Johnny2210/revive@v1.0.8-0.20210625134200-febf37ccd0f5/rule/string-of-int.go (about) 1 package rule 2 3 import ( 4 "go/ast" 5 "go/types" 6 7 "github.com/mgechev/revive/lint" 8 ) 9 10 // StringOfIntRule warns when logic expressions contains Boolean literals. 11 type StringOfIntRule struct{} 12 13 // Apply applies the rule to given file. 14 func (r *StringOfIntRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure { 15 var failures []lint.Failure 16 17 onFailure := func(failure lint.Failure) { 18 failures = append(failures, failure) 19 } 20 21 astFile := file.AST 22 file.Pkg.TypeCheck() 23 24 w := &lintStringInt{file, onFailure} 25 ast.Walk(w, astFile) 26 27 return failures 28 } 29 30 // Name returns the rule name. 31 func (r *StringOfIntRule) Name() string { 32 return "string-of-int" 33 } 34 35 type lintStringInt struct { 36 file *lint.File 37 onFailure func(lint.Failure) 38 } 39 40 func (w *lintStringInt) Visit(node ast.Node) ast.Visitor { 41 ce, ok := node.(*ast.CallExpr) 42 if !ok { 43 return w 44 } 45 46 if !w.isCallStringCast(ce.Fun) { 47 return w 48 } 49 50 if !w.isIntExpression(ce.Args) { 51 return w 52 } 53 54 w.onFailure(lint.Failure{ 55 Confidence: 1, 56 Node: ce, 57 Failure: "dubious convertion of an integer into a string, use strconv.Itoa", 58 }) 59 60 return w 61 } 62 63 func (w *lintStringInt) isCallStringCast(e ast.Expr) bool { 64 t := w.file.Pkg.TypeOf(e) 65 if t == nil { 66 return false 67 } 68 69 tb, _ := t.Underlying().(*types.Basic) 70 71 return tb != nil && tb.Kind() == types.String 72 } 73 74 func (w *lintStringInt) isIntExpression(es []ast.Expr) bool { 75 if len(es) != 1 { 76 return false 77 } 78 79 t := w.file.Pkg.TypeOf(es[0]) 80 if t == nil { 81 return false 82 } 83 84 ut, _ := t.Underlying().(*types.Basic) 85 if ut == nil || ut.Info()&types.IsInteger == 0 { 86 return false 87 } 88 89 switch ut.Kind() { 90 case types.Byte, types.Rune, types.UntypedRune: 91 return false 92 } 93 94 return true 95 }