From cd7c003cd38984ebf592aa8e4755c832a8d632bf Mon Sep 17 00:00:00 2001 From: Jean-Hadrien Chabran Date: Fri, 30 Apr 2021 21:34:57 +0200 Subject: [PATCH] internal/lsp: add support for hovering runes Enable to hover runes found in basic literals in various forms. When a rune is found, the hover message provides a summary composed of a printable version (if it exists) of the rune, its codepoint and its name. Behaviour varies slightly depending on the basic literal: rune literals always display the summary when hovered, string literals only display it when an escaped rune sequence is found to avoid providing unnecessary information, and finally number literals only when expressed as a hexadecimal number whose size ranges from one to eight bytes. Fixes golang/go#38239 Change-Id: I024fdd5c511a45c7c285e200ce1eda0669a45491 Reviewed-on: https://go-review.googlesource.com/c/tools/+/321810 Reviewed-by: Rebecca Stambler Trust: Rebecca Stambler Trust: Robert Findley Run-TryBot: Rebecca Stambler gopls-CI: kokoro TryBot-Result: Go Bot --- go.mod | 1 + go.sum | 3 + internal/lsp/cmd/test/cmdtest.go | 4 + internal/lsp/lsp_test.go | 39 ++++- internal/lsp/source/hover.go | 155 ++++++++++++++++++ internal/lsp/source/source_test.go | 35 +++- internal/lsp/testdata/basiclit/basiclit.go | 43 +++++ .../lsp/testdata/cgo/declarecgo.go.golden | 2 +- .../lsp/testdata/cgoimport/usecgo.go.golden | 2 +- internal/lsp/testdata/godef/a/a.go | 30 ++-- internal/lsp/testdata/godef/a/a.go.golden | 40 ++--- .../lsp/testdata/godef/a/a_test.go.golden | 2 +- .../lsp/testdata/godef/a/a_x_test.go.golden | 2 +- internal/lsp/testdata/godef/a/d.go | 2 +- internal/lsp/testdata/godef/a/d.go.golden | 32 ++-- internal/lsp/testdata/godef/a/f.go | 4 +- internal/lsp/testdata/godef/a/f.go.golden | 6 +- internal/lsp/testdata/godef/a/g.go | 2 +- internal/lsp/testdata/godef/a/g.go.golden | 2 +- internal/lsp/testdata/godef/a/h.go | 46 +++--- internal/lsp/testdata/godef/a/h.go.golden | 46 +++--- .../lsp/testdata/godef/a/random.go.golden | 8 +- internal/lsp/testdata/godef/b/b.go | 14 +- internal/lsp/testdata/godef/b/b.go.golden | 78 ++++----- internal/lsp/testdata/godef/b/c.go.golden | 12 +- internal/lsp/testdata/godef/b/e.go | 6 +- internal/lsp/testdata/godef/b/e.go.golden | 30 ++-- internal/lsp/testdata/godef/b/h.go | 4 +- internal/lsp/testdata/godef/b/h.go.golden | 4 +- .../godef/broken/unclosedIf.go.golden | 2 +- .../godef/infer_generics/inferred.go.golden | 10 +- internal/lsp/tests/tests.go | 23 ++- 32 files changed, 491 insertions(+), 198 deletions(-) diff --git a/go.mod b/go.mod index 1c1dad4101..ff8184facb 100644 --- a/go.mod +++ b/go.mod @@ -8,5 +8,6 @@ require ( golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d golang.org/x/sync v0.0.0-20210220032951-036812b2e83c golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e + golang.org/x/text v0.3.6 golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 ) diff --git a/go.sum b/go.sum index a56a1307ae..b4edbe6be0 100644 --- a/go.sum +++ b/go.sum @@ -18,7 +18,10 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e h1:WUoyKPm6nCo1BnNUvPGnFG3T5DUVem42yDJZZ4CNxMA= golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= diff --git a/internal/lsp/cmd/test/cmdtest.go b/internal/lsp/cmd/test/cmdtest.go index 2e9272611d..832d794c7d 100644 --- a/internal/lsp/cmd/test/cmdtest.go +++ b/internal/lsp/cmd/test/cmdtest.go @@ -108,6 +108,10 @@ func (r *runner) AddImport(t *testing.T, uri span.URI, expectedImport string) { //TODO: import addition not supported on command line } +func (r *runner) Hover(t *testing.T, spn span.Span, info string) { + //TODO: hovering not supported on command line +} + func (r *runner) runGoplsCmd(t testing.TB, args ...string) (string, string) { rStdout, wStdout, err := os.Pipe() if err != nil { diff --git a/internal/lsp/lsp_test.go b/internal/lsp/lsp_test.go index f095489c79..d21d71d666 100644 --- a/internal/lsp/lsp_test.go +++ b/internal/lsp/lsp_test.go @@ -718,7 +718,7 @@ func (r *runner) Definition(t *testing.T, spn span.Span, d tests.Definition) { didSomething := false if hover != nil { didSomething = true - tag := fmt.Sprintf("%s-hover", d.Name) + tag := fmt.Sprintf("%s-hoverdef", d.Name) expectHover := string(r.data.Golden(tag, d.Src.URI().Filename(), func() ([]byte, error) { return []byte(hover.Contents.Value), nil })) @@ -840,6 +840,43 @@ func (r *runner) Highlight(t *testing.T, src span.Span, locations []span.Span) { } } +func (r *runner) Hover(t *testing.T, src span.Span, text string) { + m, err := r.data.Mapper(src.URI()) + if err != nil { + t.Fatal(err) + } + loc, err := m.Location(src) + if err != nil { + t.Fatalf("failed for %v", err) + } + tdpp := protocol.TextDocumentPositionParams{ + TextDocument: protocol.TextDocumentIdentifier{URI: loc.URI}, + Position: loc.Range.Start, + } + params := &protocol.HoverParams{ + TextDocumentPositionParams: tdpp, + } + hover, err := r.server.Hover(r.ctx, params) + if err != nil { + t.Fatal(err) + } + if text == "" { + if hover != nil { + t.Errorf("want nil, got %v\n", hover) + } + } else { + if hover == nil { + t.Fatalf("want hover result to include %s, but got nil", text) + } + if got := hover.Contents.Value; got != text { + t.Errorf("want %v, got %v\n", text, got) + } + if want, got := loc.Range, hover.Range; want != got { + t.Errorf("want range %v, got %v instead", want, got) + } + } +} + func (r *runner) References(t *testing.T, src span.Span, itemList []span.Span) { sm, err := r.data.Mapper(src.URI()) if err != nil { diff --git a/internal/lsp/source/hover.go b/internal/lsp/source/hover.go index 0bc92d1fb4..56666d352e 100644 --- a/internal/lsp/source/hover.go +++ b/internal/lsp/source/hover.go @@ -14,9 +14,12 @@ import ( "go/format" "go/token" "go/types" + "strconv" "strings" "time" + "unicode/utf8" + "golang.org/x/text/unicode/runenames" "golang.org/x/tools/internal/event" "golang.org/x/tools/internal/lsp/protocol" "golang.org/x/tools/internal/typeparams" @@ -66,6 +69,9 @@ type HoverInformation struct { func Hover(ctx context.Context, snapshot Snapshot, fh FileHandle, position protocol.Position) (*protocol.Hover, error) { ident, err := Identifier(ctx, snapshot, fh, position) if err != nil { + if hover, innerErr := hoverRune(ctx, snapshot, fh, position); innerErr == nil { + return hover, nil + } return nil, nil } h, err := HoverIdentifier(ctx, ident) @@ -93,6 +99,155 @@ func Hover(ctx context.Context, snapshot Snapshot, fh FileHandle, position proto }, nil } +func hoverRune(ctx context.Context, snapshot Snapshot, fh FileHandle, position protocol.Position) (*protocol.Hover, error) { + ctx, done := event.Start(ctx, "source.hoverRune") + defer done() + + r, mrng, err := findRune(ctx, snapshot, fh, position) + if err != nil { + return nil, err + } + rng, err := mrng.Range() + if err != nil { + return nil, err + } + + var desc string + runeName := runenames.Name(r) + if len(runeName) > 0 && runeName[0] == '<' { + // Check if the rune looks like an HTML tag. If so, trim the surrounding <> + // characters to work around https://github.com/microsoft/vscode/issues/124042. + runeName = strings.TrimRight(runeName[1:], ">") + } + if strconv.IsPrint(r) { + desc = fmt.Sprintf("'%s', U+%04X, %s", string(r), uint32(r), runeName) + } else { + desc = fmt.Sprintf("U+%04X, %s", uint32(r), runeName) + } + return &protocol.Hover{ + Contents: protocol.MarkupContent{ + Kind: snapshot.View().Options().PreferredContentFormat, + Value: desc, + }, + Range: rng, + }, nil +} + +// ErrNoRuneFound is the error returned when no rune is found at a particular position. +var ErrNoRuneFound = errors.New("no rune found") + +// findRune returns rune information for a position in a file. +func findRune(ctx context.Context, snapshot Snapshot, fh FileHandle, pos protocol.Position) (rune, MappedRange, error) { + pkg, pgf, err := GetParsedFile(ctx, snapshot, fh, NarrowestPackage) + if err != nil { + return 0, MappedRange{}, err + } + spn, err := pgf.Mapper.PointSpan(pos) + if err != nil { + return 0, MappedRange{}, err + } + rng, err := spn.Range(pgf.Mapper.Converter) + if err != nil { + return 0, MappedRange{}, err + } + + // Find the basic literal enclosing the given position, if there is one. + var lit *ast.BasicLit + var found bool + ast.Inspect(pgf.File, func(n ast.Node) bool { + if found { + return false + } + if n, ok := n.(*ast.BasicLit); ok && rng.Start >= n.Pos() && rng.Start <= n.End() { + lit = n + found = true + } + return !found + }) + if !found { + return 0, MappedRange{}, ErrNoRuneFound + } + + var r rune + var start, end token.Pos + switch lit.Kind { + case token.CHAR: + s, err := strconv.Unquote(lit.Value) + if err != nil { + // If the conversion fails, it's because of an invalid syntax, therefore + // there is no rune to be found. + return 0, MappedRange{}, ErrNoRuneFound + } + r, _ = utf8.DecodeRuneInString(s) + if r == utf8.RuneError { + return 0, MappedRange{}, fmt.Errorf("rune error") + } + start, end = lit.Pos(), lit.End() + case token.INT: + // It's an integer, scan only if it is a hex litteral whose bitsize in + // ranging from 8 to 32. + if !(strings.HasPrefix(lit.Value, "0x") && len(lit.Value[2:]) >= 2 && len(lit.Value[2:]) <= 8) { + return 0, MappedRange{}, ErrNoRuneFound + } + v, err := strconv.ParseUint(lit.Value[2:], 16, 32) + if err != nil { + return 0, MappedRange{}, err + } + r = rune(v) + if r == utf8.RuneError { + return 0, MappedRange{}, fmt.Errorf("rune error") + } + start, end = lit.Pos(), lit.End() + case token.STRING: + // It's a string, scan only if it contains a unicode escape sequence under or before the + // current cursor position. + var found bool + strMappedRng, err := posToMappedRange(snapshot, pkg, lit.Pos(), lit.End()) + if err != nil { + return 0, MappedRange{}, err + } + strRng, err := strMappedRng.Range() + if err != nil { + return 0, MappedRange{}, err + } + offset := strRng.Start.Character + for i := pos.Character - offset; i > 0; i-- { + // Start at the cursor position and search backward for the beginning of a rune escape sequence. + rr, _ := utf8.DecodeRuneInString(lit.Value[i:]) + if rr == utf8.RuneError { + return 0, MappedRange{}, fmt.Errorf("rune error") + } + if rr == '\\' { + // Got the beginning, decode it. + var tail string + r, _, tail, err = strconv.UnquoteChar(lit.Value[i:], '"') + if err != nil { + // If the conversion fails, it's because of an invalid syntax, therefore is no rune to be found. + return 0, MappedRange{}, ErrNoRuneFound + } + // Only the rune escape sequence part of the string has to be highlighted, recompute the range. + runeLen := len(lit.Value) - (int(i) + len(tail)) + start = token.Pos(int(lit.Pos()) + int(i)) + end = token.Pos(int(start) + runeLen) + found = true + break + } + } + if !found { + // No escape sequence found + return 0, MappedRange{}, ErrNoRuneFound + } + default: + return 0, MappedRange{}, ErrNoRuneFound + } + + mappedRange, err := posToMappedRange(snapshot, pkg, start, end) + if err != nil { + return 0, MappedRange{}, err + } + return r, mappedRange, nil +} + func HoverIdentifier(ctx context.Context, i *IdentifierInfo) (*HoverInformation, error) { ctx, done := event.Start(ctx, "source.Hover") defer done() diff --git a/internal/lsp/source/source_test.go b/internal/lsp/source/source_test.go index f1ab3ff4c2..83ce712c83 100644 --- a/internal/lsp/source/source_test.go +++ b/internal/lsp/source/source_test.go @@ -576,12 +576,12 @@ func (r *runner) Definition(t *testing.T, spn span.Span, d tests.Definition) { didSomething := false if hover != "" { didSomething = true - tag := fmt.Sprintf("%s-hover", d.Name) + tag := fmt.Sprintf("%s-hoverdef", d.Name) expectHover := string(r.data.Golden(tag, d.Src.URI().Filename(), func() ([]byte, error) { return []byte(hover), nil })) if hover != expectHover { - t.Errorf("hover for %s failed:\n%s", d.Src, tests.Diff(t, expectHover, hover)) + t.Errorf("hoverdef for %s failed:\n%s", d.Src, tests.Diff(t, expectHover, hover)) } } if !d.OnlyHover { @@ -682,6 +682,37 @@ func (r *runner) Highlight(t *testing.T, src span.Span, locations []span.Span) { } } +func (r *runner) Hover(t *testing.T, src span.Span, text string) { + ctx := r.ctx + _, srcRng, err := spanToRange(r.data, src) + if err != nil { + t.Fatal(err) + } + fh, err := r.snapshot.GetFile(r.ctx, src.URI()) + if err != nil { + t.Fatal(err) + } + hover, err := source.Hover(ctx, r.snapshot, fh, srcRng.Start) + if err != nil { + t.Errorf("hover failed for %s: %v", src.URI(), err) + } + if text == "" { + if hover != nil { + t.Errorf("want nil, got %v\n", hover) + } + } else { + if hover == nil { + t.Fatalf("want hover result to not be nil") + } + if got := hover.Contents.Value; got != text { + t.Errorf("want %v, got %v\n", got, text) + } + if want, got := srcRng, hover.Range; want != got { + t.Errorf("want range %v, got %v instead", want, got) + } + } +} + func (r *runner) References(t *testing.T, src span.Span, itemList []span.Span) { ctx := r.ctx _, srcRng, err := spanToRange(r.data, src) diff --git a/internal/lsp/testdata/basiclit/basiclit.go b/internal/lsp/testdata/basiclit/basiclit.go index ab895dc011..9829003d35 100644 --- a/internal/lsp/testdata/basiclit/basiclit.go +++ b/internal/lsp/testdata/basiclit/basiclit.go @@ -10,4 +10,47 @@ func _() { _ = 1. //@complete(".") _ = 'a' //@complete("' ") + + _ = 'a' //@hover("'a'", "'a', U+0061, LATIN SMALL LETTER A") + _ = 0x61 //@hover("0x61", "'a', U+0061, LATIN SMALL LETTER A") + + _ = '\u2211' //@hover("'\\u2211'", "'āˆ‘', U+2211, N-ARY SUMMATION") + _ = 0x2211 //@hover("0x2211", "'āˆ‘', U+2211, N-ARY SUMMATION") + _ = "foo \u2211 bar" //@hover("\\u2211", "'āˆ‘', U+2211, N-ARY SUMMATION") + + _ = '\a' //@hover("'\\a'", "U+0007, control") + _ = "foo \a bar" //@hover("\\a", "U+0007, control") + + _ = '\U0001F30A' //@hover("'\\U0001F30A'", "'🌊', U+1F30A, WATER WAVE") + _ = 0x0001F30A //@hover("0x0001F30A", "'🌊', U+1F30A, WATER WAVE") + _ = "foo \U0001F30A bar" //@hover("\\U0001F30A", "'🌊', U+1F30A, WATER WAVE") + + _ = '\x7E' //@hover("'\\x7E'", "'~', U+007E, TILDE") + _ = "foo \x7E bar" //@hover("\\x7E", "'~', U+007E, TILDE") + _ = "foo \a bar" //@hover("\\a", "U+0007, control") + + _ = '\173' //@hover("'\\173'", "'{', U+007B, LEFT CURLY BRACKET") + _ = "foo \173 bar" //@hover("\\173", "'{', U+007B, LEFT CURLY BRACKET") + _ = "foo \173 bar \u2211 baz" //@hover("\\173", "'{', U+007B, LEFT CURLY BRACKET") + _ = "foo \173 bar \u2211 baz" //@hover("\\u2211", "'āˆ‘', U+2211, N-ARY SUMMATION") + _ = "foo\173bar\u2211baz" //@hover("\\173", "'{', U+007B, LEFT CURLY BRACKET") + _ = "foo\173bar\u2211baz" //@hover("\\u2211", "'āˆ‘', U+2211, N-ARY SUMMATION") + + // search for runes in string only if there is an escaped sequence + _ = "hello" //@hover("\"hello\"", "") + + // incorrect escaped rune sequences + _ = '\0' //@hover("'\\0'", "") + _ = '\u22111' //@hover("'\\u22111'", "") + _ = '\U00110000' //@hover("'\\U00110000'", "") + _ = '\u12e45'//@hover("'\\u12e45'", "") + _ = '\xa' //@hover("'\\xa'", "") + _ = 'aa' //@hover("'aa'", "") + + // other basic lits + _ = 1 //@hover("1", "") + _ = 1.2 //@hover("1.2", "") + _ = 1.2i //@hover("1.2i", "") + _ = 0123 //@hover("0123", "") + _ = 0x1234567890 //@hover("0x1234567890", "") } diff --git a/internal/lsp/testdata/cgo/declarecgo.go.golden b/internal/lsp/testdata/cgo/declarecgo.go.golden index 773f3b7d3e..b6d94d0c6c 100644 --- a/internal/lsp/testdata/cgo/declarecgo.go.golden +++ b/internal/lsp/testdata/cgo/declarecgo.go.golden @@ -22,7 +22,7 @@ func Example() "description": "```go\nfunc Example()\n```\n\n[`cgo.Example` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/cgo?utm_source=gopls#Example)" } --- funccgoexample-hover -- +-- funccgoexample-hoverdef -- ```go func Example() ``` diff --git a/internal/lsp/testdata/cgoimport/usecgo.go.golden b/internal/lsp/testdata/cgoimport/usecgo.go.golden index 8f7518a154..f33f94f84a 100644 --- a/internal/lsp/testdata/cgoimport/usecgo.go.golden +++ b/internal/lsp/testdata/cgoimport/usecgo.go.golden @@ -22,7 +22,7 @@ func cgo.Example() "description": "```go\nfunc cgo.Example()\n```\n\n[`cgo.Example` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/cgo?utm_source=gopls#Example)" } --- funccgoexample-hover -- +-- funccgoexample-hoverdef -- ```go func cgo.Example() ``` diff --git a/internal/lsp/testdata/godef/a/a.go b/internal/lsp/testdata/godef/a/a.go index 993fd86b43..5cc85527ae 100644 --- a/internal/lsp/testdata/godef/a/a.go +++ b/internal/lsp/testdata/godef/a/a.go @@ -1,5 +1,5 @@ // Package a is a package for testing go to definition. -package a //@mark(aPackage, "a "),hover("a ", aPackage) +package a //@mark(aPackage, "a "),hoverdef("a ", aPackage) import ( "fmt" @@ -9,19 +9,19 @@ import ( var ( // x is a variable. - x string //@x,hover("x", x) + x string //@x,hoverdef("x", x) ) // Constant block. When I hover on h, I should see this comment. const ( // When I hover on g, I should see this comment. - g = 1 //@g,hover("g", g) + g = 1 //@g,hoverdef("g", g) - h = 2 //@h,hover("h", h) + h = 2 //@h,hoverdef("h", h) ) // z is a variable too. -var z string //@z,hover("z", z) +var z string //@z,hoverdef("z", z) type A string //@mark(AString, "A") @@ -33,14 +33,14 @@ func AStuff() { //@AStuff var err error //@err fmt.Printf("%v", err) //@godef("err", err) - var y string //@string,hover("string", string) - _ = make([]int, 0) //@make,hover("make", make) + var y string //@string,hoverdef("string", string) + _ = make([]int, 0) //@make,hoverdef("make", make) var mu sync.Mutex - mu.Lock() //@Lock,hover("Lock", Lock) + mu.Lock() //@Lock,hoverdef("Lock", Lock) - var typ *types.Named //@mark(typesImport, "types"),hover("types", typesImport) - typ.Obj().Name() //@Name,hover("Name", Name) + var typ *types.Named //@mark(typesImport, "types"),hoverdef("types", typesImport) + typ.Obj().Name() //@Name,hoverdef("Name", Name) } type A struct { @@ -76,7 +76,7 @@ type J interface { func _() { // 1st type declaration block type ( - a struct { //@mark(declBlockA, "a"),hover("a", declBlockA) + a struct { //@mark(declBlockA, "a"),hoverdef("a", declBlockA) x string } ) @@ -84,21 +84,21 @@ func _() { // 2nd type declaration block type ( // b has a comment - b struct{} //@mark(declBlockB, "b"),hover("b", declBlockB) + b struct{} //@mark(declBlockB, "b"),hoverdef("b", declBlockB) ) // 3rd type declaration block type ( // c is a struct - c struct { //@mark(declBlockC, "c"),hover("c", declBlockC) + c struct { //@mark(declBlockC, "c"),hoverdef("c", declBlockC) f string } - d string //@mark(declBlockD, "d"),hover("d", declBlockD) + d string //@mark(declBlockD, "d"),hoverdef("d", declBlockD) ) type ( - e struct { //@mark(declBlockE, "e"),hover("e", declBlockE) + e struct { //@mark(declBlockE, "e"),hoverdef("e", declBlockE) f float64 } // e has a comment ) diff --git a/internal/lsp/testdata/godef/a/a.go.golden b/internal/lsp/testdata/godef/a/a.go.golden index c26829350b..182928eebb 100644 --- a/internal/lsp/testdata/godef/a/a.go.golden +++ b/internal/lsp/testdata/godef/a/a.go.golden @@ -1,4 +1,4 @@ --- Lock-hover -- +-- Lock-hoverdef -- ```go func (*sync.Mutex).Lock() ``` @@ -6,7 +6,7 @@ func (*sync.Mutex).Lock() [`(sync.Mutex).Lock` on pkg.go.dev](https://pkg.go.dev/sync?utm_source=gopls#Mutex.Lock) Lock locks m\. --- Name-hover -- +-- Name-hoverdef -- ```go func (*types.object).Name() string ``` @@ -38,7 +38,7 @@ func Random() int "description": "```go\nfunc Random() int\n```\n\n[`a.Random` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/a?utm_source=gopls#Random)" } --- Random-hover -- +-- Random-hoverdef -- ```go func Random() int ``` @@ -68,15 +68,15 @@ func Random2(y int) int "description": "```go\nfunc Random2(y int) int\n```\n\n[`a.Random2` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/a?utm_source=gopls#Random2)" } --- Random2-hover -- +-- Random2-hoverdef -- ```go func Random2(y int) int ``` [`a.Random2` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/a?utm_source=gopls#Random2) --- aPackage-hover -- +-- aPackage-hoverdef -- Package a is a package for testing go to definition\. --- declBlockA-hover -- +-- declBlockA-hoverdef -- ```go type a struct { x string @@ -84,13 +84,13 @@ type a struct { ``` 1st type declaration block --- declBlockB-hover -- +-- declBlockB-hoverdef -- ```go type b struct{} ``` b has a comment --- declBlockC-hover -- +-- declBlockC-hoverdef -- ```go type c struct { f string @@ -98,13 +98,13 @@ type c struct { ``` c is a struct --- declBlockD-hover -- +-- declBlockD-hoverdef -- ```go type d string ``` 3rd type declaration block --- declBlockE-hover -- +-- declBlockE-hoverdef -- ```go type e struct { f float64 @@ -125,36 +125,36 @@ var err error "start": { "line": 33, "column": 6, - "offset": 597 + "offset": 612 }, "end": { "line": 33, "column": 9, - "offset": 600 + "offset": 615 } }, "description": "```go\nvar err error\n```\n\n\\@err" } --- err-hover -- +-- err-hoverdef -- ```go var err error ``` \@err --- g-hover -- +-- g-hoverdef -- ```go const g untyped int = 1 ``` When I hover on g, I should see this comment\. --- h-hover -- +-- h-hoverdef -- ```go const h untyped int = 2 ``` Constant block\. --- make-hover -- +-- make-hoverdef -- ```go func(t Type, size ...IntegerType) Type ``` @@ -162,23 +162,23 @@ func(t Type, size ...IntegerType) Type [`make` on pkg.go.dev](https://pkg.go.dev/builtin?utm_source=gopls#make) The make built\-in function allocates and initializes an object of type slice, map, or chan \(only\)\. --- string-hover -- +-- string-hoverdef -- ```go string ``` --- typesImport-hover -- +-- typesImport-hoverdef -- ```go package types ("go/types") ``` [`types` on pkg.go.dev](https://pkg.go.dev/go/types?utm_source=gopls) --- x-hover -- +-- x-hoverdef -- ```go var x string ``` x is a variable\. --- z-hover -- +-- z-hoverdef -- ```go var z string ``` diff --git a/internal/lsp/testdata/godef/a/a_test.go.golden b/internal/lsp/testdata/godef/a/a_test.go.golden index ac50b90b95..e5cb3d799c 100644 --- a/internal/lsp/testdata/godef/a/a_test.go.golden +++ b/internal/lsp/testdata/godef/a/a_test.go.golden @@ -20,7 +20,7 @@ func TestA(t *testing.T) "description": "```go\nfunc TestA(t *testing.T)\n```" } --- TestA-hover -- +-- TestA-hoverdef -- ```go func TestA(t *testing.T) ``` diff --git a/internal/lsp/testdata/godef/a/a_x_test.go.golden b/internal/lsp/testdata/godef/a/a_x_test.go.golden index dd1d740164..2e3064794f 100644 --- a/internal/lsp/testdata/godef/a/a_x_test.go.golden +++ b/internal/lsp/testdata/godef/a/a_x_test.go.golden @@ -20,7 +20,7 @@ func TestA2(t *testing.T) "description": "```go\nfunc TestA2(t *testing.T)\n```" } --- TestA2-hover -- +-- TestA2-hoverdef -- ```go func TestA2(t *testing.T) ``` diff --git a/internal/lsp/testdata/godef/a/d.go b/internal/lsp/testdata/godef/a/d.go index d20bdad988..2da8d058ed 100644 --- a/internal/lsp/testdata/godef/a/d.go +++ b/internal/lsp/testdata/godef/a/d.go @@ -1,4 +1,4 @@ -package a //@mark(a, "a "),hover("a ", a) +package a //@mark(a, "a "),hoverdef("a ", a) import "fmt" diff --git a/internal/lsp/testdata/godef/a/d.go.golden b/internal/lsp/testdata/godef/a/d.go.golden index d80c14a9df..23c7da1ec4 100644 --- a/internal/lsp/testdata/godef/a/d.go.golden +++ b/internal/lsp/testdata/godef/a/d.go.golden @@ -13,18 +13,18 @@ field Member string "start": { "line": 6, "column": 2, - "offset": 87 + "offset": 90 }, "end": { "line": 6, "column": 8, - "offset": 93 + "offset": 96 } }, "description": "```go\nfield Member string\n```\n\n[`(a.Thing).Member` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/a?utm_source=gopls#Thing.Member)\n\n\\@Member" } --- Member-hover -- +-- Member-hoverdef -- ```go field Member string ``` @@ -45,18 +45,18 @@ func (Thing).Method(i int) string "start": { "line": 15, "column": 16, - "offset": 216 + "offset": 219 }, "end": { "line": 15, "column": 22, - "offset": 222 + "offset": 225 } }, "description": "```go\nfunc (Thing).Method(i int) string\n```\n\n[`(a.Thing).Method` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/a?utm_source=gopls#Thing.Method)" } --- Method-hover -- +-- Method-hoverdef -- ```go func (Thing).Method(i int) string ``` @@ -77,18 +77,18 @@ var Other Thing "start": { "line": 9, "column": 5, - "offset": 118 + "offset": 121 }, "end": { "line": 9, "column": 10, - "offset": 123 + "offset": 126 } }, "description": "```go\nvar Other Thing\n```\n\n[`a.Other` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/a?utm_source=gopls#Other)\n\n\\@Other" } --- Other-hover -- +-- Other-hoverdef -- ```go var Other Thing ``` @@ -111,18 +111,18 @@ type Thing struct { "start": { "line": 5, "column": 6, - "offset": 62 + "offset": 65 }, "end": { "line": 5, "column": 11, - "offset": 67 + "offset": 70 } }, "description": "```go\ntype Thing struct {\n\tMember string //@Member\n}\n```\n\n[`a.Thing` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/a?utm_source=gopls#Thing)" } --- Thing-hover -- +-- Thing-hoverdef -- ```go type Thing struct { Member string //@Member @@ -143,22 +143,22 @@ func Things(val []string) []Thing "start": { "line": 11, "column": 6, - "offset": 145 + "offset": 148 }, "end": { "line": 11, "column": 12, - "offset": 151 + "offset": 154 } }, "description": "```go\nfunc Things(val []string) []Thing\n```\n\n[`a.Things` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/a?utm_source=gopls#Things)" } --- Things-hover -- +-- Things-hoverdef -- ```go func Things(val []string) []Thing ``` [`a.Things` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/a?utm_source=gopls#Things) --- a-hover -- +-- a-hoverdef -- Package a is a package for testing go to definition\. diff --git a/internal/lsp/testdata/godef/a/f.go b/internal/lsp/testdata/godef/a/f.go index 2d3eefcfbc..589c45fc1a 100644 --- a/internal/lsp/testdata/godef/a/f.go +++ b/internal/lsp/testdata/godef/a/f.go @@ -7,9 +7,9 @@ func TypeStuff() { //@Stuff switch y := interface{}(x).(type) { //@mark(switchY, "y"),godef("y", switchY) case int: //@mark(intY, "int") - fmt.Printf("%v", y) //@hover("y", intY) + fmt.Printf("%v", y) //@hoverdef("y", intY) case string: //@mark(stringY, "string") - fmt.Printf("%v", y) //@hover("y", stringY) + fmt.Printf("%v", y) //@hoverdef("y", stringY) } } diff --git a/internal/lsp/testdata/godef/a/f.go.golden b/internal/lsp/testdata/godef/a/f.go.golden index 6c84b4d5fa..a084356c06 100644 --- a/internal/lsp/testdata/godef/a/f.go.golden +++ b/internal/lsp/testdata/godef/a/f.go.golden @@ -1,8 +1,8 @@ --- intY-hover -- +-- intY-hoverdef -- ```go var y int ``` --- stringY-hover -- +-- stringY-hoverdef -- ```go var y string ``` @@ -28,7 +28,7 @@ var y interface{} "description": "```go\nvar y interface{}\n```" } --- switchY-hover -- +-- switchY-hoverdef -- ```go var y interface{} ``` diff --git a/internal/lsp/testdata/godef/a/g.go b/internal/lsp/testdata/godef/a/g.go index 4f31857e39..dfef2fb804 100644 --- a/internal/lsp/testdata/godef/a/g.go +++ b/internal/lsp/testdata/godef/a/g.go @@ -3,4 +3,4 @@ package a import "time" // dur is a constant of type time.Duration. -const dur = 15*time.Minute + 10*time.Second + 350*time.Millisecond //@dur,hover("dur", dur) +const dur = 15*time.Minute + 10*time.Second + 350*time.Millisecond //@dur,hoverdef("dur", dur) diff --git a/internal/lsp/testdata/godef/a/g.go.golden b/internal/lsp/testdata/godef/a/g.go.golden index d46ff048bd..b7ed739280 100644 --- a/internal/lsp/testdata/godef/a/g.go.golden +++ b/internal/lsp/testdata/godef/a/g.go.golden @@ -1,4 +1,4 @@ --- dur-hover -- +-- dur-hoverdef -- ```go const dur time.Duration = 910350000000 // 15m10.35s ``` diff --git a/internal/lsp/testdata/godef/a/h.go b/internal/lsp/testdata/godef/a/h.go index efe7d4ec12..5a5dcc6784 100644 --- a/internal/lsp/testdata/godef/a/h.go +++ b/internal/lsp/testdata/godef/a/h.go @@ -25,9 +25,9 @@ func _() { } var t s - _ = t.nested.number //@hover("number", nestedNumber) - _ = t.nested2[0].str //@hover("str", nestedString) - _ = t.x.x.x.x.x.m //@hover("m", nestedMap) + _ = t.nested.number //@hoverdef("number", nestedNumber) + _ = t.nested2[0].str //@hoverdef("str", nestedString) + _ = t.x.x.x.x.x.m //@hoverdef("m", nestedMap) } func _() { @@ -40,9 +40,9 @@ func _() { c int //@mark(structC, "c") } } - _ = s.a //@hover("a", structA) - _ = s.b //@hover("b", structB) - _ = s.b.c //@hover("c", structC) + _ = s.a //@hoverdef("a", structA) + _ = s.b //@hoverdef("b", structB) + _ = s.b.c //@hoverdef("c", structC) var arr []struct { // d field @@ -53,9 +53,9 @@ func _() { f int //@mark(arrF, "f") } } - _ = arr[0].d //@hover("d", arrD) - _ = arr[0].e //@hover("e", arrE) - _ = arr[0].e.f //@hover("f", arrF) + _ = arr[0].d //@hoverdef("d", arrD) + _ = arr[0].e //@hoverdef("e", arrE) + _ = arr[0].e.f //@hoverdef("f", arrF) var complex []struct { c <-chan map[string][]struct { @@ -68,16 +68,16 @@ func _() { } } } - _ = (<-complex[0].c)["0"][0].h //@hover("h", complexH) - _ = (<-complex[0].c)["0"][0].i //@hover("i", complexI) - _ = (<-complex[0].c)["0"][0].i.j //@hover("j", complexJ) + _ = (<-complex[0].c)["0"][0].h //@hoverdef("h", complexH) + _ = (<-complex[0].c)["0"][0].i //@hoverdef("i", complexI) + _ = (<-complex[0].c)["0"][0].i.j //@hoverdef("j", complexJ) var mapWithStructKey map[struct { // X key field x []string //@mark(mapStructKeyX, "x") }]int for k := range mapWithStructKey { - _ = k.x //@hover("x", mapStructKeyX) + _ = k.x //@hoverdef("x", mapStructKeyX) } var mapWithStructKeyAndValue map[struct { @@ -90,15 +90,15 @@ func _() { for k, v := range mapWithStructKeyAndValue { // TODO: we don't show docs for y field because both map key and value // are structs. And in this case, we parse only map value - _ = k.y //@hover("y", mapStructKeyY) - _ = v.x //@hover("x", mapStructValueX) + _ = k.y //@hoverdef("y", mapStructKeyY) + _ = v.x //@hoverdef("x", mapStructValueX) } var i []map[string]interface { // open method comment open() error //@mark(openMethod, "open") } - i[0]["1"].open() //@hover("open", openMethod) + i[0]["1"].open() //@hoverdef("open", openMethod) } func _() { @@ -106,7 +106,7 @@ func _() { // test description desc string //@mark(testDescription, "desc") }{} - _ = test.desc //@hover("desc", testDescription) + _ = test.desc //@hoverdef("desc", testDescription) for _, tt := range []struct { // test input @@ -123,11 +123,11 @@ func _() { } } }{} { - _ = tt.in //@hover("in", testInput) - _ = tt.in["0"][0].key //@hover("key", testInputKey) - _ = tt.in["0"][0].value //@hover("value", testInputValue) + _ = tt.in //@hoverdef("in", testInput) + _ = tt.in["0"][0].key //@hoverdef("key", testInputKey) + _ = tt.in["0"][0].value //@hoverdef("value", testInputValue) - _ = (<-tt.result.v).value //@hover("value", testResultValue) + _ = (<-tt.result.v).value //@hoverdef("value", testResultValue) } } @@ -142,6 +142,6 @@ func _() { } r := getPoints() - r[0].x //@hover("x", returnX) - r[0].y //@hover("y", returnY) + r[0].x //@hoverdef("x", returnX) + r[0].y //@hoverdef("y", returnY) } diff --git a/internal/lsp/testdata/godef/a/h.go.golden b/internal/lsp/testdata/godef/a/h.go.golden index 3525d4cfde..4b27211e9a 100644 --- a/internal/lsp/testdata/godef/a/h.go.golden +++ b/internal/lsp/testdata/godef/a/h.go.golden @@ -1,134 +1,134 @@ --- arrD-hover -- +-- arrD-hoverdef -- ```go field d int ``` d field --- arrE-hover -- +-- arrE-hoverdef -- ```go field e struct{f int} ``` e nested struct --- arrF-hover -- +-- arrF-hoverdef -- ```go field f int ``` f field of nested struct --- complexH-hover -- +-- complexH-hoverdef -- ```go field h int ``` h field --- complexI-hover -- +-- complexI-hoverdef -- ```go field i struct{j int} ``` i nested struct --- complexJ-hover -- +-- complexJ-hoverdef -- ```go field j int ``` j field of nested struct --- mapStructKeyX-hover -- +-- mapStructKeyX-hoverdef -- ```go field x []string ``` X key field --- mapStructKeyY-hover -- +-- mapStructKeyY-hoverdef -- ```go field y string ``` --- mapStructValueX-hover -- +-- mapStructValueX-hoverdef -- ```go field x string ``` X value field --- nestedMap-hover -- +-- nestedMap-hoverdef -- ```go field m map[string]float64 ``` nested map --- nestedNumber-hover -- +-- nestedNumber-hoverdef -- ```go field number int64 ``` nested number --- nestedString-hover -- +-- nestedString-hoverdef -- ```go field str string ``` nested string --- openMethod-hover -- +-- openMethod-hoverdef -- ```go func (interface).open() error ``` open method comment --- returnX-hover -- +-- returnX-hoverdef -- ```go field x int ``` X coord --- returnY-hover -- +-- returnY-hoverdef -- ```go field y int ``` Y coord --- structA-hover -- +-- structA-hoverdef -- ```go field a int ``` a field --- structB-hover -- +-- structB-hoverdef -- ```go field b struct{c int} ``` b nested struct --- structC-hover -- +-- structC-hoverdef -- ```go field c int ``` c field of nested struct --- testDescription-hover -- +-- testDescription-hoverdef -- ```go field desc string ``` test description --- testInput-hover -- +-- testInput-hoverdef -- ```go field in map[string][]struct{key string; value interface{}} ``` test input --- testInputKey-hover -- +-- testInputKey-hoverdef -- ```go field key string ``` test key --- testInputValue-hover -- +-- testInputValue-hoverdef -- ```go field value interface{} ``` test value --- testResultValue-hover -- +-- testResultValue-hoverdef -- ```go field value int ``` diff --git a/internal/lsp/testdata/godef/a/random.go.golden b/internal/lsp/testdata/godef/a/random.go.golden index 0f99a52f34..381a11acee 100644 --- a/internal/lsp/testdata/godef/a/random.go.golden +++ b/internal/lsp/testdata/godef/a/random.go.golden @@ -22,7 +22,7 @@ func (*Pos).Sum() int "description": "```go\nfunc (*Pos).Sum() int\n```\n\n[`(a.Pos).Sum` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/a?utm_source=gopls#Pos.Sum)" } --- PosSum-hover -- +-- PosSum-hoverdef -- ```go func (*Pos).Sum() int ``` @@ -52,7 +52,7 @@ field x int "description": "```go\nfield x int\n```\n\n\\@mark\\(PosX, \\\"x\\\"\\),mark\\(PosY, \\\"y\\\"\\)" } --- PosX-hover -- +-- PosX-hoverdef -- ```go field x int ``` @@ -80,7 +80,7 @@ var y int "description": "```go\nvar y int\n```" } --- RandomParamY-hover -- +-- RandomParamY-hoverdef -- ```go var y int ``` @@ -106,7 +106,7 @@ field field string "description": "```go\nfield field string\n```" } --- TypField-hover -- +-- TypField-hoverdef -- ```go field field string ``` diff --git a/internal/lsp/testdata/godef/b/b.go b/internal/lsp/testdata/godef/b/b.go index 23d908f1f8..f9c1d64024 100644 --- a/internal/lsp/testdata/godef/b/b.go +++ b/internal/lsp/testdata/godef/b/b.go @@ -13,13 +13,13 @@ type Embed struct { func _() { e := Embed{} - e.Hi() //@hover("Hi", AHi) - e.B() //@hover("B", AB) - e.Field //@hover("Field", AField) - e.Field2 //@hover("Field2", AField2) - e.Hello() //@hover("Hello", AHello) - e.Hey() //@hover("Hey", AHey) - e.Goodbye() //@hover("Goodbye", AGoodbye) + e.Hi() //@hoverdef("Hi", AHi) + e.B() //@hoverdef("B", AB) + e.Field //@hoverdef("Field", AField) + e.Field2 //@hoverdef("Field2", AField2) + e.Hello() //@hoverdef("Hello", AHello) + e.Hey() //@hoverdef("Hey", AHey) + e.Goodbye() //@hoverdef("Goodbye", AGoodbye) } type aAlias = a.A //@mark(aAlias, "aAlias") diff --git a/internal/lsp/testdata/godef/b/b.go.golden b/internal/lsp/testdata/godef/b/b.go.golden index 553718075f..7f05a70ce1 100644 --- a/internal/lsp/testdata/godef/b/b.go.golden +++ b/internal/lsp/testdata/godef/b/b.go.golden @@ -1,4 +1,4 @@ --- AB-hover -- +-- AB-hoverdef -- ```go func (a.I).B() ``` @@ -6,7 +6,7 @@ func (a.I).B() [`(a.I).B` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/a?utm_source=gopls#I.B) \@mark\(AB, \"B\"\) --- AField-hover -- +-- AField-hoverdef -- ```go field Field int ``` @@ -14,7 +14,7 @@ field Field int [`(a.S).Field` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/a?utm_source=gopls#S.Field) \@mark\(AField, \"Field\"\) --- AField2-hover -- +-- AField2-hoverdef -- ```go field Field2 int ``` @@ -22,7 +22,7 @@ field Field2 int [`(a.R).Field2` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/a?utm_source=gopls#R.Field2) \@mark\(AField2, \"Field2\"\) --- AGoodbye-hover -- +-- AGoodbye-hoverdef -- ```go func (a.H).Goodbye() ``` @@ -30,7 +30,7 @@ func (a.H).Goodbye() [`(a.H).Goodbye` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/a?utm_source=gopls#H.Goodbye) \@mark\(AGoodbye, \"Goodbye\"\) --- AHello-hover -- +-- AHello-hoverdef -- ```go func (a.J).Hello() ``` @@ -38,13 +38,13 @@ func (a.J).Hello() [`(a.J).Hello` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/a?utm_source=gopls#J.Hello) \@mark\(AHello, \"Hello\"\) --- AHey-hover -- +-- AHey-hoverdef -- ```go func (a.R).Hey() ``` [`(a.R).Hey` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/a?utm_source=gopls#R.Hey) --- AHi-hover -- +-- AHi-hoverdef -- ```go func (a.A).Hi() ``` @@ -74,7 +74,7 @@ package a ("golang.org/x/tools/internal/lsp/godef/a") "description": "```go\npackage a (\"golang.org/x/tools/internal/lsp/godef/a\")\n```\n\n[`a` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/a?utm_source=gopls)" } --- AImport-hover -- +-- AImport-hoverdef -- ```go package a ("golang.org/x/tools/internal/lsp/godef/a") ``` @@ -95,18 +95,18 @@ type A string "start": { "line": 26, "column": 6, - "offset": 452 + "offset": 467 }, "end": { "line": 26, "column": 7, - "offset": 453 + "offset": 468 } }, "description": "```go\ntype A string\n```\n\n[`a.A` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/a?utm_source=gopls#A)\n\n\\@mark\\(AString, \\\"A\\\"\\)" } --- AString-hover -- +-- AString-hoverdef -- ```go type A string ``` @@ -127,18 +127,18 @@ func a.AStuff() "start": { "line": 28, "column": 6, - "offset": 489 + "offset": 504 }, "end": { "line": 28, "column": 12, - "offset": 495 + "offset": 510 } }, "description": "```go\nfunc a.AStuff()\n```\n\n[`a.AStuff` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/a?utm_source=gopls#AStuff)" } --- AStuff-hover -- +-- AStuff-hoverdef -- ```go func a.AStuff() ``` @@ -162,18 +162,18 @@ type S1 struct { "start": { "line": 27, "column": 6, - "offset": 566 + "offset": 587 }, "end": { "line": 27, "column": 8, - "offset": 568 + "offset": 589 } }, "description": "```go\ntype S1 struct {\n\tF1 int //@mark(S1F1, \"F1\")\n\tS2 //@godef(\"S2\", S2),mark(S1S2, \"S2\")\n\ta.A //@godef(\"A\", AString)\n\taAlias //@godef(\"a\", aAlias)\n}\n```\n\n[`b.S1` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/b?utm_source=gopls#S1)" } --- S1-hover -- +-- S1-hoverdef -- ```go type S1 struct { F1 int //@mark(S1F1, "F1") @@ -199,18 +199,18 @@ field F1 int "start": { "line": 28, "column": 2, - "offset": 585 + "offset": 606 }, "end": { "line": 28, "column": 4, - "offset": 587 + "offset": 608 } }, "description": "```go\nfield F1 int\n```\n\n[`(b.S1).F1` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/b?utm_source=gopls#S1.F1)\n\n\\@mark\\(S1F1, \\\"F1\\\"\\)" } --- S1F1-hover -- +-- S1F1-hoverdef -- ```go field F1 int ``` @@ -233,18 +233,18 @@ field S2 S2 "start": { "line": 29, "column": 2, - "offset": 617 + "offset": 638 }, "end": { "line": 29, "column": 4, - "offset": 619 + "offset": 640 } }, "description": "```go\nfield S2 S2\n```\n\n[`(b.S1).S2` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/b?utm_source=gopls#S1.S2)\n\n\\@godef\\(\\\"S2\\\", S2\\),mark\\(S1S2, \\\"S2\\\"\\)" } --- S1S2-hover -- +-- S1S2-hoverdef -- ```go field S2 S2 ``` @@ -269,18 +269,18 @@ type S2 struct { "start": { "line": 34, "column": 6, - "offset": 741 + "offset": 762 }, "end": { "line": 34, "column": 8, - "offset": 743 + "offset": 764 } }, "description": "```go\ntype S2 struct {\n\tF1 string //@mark(S2F1, \"F1\")\n\tF2 int //@mark(S2F2, \"F2\")\n\t*a.A //@godef(\"A\", AString),godef(\"a\",AImport)\n}\n```\n\n[`b.S2` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/b?utm_source=gopls#S2)" } --- S2-hover -- +-- S2-hoverdef -- ```go type S2 struct { F1 string //@mark(S2F1, "F1") @@ -305,18 +305,18 @@ field F1 string "start": { "line": 35, "column": 2, - "offset": 760 + "offset": 781 }, "end": { "line": 35, "column": 4, - "offset": 762 + "offset": 783 } }, "description": "```go\nfield F1 string\n```\n\n[`(b.S2).F1` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/b?utm_source=gopls#S2.F1)\n\n\\@mark\\(S2F1, \\\"F1\\\"\\)" } --- S2F1-hover -- +-- S2F1-hoverdef -- ```go field F1 string ``` @@ -339,18 +339,18 @@ field F2 int "start": { "line": 36, "column": 2, - "offset": 793 + "offset": 814 }, "end": { "line": 36, "column": 4, - "offset": 795 + "offset": 816 } }, "description": "```go\nfield F2 int\n```\n\n[`(b.S2).F2` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/b?utm_source=gopls#S2.F2)\n\n\\@mark\\(S2F2, \\\"F2\\\"\\)" } --- S2F2-hover -- +-- S2F2-hoverdef -- ```go field F2 int ``` @@ -371,18 +371,18 @@ type aAlias = a.A "start": { "line": 25, "column": 6, - "offset": 521 + "offset": 542 }, "end": { "line": 25, "column": 12, - "offset": 527 + "offset": 548 } }, "description": "```go\ntype aAlias = a.A\n```\n\n\\@mark\\(aAlias, \\\"aAlias\\\"\\)" } --- aAlias-hover -- +-- aAlias-hoverdef -- ```go type aAlias = a.A ``` @@ -403,18 +403,18 @@ const X untyped int = 0 "start": { "line": 57, "column": 7, - "offset": 1228 + "offset": 1249 }, "end": { "line": 57, "column": 8, - "offset": 1229 + "offset": 1250 } }, "description": "```go\nconst X untyped int = 0\n```\n\n[`b.X` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/b?utm_source=gopls#X)\n\n\\@mark\\(bX, \\\"X\\\"\\),godef\\(\\\"X\\\", bX\\)" } --- bX-hover -- +-- bX-hoverdef -- ```go const X untyped int = 0 ``` @@ -446,7 +446,7 @@ package myFoo ("golang.org/x/tools/internal/lsp/foo") "description": "```go\npackage myFoo (\"golang.org/x/tools/internal/lsp/foo\")\n```\n\n[`myFoo` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/foo?utm_source=gopls)" } --- myFoo-hover -- +-- myFoo-hoverdef -- ```go package myFoo ("golang.org/x/tools/internal/lsp/foo") ``` diff --git a/internal/lsp/testdata/godef/b/c.go.golden b/internal/lsp/testdata/godef/b/c.go.golden index 9554c0d435..3ae3e2d0ac 100644 --- a/internal/lsp/testdata/godef/b/c.go.golden +++ b/internal/lsp/testdata/godef/b/c.go.golden @@ -16,18 +16,18 @@ type S1 struct { "start": { "line": 27, "column": 6, - "offset": 566 + "offset": 587 }, "end": { "line": 27, "column": 8, - "offset": 568 + "offset": 589 } }, "description": "```go\ntype S1 struct {\n\tF1 int //@mark(S1F1, \"F1\")\n\tS2 //@godef(\"S2\", S2),mark(S1S2, \"S2\")\n\ta.A //@godef(\"A\", AString)\n\taAlias //@godef(\"a\", aAlias)\n}\n```\n\n[`b.S1` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/b?utm_source=gopls#S1)" } --- S1-hover -- +-- S1-hoverdef -- ```go type S1 struct { F1 int //@mark(S1F1, "F1") @@ -53,18 +53,18 @@ field F1 int "start": { "line": 28, "column": 2, - "offset": 585 + "offset": 606 }, "end": { "line": 28, "column": 4, - "offset": 587 + "offset": 608 } }, "description": "```go\nfield F1 int\n```\n\n[`(b.S1).F1` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/b?utm_source=gopls#S1.F1)\n\n\\@mark\\(S1F1, \\\"F1\\\"\\)" } --- S1F1-hover -- +-- S1F1-hoverdef -- ```go field F1 int ``` diff --git a/internal/lsp/testdata/godef/b/e.go b/internal/lsp/testdata/godef/b/e.go index 92037ed339..7b96cd7e8a 100644 --- a/internal/lsp/testdata/godef/b/e.go +++ b/internal/lsp/testdata/godef/b/e.go @@ -22,10 +22,10 @@ godef(bFunc, Things) func _() { var x interface{} //@mark(eInterface, "interface{}") - switch x := x.(type) { //@hover("x", eInterface) + switch x := x.(type) { //@hoverdef("x", eInterface) case string: //@mark(eString, "string") - fmt.Println(x) //@hover("x", eString) + fmt.Println(x) //@hoverdef("x", eString) case int: //@mark(eInt, "int") - fmt.Println(x) //@hover("x", eInt) + fmt.Println(x) //@hoverdef("x", eInt) } } diff --git a/internal/lsp/testdata/godef/b/e.go.golden b/internal/lsp/testdata/godef/b/e.go.golden index 13c2e0eb5d..079ed7923c 100644 --- a/internal/lsp/testdata/godef/b/e.go.golden +++ b/internal/lsp/testdata/godef/b/e.go.golden @@ -13,18 +13,18 @@ field Member string "start": { "line": 6, "column": 2, - "offset": 87 + "offset": 90 }, "end": { "line": 6, "column": 8, - "offset": 93 + "offset": 96 } }, "description": "```go\nfield Member string\n```\n\n[`(a.Thing).Member` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/a?utm_source=gopls#Thing.Member)\n\n\\@Member" } --- Member-hover -- +-- Member-hoverdef -- ```go field Member string ``` @@ -47,18 +47,18 @@ var a.Other a.Thing "start": { "line": 9, "column": 5, - "offset": 118 + "offset": 121 }, "end": { "line": 9, "column": 10, - "offset": 123 + "offset": 126 } }, "description": "```go\nvar a.Other a.Thing\n```\n\n[`a.Other` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/a?utm_source=gopls#Other)\n\n\\@Other" } --- Other-hover -- +-- Other-hoverdef -- ```go var a.Other a.Thing ``` @@ -81,18 +81,18 @@ type Thing struct { "start": { "line": 5, "column": 6, - "offset": 62 + "offset": 65 }, "end": { "line": 5, "column": 11, - "offset": 67 + "offset": 70 } }, "description": "```go\ntype Thing struct {\n\tMember string //@Member\n}\n```\n\n[`a.Thing` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/a?utm_source=gopls#Thing)" } --- Thing-hover -- +-- Thing-hoverdef -- ```go type Thing struct { Member string //@Member @@ -113,32 +113,32 @@ func a.Things(val []string) []a.Thing "start": { "line": 11, "column": 6, - "offset": 145 + "offset": 148 }, "end": { "line": 11, "column": 12, - "offset": 151 + "offset": 154 } }, "description": "```go\nfunc a.Things(val []string) []a.Thing\n```\n\n[`a.Things` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/a?utm_source=gopls#Things)" } --- Things-hover -- +-- Things-hoverdef -- ```go func a.Things(val []string) []a.Thing ``` [`a.Things` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/a?utm_source=gopls#Things) --- eInt-hover -- +-- eInt-hoverdef -- ```go var x int ``` --- eInterface-hover -- +-- eInterface-hoverdef -- ```go var x interface{} ``` --- eString-hover -- +-- eString-hoverdef -- ```go var x string ``` diff --git a/internal/lsp/testdata/godef/b/h.go b/internal/lsp/testdata/godef/b/h.go index c2776a03a5..c8cbe850f9 100644 --- a/internal/lsp/testdata/godef/b/h.go +++ b/internal/lsp/testdata/godef/b/h.go @@ -4,7 +4,7 @@ import . "golang.org/x/tools/internal/lsp/godef/a" func _() { // variable of type a.A - var _ A //@mark(AVariable, "_"),hover("_", AVariable) + var _ A //@mark(AVariable, "_"),hoverdef("_", AVariable) - AStuff() //@hover("AStuff", AStuff) + AStuff() //@hoverdef("AStuff", AStuff) } diff --git a/internal/lsp/testdata/godef/b/h.go.golden b/internal/lsp/testdata/godef/b/h.go.golden index b854dd4ab3..f32f0264f8 100644 --- a/internal/lsp/testdata/godef/b/h.go.golden +++ b/internal/lsp/testdata/godef/b/h.go.golden @@ -1,10 +1,10 @@ --- AStuff-hover -- +-- AStuff-hoverdef -- ```go func AStuff() ``` [`a.AStuff` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/a?utm_source=gopls#AStuff) --- AVariable-hover -- +-- AVariable-hoverdef -- ```go var _ A ``` diff --git a/internal/lsp/testdata/godef/broken/unclosedIf.go.golden b/internal/lsp/testdata/godef/broken/unclosedIf.go.golden index eac0339236..5c3329d8b6 100644 --- a/internal/lsp/testdata/godef/broken/unclosedIf.go.golden +++ b/internal/lsp/testdata/godef/broken/unclosedIf.go.golden @@ -22,7 +22,7 @@ var myUnclosedIf string "description": "```go\nvar myUnclosedIf string\n```\n\n\\@myUnclosedIf" } --- myUnclosedIf-hover -- +-- myUnclosedIf-hoverdef -- ```go var myUnclosedIf string ``` diff --git a/internal/lsp/testdata/godef/infer_generics/inferred.go.golden b/internal/lsp/testdata/godef/infer_generics/inferred.go.golden index 2dd97d9b6a..081ea53dc0 100644 --- a/internal/lsp/testdata/godef/infer_generics/inferred.go.golden +++ b/internal/lsp/testdata/godef/infer_generics/inferred.go.golden @@ -1,20 +1,20 @@ --- argInfer-hover -- +-- argInfer-hoverdef -- ```go func app(s []int, e int) []int // func[S₁ interface{~[]Eā‚‚}, Eā‚‚ interface{}](s S₁, e Eā‚‚) S₁ ``` --- constrInf-hover -- +-- constrInf-hoverdef -- ```go func app(s []int, e int) []int // func[S₁ interface{~[]Eā‚‚}, Eā‚‚ interface{}](s S₁, e Eā‚‚) S₁ ``` --- constrInfer-hover -- +-- constrInfer-hoverdef -- ```go func app(s []int, e int) []int // func[S₁ interface{~[]Eā‚‚}, Eā‚‚ interface{}](s S₁, e Eā‚‚) S₁ ``` --- instance-hover -- +-- instance-hoverdef -- ```go func app(s []int, e int) []int // func[S₁ interface{~[]Eā‚‚}, Eā‚‚ interface{}](s S₁, e Eā‚‚) S₁ ``` --- partialInfer-hover -- +-- partialInfer-hoverdef -- ```go func app(s []int, e int) []int // func[S₁ interface{~[]Eā‚‚}, Eā‚‚ interface{}](s S₁, e Eā‚‚) S₁ ``` diff --git a/internal/lsp/tests/tests.go b/internal/lsp/tests/tests.go index d5db454b73..5d6af9ed1b 100644 --- a/internal/lsp/tests/tests.go +++ b/internal/lsp/tests/tests.go @@ -84,6 +84,7 @@ type WorkspaceSymbols map[WorkspaceSymbolsTestType]map[span.URI][]string type Signatures map[span.Span]*protocol.SignatureHelp type Links map[span.URI][]Link type AddImport map[span.URI]string +type Hovers map[span.Span]string type Data struct { Config packages.Config @@ -119,6 +120,7 @@ type Data struct { Signatures Signatures Links Links AddImport AddImport + Hovers Hovers t testing.TB fragments map[string]string @@ -161,6 +163,7 @@ type Tests interface { SignatureHelp(*testing.T, span.Span, *protocol.SignatureHelp) Link(*testing.T, span.URI, []Link) AddImport(*testing.T, span.URI, string) + Hover(*testing.T, span.Span, string) } type Definition struct { @@ -309,6 +312,7 @@ func load(t testing.TB, mode string, dir string) *Data { Signatures: make(Signatures), Links: make(Links), AddImport: make(AddImport), + Hovers: make(Hovers), t: t, dir: dir, @@ -459,7 +463,8 @@ func load(t testing.TB, mode string, dir string) *Data { "godef": datum.collectDefinitions, "implementations": datum.collectImplementations, "typdef": datum.collectTypeDefinitions, - "hover": datum.collectHoverDefinitions, + "hoverdef": datum.collectHoverDefinitions, + "hover": datum.collectHovers, "highlight": datum.collectHighlights, "refs": datum.collectReferences, "rename": datum.collectRenames, @@ -485,7 +490,7 @@ func load(t testing.TB, mode string, dir string) *Data { // Collect names for the entries that require golden files. if err := datum.Exported.Expect(map[string]interface{}{ "godef": datum.collectDefinitionNames, - "hover": datum.collectDefinitionNames, + "hoverdef": datum.collectDefinitionNames, "workspacesymbol": datum.collectWorkspaceSymbols(WorkspaceSymbolsDefault), "workspacesymbolfuzzy": datum.collectWorkspaceSymbols(WorkspaceSymbolsFuzzy), "workspacesymbolcasesensitive": datum.collectWorkspaceSymbols(WorkspaceSymbolsCaseSensitive), @@ -730,6 +735,16 @@ func Run(t *testing.T, tests Tests, data *Data) { } }) + t.Run("Hover", func(t *testing.T) { + t.Helper() + for pos, info := range data.Hovers { + t.Run(SpanName(pos), func(t *testing.T) { + t.Helper() + tests.Hover(t, pos, info) + }) + } + }) + t.Run("References", func(t *testing.T) { t.Helper() for src, itemList := range data.References { @@ -1222,6 +1237,10 @@ func (data *Data) collectHoverDefinitions(src, target span.Span) { } } +func (data *Data) collectHovers(src span.Span, expected string) { + data.Hovers[src] = expected +} + func (data *Data) collectTypeDefinitions(src, target span.Span) { data.Definitions[src] = Definition{ Src: src,