go/analysis/passes/modernize: rangeint: result vars are implicit uses
This CL fixes a bug in rangeint that caused it to make unsound
fixes because it failed to consider that result variables can be
implicit uses of a loop index variable after the loop, and thus
the fix to golang/go#71952 was insufficient.
+ test
Fixes golang/go#76880
diff --git a/go/analysis/passes/modernize/rangeint.go b/go/analysis/passes/modernize/rangeint.go
index c42ec58..edffcee 100644
--- a/go/analysis/passes/modernize/rangeint.go
+++ b/go/analysis/passes/modernize/rangeint.go
@@ -18,6 +18,7 @@
"golang.org/x/tools/internal/analysis/analyzerutil"
typeindexanalyzer "golang.org/x/tools/internal/analysis/typeindex"
"golang.org/x/tools/internal/astutil"
+ "golang.org/x/tools/internal/moreiters"
"golang.org/x/tools/internal/typesinternal"
"golang.org/x/tools/internal/typesinternal/typeindex"
"golang.org/x/tools/internal/versions"
@@ -133,6 +134,14 @@
if typesinternal.IsPackageLevel(v) {
continue nextLoop
}
+
+ // If v is a named result, it is implicitly
+ // used after the loop (go.dev/issue/76880).
+ // TODO(adonovan): use go1.25 v.Kind() == types.ResultVar.
+ if moreiters.Contains(enclosingSignature(curLoop, info).Results().Variables(), v) {
+ continue nextLoop
+ }
+
used := false
for curId := range curLoop.Child(loop.Body).Preorder((*ast.Ident)(nil)) {
id := curId.Node().(*ast.Ident)
@@ -320,3 +329,24 @@
}
return false
}
+
+// enclosingSignature returns the signature of the innermost
+// function enclosing the syntax node denoted by cur
+// or nil if the node is not within a function.
+//
+// TODO(adonovan): factor with gopls/internal/util/typesutil.EnclosingSignature.
+func enclosingSignature(cur inspector.Cursor, info *types.Info) *types.Signature {
+ if c, ok := enclosingFunc(cur); ok {
+ switch n := c.Node().(type) {
+ case *ast.FuncDecl:
+ if f, ok := info.Defs[n.Name]; ok {
+ return f.Type().(*types.Signature)
+ }
+ case *ast.FuncLit:
+ if f, ok := info.Types[n]; ok {
+ return f.Type.(*types.Signature)
+ }
+ }
+ }
+ return nil
+}
diff --git a/go/analysis/passes/modernize/testdata/src/rangeint/rangeint.go b/go/analysis/passes/modernize/testdata/src/rangeint/rangeint.go
index 2a3de6b..11ddc69 100644
--- a/go/analysis/passes/modernize/testdata/src/rangeint/rangeint.go
+++ b/go/analysis/passes/modernize/testdata/src/rangeint/rangeint.go
@@ -262,6 +262,13 @@
}()
}
+// See go.dev/issue/76880.
+func _() (i int) {
+ for i = 0; i < 3; i++ { // nope: i is implicitly accessed after the loop
+ }
+ return
+}
+
func issue74687() {
for i := a.ID(0); i < 10; i++ { // want "for loop can be modernized using range over int"
println(i)
diff --git a/go/analysis/passes/modernize/testdata/src/rangeint/rangeint.go.golden b/go/analysis/passes/modernize/testdata/src/rangeint/rangeint.go.golden
index b8d9d7c..2b52145 100644
--- a/go/analysis/passes/modernize/testdata/src/rangeint/rangeint.go.golden
+++ b/go/analysis/passes/modernize/testdata/src/rangeint/rangeint.go.golden
@@ -261,6 +261,13 @@
}()
}
+// See go.dev/issue/76880.
+func _() (i int) {
+ for i = 0; i < 3; i++ { // nope: i is implicitly accessed after the loop
+ }
+ return
+}
+
func issue74687() {
for i := range a.ID(10) { // want "for loop can be modernized using range over int"
println(i)
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
| Code-Review | +2 |
Tested this on real code from math/rand and it appears to solve the issue.
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
I've also updated CL 730960 (re-generated with changes from this CL included) for testing purposes, it passes the tests now.
| Code-Review | +2 |
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
Alan DonovanTested this on real code from math/rand and it appears to solve the issue.
Thanks!
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
| Commit-Queue | +1 |
| TryBot-Bypass | +1 |
Test failure is preexisting; bypassing trybot.
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
go/analysis/passes/modernize: rangeint: result vars are implicit uses
This CL fixes a bug in rangeint that caused it to make unsound
fixes because it failed to consider that result variables can be
implicit uses of a loop index variable after the loop, and thus
the fix to golang/go#71952 was insufficient.
+ test
Fixes golang/go#76880
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
[internal-branch.go1.26-vendor] go/analysis/passes/modernize: rangeint: result vars are implicit uses
This CL fixes a bug in rangeint that caused it to make unsound
fixes because it failed to consider that result variables can be
implicit uses of a loop index variable after the loop, and thus
the fix to golang/go#71952 was insufficient.
+ test
Fixes golang/go#76880
Change-Id: I9c4d2082d93204023f50afb07318037d9134de23
Reviewed-on: https://go-review.googlesource.com/c/tools/+/731220
TryBot-Bypass: Alan Donovan <adon...@google.com>
Auto-Submit: Alan Donovan <adon...@google.com>
Reviewed-by: Madeline Kalil <mka...@google.com>
Reviewed-by: Kirill Kolyshkin <koly...@gmail.com>
Commit-Queue: Alan Donovan <adon...@google.com>
(cherry picked from commit 95246c4aa04977c8425289eb81fd0054c9fcd48a)
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
| Code-Review | +2 |
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |