internal/lsp: get file URI from beginFileRequest in SemanticTokens
Unguarded calls to span.URI.Filename() can panic. beginFileRequest
handles this, so use the URI of the returned FileHandle instead.
Fixes golang/vscode-go#1498
Change-Id: Ie48c27854e4a8ed8cca52ff6547ff580eccb5fd5
Reviewed-on: https://go-review.googlesource.com/c/tools/+/319529
Trust: Robert Findley <rfindley@google.com>
Run-TryBot: Robert Findley <rfindley@google.com>
Reviewed-by: Heschi Kreinick <heschi@google.com>
gopls-CI: kokoro <noreply+kokoro@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
diff --git a/gopls/internal/regtest/misc/semantictokens_test.go b/gopls/internal/regtest/misc/semantictokens_test.go
new file mode 100644
index 0000000..7950787
--- /dev/null
+++ b/gopls/internal/regtest/misc/semantictokens_test.go
@@ -0,0 +1,44 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package misc
+
+import (
+ "testing"
+
+ "golang.org/x/tools/internal/lsp/protocol"
+ . "golang.org/x/tools/internal/lsp/regtest"
+)
+
+func TestBadURICrash_VSCodeIssue1498(t *testing.T) {
+ const src = `
+-- go.mod --
+module example.com
+
+go 1.12
+
+-- main.go --
+package main
+
+func main() {}
+
+`
+ WithOptions(
+ Modes(Singleton),
+ EditorConfig{
+ AllExperiments: true,
+ },
+ ).Run(t, src, func(t *testing.T, env *Env) {
+ params := &protocol.SemanticTokensParams{}
+ const badURI = "http://foo"
+ params.TextDocument.URI = badURI
+ // This call panicked in the past: golang/vscode-go#1498.
+ if _, err := env.Editor.Server.SemanticTokensFull(env.Ctx, params); err != nil {
+ // Requests to an invalid URI scheme shouldn't result in an error, we
+ // simply don't support this so return empty result. This could be
+ // changed, but for now assert on the current behavior.
+ t.Errorf("SemanticTokensFull(%q): %v", badURI, err)
+ }
+ })
+}
diff --git a/internal/lsp/semantic.go b/internal/lsp/semantic.go
index 8ef30ff..d8feea7 100644
--- a/internal/lsp/semantic.go
+++ b/internal/lsp/semantic.go
@@ -49,8 +49,7 @@
ans := protocol.SemanticTokens{
Data: []uint32{},
}
- kind := source.DetectLanguage("", td.URI.SpanURI().Filename())
- snapshot, _, ok, release, err := s.beginFileRequest(ctx, td.URI, kind)
+ snapshot, fh, ok, release, err := s.beginFileRequest(ctx, td.URI, source.UnknownKind)
defer release()
if !ok {
return nil, err
@@ -61,7 +60,7 @@
// the client won't remember the wrong answer
return nil, errors.Errorf("semantictokens are disabled")
}
- if kind == source.Tmpl {
+ if fh.Kind() == source.Tmpl {
// this is a little cumbersome to avoid both exporting 'encoded' and its methods
// and to avoid import cycles
e := &encoded{
@@ -76,14 +75,14 @@
data := func() ([]uint32, error) {
return e.Data()
}
- return template.SemanticTokens(ctx, snapshot, td.URI.SpanURI(), add, data)
+ return template.SemanticTokens(ctx, snapshot, fh.URI(), add, data)
}
- pkg, err := snapshot.PackageForFile(ctx, td.URI.SpanURI(), source.TypecheckFull, source.WidestPackage)
+ pkg, err := snapshot.PackageForFile(ctx, fh.URI(), source.TypecheckFull, source.WidestPackage)
if err != nil {
return nil, err
}
info := pkg.GetTypesInfo()
- pgf, err := pkg.File(td.URI.SpanURI())
+ pgf, err := pkg.File(fh.URI())
if err != nil {
return nil, err
}
@@ -92,7 +91,7 @@
}
if rng == nil && len(pgf.Src) > maxFullFileSize {
err := fmt.Errorf("semantic tokens: file %s too large for full (%d>%d)",
- td.URI.SpanURI().Filename(), len(pgf.Src), maxFullFileSize)
+ fh.URI().Filename(), len(pgf.Src), maxFullFileSize)
return nil, err
}
e := &encoded{