gopls/internal/completion: fix issue 80268
When completing the argument to func foo(_ *[10]int), the existing
code can produce syntactically invalid code because it discards
a conversion to slice.
More precisely: in
func foo(p *[10]int) {}
func bar() {
var array [10]int
foo(arr<cursor>)
}
the completion at 'arr' was (*[10]int)(array), but the code should
have produced (*[10]int)(array[:]). [Even better would have been
&array, but that's not how the completion logic is organized.]
Fixes: golang/go#80268
Change-Id: Ief2ccc963d30cd275d8383b110fbd3b40661534f
Reviewed-on: https://go-review.googlesource.com/c/tools/+/799560
LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Madeline Kalil <mkalil@google.com>
diff --git a/gopls/internal/golang/completion/format.go b/gopls/internal/golang/completion/format.go
index ba50c4a..583cfe6 100644
--- a/gopls/internal/golang/completion/format.go
+++ b/gopls/internal/golang/completion/format.go
@@ -198,10 +198,15 @@
}
}
+ // replacing suffix with conv.suffix was wrong (Issue 80268)
+ // That produced `(*[10]int)(array)` for passing an
+ // array to a function expecting an array pointer. But
+ // `(*[10]int)(array[:])` is what is wanted.
+ // (conv.suffix is always ")" or empty)
if cand.convertTo != nil {
conv := c.formatConversion(cand.convertTo)
prefix = conv.prefix + prefix
- suffix = conv.suffix
+ suffix = suffix + conv.suffix
}
if prefix != "" {
diff --git a/gopls/internal/test/integration/completion/completion_test.go b/gopls/internal/test/integration/completion/completion_test.go
index 9a2e591..cedb5f2 100644
--- a/gopls/internal/test/integration/completion/completion_test.go
+++ b/gopls/internal/test/integration/completion/completion_test.go
@@ -1638,3 +1638,46 @@
}
})
}
+
+// ensure that completion converts the array to a slice
+func TestIssue80268(t *testing.T) {
+ const src = `
+-- go.mod --
+module mod.com
+go 1.22
+-- main.go --
+package example
+
+func foo(p *[10]int) {}
+
+func Bar() {
+ var array [10]int
+ foo(arr)
+}
+`
+ Run(t, src, func(t *testing.T, env *Env) {
+ env.OpenFile("main.go")
+ env.Await(env.DoneWithOpen())
+ loc := env.RegexpSearch("main.go", `foo\(arr()\)`)
+ completions := env.Completion(loc)
+ if len(completions.Items) == 0 {
+ t.Fatal("no completions found")
+ }
+ env.AcceptCompletion(loc, completions.Items[0])
+ env.Await(env.DoneWithChange())
+
+ fmt.Printf("New main.go content:\n%s\n", env.BufferText("main.go"))
+
+ var diags protocol.PublishDiagnosticsParams
+ env.Await(ReadDiagnostics("main.go", &diags))
+ if len(diags.Diagnostics) != 0 {
+ t.Errorf("unexpected diagnostics:\n")
+ for _, d := range diags.Diagnostics {
+ t.Errorf("Diagnostic: %d:%d: %s\n", d.Range.Start.Line, d.Range.Start.Character, d.Message)
+ }
+ for _, item := range completions.Items {
+ t.Errorf("Completion: %s (Kind: %v, Detail: %q)\n", item.Label, item.Kind, item.Detail)
+ }
+ }
+ })
+}