aboutsummaryrefslogtreecommitdiff
path: root/gopls/internal/regtest/misc/semantictokens_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'gopls/internal/regtest/misc/semantictokens_test.go')
-rw-r--r--gopls/internal/regtest/misc/semantictokens_test.go172
1 files changed, 166 insertions, 6 deletions
diff --git a/gopls/internal/regtest/misc/semantictokens_test.go b/gopls/internal/regtest/misc/semantictokens_test.go
index 79507876a..a96024b9c 100644
--- a/gopls/internal/regtest/misc/semantictokens_test.go
+++ b/gopls/internal/regtest/misc/semantictokens_test.go
@@ -5,10 +5,14 @@
package misc
import (
+ "strings"
"testing"
- "golang.org/x/tools/internal/lsp/protocol"
- . "golang.org/x/tools/internal/lsp/regtest"
+ "github.com/google/go-cmp/cmp"
+ "golang.org/x/tools/gopls/internal/lsp"
+ "golang.org/x/tools/gopls/internal/lsp/protocol"
+ . "golang.org/x/tools/gopls/internal/lsp/regtest"
+ "golang.org/x/tools/internal/typeparams"
)
func TestBadURICrash_VSCodeIssue1498(t *testing.T) {
@@ -25,10 +29,8 @@ func main() {}
`
WithOptions(
- Modes(Singleton),
- EditorConfig{
- AllExperiments: true,
- },
+ Modes(Default),
+ Settings{"allExperiments": true},
).Run(t, src, func(t *testing.T, env *Env) {
params := &protocol.SemanticTokensParams{}
const badURI = "http://foo"
@@ -42,3 +44,161 @@ func main() {}
}
})
}
+
+// fix bug involving type parameters and regular parameters
+// (golang/vscode-go#2527)
+func TestSemantic_2527(t *testing.T) {
+ if !typeparams.Enabled {
+ t.Skip("type parameters are needed for this test")
+ }
+ // these are the expected types of identifiers in text order
+ want := []result{
+ {"package", "keyword", ""},
+ {"foo", "namespace", ""},
+ {"func", "keyword", ""},
+ {"Add", "function", "definition deprecated"},
+ {"T", "typeParameter", "definition"},
+ {"int", "type", "defaultLibrary"},
+ {"target", "parameter", "definition"},
+ {"T", "typeParameter", ""},
+ {"l", "parameter", "definition"},
+ {"T", "typeParameter", ""},
+ {"T", "typeParameter", ""},
+ {"return", "keyword", ""},
+ {"append", "function", "defaultLibrary"},
+ {"l", "parameter", ""},
+ {"target", "parameter", ""},
+ {"for", "keyword", ""},
+ {"range", "keyword", ""},
+ {"l", "parameter", ""},
+ {"return", "keyword", ""},
+ {"nil", "variable", "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")),
+ )
+ p := &protocol.SemanticTokensParams{
+ TextDocument: protocol.TextDocumentIdentifier{
+ URI: env.Sandbox.Workdir.URI("main.go"),
+ },
+ }
+ v, err := env.Editor.Server.SemanticTokensFull(env.Ctx, p)
+ if err != nil {
+ t.Fatal(err)
+ }
+ seen := interpret(v.Data, env.BufferText("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) {
+ if !typeparams.Enabled {
+ t.Skip("type parameters are needed for this test")
+ }
+ 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")
+ p := &protocol.SemanticTokensParams{
+ TextDocument: protocol.TextDocumentIdentifier{
+ URI: env.Sandbox.Workdir.URI("main.go"),
+ },
+ }
+ v, err := env.Editor.Server.SemanticTokensFull(env.Ctx, p)
+ if err != nil {
+ t.Fatal(err)
+ }
+ seen := interpret(v.Data, env.BufferText("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)
+ }
+ }
+ })
+}
+
+type result struct {
+ Token string
+ TokenType string
+ Mod string
+}
+
+// human-readable version of the semantic tokens
+// comment, string, number are elided
+// (and in the future, maybe elide other things, like operators)
+func interpret(x []uint32, contents string) []result {
+ lines := strings.Split(contents, "\n")
+ ans := []result{}
+ line, col := 1, 1
+ for i := 0; i < len(x); i += 5 {
+ line += int(x[i])
+ col += int(x[i+1])
+ if x[i] != 0 { // new line
+ col = int(x[i+1]) + 1 // 1-based column numbers
+ }
+ sz := x[i+2]
+ t := semanticTypes[x[i+3]]
+ if t == "comment" || t == "string" || t == "number" {
+ continue
+ }
+ l := x[i+4]
+ var mods []string
+ for i, mod := range semanticModifiers {
+ if l&(1<<i) != 0 {
+ mods = append(mods, mod)
+ }
+ }
+ // col is a utf-8 offset
+ tok := lines[line-1][col-1 : col-1+int(sz)]
+ ans = append(ans, result{tok, t, strings.Join(mods, " ")})
+ }
+ return ans
+}
+
+var (
+ semanticTypes = lsp.SemanticTypes()
+ semanticModifiers = lsp.SemanticModifiers()
+)