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  }