diff --git a/go/analysis/passes/modernize/bloop.go b/go/analysis/passes/modernize/bloop.go
index d44c856..c060788 100644
--- a/go/analysis/passes/modernize/bloop.go
+++ b/go/analysis/passes/modernize/bloop.go
@@ -72,7 +72,8 @@
}
if call, ok := stmt.X.(*ast.CallExpr); ok {
obj := typeutil.Callee(info, call)
- if typesinternal.IsMethodNamed(obj, "testing", "B", "StopTimer", "StartTimer", "ResetTimer") {
+ if typesinternal.IsMethodNamed(obj, "testing", "B", "StopTimer", "StartTimer", "ResetTimer") &&
+ timerCallReceiverIs(call, b) {
// Delete call statement.
// TODO(adonovan): delete following newline, or
// up to start of next stmt? (May delete a comment.)
@@ -160,6 +161,14 @@
return nil, nil
}
+// timerCallReceiverIs reports whether call is an ordinary method call whose
+// receiver is syntactically equal to want. Method expressions such as
+// (*testing.B).ResetTimer(b) are conservatively ignored.
+func timerCallReceiverIs(call *ast.CallExpr, want ast.Expr) bool {
+ sel, ok := ast.Unparen(call.Fun).(*ast.SelectorExpr)
+ return ok && astutil.EqualSyntax(sel.X, want)
+}
+
// uses reports whether the subtree cur contains a use of obj.
func uses(index *typeindex.Index, cur inspector.Cursor, obj types.Object) bool {
for use := range index.Uses(obj) {
diff --git a/go/analysis/passes/modernize/testdata/src/bloop/bloop_test.go b/go/analysis/passes/modernize/testdata/src/bloop/bloop_test.go
index 33ffd77..f55b096 100644
--- a/go/analysis/passes/modernize/testdata/src/bloop/bloop_test.go
+++ b/go/analysis/passes/modernize/testdata/src/bloop/bloop_test.go
@@ -15,6 +15,24 @@
}
}
+var otherBenchmark *testing.B
+
+func BenchmarkOtherReceiver(b *testing.B) {
+ other := new(testing.B)
+ other.ResetTimer() // not deleted: receiver is not b
+ otherBenchmark = other
+
+ for range b.N { // want "b.N can be modernized using b.Loop.."
+ }
+}
+
+func BenchmarkMethodExpression(b *testing.B) {
+ (*testing.B).ResetTimer(b) // conservatively not deleted
+
+ for range b.N { // want "b.N can be modernized using b.Loop.."
+ }
+}
+
func BenchmarkB(b *testing.B) {
// setup
{
diff --git a/go/analysis/passes/modernize/testdata/src/bloop/bloop_test.go.golden b/go/analysis/passes/modernize/testdata/src/bloop/bloop_test.go.golden
index a2def76..0f7b411 100644
--- a/go/analysis/passes/modernize/testdata/src/bloop/bloop_test.go.golden
+++ b/go/analysis/passes/modernize/testdata/src/bloop/bloop_test.go.golden
@@ -14,6 +14,24 @@
}
}
+var otherBenchmark *testing.B
+
+func BenchmarkOtherReceiver(b *testing.B) {
+ other := new(testing.B)
+ other.ResetTimer() // not deleted: receiver is not b
+ otherBenchmark = other
+
+ for b.Loop() { // want "b.N can be modernized using b.Loop.."
+ }
+}
+
+func BenchmarkMethodExpression(b *testing.B) {
+ (*testing.B).ResetTimer(b) // conservatively not deleted
+
+ for b.Loop() { // want "b.N can be modernized using b.Loop.."
+ }
+}
+
func BenchmarkB(b *testing.B) {
// setup
{