Skip to content

Commit 92a0949

Browse files
nicholashusingopherbot
authored andcommitted
go/analysis/passes/modernize: rangeint: handle usages of loop label
Currently, when a label is used, the rangeint modernizer fails to properly detect when i is used after a loop. This is because we only search for i usage within the for loop's parent subtree. When a label is used, the label becomes the loop's parent, and i can only be found in the loop's loop's parent subtree. To fix this, this change makes the rangeint modernizer look for i usage in the first ancestor of a for loop that is not a label. Fixes golang/go#76470 Change-Id: I79395efba26ad689514b7841d343932448ea9318 Reviewed-on: https://go-review.googlesource.com/c/tools/+/724960 Auto-Submit: Nicholas Husin <[email protected]> Reviewed-by: Nicholas Husin <[email protected]> Reviewed-by: Alan Donovan <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]> Reviewed-by: Josh Rickmar <[email protected]>
1 parent ffbdcac commit 92a0949

File tree

3 files changed

+47
-1
lines changed

3 files changed

+47
-1
lines changed

go/analysis/passes/modernize/rangeint.go

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,22 @@ func rangeint(pass *analysis.Pass) (any, error) {
161161
// don't offer a fix, as a range loop
162162
// leaves i with a different final value (limit-1).
163163
if init.Tok == token.ASSIGN {
164-
for curId := range curLoop.Parent().Preorder((*ast.Ident)(nil)) {
164+
// Find the nearest ancestor that is not a label.
165+
// Otherwise, checking for i usage outside of a for
166+
// loop might not function properly further below.
167+
// This is because the i usage might be a child of
168+
// the loop's parent's parent, for example:
169+
// var i int
170+
// Loop:
171+
// for i = 0; i < 10; i++ { break loop }
172+
// // i is in the sibling of the label, not the loop
173+
// fmt.Println(i)
174+
//
175+
ancestor := curLoop.Parent()
176+
for is[*ast.LabeledStmt](ancestor.Node()) {
177+
ancestor = ancestor.Parent()
178+
}
179+
for curId := range ancestor.Preorder((*ast.Ident)(nil)) {
165180
id := curId.Node().(*ast.Ident)
166181
if info.Uses[id] == v {
167182
// Is i used after loop?

go/analysis/passes/modernize/testdata/src/rangeint/rangeint.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,3 +271,19 @@ func issue74687() {
271271
println(i)
272272
}
273273
}
274+
275+
func issue76470() {
276+
var i, j int
277+
UsedAfter:
278+
for i = 0; i < 10; i++ { // nope: i is accessed after the loop
279+
break UsedAfter
280+
}
281+
if i == 9 {
282+
panic("Modernizer changes behavior")
283+
}
284+
285+
NotUsedAfter:
286+
for j = 0; j < 10; j++ { // want "for loop can be modernized using range over int"
287+
break NotUsedAfter
288+
}
289+
}

go/analysis/passes/modernize/testdata/src/rangeint/rangeint.go.golden

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,3 +271,18 @@ func issue74687() {
271271
}
272272
}
273273

274+
func issue76470() {
275+
var i, j int
276+
UsedAfter:
277+
for i = 0; i < 10; i++ { // nope: i is accessed after the loop
278+
break UsedAfter
279+
}
280+
if i == 9 {
281+
panic("Modernizer changes behavior")
282+
}
283+
284+
NotUsedAfter:
285+
for j = range(10) { // want "for loop can be modernized using range over int"
286+
break NotUsedAfter
287+
}
288+
}

0 commit comments

Comments
 (0)