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