diff options
Diffstat (limited to 'gopls/internal/regtest/marker')
18 files changed, 1347 insertions, 0 deletions
diff --git a/gopls/internal/regtest/marker/marker_test.go b/gopls/internal/regtest/marker/marker_test.go new file mode 100644 index 000000000..ac051a555 --- /dev/null +++ b/gopls/internal/regtest/marker/marker_test.go @@ -0,0 +1,21 @@ +// Copyright 2023 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package marker + +import ( + "testing" + + . "golang.org/x/tools/gopls/internal/lsp/regtest" +) + +// Note: we use a separate package for the marker tests so that we can easily +// compare their performance to the existing marker tests in ./internal/lsp. + +// TestMarkers runs the marker tests from the testdata directory. +// +// See RunMarkerTests for details on how marker tests work. +func TestMarkers(t *testing.T) { + RunMarkerTests(t, "testdata") +} diff --git a/gopls/internal/regtest/marker/testdata/definition/embed.txt b/gopls/internal/regtest/marker/testdata/definition/embed.txt new file mode 100644 index 000000000..e28c7fed6 --- /dev/null +++ b/gopls/internal/regtest/marker/testdata/definition/embed.txt @@ -0,0 +1,254 @@ +This test checks definition and hover operations over embedded fields and methods. + +-- go.mod -- +module mod.com + +go 1.18 + +-- a/a.go -- +package a + +type A string //@loc(AString, "A") + +func (_ A) Hi() {} //@loc(AHi, "Hi") + +type S struct { + Field int //@loc(SField, "Field") + R // embed a struct + H // embed an interface +} + +type R struct { + Field2 int //@loc(RField2, "Field2") +} + +func (_ R) Hey() {} //@loc(RHey, "Hey") + +type H interface { //@loc(H, "H") + Goodbye() //@loc(HGoodbye, "Goodbye") +} + +type I interface { //@loc(I, "I") + B() //@loc(IB, "B") + J +} + +type J interface { //@loc(J, "J") + Hello() //@loc(JHello, "Hello") +} + +-- b/b.go -- +package b + +import "mod.com/a" //@loc(AImport, re"\".*\"") + +type embed struct { + F int //@loc(F, "F") +} + +func (embed) M() //@loc(M, "M") + +type Embed struct { + embed + *a.A + a.I + a.S +} + +func _() { + e := Embed{} + e.Hi() //@def("Hi", AHi),hover("Hi", "Hi", AHi) + e.B() //@def("B", IB),hover("B", "B", IB) + _ = e.Field //@def("Field", SField),hover("Field", "Field", SField) + _ = e.Field2 //@def("Field2", RField2),hover("Field2", "Field2", RField2) + e.Hello() //@def("Hello", JHello),hover("Hello", "Hello",JHello) + e.Hey() //@def("Hey", RHey),hover("Hey", "Hey", RHey) + e.Goodbye() //@def("Goodbye", HGoodbye),hover("Goodbye", "Goodbye", HGoodbye) + e.M() //@def("M", M),hover("M", "M", M) + _ = e.F //@def("F", F),hover("F", "F", F) +} + +type aAlias = a.A //@loc(aAlias, "aAlias") + +type S1 struct { //@loc(S1, "S1") + F1 int //@loc(S1F1, "F1") + S2 //@loc(S1S2, "S2"),def("S2", S2),hover("S2", "S2", S2) + a.A //@def("A", AString),hover("A", "A", aA) + aAlias //@def("a", aAlias),hover("a", "aAlias", aAlias) +} + +type S2 struct { //@loc(S2, "S2") + F1 string //@loc(S2F1, "F1") + F2 int //@loc(S2F2, "F2") + *a.A //@def("A", AString),def("a",AImport) +} + +type S3 struct { + F1 struct { + a.A //@def("A", AString) + } +} + +func Bar() { + var x S1 //@def("S1", S1),hover("S1", "S1", S1) + _ = x.S2 //@def("S2", S1S2),hover("S2", "S2", S1S2) + _ = x.F1 //@def("F1", S1F1),hover("F1", "F1", S1F1) + _ = x.F2 //@def("F2", S2F2),hover("F2", "F2", S2F2) + _ = x.S2.F1 //@def("F1", S2F1),hover("F1", "F1", S2F1) +} + +-- b/c.go -- +package b + +var _ = S1{ //@def("S1", S1),hover("S1", "S1", S1) + F1: 99, //@def("F1", S1F1),hover("F1", "F1", S1F1) +} + +-- @AHi/hover.md -- +```go +func (a.A).Hi() +``` + +[`(a.A).Hi` on pkg.go.dev](https://pkg.go.dev/mod.com/a#A.Hi) +-- @F/hover.md -- +```go +field F int +``` + +@loc(F, "F") + + +[`(b.Embed).F` on pkg.go.dev](https://pkg.go.dev/mod.com/b#Embed.F) +-- @HGoodbye/hover.md -- +```go +func (a.H).Goodbye() +``` + +@loc(HGoodbye, "Goodbye") + + +[`(a.H).Goodbye` on pkg.go.dev](https://pkg.go.dev/mod.com/a#H.Goodbye) +-- @IB/hover.md -- +```go +func (a.I).B() +``` + +@loc(IB, "B") + + +[`(a.I).B` on pkg.go.dev](https://pkg.go.dev/mod.com/a#I.B) +-- @JHello/hover.md -- +```go +func (a.J).Hello() +``` + +@loc(JHello, "Hello") + + +[`(a.J).Hello` on pkg.go.dev](https://pkg.go.dev/mod.com/a#J.Hello) +-- @M/hover.md -- +```go +func (embed).M() +``` + +[`(b.Embed).M` on pkg.go.dev](https://pkg.go.dev/mod.com/b#Embed.M) +-- @RField2/hover.md -- +```go +field Field2 int +``` + +@loc(RField2, "Field2") + + +[`(a.R).Field2` on pkg.go.dev](https://pkg.go.dev/mod.com/a#R.Field2) +-- @RHey/hover.md -- +```go +func (a.R).Hey() +``` + +[`(a.R).Hey` on pkg.go.dev](https://pkg.go.dev/mod.com/a#R.Hey) +-- @S1/hover.md -- +```go +type S1 struct { + F1 int //@loc(S1F1, "F1") + S2 //@loc(S1S2, "S2"),def("S2", S2),hover("S2", "S2", S2) + a.A //@def("A", AString),hover("A", "A", aA) + aAlias //@def("a", aAlias),hover("a", "aAlias", aAlias) +} +``` + +[`b.S1` on pkg.go.dev](https://pkg.go.dev/mod.com/b#S1) +-- @S1F1/hover.md -- +```go +field F1 int +``` + +@loc(S1F1, "F1") + + +[`(b.S1).F1` on pkg.go.dev](https://pkg.go.dev/mod.com/b#S1.F1) +-- @S1S2/hover.md -- +```go +field S2 S2 +``` + +@loc(S1S2, "S2"),def("S2", S2),hover("S2", "S2", S2) + + +[`(b.S1).S2` on pkg.go.dev](https://pkg.go.dev/mod.com/b#S1.S2) +-- @S2/hover.md -- +```go +type S2 struct { + F1 string //@loc(S2F1, "F1") + F2 int //@loc(S2F2, "F2") + *a.A //@def("A", AString),def("a",AImport) +} +``` + +[`b.S2` on pkg.go.dev](https://pkg.go.dev/mod.com/b#S2) +-- @S2F1/hover.md -- +```go +field F1 string +``` + +@loc(S2F1, "F1") + + +[`(b.S2).F1` on pkg.go.dev](https://pkg.go.dev/mod.com/b#S2.F1) +-- @S2F2/hover.md -- +```go +field F2 int +``` + +@loc(S2F2, "F2") + + +[`(b.S2).F2` on pkg.go.dev](https://pkg.go.dev/mod.com/b#S2.F2) +-- @SField/hover.md -- +```go +field Field int +``` + +@loc(SField, "Field") + + +[`(a.S).Field` on pkg.go.dev](https://pkg.go.dev/mod.com/a#S.Field) +-- @aA/hover.md -- +```go +type A string + +func (a.A).Hi() +``` + +@loc(AString, "A") + + +[`a.A` on pkg.go.dev](https://pkg.go.dev/mod.com/a#A) +-- @aAlias/hover.md -- +```go +type aAlias = a.A + +func (a.A).Hi() +``` + +@loc(aAlias, "aAlias") diff --git a/gopls/internal/regtest/marker/testdata/definition/import.txt b/gopls/internal/regtest/marker/testdata/definition/import.txt new file mode 100644 index 000000000..9e5e5929a --- /dev/null +++ b/gopls/internal/regtest/marker/testdata/definition/import.txt @@ -0,0 +1,52 @@ +This test checks definition and hover over imports. +-- go.mod -- +module mod.com + +go 1.18 +-- foo/foo.go -- +package foo + +type Foo struct{} + +// DoFoo does foo. +func DoFoo() {} //@loc(DoFoo, "DoFoo") +-- bar/bar.go -- +package bar + +import ( + myFoo "mod.com/foo" //@loc(myFoo, "myFoo") +) + +var _ *myFoo.Foo //@def("myFoo", myFoo),hover("myFoo", "myFoo", myFoo) +-- bar/dotimport.go -- +package bar + +import . "mod.com/foo" + +func _() { + // variable of type foo.Foo + var _ Foo //@hover("_", "_", FooVar) + + DoFoo() //@hover("DoFoo", "DoFoo", DoFoo) +} +-- @DoFoo/hover.md -- +```go +func DoFoo() +``` + +DoFoo does foo. + + +[`foo.DoFoo` on pkg.go.dev](https://pkg.go.dev/mod.com/foo#DoFoo) +-- @FooVar/hover.md -- +```go +var _ Foo +``` + +variable of type foo.Foo +-- @myFoo/hover.md -- +```go +package myFoo ("mod.com/foo") +``` + +[`myFoo` on pkg.go.dev](https://pkg.go.dev/mod.com/foo) diff --git a/gopls/internal/regtest/marker/testdata/definition/misc.txt b/gopls/internal/regtest/marker/testdata/definition/misc.txt new file mode 100644 index 000000000..48f5d340c --- /dev/null +++ b/gopls/internal/regtest/marker/testdata/definition/misc.txt @@ -0,0 +1,230 @@ +This test exercises miscellaneous definition and hover requests. +-- go.mod -- +module mod.com + +go 1.16 +-- a.go -- +package a //@loc(aPackage, re"package (a)"),hover(aPackage, aPackage, aPackage) + +var ( + // x is a variable. + x string //@loc(x, "x"),hover(x, x, hoverx) +) + +// 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 //@hover("g", "g", hoverg) + + h = 2 //@hover("h", "h", hoverh) +) + +// z is a variable too. +var z string //@loc(z, "z"),hover(z, z, hoverz) + +func AStuff() { //@loc(AStuff, "AStuff") + x := 5 + Random2(x) //@def("dom2", Random2) + Random() //@def("()", Random) +} + +type H interface { //@loc(H, "H") + Goodbye() +} + +type I interface { //@loc(I, "I") + B() + J +} + +type J interface { //@loc(J, "J") + Hello() +} + +func _() { + // 1st type declaration block + type ( + a struct { //@hover("a", "a", hoverDeclBlocka) + x string + } + ) + + // 2nd type declaration block + type ( + // b has a comment + b struct{} //@hover("b", "b", hoverDeclBlockb) + ) + + // 3rd type declaration block + type ( + // c is a struct + c struct { //@hover("c", "c", hoverDeclBlockc) + f string + } + + d string //@hover("d", "d", hoverDeclBlockd) + ) + + type ( + e struct { //@hover("e", "e", hoverDeclBlocke) + f float64 + } // e has a comment + ) +} + +var ( + hh H //@hover("H", "H", hoverH) + ii I //@hover("I", "I", hoverI) + jj J //@hover("J", "J", hoverJ) +) +-- a_test.go -- +package a + +import ( + "testing" +) + +func TestA(t *testing.T) { //@hover("TestA", "TestA", hoverTestA) +} +-- random.go -- +package a + +func Random() int { //@loc(Random, "Random") + y := 6 + 7 + return y +} + +func Random2(y int) int { //@loc(Random2, "Random2"),loc(RandomParamY, "y") + return y //@def("y", RandomParamY),hover("y", "y", hovery) +} + +type Pos struct { + x, y int //@loc(PosX, "x"),loc(PosY, "y") +} + +// Typ has a comment. Its fields do not. +type Typ struct{ field string } //@loc(TypField, "field") + +func _() { + x := &Typ{} + _ = x.field //@def("field", TypField),hover("field", "field", hoverfield) +} + +func (p *Pos) Sum() int { //@loc(PosSum, "Sum") + return p.x + p.y //@hover("x", "x", hoverpx) +} + +func _() { + var p Pos + _ = p.Sum() //@def("()", PosSum),hover("()", `Sum`, hoverSum) +} +-- @aPackage/hover.md -- +-- @hoverDeclBlocka/hover.md -- +```go +type a struct { + x string +} +``` + +1st type declaration block +-- @hoverDeclBlockb/hover.md -- +```go +type b struct{} +``` + +b has a comment +-- @hoverDeclBlockc/hover.md -- +```go +type c struct { + f string +} +``` + +c is a struct +-- @hoverDeclBlockd/hover.md -- +```go +type d string +``` + +3rd type declaration block +-- @hoverDeclBlocke/hover.md -- +```go +type e struct { + f float64 +} +``` + +e has a comment +-- @hoverH/hover.md -- +```go +type H interface { + Goodbye() +} +``` + +[`a.H` on pkg.go.dev](https://pkg.go.dev/mod.com#H) +-- @hoverI/hover.md -- +```go +type I interface { + B() + J +} +``` + +[`a.I` on pkg.go.dev](https://pkg.go.dev/mod.com#I) +-- @hoverJ/hover.md -- +```go +type J interface { + Hello() +} +``` + +[`a.J` on pkg.go.dev](https://pkg.go.dev/mod.com#J) +-- @hoverSum/hover.md -- +```go +func (*Pos).Sum() int +``` + +[`(a.Pos).Sum` on pkg.go.dev](https://pkg.go.dev/mod.com#Pos.Sum) +-- @hoverTestA/hover.md -- +```go +func TestA(t *testing.T) +``` +-- @hoverfield/hover.md -- +```go +field field string +``` +-- @hoverg/hover.md -- +```go +const g untyped int = 1 +``` + +When I hover on g, I should see this comment. +-- @hoverh/hover.md -- +```go +const h untyped int = 2 +``` + +Constant block. When I hover on h, I should see this comment. +-- @hoverpx/hover.md -- +```go +field x int +``` + +@loc(PosX, "x"),loc(PosY, "y") +-- @hoverx/hover.md -- +```go +var x string +``` + +x is a variable. +-- @hovery/hover.md -- +```go +var y int +``` +-- @hoverz/hover.md -- +```go +var z string +``` + +z is a variable too. diff --git a/gopls/internal/regtest/marker/testdata/hover/basiclit.txt b/gopls/internal/regtest/marker/testdata/hover/basiclit.txt new file mode 100644 index 000000000..32527420d --- /dev/null +++ b/gopls/internal/regtest/marker/testdata/hover/basiclit.txt @@ -0,0 +1,60 @@ +This test checks gopls behavior when hovering over basic literals. +-- basiclit.go -- +package basiclit + +func _() { + _ = 'a' //@hover("'a'", "'a'", latinA) + _ = 0x61 //@hover("0x61", "0x61", latinA) + + _ = '\u2211' //@hover("'\\u2211'", "'\\u2211'", summation) + _ = 0x2211 //@hover("0x2211", "0x2211", summation) + _ = "foo \u2211 bar" //@hover("\\u2211", "\\u2211", summation) + + _ = '\a' //@hover("'\\a'", "'\\a'", control) + _ = "foo \a bar" //@hover("\\a", "\\a", control) + + _ = '\U0001F30A' //@hover("'\\U0001F30A'", "'\\U0001F30A'", waterWave) + _ = 0x0001F30A //@hover("0x0001F30A", "0x0001F30A", waterWave) + _ = "foo \U0001F30A bar" //@hover("\\U0001F30A", "\\U0001F30A", waterWave) + + _ = '\x7E' //@hover("'\\x7E'", "'\\x7E'", tilde) + _ = "foo \x7E bar" //@hover("\\x7E", "\\x7E", tilde) + _ = "foo \a bar" //@hover("\\a", "\\a", control) + + _ = '\173' //@hover("'\\173'", "'\\173'", leftCurly) + _ = "foo \173 bar" //@hover("\\173","\\173", leftCurly) + _ = "foo \173 bar \u2211 baz" //@hover("\\173","\\173", leftCurly) + _ = "foo \173 bar \u2211 baz" //@hover("\\u2211","\\u2211", summation) + _ = "foo\173bar\u2211baz" //@hover("\\173","\\173", leftCurly) + _ = "foo\173bar\u2211baz" //@hover("\\u2211","\\u2211", summation) + + // search for runes in string only if there is an escaped sequence + _ = "hello" //@hover(`"hello"`, _, _) + + // incorrect escaped rune sequences + _ = '\0' //@hover("'\\0'", _, _),diag(re`\\0()'`, re"illegal character") + _ = '\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", _, _) +) +-- @control/hover.md -- +U+0007, control +-- @latinA/hover.md -- +'a', U+0061, LATIN SMALL LETTER A +-- @leftCurly/hover.md -- +'{', U+007B, LEFT CURLY BRACKET +-- @summation/hover.md -- +'∑', U+2211, N-ARY SUMMATION +-- @tilde/hover.md -- +'~', U+007E, TILDE +-- @waterWave/hover.md -- +'🌊', U+1F30A, WATER WAVE diff --git a/gopls/internal/regtest/marker/testdata/hover/const.txt b/gopls/internal/regtest/marker/testdata/hover/const.txt new file mode 100644 index 000000000..cdb0e51e2 --- /dev/null +++ b/gopls/internal/regtest/marker/testdata/hover/const.txt @@ -0,0 +1,18 @@ +This test checks hovering over constants. +-- go.mod -- +module mod.com + +go 1.18 +-- c.go -- +package c + +const X = 0 //@hover("X", "X", bX) +-- @bX/hover.md -- +```go +const X untyped int = 0 +``` + +@hover("X", "X", bX) + + +[`c.X` on pkg.go.dev](https://pkg.go.dev/mod.com#X) diff --git a/gopls/internal/regtest/marker/testdata/hover/generics.txt b/gopls/internal/regtest/marker/testdata/hover/generics.txt new file mode 100644 index 000000000..673e860a3 --- /dev/null +++ b/gopls/internal/regtest/marker/testdata/hover/generics.txt @@ -0,0 +1,77 @@ +This file contains tests for hovering over generic Go code. + +-- flags -- +-min_go=go1.18 + +-- go.mod -- +// A go.mod is require for correct pkgsite links. +// TODO(rfindley): don't link to ad-hoc or command-line-arguments packages! +module mod.com + +go 1.18 + +-- generics.go -- +package generics + +type value[T any] struct { //hover("lue", "value", value),hover("T", "T", valueT) + val T //@hover("T", "T", valuevalT) + Q int //@hover("Q", "Q", valueQ) +} + +type Value[T any] struct { //@hover("T", "T", ValueT) + val T //@hover("T", "T", ValuevalT) + Q int //@hover("Q", "Q", ValueQ) +} + +// disabled - see issue #54822 +func F[P interface{ ~int | string }]() { // hover("P","P",Ptparam) + // disabled - see issue #54822 + var _ P // hover("P","P",Pvar) +} + +-- inferred.go -- +package generics + +func app[S interface{ ~[]E }, E interface{}](s S, e E) S { + return append(s, e) +} + +func _() { + _ = app[[]int] //@hover("app", "app", appint) + _ = app[[]int, int] //@hover("app", "app", appint) + // TODO(rfindley): eliminate this diagnostic. + _ = app[[]int]([]int{}, 0) //@hover("app", "app", appint),diag("[[]int]", re"unnecessary type arguments") + _ = app([]int{}, 0) //@hover("app", "app", appint) +} + +-- @ValueQ/hover.md -- +```go +field Q int +``` + +@hover("Q", "Q", ValueQ) + + +[`(generics.Value).Q` on pkg.go.dev](https://pkg.go.dev/mod.com#Value.Q) +-- @ValueT/hover.md -- +```go +type parameter T any +``` +-- @ValuevalT/hover.md -- +```go +type parameter T any +``` +-- @appint/hover.md -- +```go +func app(s []int, e int) []int // func[S interface{~[]E}, E interface{}](s S, e E) S +``` +-- @valueQ/hover.md -- +```go +field Q int +``` + +@hover("Q", "Q", valueQ) +-- @valuevalT/hover.md -- +```go +type parameter T any +``` diff --git a/gopls/internal/regtest/marker/testdata/hover/goprivate.txt b/gopls/internal/regtest/marker/testdata/hover/goprivate.txt new file mode 100644 index 000000000..4c309ef38 --- /dev/null +++ b/gopls/internal/regtest/marker/testdata/hover/goprivate.txt @@ -0,0 +1,27 @@ +This test checks that links in hover obey GOPRIVATE. +-- env -- +GOPRIVATE=mod.com +-- go.mod -- +module mod.com +-- p.go -- +package p + +// T should not be linked, as it is private. +type T struct{} //@hover("T", "T", T) +-- lib/lib.go -- +package lib + +// GOPRIVATE should also match nested packages. +type L struct{} //@hover("L", "L", L) +-- @L/hover.md -- +```go +type L struct{} +``` + +GOPRIVATE should also match nested packages. +-- @T/hover.md -- +```go +type T struct{} +``` + +T should not be linked, as it is private. diff --git a/gopls/internal/regtest/marker/testdata/hover/hover.txt b/gopls/internal/regtest/marker/testdata/hover/hover.txt new file mode 100644 index 000000000..f9cd3311b --- /dev/null +++ b/gopls/internal/regtest/marker/testdata/hover/hover.txt @@ -0,0 +1,29 @@ +This test demonstrates some features of the new marker test runner. +-- a.go -- +package a + +const abc = 0x2a //@hover("b", "abc", abc),hover(" =", "abc", abc) +-- typeswitch.go -- +package a + +func _() { + var y interface{} + switch x := y.(type) { //@hover("x", "x", x) + case int: + println(x) //@hover("x", "x", xint),hover(")", "x", xint) + } +} +-- @abc/hover.md -- +```go +const abc untyped int = 42 +``` + +@hover("b", "abc", abc),hover(" =", "abc", abc) +-- @x/hover.md -- +```go +var x interface{} +``` +-- @xint/hover.md -- +```go +var x int +``` diff --git a/gopls/internal/regtest/marker/testdata/hover/linkable.txt b/gopls/internal/regtest/marker/testdata/hover/linkable.txt new file mode 100644 index 000000000..981716d84 --- /dev/null +++ b/gopls/internal/regtest/marker/testdata/hover/linkable.txt @@ -0,0 +1,120 @@ +This test checks that we correctly determine pkgsite links for various +identifiers. + +We should only produce links that work, meaning the object is reachable via the +package's public API. +-- go.mod -- +module mod.com + +go 1.18 +-- p.go -- +package p + +type E struct { + Embed int +} + +// T is in the package scope, and so should be linkable. +type T struct{ //@hover("T", "T", T) + // Only exported fields should be linkable + + f int //@hover("f", "f", f) + F int //@hover("F", "F", F) + + E + + // TODO(rfindley): is the link here correct? It ignores N. + N struct { + // Nested fields should also be linkable. + Nested int //@hover("Nested", "Nested", Nested) + } +} +// M is an exported method, and so should be linkable. +func (T) M() {} + +// m is not exported, and so should not be linkable. +func (T) m() {} + +func _() { + var t T + + // Embedded fields should be linkable. + _ = t.Embed //@hover("Embed", "Embed", Embed) + + // Local variables should not be linkable, even if they are capitalized. + var X int //@hover("X", "X", X) + _ = X + + // Local types should not be linkable, even if they are capitalized. + type Local struct { //@hover("Local", "Local", Local) + E + } + + // But the embedded field should still be linkable. + var l Local + _ = l.Embed //@hover("Embed", "Embed", Embed) +} +-- @Embed/hover.md -- +```go +field Embed int +``` + +[`(p.E).Embed` on pkg.go.dev](https://pkg.go.dev/mod.com#E.Embed) +-- @F/hover.md -- +```go +field F int +``` + +@hover("F", "F", F) + + +[`(p.T).F` on pkg.go.dev](https://pkg.go.dev/mod.com#T.F) +-- @Local/hover.md -- +```go +type Local struct { + E +} +``` + +Local types should not be linkable, even if they are capitalized. +-- @Nested/hover.md -- +```go +field Nested int +``` + +Nested fields should also be linkable. +-- @T/hover.md -- +```go +type T struct { + f int //@hover("f", "f", f) + F int //@hover("F", "F", F) + + E + + // TODO(rfindley): is the link here correct? It ignores N. + N struct { + // Nested fields should also be linkable. + Nested int //@hover("Nested", "Nested", Nested) + } +} + +func (T).M() +func (T).m() +``` + +T is in the package scope, and so should be linkable. + + +[`p.T` on pkg.go.dev](https://pkg.go.dev/mod.com#T) +-- @X/hover.md -- +```go +var X int +``` + +Local variables should not be linkable, even if they are capitalized. +-- @f/hover.md -- +```go +field f int +``` + +@hover("f", "f", f) diff --git a/gopls/internal/regtest/marker/testdata/hover/linkable_generics.txt b/gopls/internal/regtest/marker/testdata/hover/linkable_generics.txt new file mode 100644 index 000000000..be8e9e5cd --- /dev/null +++ b/gopls/internal/regtest/marker/testdata/hover/linkable_generics.txt @@ -0,0 +1,145 @@ +This file contains tests for documentation links to generic code in hover. + +-- flags -- +-min_go=go1.18 + +-- go.mod -- +module mod.com + +go 1.19 + +-- a.go -- +package a + +import "mod.com/generic" + +func _() { + // Hovering over instantiated object should produce accurate type + // information, but link to the generic declarations. + + var x generic.GT[int] //@hover("GT", "GT", xGT) + _ = x.F //@hover("x", "x", x),hover("F", "F", xF) + + f := generic.GF[int] //@hover("GF", "GF", fGF) + _ = f //@hover("f", "f", f) +} + +-- generic/generic.go -- +package generic + +// Hovering over type parameters should link to documentation. +// +// TODO(rfindley): should it? We should probably link to the type. +type GT[P any] struct{ //@hover("GT", "GT", GT),hover("P", "P", GTP) + F P //@hover("F", "F", F),hover("P", "P", FP) +} + +func (GT[P]) M(p P) { //@hover("GT", "GT", GTrecv),hover("M","M", M),hover(re"p (P)", re"p (P)", pP) +} + +func GF[P any] (p P) { //@hover("GF", "GF", GF) +} + +-- @F/hover.md -- +```go +field F P +``` + +@hover("F", "F", F),hover("P", "P", FP) + + +[`(generic.GT).F` on pkg.go.dev](https://pkg.go.dev/mod.com/generic#GT.F) +-- @FP/hover.md -- +```go +type parameter P any +``` +-- @GF/hover.md -- +```go +func GF[P any](p P) +``` + +[`generic.GF` on pkg.go.dev](https://pkg.go.dev/mod.com/generic#GF) +-- @GT/hover.md -- +```go +type GT[P any] struct { + F P //@hover("F", "F", F),hover("P", "P", FP) +} + +func (GT[P]).M(p P) +``` + +Hovering over type parameters should link to documentation. + +TODO(rfindley): should it? We should probably link to the type. + + +[`generic.GT` on pkg.go.dev](https://pkg.go.dev/mod.com/generic#GT) +-- @GTP/hover.md -- +```go +type parameter P any +``` +-- @GTrecv/hover.md -- +```go +type GT[P any] struct { + F P //@hover("F", "F", F),hover("P", "P", FP) +} + +func (GT[P]).M(p P) +``` + +Hovering over type parameters should link to documentation. + +TODO(rfindley): should it? We should probably link to the type. + + +[`generic.GT` on pkg.go.dev](https://pkg.go.dev/mod.com/generic#GT) +-- @M/hover.md -- +```go +func (GT[P]).M(p P) +``` + +[`(generic.GT).M` on pkg.go.dev](https://pkg.go.dev/mod.com/generic#GT.M) +-- @f/hover.md -- +```go +var f func(p int) +``` +-- @fGF/hover.md -- +```go +func generic.GF(p int) // func[P any](p P) +``` + +[`generic.GF` on pkg.go.dev](https://pkg.go.dev/mod.com/generic#GF) +-- @pP/hover.md -- +```go +type parameter P any +``` +-- @x/hover.md -- +```go +var x generic.GT[int] +``` + +@hover("GT", "GT", xGT) +-- @xF/hover.md -- +```go +field F int +``` + +@hover("F", "F", F),hover("P", "P", FP) + + +[`(generic.GT).F` on pkg.go.dev](https://pkg.go.dev/mod.com/generic#GT.F) +-- @xGT/hover.md -- +```go +type GT[P any] struct { + F P //@hover("F", "F", F),hover("P", "P", FP) +} + +func (generic.GT[P]).M(p P) +``` + +Hovering over type parameters should link to documentation. + +TODO(rfindley): should it? We should probably link to the type. + + +[`generic.GT` on pkg.go.dev](https://pkg.go.dev/mod.com/generic#GT) diff --git a/gopls/internal/regtest/marker/testdata/hover/std.txt b/gopls/internal/regtest/marker/testdata/hover/std.txt new file mode 100644 index 000000000..a526b5211 --- /dev/null +++ b/gopls/internal/regtest/marker/testdata/hover/std.txt @@ -0,0 +1,80 @@ +This test checks hover results for built-in or standard library symbols. + +It uses synopsis documentation as full documentation for some of these +built-ins varies across Go versions, where as it just so happens that the +synopsis does not. + +In the future we may need to limit this test to the latest Go version to avoid +documentation churn. +-- settings.json -- +{ + "hoverKind": "SynopsisDocumentation" +} +-- go.mod -- +module mod.com + +go 1.18 +-- std.go -- +package std + +import ( + "fmt" + "go/types" + "sync" +) + +func _() { + var err error //@loc(err, "err") + fmt.Printf("%v", err) //@def("err", err) + + var _ string //@hover("string", "string", hoverstring) + _ = make([]int, 0) //@hover("make", "make", hovermake) + + var mu sync.Mutex + mu.Lock() //@hover("Lock", "Lock", hoverLock) + + var typ *types.Named //@hover("types", "types", hoverTypes) + typ.Obj().Name() //@hover("Name", "Name", hoverName) +} +-- @hoverLock/hover.md -- +```go +func (*sync.Mutex).Lock() +``` + +Lock locks m. + + +[`(sync.Mutex).Lock` on pkg.go.dev](https://pkg.go.dev/sync#Mutex.Lock) +-- @hoverName/hover.md -- +```go +func (*types.object).Name() string +``` + +Name returns the object's (package-local, unqualified) name. + + +[`(types.TypeName).Name` on pkg.go.dev](https://pkg.go.dev/go/types#TypeName.Name) +-- @hoverTypes/hover.md -- +```go +package types ("go/types") +``` + +[`types` on pkg.go.dev](https://pkg.go.dev/go/types) +-- @hovermake/hover.md -- +```go +func make(t Type, size ...int) Type +``` + +The make built-in function allocates and initializes an object of type slice, map, or chan (only). + + +[`make` on pkg.go.dev](https://pkg.go.dev/builtin#make) +-- @hoverstring/hover.md -- +```go +type string string +``` + +string is the set of all strings of 8-bit bytes, conventionally but not necessarily representing UTF-8-encoded text. + + +[`string` on pkg.go.dev](https://pkg.go.dev/builtin#string) diff --git a/gopls/internal/regtest/marker/testdata/rename/basic.txt b/gopls/internal/regtest/marker/testdata/rename/basic.txt new file mode 100644 index 000000000..fe723cf9f --- /dev/null +++ b/gopls/internal/regtest/marker/testdata/rename/basic.txt @@ -0,0 +1,22 @@ +This test performs basic coverage of 'rename' within a single package. + +-- basic.go -- +package p + +func f(x int) { println(x) } //@rename("x", y, param_x) + +-- @param_x/basic.go -- +package p + +func f(y int) { println(y) } //@rename("x", y, param_x) + +-- errors.go -- +package p + +func _(x []int) { //@renameerr("_", blank, `can't rename "_"`) + x = append(x, 1) //@renameerr("append", blank, "built in and cannot be renamed") + x = nil //@renameerr("nil", blank, "built in and cannot be renamed") + x = nil //@renameerr("x", x, "old and new names are the same: x") + _ = 1 //@renameerr("1", x, "no identifier found") +} + diff --git a/gopls/internal/regtest/marker/testdata/rename/conflict.txt b/gopls/internal/regtest/marker/testdata/rename/conflict.txt new file mode 100644 index 000000000..18438c8a8 --- /dev/null +++ b/gopls/internal/regtest/marker/testdata/rename/conflict.txt @@ -0,0 +1,59 @@ +This test exercises some renaming conflict scenarios +and ensures that the errors are informative. + +-- go.mod -- +module example.com +go 1.12 + +-- super/p.go -- +package super + +var x int + +func f(y int) { + println(x) + println(y) //@renameerr("y", x, errSuperBlockConflict) +} + +-- @errSuperBlockConflict -- +super/p.go:5:8: renaming this var "y" to "x" +super/p.go:6:10: would shadow this reference +super/p.go:3:5: to the var declared here +-- sub/p.go -- +package sub + +var a int + +func f2(b int) { + println(a) //@renameerr("a", b, errSubBlockConflict) + println(b) +} + +-- @errSubBlockConflict -- +sub/p.go:3:5: renaming this var "a" to "b" +sub/p.go:6:10: would cause this reference to become shadowed +sub/p.go:5:9: by this intervening var definition +-- pkgname/p.go -- +package pkgname + +import e1 "errors" //@renameerr("e1", errors, errImportConflict) +import "errors" + +var _ = errors.New +var _ = e1.New + +-- @errImportConflict -- +pkgname/p.go:3:8: renaming this imported package name "e1" to "errors" +pkgname/p.go:4:8: conflicts with imported package name in same block +-- pkgname2/p1.go -- +package pkgname2 +var x int + +-- pkgname2/p2.go -- +package pkgname2 +import "errors" //@renameerr("errors", x, errImportConflict2) +var _ = errors.New + +-- @errImportConflict2 -- +pkgname2/p2.go:2:8: renaming this imported package name "errors" to "x" would conflict +pkgname2/p1.go:2:5: with this package member var diff --git a/gopls/internal/regtest/marker/testdata/rename/embed.txt b/gopls/internal/regtest/marker/testdata/rename/embed.txt new file mode 100644 index 000000000..68cf771bc --- /dev/null +++ b/gopls/internal/regtest/marker/testdata/rename/embed.txt @@ -0,0 +1,36 @@ +This test exercises renaming of types used as embedded fields. + +-- go.mod -- +module example.com +go 1.12 + +-- a/a.go -- +package a + +type A int //@rename("A", A2, type) + +-- b/b.go -- +package b + +import "example.com/a" + +type B struct { a.A } //@renameerr("A", A3, errAnonField) + +var _ = new(B).A //@renameerr("A", A4, errAnonField) + +-- @errAnonField -- +can't rename embedded fields: rename the type directly or name the field +-- @type/a/a.go -- +package a + +type A2 int //@rename("A", A2, type) + +-- @type/b/b.go -- +package b + +import "example.com/a" + +type B struct { a.A2 } //@renameerr("A", A3, errAnonField) + +var _ = new(B).A2 //@renameerr("A", A4, errAnonField) + diff --git a/gopls/internal/regtest/marker/testdata/rename/methods.txt b/gopls/internal/regtest/marker/testdata/rename/methods.txt new file mode 100644 index 000000000..1bd985bcf --- /dev/null +++ b/gopls/internal/regtest/marker/testdata/rename/methods.txt @@ -0,0 +1,67 @@ +This test exercises renaming of interface methods. + +The golden is currently wrong due to https://github.com/golang/go/issues/58506: +the reference to B.F in package b should be renamed too. + +-- go.mod -- +module example.com +go 1.12 + +-- a/a.go -- +package a + +type A int + +func (A) F() {} //@renameerr("F", G, errAfToG) + +-- b/b.go -- +package b + +import "example.com/a" +import "example.com/c" + +type B interface { F() } //@rename("F", G, BfToG) + +var _ B = a.A(0) +var _ B = c.C(0) + +-- c/c.go -- +package c + +type C int + +func (C) F() {} //@renameerr("F", G, errCfToG) + +-- d/d.go -- +package d + +import "example.com/b" + +var _ = b.B.F + +-- @errAfToG -- +a/a.go:5:10: renaming this method "F" to "G" +b/b.go:6:6: would make example.com/a.A no longer assignable to interface B +b/b.go:6:20: (rename example.com/b.B.F if you intend to change both types) +-- @BfToG/b/b.go -- +package b + +import "example.com/a" +import "example.com/c" + +type B interface { G() } //@rename("F", G, BfToG) + +var _ B = a.A(0) +var _ B = c.C(0) + +-- @BfToG/d/d.go -- +package d + +import "example.com/b" + +var _ = b.B.G + +-- @errCfToG -- +c/c.go:5:10: renaming this method "F" to "G" +b/b.go:6:6: would make example.com/c.C no longer assignable to interface B +b/b.go:6:20: (rename example.com/b.B.F if you intend to change both types) diff --git a/gopls/internal/regtest/marker/testdata/rename/typeswitch.txt b/gopls/internal/regtest/marker/testdata/rename/typeswitch.txt new file mode 100644 index 000000000..6743b99ef --- /dev/null +++ b/gopls/internal/regtest/marker/testdata/rename/typeswitch.txt @@ -0,0 +1,26 @@ +This test covers the special case of renaming a type switch var. + +-- p.go -- +package p + +func _(x interface{}) { + switch y := x.(type) { //@rename("y", z, yToZ) + case string: + print(y) //@rename("y", z, yToZ) + default: + print(y) //@rename("y", z, yToZ) + } +} + +-- @yToZ/p.go -- +package p + +func _(x interface{}) { + switch z := x.(type) { //@rename("y", z, yToZ) + case string: + print(z) //@rename("y", z, yToZ) + default: + print(z) //@rename("y", z, yToZ) + } +} + diff --git a/gopls/internal/regtest/marker/testdata/stubmethods/basic.txt b/gopls/internal/regtest/marker/testdata/stubmethods/basic.txt new file mode 100644 index 000000000..bb53e6767 --- /dev/null +++ b/gopls/internal/regtest/marker/testdata/stubmethods/basic.txt @@ -0,0 +1,24 @@ +This test exercises basic 'stub methods' functionality. + +-- go.mod -- +module example.com +go 1.12 + +-- a/a.go -- +package a + +type C int + +var _ error = C(0) //@suggestedfix(re"C.0.", re"missing method Error", "refactor.rewrite", stub) + +-- @stub/a/a.go -- +package a + +type C int + +// Error implements error +func (C) Error() string { + panic("unimplemented") +} + +var _ error = C(0) //@suggestedfix(re"C.0.", re"missing method Error", "refactor.rewrite", stub) |