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  }