internal/lsp/template: fix processing of multi-line tokens

Aside from the logic error, the root flaw was inadequate
test coverage.

Fixes golang/go#51731

Change-Id: I50787a951ab742700d9890b4b5232e90189cb8ee
Reviewed-on: https://go-review.googlesource.com/c/tools/+/393634
Run-TryBot: Peter Weinberger <pjw@google.com>
gopls-CI: kokoro <noreply+kokoro@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Trust: Peter Weinberger <pjw@google.com>
Reviewed-by: Suzy Mueller <suzmue@golang.org>
This commit is contained in:
Peter Weinbergr 2022-03-17 08:13:07 -04:00 committed by Peter Weinberger
parent e998cd2c59
commit c7b0e9aca6
2 changed files with 40 additions and 6 deletions

View File

@ -17,6 +17,41 @@ func TestMain(m *testing.M) {
Main(m, hooks.Options)
}
func TestMultilineTokens(t *testing.T) {
// 51731: panic: runtime error: slice bounds out of range [38:3]
const files = `
-- go.mod --
module mod.com
go 1.17
-- hi.tmpl --
{{if (foÜx .X.Y)}}😀{{$A :=
"hi"
}}{{.Z $A}}{{else}}
{{$A.X 12}}
{{foo (.X.Y) 23 ($A.Z)}}
{{end}}
`
WithOptions(
EditorConfig{
Settings: map[string]interface{}{
"templateExtensions": []string{"tmpl"},
"semanticTokens": true,
},
},
).Run(t, files, func(t *testing.T, env *Env) {
var p protocol.SemanticTokensParams
p.TextDocument.URI = env.Sandbox.Workdir.URI("hi.tmpl")
toks, err := env.Editor.Server.SemanticTokensFull(env.Ctx, &p)
if err != nil {
t.Errorf("semantic token failed: %v", err)
}
if toks == nil || len(toks.Data) == 0 {
t.Errorf("got no semantic tokens")
}
})
}
func TestTemplatesFromExtensions(t *testing.T) {
const files = `
-- go.mod --
@ -28,7 +63,6 @@ go 1.12
Hello {{}} <-- missing body
{{end}}
`
WithOptions(
EditorConfig{
Settings: map[string]interface{}{
@ -193,5 +227,4 @@ func shorten(fn protocol.DocumentURI) string {
return pieces[j-2] + "/" + pieces[j-1]
}
// Hover, SemTok, Diagnose with errors
// and better coverage
// Hover needs tests

View File

@ -291,11 +291,12 @@ func (p *Parsed) TokenSize(t Token) (int, error) {
return ans, nil
}
// RuneCount counts runes in a line
// RuneCount counts runes in line l, from col s to e
// (e==0 for end of line. called only for multiline tokens)
func (p *Parsed) RuneCount(l, s, e uint32) uint32 {
start := p.nls[l] + 1 + int(s)
end := int(e)
if e == 0 || int(e) >= p.nls[l+1] {
end := p.nls[l] + 1 + int(e)
if e == 0 || end > p.nls[l+1] {
end = p.nls[l+1]
}
return uint32(utf8.RuneCount(p.buf[start:end]))