blob: b0b49ec032b3de98d64bd511973bce09d0acf6e2 [file] [log] [blame]
// 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 (
"fmt"
"strings"
"testing"
"github.com/google/go-cmp/cmp"
"golang.org/x/tools/gopls/internal/lsp/protocol"
. "golang.org/x/tools/gopls/internal/test/integration"
"golang.org/x/tools/gopls/internal/test/integration/fake"
)
func TestBadURICrash_VSCodeIssue1498(t *testing.T) {
const src = `
-- go.mod --
module example.com
go 1.12
-- main.go --
package main
func main() {}
`
WithOptions(
Modes(Default),
Settings{"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.
_, err := env.Editor.Server.SemanticTokensFull(env.Ctx, params)
// Requests to an invalid URI scheme now result in an LSP error.
got := fmt.Sprint(err)
want := `DocumentURI scheme is not 'file': http://foo`
if !strings.Contains(got, want) {
t.Errorf("SemanticTokensFull error is %v, want substring %q", got, want)
}
})
}
// fix bug involving type parameters and regular parameters
// (golang/vscode-go#2527)
func TestSemantic_2527(t *testing.T) {
// these are the expected types of identifiers in text order
want := []fake.SemanticToken{
{Token: "package", TokenType: "keyword"},
{Token: "foo", TokenType: "namespace"},
{Token: "// Deprecated (for testing)", TokenType: "comment"},
{Token: "func", TokenType: "keyword"},
{Token: "Add", TokenType: "function", Mod: "definition deprecated"},
{Token: "T", TokenType: "typeParameter", Mod: "definition"},
{Token: "int", TokenType: "type", Mod: "defaultLibrary"},
{Token: "target", TokenType: "parameter", Mod: "definition"},
{Token: "T", TokenType: "typeParameter"},
{Token: "l", TokenType: "parameter", Mod: "definition"},
{Token: "T", TokenType: "typeParameter"},
{Token: "T", TokenType: "typeParameter"},
{Token: "return", TokenType: "keyword"},
{Token: "append", TokenType: "function", Mod: "defaultLibrary"},
{Token: "l", TokenType: "parameter"},
{Token: "target", TokenType: "parameter"},
{Token: "for", TokenType: "keyword"},
{Token: "range", TokenType: "keyword"},
{Token: "l", TokenType: "parameter"},
{Token: "// test coverage", TokenType: "comment"},
{Token: "return", TokenType: "keyword"},
{Token: "nil", TokenType: "variable", Mod: "readonly defaultLibrary"},
}
src := `
-- go.mod --
module example.com
go 1.19
-- main.go --
package foo
// Deprecated (for testing)
func Add[T int](target T, l []T) []T {
return append(l, target)
for range l {} // test coverage
return nil
}
`
WithOptions(
Modes(Default),
Settings{"semanticTokens": true},
).Run(t, src, func(t *testing.T, env *Env) {
env.OpenFile("main.go")
env.AfterChange(
Diagnostics(env.AtRegexp("main.go", "for range")),
)
seen := env.SemanticTokensFull("main.go")
if x := cmp.Diff(want, seen); x != "" {
t.Errorf("Semantic tokens do not match (-want +got):\n%s", x)
}
})
}
// fix inconsistency in TypeParameters
// https://github.com/golang/go/issues/57619
func TestSemantic_57619(t *testing.T) {
src := `
-- go.mod --
module example.com
go 1.19
-- main.go --
package foo
type Smap[K int, V any] struct {
Store map[K]V
}
func (s *Smap[K, V]) Get(k K) (V, bool) {
v, ok := s.Store[k]
return v, ok
}
func New[K int, V any]() Smap[K, V] {
return Smap[K, V]{Store: make(map[K]V)}
}
`
WithOptions(
Modes(Default),
Settings{"semanticTokens": true},
).Run(t, src, func(t *testing.T, env *Env) {
env.OpenFile("main.go")
seen := env.SemanticTokensFull("main.go")
for i, s := range seen {
if (s.Token == "K" || s.Token == "V") && s.TokenType != "typeParameter" {
t.Errorf("%d: expected K and V to be type parameters, but got %v", i, s)
}
}
})
}
func TestSemanticGoDirectives(t *testing.T) {
src := `
-- go.mod --
module example.com
go 1.19
-- main.go --
package foo
//go:linkname now time.Now
func now()
//go:noinline
func foo() {}
// Mentioning go:noinline should not tokenize.
//go:notadirective
func bar() {}
`
want := []fake.SemanticToken{
{Token: "package", TokenType: "keyword"},
{Token: "foo", TokenType: "namespace"},
{Token: "//", TokenType: "comment"},
{Token: "go:linkname", TokenType: "namespace"},
{Token: "now time.Now", TokenType: "comment"},
{Token: "func", TokenType: "keyword"},
{Token: "now", TokenType: "function", Mod: "definition"},
{Token: "//", TokenType: "comment"},
{Token: "go:noinline", TokenType: "namespace"},
{Token: "func", TokenType: "keyword"},
{Token: "foo", TokenType: "function", Mod: "definition"},
{Token: "// Mentioning go:noinline should not tokenize.", TokenType: "comment"},
{Token: "//go:notadirective", TokenType: "comment"},
{Token: "func", TokenType: "keyword"},
{Token: "bar", TokenType: "function", Mod: "definition"},
}
WithOptions(
Modes(Default),
Settings{"semanticTokens": true},
).Run(t, src, func(t *testing.T, env *Env) {
env.OpenFile("main.go")
seen := env.SemanticTokensFull("main.go")
if x := cmp.Diff(want, seen); x != "" {
t.Errorf("Semantic tokens do not match (-want +got):\n%s", x)
}
})
}