cmd/fix: avoid non-bool assignment rewrite in slicescontains
The slicescontains modernizer folds certain search loops into a
slices.Contains assignment. It previously checked whether the
pre-loop and loop-body assignments were opposite boolean literals,
but did not verify that they were actually boolean literals.
For non-boolean expressions isTrueOrFalse returns 0, which caused the
condition to match accidentally (0 == -0). This could incorrectly
rewrite non-boolean assignments.
Require the loop-body assignment to be a boolean literal before
applying the rewrite.
Fixes #78149
diff --git a/src/cmd/go/testdata/script/fix_slicescontains_regression.txt b/src/cmd/go/testdata/script/fix_slicescontains_regression.txt
new file mode 100644
index 0000000..23e886d
--- /dev/null
+++ b/src/cmd/go/testdata/script/fix_slicescontains_regression.txt
@@ -0,0 +1,54 @@
+# Regression test for the slicescontains modernizer.
+# A loop that mutates a non-bool value before breaking must stay on the generic
+# if-Contains path instead of being folded into an assignment.
+# issue #78149
+
+go fix example.com/x
+cmp x.go x.go.want
+
+-- go.mod --
+module example.com/x
+go 1.26
+
+-- x.go --
+package x
+
+import "fmt"
+
+type Object struct{}
+
+func (o Object) Do() Object { return Object{} }
+func (o Object) Print() { fmt.Println("Hello, World!") }
+
+func doSomething(obj Object, opts ...string) {
+ o := obj
+ for _, opt := range opts {
+ if opt == "something" {
+ o = o.Do()
+ break
+ }
+ }
+
+ o.Print()
+}
+
+-- x.go.want --
+package x
+
+import "slices"
+
+import "fmt"
+
+type Object struct{}
+
+func (o Object) Do() Object { return Object{} }
+func (o Object) Print() { fmt.Println("Hello, World!") }
+
+func doSomething(obj Object, opts ...string) {
+ o := obj
+ if slices.Contains(opts, "something") {
+ o = o.Do()
+ }
+
+ o.Print()
+}
diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/slicescontains.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/slicescontains.go
index 3b32685..e5eb49f 100644
--- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/slicescontains.go
+++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/slicescontains.go
@@ -316,12 +316,13 @@
len(assign.Rhs) == 1 {
// Have: body={ lhs = rhs; break }
+ assignBool := isTrueOrFalse(info, assign.Rhs[0])
if prevAssign, ok := prevStmt.(*ast.AssignStmt); ok &&
len(prevAssign.Lhs) == 1 &&
len(prevAssign.Rhs) == 1 &&
astutil.EqualSyntax(prevAssign.Lhs[0], assign.Lhs[0]) &&
- isTrueOrFalse(info, assign.Rhs[0]) ==
- -isTrueOrFalse(info, prevAssign.Rhs[0]) {
+ assignBool != 0 &&
+ assignBool == -isTrueOrFalse(info, prevAssign.Rhs[0]) {
// Have:
// lhs = false
@@ -332,7 +333,7 @@
// TODO(adonovan):
// - support "var lhs bool = false" and variants.
// - allow the break to be omitted.
- neg := cond(isTrueOrFalse(info, assign.Rhs[0]) < 0, "!", "")
+ neg := cond(assignBool < 0, "!", "")
report([]analysis.TextEdit{
// Replace "rhs" of previous assignment by [!]slices.Contains(...)
{
| 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. |
Hello, thank you for working on this. We'll need to make this change in the x/tools repo first and then vendor it to the main go repo.
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
Hello, thank you for working on this. We'll need to make this change in the x/tools repo first and then vendor it to the main go repo.
So instead of changing src/cmd/go/vendor.. you'll need to send a CL to update x/tools/go/analysis/passes/modernize/slicescontains.go. Let me know if you're still interested in working on this! If not, I'm happy to finish it up
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
Madeline KalilHello, thank you for working on this. We'll need to make this change in the x/tools repo first and then vendor it to the main go repo.
So instead of changing src/cmd/go/vendor.. you'll need to send a CL to update x/tools/go/analysis/passes/modernize/slicescontains.go. Let me know if you're still interested in working on this! If not, I'm happy to finish it up
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |