golang.org/x/tools/gopls@v0.15.3/internal/test/integration/misc/semantictokens_test.go (about) 1 // Copyright 2021 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package misc 6 7 import ( 8 "fmt" 9 "strings" 10 "testing" 11 12 "github.com/google/go-cmp/cmp" 13 "golang.org/x/tools/gopls/internal/protocol" 14 . "golang.org/x/tools/gopls/internal/test/integration" 15 "golang.org/x/tools/gopls/internal/test/integration/fake" 16 ) 17 18 func TestBadURICrash_VSCodeIssue1498(t *testing.T) { 19 const src = ` 20 -- go.mod -- 21 module example.com 22 23 go 1.12 24 25 -- main.go -- 26 package main 27 28 func main() {} 29 30 ` 31 WithOptions( 32 Modes(Default), 33 Settings{"allExperiments": true}, 34 ).Run(t, src, func(t *testing.T, env *Env) { 35 params := &protocol.SemanticTokensParams{} 36 const badURI = "http://foo" 37 params.TextDocument.URI = badURI 38 // This call panicked in the past: golang/vscode-go#1498. 39 _, err := env.Editor.Server.SemanticTokensFull(env.Ctx, params) 40 41 // Requests to an invalid URI scheme now result in an LSP error. 42 got := fmt.Sprint(err) 43 want := `DocumentURI scheme is not 'file': http://foo` 44 if !strings.Contains(got, want) { 45 t.Errorf("SemanticTokensFull error is %v, want substring %q", got, want) 46 } 47 }) 48 } 49 50 // fix bug involving type parameters and regular parameters 51 // (golang/vscode-go#2527) 52 func TestSemantic_2527(t *testing.T) { 53 // these are the expected types of identifiers in text order 54 want := []fake.SemanticToken{ 55 {Token: "package", TokenType: "keyword"}, 56 {Token: "foo", TokenType: "namespace"}, 57 {Token: "// Deprecated (for testing)", TokenType: "comment"}, 58 {Token: "func", TokenType: "keyword"}, 59 {Token: "Add", TokenType: "function", Mod: "definition deprecated"}, 60 {Token: "T", TokenType: "typeParameter", Mod: "definition"}, 61 {Token: "int", TokenType: "type", Mod: "defaultLibrary"}, 62 {Token: "target", TokenType: "parameter", Mod: "definition"}, 63 {Token: "T", TokenType: "typeParameter"}, 64 {Token: "l", TokenType: "parameter", Mod: "definition"}, 65 {Token: "T", TokenType: "typeParameter"}, 66 {Token: "T", TokenType: "typeParameter"}, 67 {Token: "return", TokenType: "keyword"}, 68 {Token: "append", TokenType: "function", Mod: "defaultLibrary"}, 69 {Token: "l", TokenType: "parameter"}, 70 {Token: "target", TokenType: "parameter"}, 71 {Token: "for", TokenType: "keyword"}, 72 {Token: "range", TokenType: "keyword"}, 73 {Token: "l", TokenType: "parameter"}, 74 {Token: "// test coverage", TokenType: "comment"}, 75 {Token: "return", TokenType: "keyword"}, 76 {Token: "nil", TokenType: "variable", Mod: "readonly defaultLibrary"}, 77 } 78 src := ` 79 -- go.mod -- 80 module example.com 81 82 go 1.19 83 -- main.go -- 84 package foo 85 // Deprecated (for testing) 86 func Add[T int](target T, l []T) []T { 87 return append(l, target) 88 for range l {} // test coverage 89 return nil 90 } 91 ` 92 WithOptions( 93 Modes(Default), 94 Settings{"semanticTokens": true}, 95 ).Run(t, src, func(t *testing.T, env *Env) { 96 env.OpenFile("main.go") 97 env.AfterChange( 98 Diagnostics(env.AtRegexp("main.go", "for range")), 99 ) 100 seen := env.SemanticTokensFull("main.go") 101 if x := cmp.Diff(want, seen); x != "" { 102 t.Errorf("Semantic tokens do not match (-want +got):\n%s", x) 103 } 104 }) 105 106 } 107 108 // fix inconsistency in TypeParameters 109 // https://github.com/golang/go/issues/57619 110 func TestSemantic_57619(t *testing.T) { 111 src := ` 112 -- go.mod -- 113 module example.com 114 115 go 1.19 116 -- main.go -- 117 package foo 118 type Smap[K int, V any] struct { 119 Store map[K]V 120 } 121 func (s *Smap[K, V]) Get(k K) (V, bool) { 122 v, ok := s.Store[k] 123 return v, ok 124 } 125 func New[K int, V any]() Smap[K, V] { 126 return Smap[K, V]{Store: make(map[K]V)} 127 } 128 ` 129 WithOptions( 130 Modes(Default), 131 Settings{"semanticTokens": true}, 132 ).Run(t, src, func(t *testing.T, env *Env) { 133 env.OpenFile("main.go") 134 seen := env.SemanticTokensFull("main.go") 135 for i, s := range seen { 136 if (s.Token == "K" || s.Token == "V") && s.TokenType != "typeParameter" { 137 t.Errorf("%d: expected K and V to be type parameters, but got %v", i, s) 138 } 139 } 140 }) 141 } 142 143 func TestSemanticGoDirectives(t *testing.T) { 144 src := ` 145 -- go.mod -- 146 module example.com 147 148 go 1.19 149 -- main.go -- 150 package foo 151 152 //go:linkname now time.Now 153 func now() 154 155 //go:noinline 156 func foo() {} 157 158 // Mentioning go:noinline should not tokenize. 159 160 //go:notadirective 161 func bar() {} 162 ` 163 want := []fake.SemanticToken{ 164 {Token: "package", TokenType: "keyword"}, 165 {Token: "foo", TokenType: "namespace"}, 166 167 {Token: "//", TokenType: "comment"}, 168 {Token: "go:linkname", TokenType: "namespace"}, 169 {Token: "now time.Now", TokenType: "comment"}, 170 {Token: "func", TokenType: "keyword"}, 171 {Token: "now", TokenType: "function", Mod: "definition"}, 172 173 {Token: "//", TokenType: "comment"}, 174 {Token: "go:noinline", TokenType: "namespace"}, 175 {Token: "func", TokenType: "keyword"}, 176 {Token: "foo", TokenType: "function", Mod: "definition"}, 177 178 {Token: "// Mentioning go:noinline should not tokenize.", TokenType: "comment"}, 179 180 {Token: "//go:notadirective", TokenType: "comment"}, 181 {Token: "func", TokenType: "keyword"}, 182 {Token: "bar", TokenType: "function", Mod: "definition"}, 183 } 184 185 WithOptions( 186 Modes(Default), 187 Settings{"semanticTokens": true}, 188 ).Run(t, src, func(t *testing.T, env *Env) { 189 env.OpenFile("main.go") 190 seen := env.SemanticTokensFull("main.go") 191 if x := cmp.Diff(want, seen); x != "" { 192 t.Errorf("Semantic tokens do not match (-want +got):\n%s", x) 193 } 194 }) 195 } 196 197 // Make sure no zero-length tokens occur 198 func TestSemantic_65254(t *testing.T) { 199 src := ` 200 -- go.mod -- 201 module example.com 202 203 go 1.21 204 -- main.go -- 205 package main 206 207 /* a comment with an 208 209 empty line 210 */ 211 212 const bad = ` 213 214 src += "`foo" + ` 215 ` + "bar`" 216 want := []fake.SemanticToken{ 217 {Token: "package", TokenType: "keyword"}, 218 {Token: "main", TokenType: "namespace"}, 219 {Token: "/* a comment with an", TokenType: "comment"}, 220 // --- Note that the zero length line does not show up 221 {Token: "empty line", TokenType: "comment"}, 222 {Token: "*/", TokenType: "comment"}, 223 {Token: "const", TokenType: "keyword"}, 224 {Token: "bad", TokenType: "variable", Mod: "definition readonly"}, 225 {Token: "`foo", TokenType: "string"}, 226 // --- Note the zero length line does not show up 227 {Token: "\tbar`", TokenType: "string"}, 228 } 229 WithOptions( 230 Modes(Default), 231 Settings{"semanticTokens": true}, 232 ).Run(t, src, func(t *testing.T, env *Env) { 233 env.OpenFile("main.go") 234 seen := env.SemanticTokensFull("main.go") 235 if x := cmp.Diff(want, seen); x != "" { 236 t.Errorf("Semantic tokens do not match (-want +got):\n%s", x) 237 } 238 }) 239 }