diff --git a/staticcheck/lint.go b/staticcheck/lint.go index 40ca2c131..d09d079b3 100644 --- a/staticcheck/lint.go +++ b/staticcheck/lint.go @@ -1360,6 +1360,9 @@ func CheckLhsRhsIdentical(pass *analysis.Pass) (interface{}, error) { // happily flags fn() == fn() – so far, we've had nobody complain // about a false positive, and it's caught several bugs in real // code. + // + // We special case functions from the math/rand package. Someone ran + // 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." fn := func(node ast.Node) { op := node.(*ast.BinaryExpr) switch op.Op { @@ -1399,6 +1402,38 @@ func CheckLhsRhsIdentical(pass *analysis.Pass) (interface{}, error) { // 0 == 0 are slim. return } + + if expr, ok := op.X.(*ast.CallExpr); ok { + call := code.CallName(pass, expr) + switch call { + case "math/rand.Int", + "math/rand.Int31", + "math/rand.Int31n", + "math/rand.Int63", + "math/rand.Int63n", + "math/rand.Intn", + "math/rand.Uint32", + "math/rand.Uint64", + "math/rand.ExpFloat64", + "math/rand.Float32", + "math/rand.Float64", + "math/rand.NormFloat64", + "(*math/rand.Rand).Int", + "(*math/rand.Rand).Int31", + "(*math/rand.Rand).Int31n", + "(*math/rand.Rand).Int63", + "(*math/rand.Rand).Int63n", + "(*math/rand.Rand).Intn", + "(*math/rand.Rand).Uint32", + "(*math/rand.Rand).Uint64", + "(*math/rand.Rand).ExpFloat64", + "(*math/rand.Rand).Float32", + "(*math/rand.Rand).Float64", + "(*math/rand.Rand).NormFloat64": + return + } + } + report.Report(pass, op, fmt.Sprintf("identical expressions on the left and right side of the '%s' operator", op.Op)) } code.Preorder(pass, fn, (*ast.BinaryExpr)(nil)) diff --git a/staticcheck/testdata/src/CheckLhsRhsIdentical/CheckLhsRhsIdentical.go b/staticcheck/testdata/src/CheckLhsRhsIdentical/CheckLhsRhsIdentical.go index 2f344ff55..39e57dd80 100644 --- a/staticcheck/testdata/src/CheckLhsRhsIdentical/CheckLhsRhsIdentical.go +++ b/staticcheck/testdata/src/CheckLhsRhsIdentical/CheckLhsRhsIdentical.go @@ -1,5 +1,7 @@ package pkg +import "math/rand" + type Float float64 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) println() } } + +func fn2() { + _ = rand.Int() - rand.Int() + _ = rand.Int31() - rand.Int31() + _ = rand.Int31n(0) - rand.Int31n(0) + _ = rand.Int63() - rand.Int63() + _ = rand.Int63n(0) - rand.Int63n(0) + _ = rand.Intn(0) - rand.Intn(0) + _ = rand.Uint32() - rand.Uint32() + _ = rand.Uint64() - rand.Uint64() + _ = rand.ExpFloat64() - rand.ExpFloat64() + _ = rand.Float32() - rand.Float32() + _ = rand.Float64() - rand.Float64() + _ = rand.NormFloat64() - rand.NormFloat64() + + var rng *rand.Rand + _ = rng.Int() - rng.Int() + _ = rng.Int31() - rng.Int31() + _ = rng.Int31n(0) - rng.Int31n(0) + _ = rng.Int63() - rng.Int63() + _ = rng.Int63n(0) - rng.Int63n(0) + _ = rng.Intn(0) - rng.Intn(0) + _ = rng.Uint32() - rng.Uint32() + _ = rng.Uint64() - rng.Uint64() + _ = rng.ExpFloat64() - rng.ExpFloat64() + _ = rng.Float32() - rng.Float32() + _ = rng.Float64() - rng.Float64() + _ = rng.NormFloat64() - rng.NormFloat64() + + _ = rand.NewSource(0) == rand.NewSource(0) // want `identical expressions` +}