sa4015.go raw

   1  package sa4015
   2  
   3  import (
   4  	"fmt"
   5  	"go/types"
   6  
   7  	"honnef.co/go/tools/analysis/callcheck"
   8  	"honnef.co/go/tools/analysis/lint"
   9  	"honnef.co/go/tools/go/ir"
  10  	"honnef.co/go/tools/go/ir/irutil"
  11  	"honnef.co/go/tools/go/types/typeutil"
  12  	"honnef.co/go/tools/internal/passes/buildir"
  13  
  14  	"golang.org/x/tools/go/analysis"
  15  )
  16  
  17  var SCAnalyzer = lint.InitializeAnalyzer(&lint.Analyzer{
  18  	Analyzer: &analysis.Analyzer{
  19  		Name:     "SA4015",
  20  		Requires: []*analysis.Analyzer{buildir.Analyzer},
  21  		Run:      callcheck.Analyzer(checkMathIntRules),
  22  	},
  23  	Doc: &lint.RawDocumentation{
  24  		Title:    `Calling functions like \'math.Ceil\' on floats converted from integers doesn't do anything useful`,
  25  		Since:    "2017.1",
  26  		Severity: lint.SeverityWarning,
  27  		MergeIf:  lint.MergeIfAll,
  28  	},
  29  })
  30  
  31  var Analyzer = SCAnalyzer.Analyzer
  32  
  33  var checkMathIntRules = map[string]callcheck.Check{
  34  	"math.Ceil":  pointlessIntMath,
  35  	"math.Floor": pointlessIntMath,
  36  	"math.IsNaN": pointlessIntMath,
  37  	"math.Trunc": pointlessIntMath,
  38  	"math.IsInf": pointlessIntMath,
  39  }
  40  
  41  func pointlessIntMath(call *callcheck.Call) {
  42  	if ConvertedFromInt(call.Args[0].Value) {
  43  		call.Invalid(fmt.Sprintf("calling %s on a converted integer is pointless", irutil.CallName(call.Instr.Common())))
  44  	}
  45  }
  46  
  47  func ConvertedFromInt(v callcheck.Value) bool {
  48  	conv, ok := v.Value.(*ir.Convert)
  49  	if !ok {
  50  		return false
  51  	}
  52  	return typeutil.NewTypeSet(conv.X.Type()).All(func(t *types.Term) bool {
  53  		b, ok := t.Type().Underlying().(*types.Basic)
  54  		return ok && b.Info()&types.IsInteger != 0
  55  	})
  56  }
  57