go/analysis/passes/modernize: fix rangeint rewriting
The rangeint modernizer looks for references to "i"
within the loop body and does not suggest a fix if any
of them is an l-value. However, it does not count the
key of a RangeStmt as an l-value when it should,
resulting in invalid suggested fixes.
This CL modifes the l-value logic and adds a test.
Fixes golang/go#77034
Change-Id: Ic0cdbaf5ba64f82c5dba41773ad29f06953aab5c
Reviewed-on: https://go-review.googlesource.com/c/tools/+/734480
Reviewed-by: Alan Donovan <adonovan@google.com>
Auto-Submit: Madeline Kalil <mkalil@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
diff --git a/go/analysis/passes/modernize/rangeint.go b/go/analysis/passes/modernize/rangeint.go
index fccd6e5..600c561 100644
--- a/go/analysis/passes/modernize/rangeint.go
+++ b/go/analysis/passes/modernize/rangeint.go
@@ -332,6 +332,11 @@
if v, ok := info.Defs[id]; ok && v.Pos() != id.Pos() {
return true // reassignment of i (i, j := 1, 2)
}
+ case edge.RangeStmt_Key:
+ rng := cur.Parent().Node().(*ast.RangeStmt)
+ if rng.Tok == token.ASSIGN {
+ return true // "for k, v = range x" is like an AssignStmt to k, v
+ }
case edge.IncDecStmt_X:
return true // i++, i--
case edge.UnaryExpr_X:
diff --git a/go/analysis/passes/modernize/testdata/src/rangeint/rangeint.go b/go/analysis/passes/modernize/testdata/src/rangeint/rangeint.go
index a14dc38..0ec4374 100644
--- a/go/analysis/passes/modernize/testdata/src/rangeint/rangeint.go
+++ b/go/analysis/passes/modernize/testdata/src/rangeint/rangeint.go
@@ -307,3 +307,20 @@
break NotUsedAfter
}
}
+
+// Don't allow rewriting of an outer loop when its inner loop modifies the outer
+// loop variable.
+func issue77034() {
+ for i := 0; i < 5; i++ {
+ for i = range 10 {
+ }
+ }
+}
+
+func issue77034_define_inner() {
+ for i := 0; i < 5; i++ { // want "for loop can be modernized using range over int"
+ for i := range 10 { // inner "i" doesn't modify outer "i"
+ 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 0e92147..ad98069 100644
--- a/go/analysis/passes/modernize/testdata/src/rangeint/rangeint.go.golden
+++ b/go/analysis/passes/modernize/testdata/src/rangeint/rangeint.go.golden
@@ -306,3 +306,20 @@
break NotUsedAfter
}
}
+
+// Don't allow rewriting of an outer loop when its inner loop modifies the outer
+// loop variable.
+func issue77034() {
+ for i := 0; i < 5; i++ {
+ for i = range 10 {
+ }
+ }
+}
+
+func issue77034_define_inner() {
+ for range 5 { // want "for loop can be modernized using range over int"
+ for i := range 10 { // inner "i" doesn't modify outer "i"
+ println(i)
+ }
+ }
+}