From 73d6794ebbd4a16f44bdf838c2aa5fe79a63830d Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Mon, 28 Oct 2024 18:25:20 +0000 Subject: [PATCH] gopls/internal/template: fix completion token boundary conditions The template completion logic checked to see if the cursor position was inside a logical {{ }} block, but the boundary conditions in the relevant checks was wrong: in one case, a panic would occur if the cursor was in between the pair of left braces. In another, it would panic even if the cursor was at the start of a pair of left braces. Fix the boundary conditions, with a test. Fixes golang/go#57621 Change-Id: I826349906ee1ae67b2c5378e1b59d56e94c14fb2 Reviewed-on: https://go-review.googlesource.com/c/tools/+/622875 Auto-Submit: Robert Findley Reviewed-by: Alan Donovan LUCI-TryBot-Result: Go LUCI --- gopls/internal/template/completion.go | 8 +++--- .../integration/template/template_test.go | 26 +++++++++++++++++++ 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/gopls/internal/template/completion.go b/gopls/internal/template/completion.go index dfacefc93..dbb80cf2e 100644 --- a/gopls/internal/template/completion.go +++ b/gopls/internal/template/completion.go @@ -84,13 +84,15 @@ func inTemplate(fc *Parsed, pos protocol.Position) int { offset := fc.FromPosition(pos) // this could be a binary search, as the tokens are ordered for _, tk := range fc.tokens { - if tk.Start < offset && offset <= tk.End { + if tk.Start+len(Left) <= offset && offset+len(Right) <= tk.End { return tk.Start } } for _, x := range fc.elided { - if x > offset { - // fc.elided is sorted + if x+len(Left) > offset { + // fc.elided is sorted, and x is the position where a '{{' was replaced + // by ' '. We consider only cases where the replaced {{ is to the left + // of the cursor. break } // If the interval [x,offset] does not contain Left or Right diff --git a/gopls/internal/test/integration/template/template_test.go b/gopls/internal/test/integration/template/template_test.go index 47398f5a3..3087e1d60 100644 --- a/gopls/internal/test/integration/template/template_test.go +++ b/gopls/internal/test/integration/template/template_test.go @@ -228,4 +228,30 @@ func shorten(fn protocol.DocumentURI) string { return pieces[j-2] + "/" + pieces[j-1] } +func TestCompletionPanic_Issue57621(t *testing.T) { + const src = ` +-- go.mod -- +module mod.com + +go 1.12 +-- hello.tmpl -- +{{range .Planets}} +Hello {{ +{{end}} +` + Run(t, src, func(t *testing.T, env *Env) { + env.OpenFile("hello.tmpl") + // None of these should panic. + env.Completion(env.RegexpSearch("hello.tmpl", `Hello ()\{\{`)) + env.Completion(env.RegexpSearch("hello.tmpl", `Hello \{()\{`)) + env.Completion(env.RegexpSearch("hello.tmpl", `Hello \{\{()`)) + env.Completion(env.RegexpSearch("hello.tmpl", `()\{\{range`)) + env.Completion(env.RegexpSearch("hello.tmpl", `\{()\{range`)) + env.Completion(env.RegexpSearch("hello.tmpl", `\{\{()range`)) + env.Completion(env.RegexpSearch("hello.tmpl", `Planets()}}`)) + env.Completion(env.RegexpSearch("hello.tmpl", `Planets}()}`)) + env.Completion(env.RegexpSearch("hello.tmpl", `Planets}}()`)) + }) +} + // Hover needs tests