internal/lsp: enable enhanced hover by default

This change removes the explicit configuration for improved
documentation on hover. We use a comment's synopsis rather than the full
comment.

However, we also add a "noDocsOnHover" setting that is used by the cmd
tests. Ultimately, no one should use this setting and we should remove
it. We leave it temporarily because the cmd tests still need work.

Change-Id: I5488eca96a729ed7edad8f59b95af163903740d6
Reviewed-on: https://go-review.googlesource.com/c/tools/+/174378
Run-TryBot: Rebecca Stambler <rstambler@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Cottrell <iancottrell@google.com>
This commit is contained in:
Rebecca Stambler 2019-04-27 22:45:06 -04:00
parent e5f21acdc3
commit abbb706b23
15 changed files with 92 additions and 228 deletions

View File

@ -273,7 +273,10 @@ func (c *cmdClient) Configuration(ctx context.Context, p *protocol.Configuration
}
env[l[0]] = l[1]
}
results[i] = map[string]interface{}{"env": env}
results[i] = map[string]interface{}{
"env": env,
"noDocsOnHover": true,
}
}
return results, nil
}

View File

@ -8,7 +8,6 @@ import (
"context"
"fmt"
"os"
"os/exec"
"path/filepath"
"regexp"
"runtime"
@ -31,14 +30,11 @@ type godefMode int
const (
plainGodef = godefMode(1 << iota)
jsonGoDef
guruGoDef
)
var godefModes = []godefMode{
plainGodef,
jsonGoDef,
guruGoDef,
jsonGoDef | guruGoDef,
}
func TestDefinitionHelpExample(t *testing.T) {
@ -52,7 +48,7 @@ func TestDefinitionHelpExample(t *testing.T) {
}
thisFile := filepath.Join(dir, "definition.go")
baseArgs := []string{"query", "definition"}
expect := regexp.MustCompile(`^[\w/\\:_-]+flag[/\\]flag.go:\d+:\d+-\d+: defined here as type flag.FlagSet struct{.*}$`)
expect := regexp.MustCompile(`(?s)^[\w/\\:_-]+flag[/\\]flag.go:\d+:\d+-\d+: defined here as FlagSet struct {.*}$`)
for _, query := range []string{
fmt.Sprintf("%v:%v:%v", thisFile, cmd.ExampleLine, cmd.ExampleColumn),
fmt.Sprintf("%v:#%v", thisFile, cmd.ExampleOffset)} {
@ -66,20 +62,6 @@ func TestDefinitionHelpExample(t *testing.T) {
}
}
var brokenDefinitionTests = map[string]bool{
// The following tests all have extra information in the description
"A-definition-json-guru": true,
"err-definition-json-guru": true,
"myUnclosedIf-definition-json-guru": true,
"Other-definition-json-guru": true,
"RandomParamY-definition-json-guru": true,
"S1-definition-json-guru": true,
"S2-definition-json-guru": true,
"Stuff-definition-json-guru": true,
"Thing-definition-json-guru": true,
"Things-definition-json-guru": true,
}
func (r *runner) Definition(t *testing.T, data tests.Definitions) {
for _, d := range data {
if d.IsType {
@ -94,21 +76,6 @@ func (r *runner) Definition(t *testing.T, data tests.Definitions) {
tag += "-json"
args = append(args, "-json")
}
if mode&guruGoDef != 0 {
if r.exporter.Name() != "GOPATH" {
//only run guru compatability tests in GOPATH mode
continue
}
if d.Name == "PackageFoo" {
//guru does not support definition on packages
continue
}
tag += "-guru"
args = append(args, "-emulate=guru")
}
if _, found := brokenDefinitionTests[tag]; found {
continue
}
args = append(args, "definition")
uri := d.Src.URI()
filename, err := uri.Filename()
@ -123,35 +90,8 @@ func (r *runner) Definition(t *testing.T, data tests.Definitions) {
if mode&jsonGoDef != 0 && runtime.GOOS == "windows" {
got = strings.Replace(got, "file:///", "file://", -1)
}
if mode&guruGoDef == 0 {
expect := string(r.data.Golden(tag, filename, func() ([]byte, error) {
return []byte(got), nil
}))
if got != expect {
t.Errorf("definition %v failed with %#v expected:\n%s\ngot:\n%s", tag, args, expect, got)
}
continue
}
guruArgs := []string{}
if mode&jsonGoDef != 0 {
guruArgs = append(guruArgs, "-json")
}
guruArgs = append(guruArgs, "definition", fmt.Sprint(d.Src))
expect := strings.TrimSpace(string(r.data.Golden(tag, filename, func() ([]byte, error) {
cmd := exec.Command("guru", guruArgs...)
cmd.Env = r.data.Exported.Config.Env
out, _ := cmd.Output()
if err != nil {
if _, ok := err.(*exec.ExitError); !ok {
return nil, fmt.Errorf("Could not run guru %v: %v\n%s", guruArgs, err, out)
}
}
result := normalizePaths(r.data, string(out))
// guru sometimes puts the full package path in type names, but we don't
if mode&jsonGoDef == 0 && d.Name != "AImport" {
result = strings.Replace(result, "golang.org/x/tools/internal/lsp/godef/", "", -1)
}
return []byte(result), nil
return []byte(got), nil
})))
if expect != "" && !strings.HasPrefix(got, expect) {
t.Errorf("definition %v failed with %#v expected:\n%q\ngot:\n%q", tag, args, expect, got)

View File

@ -169,9 +169,9 @@ func (s *Server) processConfig(view source.View, config interface{}) error {
if usePlaceholders, ok := c["usePlaceholders"].(bool); ok {
s.usePlaceholders = usePlaceholders
}
// Check if enhancedHover is enabled.
if enhancedHover, ok := c["enhancedHover"].(bool); ok {
s.enhancedHover = enhancedHover
// Check if user has disabled documentation on hover.
if noDocsOnHover, ok := c["noDocsOnHover"].(bool); ok {
s.noDocsOnHover = noDocsOnHover
}
return nil
}

View File

@ -32,7 +32,7 @@ func (s *Server) hover(ctx context.Context, params *protocol.TextDocumentPositio
if err != nil {
return nil, err
}
hover, err := ident.Hover(ctx, nil, s.enhancedHover, s.preferredContentFormat == protocol.Markdown)
hover, err := ident.Hover(ctx, nil, s.preferredContentFormat == protocol.Markdown, !s.noDocsOnHover)
if err != nil {
return nil, err
}

View File

@ -73,7 +73,7 @@ type Server struct {
// Configurations.
// TODO(rstambler): Separate these into their own struct?
usePlaceholders bool
enhancedHover bool
noDocsOnHover bool
insertTextFormat protocol.InsertTextFormat
configurationSupported bool
dynamicConfigurationSupported bool

View File

@ -8,6 +8,7 @@ import (
"context"
"fmt"
"go/ast"
"go/doc"
"go/format"
"go/token"
"go/types"
@ -17,7 +18,7 @@ import (
// formatter returns the a hover value formatted with its documentation.
type formatter func(interface{}, *ast.CommentGroup) (string, error)
func (i *IdentifierInfo) Hover(ctx context.Context, qf types.Qualifier, enhancedHover, markdownSupported bool) (string, error) {
func (i *IdentifierInfo) Hover(ctx context.Context, qf types.Qualifier, markdownSupported, wantComments bool) (string, error) {
file := i.File.GetAST(ctx)
if qf == nil {
pkg := i.File.GetPackage(ctx)
@ -25,11 +26,12 @@ func (i *IdentifierInfo) Hover(ctx context.Context, qf types.Qualifier, enhanced
}
var b strings.Builder
f := func(x interface{}, c *ast.CommentGroup) (string, error) {
if !wantComments {
c = nil
}
return writeHover(x, i.File.GetFileSet(ctx), &b, c, markdownSupported, qf)
}
obj := i.Declaration.Object
// TODO(rstambler): Remove this configuration when hover behavior is stable.
if enhancedHover {
switch node := i.Declaration.Node.(type) {
case *ast.GenDecl:
switch obj := obj.(type) {
@ -41,7 +43,6 @@ func (i *IdentifierInfo) Hover(ctx context.Context, qf types.Qualifier, enhanced
return f(obj, node.Doc)
}
}
}
return f(obj, nil)
}
@ -70,8 +71,8 @@ func formatGenDecl(node *ast.GenDecl, obj types.Object, typ types.Type, f format
// Handle types.
switch spec := spec.(type) {
case *ast.TypeSpec:
// If multiple types are declared in the same block.
if len(node.Specs) > 1 {
// If multiple types are declared in the same block.
return f(spec.Type, spec.Doc)
} else {
return f(spec, node.Doc)
@ -97,7 +98,7 @@ func formatVar(node ast.Spec, obj types.Object, f formatter) (string, error) {
// If we have a struct or interface declaration,
// we need to match the object to the corresponding field or method.
if fieldList != nil {
for i := 0; i < fieldList.NumFields(); i++ {
for i := 0; i < len(fieldList.List); i++ {
field := fieldList.List[i]
if field.Pos() <= obj.Pos() && obj.Pos() <= field.End() {
if field.Doc.Text() != "" {
@ -115,7 +116,8 @@ func formatVar(node ast.Spec, obj types.Object, f formatter) (string, error) {
// writeHover writes the hover for a given node and its documentation.
func writeHover(x interface{}, fset *token.FileSet, b *strings.Builder, c *ast.CommentGroup, markdownSupported bool, qf types.Qualifier) (string, error) {
if c != nil {
b.WriteString(c.Text())
// TODO(rstambler): Improve conversion from Go docs to markdown.
b.WriteString(doc.Synopsis(c.Text()))
b.WriteRune('\n')
}
if markdownSupported {

View File

@ -301,7 +301,7 @@ func (r *runner) Definition(t *testing.T, data tests.Definitions) {
if err != nil {
t.Fatalf("failed for %v: %v", d.Src, err)
}
hover, err := ident.Hover(ctx, nil, false, false)
hover, err := ident.Hover(ctx, nil, false, true)
if err != nil {
t.Fatalf("failed for %v: %v", d.Src, err)
}

View File

@ -1,6 +1,5 @@
-- Random-definition --
godef/a/random.go:3:6-12: defined here as func Random() int
-- Random-definition-guru --
-- Random-definition-json --
{
@ -20,14 +19,10 @@ godef/a/random.go:3:6-12: defined here as func Random() int
"description": "func Random() int"
}
-- Random-definition-json-guru --
-- Random-hover --
func Random() int
-- Random2-definition --
godef/a/random.go:8:6-13: defined here as func Random2(y int) int
-- Random2-definition-guru --
godef/a/random.go:8:6: defined here as func Random2(y int) int
-- Random2-definition-json --
{
@ -47,18 +42,10 @@ godef/a/random.go:8:6: defined here as func Random2(y int) int
"description": "func Random2(y int) int"
}
-- Random2-definition-json-guru --
{
"objpos": "godef/a/random.go:8:6",
"desc": "func Random2(y int) int"
}
-- Random2-hover --
func Random2(y int) int
-- err-definition --
godef/a/a.go:14:6-9: defined here as var err error
-- err-definition-guru --
godef/a/a.go:14:6: defined here as var err
-- err-definition-json --
{

View File

@ -1,7 +1,5 @@
-- Member-definition --
godef/a/d.go:6:2-8: defined here as field Member string
-- Member-definition-guru --
godef/a/d.go:6:2: defined here as field Member string
-- Member-definition-json --
{
@ -21,18 +19,11 @@ godef/a/d.go:6:2: defined here as field Member string
"description": "field Member string"
}
-- Member-definition-json-guru --
{
"objpos": "godef/a/d.go:6:2",
"desc": "field Member string"
}
-- Member-hover --
@Member
field Member string
-- Method-definition --
godef/a/d.go:15:16-22: defined here as func (Thing).Method(i int) string
-- Method-definition-guru --
godef/a/d.go:15:16: defined here as func (Thing).Method(i int) string
-- Method-definition-json --
{
@ -52,18 +43,10 @@ godef/a/d.go:15:16: defined here as func (Thing).Method(i int) string
"description": "func (Thing).Method(i int) string"
}
-- Method-definition-json-guru --
{
"objpos": "godef/a/d.go:15:16",
"desc": "func (Thing).Method(i int) string"
}
-- Method-hover --
func (Thing).Method(i int) string
-- Other-definition --
godef/a/d.go:9:5-10: defined here as var Other Thing
-- Other-definition-guru --
godef/a/d.go:9:5: defined here as var Other
-- Other-definition-json --
{
@ -86,9 +69,9 @@ godef/a/d.go:9:5: defined here as var Other
-- Other-hover --
var Other Thing
-- Thing-definition --
godef/a/d.go:5:6-11: defined here as type Thing struct{Member string}
-- Thing-definition-guru --
godef/a/d.go:5:6: defined here as type Thing
godef/a/d.go:5:6-11: defined here as Thing struct {
Member string //@Member
}
-- Thing-definition-json --
{
@ -105,15 +88,15 @@ godef/a/d.go:5:6: defined here as type Thing
"offset": 35
}
},
"description": "type Thing struct{Member string}"
"description": "Thing struct {\n\tMember string //@Member\n}"
}
-- Thing-hover --
type Thing struct{Member string}
Thing struct {
Member string //@Member
}
-- Things-definition --
godef/a/d.go:11:6-12: defined here as func Things(val []string) []Thing
-- Things-definition-guru --
godef/a/d.go:11:6: defined here as func Things
-- Things-definition-json --
{

View File

@ -1,6 +1,5 @@
-- PosSum-definition --
godef/a/random.go:16:15-18: defined here as func (*Pos).Sum() int
-- PosSum-definition-guru --
-- PosSum-definition-json --
{
@ -20,14 +19,10 @@ godef/a/random.go:16:15-18: defined here as func (*Pos).Sum() int
"description": "func (*Pos).Sum() int"
}
-- PosSum-definition-json-guru --
-- PosSum-hover --
func (*Pos).Sum() int
-- PosX-definition --
godef/a/random.go:13:2-3: defined here as field x int
-- PosX-definition-guru --
godef/a/random.go:13:2: defined here as field x int
-- PosX-definition-json --
{
@ -47,18 +42,11 @@ godef/a/random.go:13:2: defined here as field x int
"description": "field x int"
}
-- PosX-definition-json-guru --
{
"objpos": "godef/a/random.go:13:2",
"desc": "field x int"
}
-- PosX-hover --
@mark(PosX, "x"),mark(PosY, "y")
field x int
-- RandomParamY-definition --
godef/a/random.go:8:14-15: defined here as var y int
-- RandomParamY-definition-guru --
godef/a/random.go:8:14: defined here as var y
-- RandomParamY-definition-json --
{

View File

@ -1,7 +1,5 @@
-- A-definition --
godef/a/a.go:7:6-7: defined here as type a.A string
-- A-definition-guru --
godef/a/a.go:7:6: defined here as type a.A
godef/a/a.go:7:6-7: defined here as A string //@A
-- A-definition-json --
{
@ -18,15 +16,14 @@ godef/a/a.go:7:6: defined here as type a.A
"offset": 76
}
},
"description": "type a.A string"
"description": "A string //@A"
}
-- A-hover --
type a.A string
A string //@A
-- AImport-definition --
godef/b/b.go:5:2-3: defined here as package a ("golang.org/x/tools/internal/lsp/godef/a")
-- AImport-definition-guru --
godef/b/b.go:5:2: defined here as package a ("golang.org/x/tools/internal/lsp/godef/a")
-- AImport-definition-json --
{
@ -46,12 +43,6 @@ godef/b/b.go:5:2: defined here as package a ("golang.org/x/tools/internal/lsp/go
"description": "package a (\"golang.org/x/tools/internal/lsp/godef/a\")"
}
-- AImport-definition-json-guru --
{
"objpos": "godef/b/b.go:5:2",
"desc": "package a (\"golang.org/x/tools/internal/lsp/godef/a\")"
}
-- AImport-hover --
package a ("golang.org/x/tools/internal/lsp/godef/a")
-- PackageFoo-definition --
@ -77,9 +68,11 @@ foo/foo.go:1:9-12: defined here as
-- PackageFoo-hover --
-- S1-definition --
godef/b/b.go:8:6-8: defined here as type S1 struct{F1 int; S2; a.A}
-- S1-definition-guru --
godef/b/b.go:8:6: defined here as type S1
godef/b/b.go:8:6-8: defined here as S1 struct {
F1 int //@mark(S1F1, "F1")
S2 //@godef("S2", S2), mark(S1S2, "S2")
a.A //@godef("A", A)
}
-- S1-definition-json --
{
@ -96,15 +89,17 @@ godef/b/b.go:8:6: defined here as type S1
"offset": 198
}
},
"description": "type S1 struct{F1 int; S2; a.A}"
"description": "S1 struct {\n\tF1 int //@mark(S1F1, \"F1\")\n\tS2 //@godef(\"S2\", S2), mark(S1S2, \"S2\")\n\ta.A //@godef(\"A\", A)\n}"
}
-- S1-hover --
type S1 struct{F1 int; S2; a.A}
S1 struct {
F1 int //@mark(S1F1, "F1")
S2 //@godef("S2", S2), mark(S1S2, "S2")
a.A //@godef("A", A)
}
-- S1F1-definition --
godef/b/b.go:9:2-4: defined here as field F1 int
-- S1F1-definition-guru --
godef/b/b.go:9:2: defined here as field F1 int
-- S1F1-definition-json --
{
@ -124,18 +119,11 @@ godef/b/b.go:9:2: defined here as field F1 int
"description": "field F1 int"
}
-- S1F1-definition-json-guru --
{
"objpos": "godef/b/b.go:9:2",
"desc": "field F1 int"
}
-- S1F1-hover --
@mark(S1F1, "F1")
field F1 int
-- S1S2-definition --
godef/b/b.go:10:2-4: defined here as field S2 S2
-- S1S2-definition-guru --
godef/b/b.go:10:2: defined here as field S2 S2
-- S1S2-definition-json --
{
@ -155,18 +143,15 @@ godef/b/b.go:10:2: defined here as field S2 S2
"description": "field S2 S2"
}
-- S1S2-definition-json-guru --
{
"objpos": "godef/b/b.go:10:2",
"desc": "field S2 S2"
}
-- S1S2-hover --
@godef("S2", S2), mark(S1S2, "S2")
field S2 S2
-- S2-definition --
godef/b/b.go:14:6-8: defined here as type S2 struct{F1 string; F2 int; *a.A}
-- S2-definition-guru --
godef/b/b.go:14:6: defined here as type S2
godef/b/b.go:14:6-8: defined here as S2 struct {
F1 string //@mark(S2F1, "F1")
F2 int //@mark(S2F2, "F2")
*a.A //@godef("A", A),godef("a",AImport)
}
-- S2-definition-json --
{
@ -183,15 +168,17 @@ godef/b/b.go:14:6: defined here as type S2
"offset": 325
}
},
"description": "type S2 struct{F1 string; F2 int; *a.A}"
"description": "S2 struct {\n\tF1 string //@mark(S2F1, \"F1\")\n\tF2 int //@mark(S2F2, \"F2\")\n\t*a.A //@godef(\"A\", A),godef(\"a\",AImport)\n}"
}
-- S2-hover --
type S2 struct{F1 string; F2 int; *a.A}
S2 struct {
F1 string //@mark(S2F1, "F1")
F2 int //@mark(S2F2, "F2")
*a.A //@godef("A", A),godef("a",AImport)
}
-- S2F1-definition --
godef/b/b.go:15:2-4: defined here as field F1 string
-- S2F1-definition-guru --
godef/b/b.go:15:2: defined here as field F1 string
-- S2F1-definition-json --
{
@ -211,18 +198,11 @@ godef/b/b.go:15:2: defined here as field F1 string
"description": "field F1 string"
}
-- S2F1-definition-json-guru --
{
"objpos": "godef/b/b.go:15:2",
"desc": "field F1 string"
}
-- S2F1-hover --
@mark(S2F1, "F1")
field F1 string
-- S2F2-definition --
godef/b/b.go:16:2-4: defined here as field F2 int
-- S2F2-definition-guru --
godef/b/b.go:16:2: defined here as field F2 int
-- S2F2-definition-json --
{
@ -242,18 +222,11 @@ godef/b/b.go:16:2: defined here as field F2 int
"description": "field F2 int"
}
-- S2F2-definition-json-guru --
{
"objpos": "godef/b/b.go:16:2",
"desc": "field F2 int"
}
-- S2F2-hover --
@mark(S2F2, "F2")
field F2 int
-- Stuff-definition --
godef/a/a.go:9:6-11: defined here as func a.Stuff()
-- Stuff-definition-guru --
godef/a/a.go:9:6: defined here as func a.Stuff
-- Stuff-definition-json --
{

View File

@ -1,7 +1,9 @@
-- S1-definition --
godef/b/b.go:8:6-8: defined here as type S1 struct{F1 int; S2; a.A}
-- S1-definition-guru --
godef/b/b.go:8:6: defined here as type S1 struct{F1 int; S2; a.A}
godef/b/b.go:8:6-8: defined here as S1 struct {
F1 int //@mark(S1F1, "F1")
S2 //@godef("S2", S2), mark(S1S2, "S2")
a.A //@godef("A", A)
}
-- S1-definition-json --
{
@ -18,15 +20,17 @@ godef/b/b.go:8:6: defined here as type S1 struct{F1 int; S2; a.A}
"offset": 198
}
},
"description": "type S1 struct{F1 int; S2; a.A}"
"description": "S1 struct {\n\tF1 int //@mark(S1F1, \"F1\")\n\tS2 //@godef(\"S2\", S2), mark(S1S2, \"S2\")\n\ta.A //@godef(\"A\", A)\n}"
}
-- S1-hover --
type S1 struct{F1 int; S2; a.A}
S1 struct {
F1 int //@mark(S1F1, "F1")
S2 //@godef("S2", S2), mark(S1S2, "S2")
a.A //@godef("A", A)
}
-- S1F1-definition --
godef/b/b.go:9:2-4: defined here as field F1 int
-- S1F1-definition-guru --
godef/b/b.go:9:2: defined here as field F1 int
-- S1F1-definition-json --
{
@ -46,11 +50,6 @@ godef/b/b.go:9:2: defined here as field F1 int
"description": "field F1 int"
}
-- S1F1-definition-json-guru --
{
"objpos": "godef/b/b.go:9:2",
"desc": "field F1 int"
}
-- S1F1-hover --
@mark(S1F1, "F1")
field F1 int

View File

@ -1,7 +1,5 @@
-- Member-definition --
godef/a/d.go:6:2-8: defined here as field Member string
-- Member-definition-guru --
godef/a/d.go:6:2: defined here as field Member string
-- Member-definition-json --
{
@ -21,18 +19,11 @@ godef/a/d.go:6:2: defined here as field Member string
"description": "field Member string"
}
-- Member-definition-json-guru --
{
"objpos": "godef/a/d.go:6:2",
"desc": "field Member string"
}
-- Member-hover --
@Member
field Member string
-- Other-definition --
godef/a/d.go:9:5-10: defined here as var a.Other a.Thing
-- Other-definition-guru --
godef/a/d.go:9:5: defined here as var a.Other
-- Other-definition-json --
{
@ -55,9 +46,9 @@ godef/a/d.go:9:5: defined here as var a.Other
-- Other-hover --
var a.Other a.Thing
-- Thing-definition --
godef/a/d.go:5:6-11: defined here as type a.Thing struct{Member string}
-- Thing-definition-guru --
godef/a/d.go:5:6: defined here as type a.Thing
godef/a/d.go:5:6-11: defined here as Thing struct {
Member string //@Member
}
-- Thing-definition-json --
{
@ -74,15 +65,15 @@ godef/a/d.go:5:6: defined here as type a.Thing
"offset": 35
}
},
"description": "type a.Thing struct{Member string}"
"description": "Thing struct {\n\tMember string //@Member\n}"
}
-- Thing-hover --
type a.Thing struct{Member string}
Thing struct {
Member string //@Member
}
-- Things-definition --
godef/a/d.go:11:6-12: defined here as func a.Things(val []string) []a.Thing
-- Things-definition-guru --
godef/a/d.go:11:6: defined here as func a.Things
-- Things-definition-json --
{

View File

@ -1,7 +1,5 @@
-- myUnclosedIf-definition --
godef/broken/unclosedIf.go:7:7-19: defined here as var myUnclosedIf string
-- myUnclosedIf-definition-guru --
godef/broken/unclosedIf.go:7:7: defined here as var myUnclosedIf
-- myUnclosedIf-definition-json --
{

View File

@ -267,7 +267,7 @@ func Run(t *testing.T, tests Tests, data *Data) {
tests.Format(t, data.Formats)
})
t.Run("Definitions", func(t *testing.T) {
t.Run("Definition", func(t *testing.T) {
t.Helper()
if len(data.Definitions) != ExpectedDefinitionsCount {
t.Errorf("got %v definitions expected %v", len(data.Definitions), ExpectedDefinitionsCount)
@ -275,7 +275,7 @@ func Run(t *testing.T, tests Tests, data *Data) {
tests.Definition(t, data.Definitions)
})
t.Run("Highlights", func(t *testing.T) {
t.Run("Highlight", func(t *testing.T) {
t.Helper()
if len(data.Highlights) != ExpectedHighlightsCount {
t.Errorf("got %v highlights expected %v", len(data.Highlights), ExpectedHighlightsCount)
@ -299,7 +299,7 @@ func Run(t *testing.T, tests Tests, data *Data) {
tests.SignatureHelp(t, data.Signatures)
})
t.Run("Links", func(t *testing.T) {
t.Run("Link", func(t *testing.T) {
t.Helper()
linksCount := 0
for _, want := range data.Links {