Skip to content

Commit 7fed2a4

Browse files
adonovangopherbot
authored andcommitted
gopls/internal/analysis/modernize: fix bug in rangeint
for and range loops leave their index variables with a different final value: limit, and limit-1, respectively. Thus we must not offer a fix if the loop variable is used after the loop. + test Fixes golang/go#71952 Change-Id: Iaabd20792724166ace0ed5fd9dd997edaa96a435 Reviewed-on: https://go-review.googlesource.com/c/tools/+/652496 Auto-Submit: Alan Donovan <[email protected]> Reviewed-by: Jonathan Amsterdam <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]>
1 parent 6f7906b commit 7fed2a4

File tree

3 files changed

+44
-2
lines changed

3 files changed

+44
-2
lines changed

gopls/internal/analysis/modernize/rangeint.go

+12
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,18 @@ func rangeint(pass *analysis.Pass) {
100100
})
101101
}
102102

103+
// If i is used after the loop,
104+
// don't offer a fix, as a range loop
105+
// leaves i with a different final value (limit-1).
106+
if init.Tok == token.ASSIGN {
107+
for curId := range curLoop.Parent().Preorder((*ast.Ident)(nil)) {
108+
id := curId.Node().(*ast.Ident)
109+
if id.Pos() > loop.End() && info.Uses[id] == v {
110+
continue nextLoop
111+
}
112+
}
113+
}
114+
103115
// If limit is len(slice),
104116
// simplify "range len(slice)" to "range slice".
105117
if call, ok := limit.(*ast.CallExpr); ok &&

gopls/internal/analysis/modernize/testdata/src/rangeint/rangeint.go

+16-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,11 @@ func _(i int, s struct{ i int }, slice []int) {
44
for i := 0; i < 10; i++ { // want "for loop can be modernized using range over int"
55
println(i)
66
}
7-
for i = 0; i < f(); i++ { // want "for loop can be modernized using range over int"
7+
{
8+
var i int
9+
for i = 0; i < f(); i++ { // want "for loop can be modernized using range over int"
10+
}
11+
// NB: no uses of i after loop.
812
}
913
for i := 0; i < 10; i++ { // want "for loop can be modernized using range over int"
1014
// i unused within loop
@@ -51,3 +55,14 @@ func _(s string) {
5155
}
5256
}
5357
}
58+
59+
// Repro for #71952: for and range loops have different final values
60+
// on i (n and n-1, respectively) so we can't offer the fix if i is
61+
// used after the loop.
62+
func nopePostconditionDiffers() {
63+
i := 0
64+
for i = 0; i < 5; i++ {
65+
println(i)
66+
}
67+
println(i) // must print 5, not 4
68+
}

gopls/internal/analysis/modernize/testdata/src/rangeint/rangeint.go.golden

+16-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,11 @@ func _(i int, s struct{ i int }, slice []int) {
44
for i := range 10 { // want "for loop can be modernized using range over int"
55
println(i)
66
}
7-
for i = range f() { // want "for loop can be modernized using range over int"
7+
{
8+
var i int
9+
for i = range f() { // want "for loop can be modernized using range over int"
10+
}
11+
// NB: no uses of i after loop.
812
}
913
for range 10 { // want "for loop can be modernized using range over int"
1014
// i unused within loop
@@ -51,3 +55,14 @@ func _(s string) {
5155
}
5256
}
5357
}
58+
59+
// Repro for #71952: for and range loops have different final values
60+
// on i (n and n-1, respectively) so we can't offer the fix if i is
61+
// used after the loop.
62+
func nopePostconditionDiffers() {
63+
i := 0
64+
for i = 0; i < 5; i++ {
65+
println(i)
66+
}
67+
println(i) // must print 5, not 4
68+
}

0 commit comments

Comments
 (0)