Skip to content

Commit 2659add

Browse files
committed
SA4000: add exceptions for functions from math/rand
Closes gh-1087 (cherry picked from commit c4bd432)
1 parent 40877a4 commit 2659add

File tree

2 files changed

+68
-0
lines changed

2 files changed

+68
-0
lines changed

staticcheck/lint.go

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1360,6 +1360,9 @@ func CheckLhsRhsIdentical(pass *analysis.Pass) (interface{}, error) {
13601360
// happily flags fn() == fn() – so far, we've had nobody complain
13611361
// about a false positive, and it's caught several bugs in real
13621362
// code.
1363+
//
1364+
// We special case functions from the math/rand package. Someone ran
1365+
// into the following false positive: "rand.Intn(2) - rand.Intn(2), which I wrote to generate values {-1, 0, 1} with {0.25, 0.5, 0.25} probability."
13631366
fn := func(node ast.Node) {
13641367
op := node.(*ast.BinaryExpr)
13651368
switch op.Op {
@@ -1399,6 +1402,38 @@ func CheckLhsRhsIdentical(pass *analysis.Pass) (interface{}, error) {
13991402
// 0 == 0 are slim.
14001403
return
14011404
}
1405+
1406+
if expr, ok := op.X.(*ast.CallExpr); ok {
1407+
call := code.CallName(pass, expr)
1408+
switch call {
1409+
case "math/rand.Int",
1410+
"math/rand.Int31",
1411+
"math/rand.Int31n",
1412+
"math/rand.Int63",
1413+
"math/rand.Int63n",
1414+
"math/rand.Intn",
1415+
"math/rand.Uint32",
1416+
"math/rand.Uint64",
1417+
"math/rand.ExpFloat64",
1418+
"math/rand.Float32",
1419+
"math/rand.Float64",
1420+
"math/rand.NormFloat64",
1421+
"(*math/rand.Rand).Int",
1422+
"(*math/rand.Rand).Int31",
1423+
"(*math/rand.Rand).Int31n",
1424+
"(*math/rand.Rand).Int63",
1425+
"(*math/rand.Rand).Int63n",
1426+
"(*math/rand.Rand).Intn",
1427+
"(*math/rand.Rand).Uint32",
1428+
"(*math/rand.Rand).Uint64",
1429+
"(*math/rand.Rand).ExpFloat64",
1430+
"(*math/rand.Rand).Float32",
1431+
"(*math/rand.Rand).Float64",
1432+
"(*math/rand.Rand).NormFloat64":
1433+
return
1434+
}
1435+
}
1436+
14021437
report.Report(pass, op, fmt.Sprintf("identical expressions on the left and right side of the '%s' operator", op.Op))
14031438
}
14041439
code.Preorder(pass, fn, (*ast.BinaryExpr)(nil))

staticcheck/testdata/src/CheckLhsRhsIdentical/CheckLhsRhsIdentical.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package pkg
22

3+
import "math/rand"
4+
35
type Float float64
46

57
type Floats [5]float64
@@ -65,3 +67,34 @@ func fn(a int, s []int, f1 float64, f2 Float, fs Floats, is Ints, t1 T1, t2 T2)
6567
println()
6668
}
6769
}
70+
71+
func fn2() {
72+
_ = rand.Int() - rand.Int()
73+
_ = rand.Int31() - rand.Int31()
74+
_ = rand.Int31n(0) - rand.Int31n(0)
75+
_ = rand.Int63() - rand.Int63()
76+
_ = rand.Int63n(0) - rand.Int63n(0)
77+
_ = rand.Intn(0) - rand.Intn(0)
78+
_ = rand.Uint32() - rand.Uint32()
79+
_ = rand.Uint64() - rand.Uint64()
80+
_ = rand.ExpFloat64() - rand.ExpFloat64()
81+
_ = rand.Float32() - rand.Float32()
82+
_ = rand.Float64() - rand.Float64()
83+
_ = rand.NormFloat64() - rand.NormFloat64()
84+
85+
var rng *rand.Rand
86+
_ = rng.Int() - rng.Int()
87+
_ = rng.Int31() - rng.Int31()
88+
_ = rng.Int31n(0) - rng.Int31n(0)
89+
_ = rng.Int63() - rng.Int63()
90+
_ = rng.Int63n(0) - rng.Int63n(0)
91+
_ = rng.Intn(0) - rng.Intn(0)
92+
_ = rng.Uint32() - rng.Uint32()
93+
_ = rng.Uint64() - rng.Uint64()
94+
_ = rng.ExpFloat64() - rng.ExpFloat64()
95+
_ = rng.Float32() - rng.Float32()
96+
_ = rng.Float64() - rng.Float64()
97+
_ = rng.NormFloat64() - rng.NormFloat64()
98+
99+
_ = rand.NewSource(0) == rand.NewSource(0) // want `identical expressions`
100+
}

0 commit comments

Comments
 (0)