[tools] go/analysis/passes/modernize: preserve timer calls on unrelated benchmarks

0 views
Skip to first unread message

shuang cui (Gerrit)

unread,
Aug 11, 2026, 11:24:28 PM (4 hours ago) Aug 11
to goph...@pubsubhelper.golang.org, golang-co...@googlegroups.com

shuang cui has uploaded the change for review

Commit message

go/analysis/passes/modernize: preserve timer calls on unrelated benchmarks

The bloop analyzer removed preceding timer calls based only on the called
testing.B method. As a result, it could remove StartTimer, StopTimer, or
ResetTimer calls made on a different *testing.B value.

Only remove ordinary timer method calls when their receiver matches the
receiver of the b.N loop. Conservatively preserve method expressions.

Add regression tests for unrelated receivers and method expressions.

Fixes golang/go#80841
Change-Id: Iba36ab43415739c3d30bff16de31d56eaee7f2f5

Change diff

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
{

Change information

Files:
  • M go/analysis/passes/modernize/bloop.go
  • M go/analysis/passes/modernize/testdata/src/bloop/bloop_test.go
  • M go/analysis/passes/modernize/testdata/src/bloop/bloop_test.go.golden
Change size: S
Delta: 3 files changed, 46 insertions(+), 1 deletion(-)
Open in Gerrit

Related details

Attention set is empty
Submit Requirements:
  • requirement is not satisfiedCode-Review
  • requirement satisfiedNo-Unresolved-Comments
  • requirement is not satisfiedReview-Enforcement
  • requirement is not satisfiedTryBots-Pass
Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
Gerrit-MessageType: newchange
Gerrit-Project: tools
Gerrit-Branch: master
Gerrit-Change-Id: Iba36ab43415739c3d30bff16de31d56eaee7f2f5
Gerrit-Change-Number: 813740
Gerrit-PatchSet: 1
Gerrit-Owner: shuang cui <imc...@gmail.com>
unsatisfied_requirement
satisfied_requirement
open
diffy

shuang cui (Gerrit)

unread,
Aug 11, 2026, 11:25:08 PM (4 hours ago) Aug 11
to goph...@pubsubhelper.golang.org, golang-co...@googlegroups.com

shuang cui voted Commit-Queue+1

Commit-Queue+1
Open in Gerrit

Related details

Attention set is empty
Submit Requirements:
  • requirement is not satisfiedCode-Review
  • requirement satisfiedNo-Unresolved-Comments
  • requirement is not satisfiedReview-Enforcement
  • requirement is not satisfiedTryBots-Pass
Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
Gerrit-MessageType: comment
Gerrit-Project: tools
Gerrit-Branch: master
Gerrit-Change-Id: Iba36ab43415739c3d30bff16de31d56eaee7f2f5
Gerrit-Change-Number: 813740
Gerrit-PatchSet: 1
Gerrit-Owner: shuang cui <imc...@gmail.com>
Gerrit-Reviewer: shuang cui <imc...@gmail.com>
Gerrit-Comment-Date: Wed, 12 Aug 2026 03:25:00 +0000
Gerrit-HasComments: No
Gerrit-Has-Labels: Yes
unsatisfied_requirement
satisfied_requirement
open
diffy
Reply all
Reply to author
Forward
0 new messages