diff options
Diffstat (limited to 'gopls/internal/lsp/testdata')
386 files changed, 11612 insertions, 0 deletions
diff --git a/gopls/internal/lsp/testdata/%percent/perc%ent.go b/gopls/internal/lsp/testdata/%percent/perc%ent.go new file mode 100644 index 000000000..93b5e5570 --- /dev/null +++ b/gopls/internal/lsp/testdata/%percent/perc%ent.go @@ -0,0 +1 @@ +package percent diff --git a/gopls/internal/lsp/testdata/addimport/addimport.go.golden b/gopls/internal/lsp/testdata/addimport/addimport.go.golden new file mode 100644 index 000000000..9605aa6f9 --- /dev/null +++ b/gopls/internal/lsp/testdata/addimport/addimport.go.golden @@ -0,0 +1,7 @@ +-- addimport -- +package addimport //@addimport("", "bytes") + +import "bytes" + +func main() {} + diff --git a/gopls/internal/lsp/testdata/addimport/addimport.go.in b/gopls/internal/lsp/testdata/addimport/addimport.go.in new file mode 100644 index 000000000..07b454f52 --- /dev/null +++ b/gopls/internal/lsp/testdata/addimport/addimport.go.in @@ -0,0 +1,3 @@ +package addimport //@addimport("", "bytes") + +func main() {} diff --git a/gopls/internal/lsp/testdata/address/address.go b/gopls/internal/lsp/testdata/address/address.go new file mode 100644 index 000000000..3f1c2fa8d --- /dev/null +++ b/gopls/internal/lsp/testdata/address/address.go @@ -0,0 +1,78 @@ +package address + +func wantsPtr(*int) {} +func wantsVariadicPtr(...*int) {} + +func wantsVariadic(...int) {} + +type foo struct{ c int } //@item(addrFieldC, "c", "int", "field") + +func _() { + var ( + a string //@item(addrA, "a", "string", "var") + b int //@item(addrB, "b", "int", "var") + ) + + wantsPtr() //@rank(")", addrB, addrA),snippet(")", addrB, "&b", "&b") + wantsPtr(&b) //@snippet(")", addrB, "b", "b") + + wantsVariadicPtr() //@rank(")", addrB, addrA),snippet(")", addrB, "&b", "&b") + + var s foo + s.c //@item(addrDeepC, "s.c", "int", "field") + wantsPtr() //@snippet(")", addrDeepC, "&s.c", "&s.c") + wantsPtr(s) //@snippet(")", addrDeepC, "&s.c", "&s.c") + wantsPtr(&s) //@snippet(")", addrDeepC, "s.c", "s.c") + + // don't add "&" in item (it gets added as an additional edit) + wantsPtr(&s.c) //@snippet(")", addrFieldC, "c", "c") + + // check dereferencing as well + var c *int //@item(addrCPtr, "c", "*int", "var") + var _ int = _ //@rank("_ //", addrCPtr, addrA),snippet("_ //", addrCPtr, "*c", "*c") + + wantsVariadic() //@rank(")", addrCPtr, addrA),snippet(")", addrCPtr, "*c", "*c") + + var d **int //@item(addrDPtr, "d", "**int", "var") + var _ int = _ //@rank("_ //", addrDPtr, addrA),snippet("_ //", addrDPtr, "**d", "**d") + + type namedPtr *int + var np namedPtr //@item(addrNamedPtr, "np", "namedPtr", "var") + + var _ int = _ //@rank("_ //", addrNamedPtr, addrA) + + // don't get tripped up by recursive pointer type + type dontMessUp *dontMessUp + var dmu *dontMessUp //@item(addrDMU, "dmu", "*dontMessUp", "var") + + var _ int = dmu //@complete(" //", addrDMU) +} + +func (f foo) ptr() *foo { return &f } + +func _() { + getFoo := func() foo { return foo{} } + + // not addressable + getFoo().c //@item(addrGetFooC, "getFoo().c", "int", "field") + + // addressable + getFoo().ptr().c //@item(addrGetFooPtrC, "getFoo().ptr().c", "int", "field") + + wantsPtr() //@rank(addrGetFooPtrC, addrGetFooC),snippet(")", addrGetFooPtrC, "&getFoo().ptr().c", "&getFoo().ptr().c") + wantsPtr(&g) //@rank(addrGetFooPtrC, addrGetFooC),snippet(")", addrGetFooPtrC, "getFoo().ptr().c", "getFoo().ptr().c") +} + +type nested struct { + f foo +} + +func _() { + getNested := func() nested { return nested{} } + + getNested().f.c //@item(addrNestedC, "getNested().f.c", "int", "field") + getNested().f.ptr().c //@item(addrNestedPtrC, "getNested().f.ptr().c", "int", "field") + + // addrNestedC is not addressable, so rank lower + wantsPtr(getNestedfc) //@fuzzy(")", addrNestedPtrC, addrNestedC) +} diff --git a/gopls/internal/lsp/testdata/analyzer/bad_test.go b/gopls/internal/lsp/testdata/analyzer/bad_test.go new file mode 100644 index 000000000..b1724c666 --- /dev/null +++ b/gopls/internal/lsp/testdata/analyzer/bad_test.go @@ -0,0 +1,24 @@ +package analyzer + +import ( + "fmt" + "sync" + "testing" + "time" +) + +func Testbad(t *testing.T) { //@diag("", "tests", "Testbad has malformed name: first letter after 'Test' must not be lowercase", "warning") + var x sync.Mutex + _ = x //@diag("x", "copylocks", "assignment copies lock value to _: sync.Mutex", "warning") + + printfWrapper("%s") //@diag(re`printfWrapper\(.*\)`, "printf", "golang.org/lsptests/analyzer.printfWrapper format %s reads arg #1, but call has 0 args", "warning") +} + +func printfWrapper(format string, args ...interface{}) { + fmt.Printf(format, args...) +} + +func _() { + now := time.Now() + fmt.Println(now.Format("2006-02-01")) //@diag("2006-02-01", "timeformat", "2006-02-01 should be 2006-01-02", "warning") +} diff --git a/gopls/internal/lsp/testdata/anon/anon.go.in b/gopls/internal/lsp/testdata/anon/anon.go.in new file mode 100644 index 000000000..36611b268 --- /dev/null +++ b/gopls/internal/lsp/testdata/anon/anon.go.in @@ -0,0 +1,23 @@ +package anon + +func _() { + for _, _ := range []struct { + i, j int //@item(anonI, "i", "int", "field"),item(anonJ, "j", "int", "field") + }{ + { + i: 1, + //@complete("", anonJ) + }, + { + //@complete("", anonI, anonJ) + }, + } { + continue + } + + s := struct{ f int }{ } //@item(anonF, "f", "int", "field"),item(structS, "s", "struct{...}", "var"),complete(" }", anonF) + + _ = map[struct{ x int }]int{ //@item(anonX, "x", "int", "field") + struct{ x int }{ }: 1, //@complete(" }", anonX, structS) + } +} diff --git a/gopls/internal/lsp/testdata/append/append.go b/gopls/internal/lsp/testdata/append/append.go new file mode 100644 index 000000000..2880e59db --- /dev/null +++ b/gopls/internal/lsp/testdata/append/append.go @@ -0,0 +1,38 @@ +package append + +func foo([]string) {} +func bar(...string) {} + +func _() { + var ( + aInt []int //@item(appendInt, "aInt", "[]int", "var") + aStrings []string //@item(appendStrings, "aStrings", "[]string", "var") + aString string //@item(appendString, "aString", "string", "var") + ) + + append(aStrings, a) //@rank(")", appendString, appendInt) + var _ interface{} = append(aStrings, a) //@rank(")", appendString, appendInt) + var _ []string = append(oops, a) //@rank(")", appendString, appendInt) + + foo(append()) //@rank("))", appendStrings, appendInt),rank("))", appendStrings, appendString) + foo(append([]string{}, a)) //@rank("))", appendStrings, appendInt),rank("))", appendString, appendInt),snippet("))", appendStrings, "aStrings...", "aStrings...") + foo(append([]string{}, "", a)) //@rank("))", appendString, appendInt),rank("))", appendString, appendStrings) + + // Don't add "..." to append() argument. + bar(append()) //@snippet("))", appendStrings, "aStrings", "aStrings") + + type baz struct{} + baz{} //@item(appendBazLiteral, "baz{}", "", "var") + var bazzes []baz //@item(appendBazzes, "bazzes", "[]baz", "var") + var bazzy baz //@item(appendBazzy, "bazzy", "baz", "var") + bazzes = append(bazzes, ba) //@rank(")", appendBazzy, appendBazLiteral, appendBazzes) + + var b struct{ b []baz } + b.b //@item(appendNestedBaz, "b.b", "[]baz", "field") + b.b = append(b.b, b) //@rank(")", appendBazzy, appendBazLiteral, appendNestedBaz) + + var aStringsPtr *[]string //@item(appendStringsPtr, "aStringsPtr", "*[]string", "var") + foo(append([]string{}, a)) //@snippet("))", appendStringsPtr, "*aStringsPtr...", "*aStringsPtr...") + + foo(append([]string{}, *a)) //@snippet("))", appendStringsPtr, "aStringsPtr...", "aStringsPtr...") +} diff --git a/gopls/internal/lsp/testdata/append/append2.go.in b/gopls/internal/lsp/testdata/append/append2.go.in new file mode 100644 index 000000000..15bd357b2 --- /dev/null +++ b/gopls/internal/lsp/testdata/append/append2.go.in @@ -0,0 +1,5 @@ +package append + +func _() { + _ = append(a, struct) //@complete(")") +}
\ No newline at end of file diff --git a/gopls/internal/lsp/testdata/arraytype/array_type.go.in b/gopls/internal/lsp/testdata/arraytype/array_type.go.in new file mode 100644 index 000000000..ac1a3e782 --- /dev/null +++ b/gopls/internal/lsp/testdata/arraytype/array_type.go.in @@ -0,0 +1,50 @@ +package arraytype + +import ( + "golang.org/lsptests/foo" +) + +func _() { + var ( + val string //@item(atVal, "val", "string", "var") + ) + + // disabled - see issue #54822 + [] // complete(" //", PackageFoo) + + []val //@complete(" //") + + []foo.StructFoo //@complete(" //", StructFoo) + + []foo.StructFoo(nil) //@complete("(", StructFoo) + + []*foo.StructFoo //@complete(" //", StructFoo) + + [...]foo.StructFoo //@complete(" //", StructFoo) + + [2][][4]foo.StructFoo //@complete(" //", StructFoo) + + []struct { f []foo.StructFoo } //@complete(" }", StructFoo) +} + +func _() { + type myInt int //@item(atMyInt, "myInt", "int", "type") + + var mark []myInt //@item(atMark, "mark", "[]myInt", "var") + + var s []myInt //@item(atS, "s", "[]myInt", "var") + s = []m //@complete(" //", atMyInt) + // disabled - see issue #54822 + s = [] // complete(" //", atMyInt, PackageFoo) + + var a [1]myInt + a = [1]m //@complete(" //", atMyInt) + + var ds [][]myInt + ds = [][]m //@complete(" //", atMyInt) +} + +func _() { + var b [0]byte //@item(atByte, "b", "[0]byte", "var") + var _ []byte = b //@snippet(" //", atByte, "b[:]", "b[:]") +} diff --git a/gopls/internal/lsp/testdata/assign/assign.go.in b/gopls/internal/lsp/testdata/assign/assign.go.in new file mode 100644 index 000000000..93a622c83 --- /dev/null +++ b/gopls/internal/lsp/testdata/assign/assign.go.in @@ -0,0 +1,26 @@ +package assign + +import "golang.org/lsptests/assign/internal/secret" + +func _() { + secret.Hello() + var ( + myInt int //@item(assignInt, "myInt", "int", "var") + myStr string //@item(assignStr, "myStr", "string", "var") + ) + + var _ string = my //@rank(" //", assignStr, assignInt) + var _ string = //@rank(" //", assignStr, assignInt) +} + +func _() { + var a string = a //@complete(" //") +} + +func _() { + fooBar := fooBa //@complete(" //"),item(assignFooBar, "fooBar", "", "var") + abc, fooBar := 123, fooBa //@complete(" //", assignFooBar) + { + fooBar := fooBa //@complete(" //", assignFooBar) + } +} diff --git a/gopls/internal/lsp/testdata/assign/internal/secret/secret.go b/gopls/internal/lsp/testdata/assign/internal/secret/secret.go new file mode 100644 index 000000000..5ee1554df --- /dev/null +++ b/gopls/internal/lsp/testdata/assign/internal/secret/secret.go @@ -0,0 +1,3 @@ +package secret + +func Hello() {}
\ No newline at end of file diff --git a/gopls/internal/lsp/testdata/bad/bad0.go b/gopls/internal/lsp/testdata/bad/bad0.go new file mode 100644 index 000000000..0f23a3911 --- /dev/null +++ b/gopls/internal/lsp/testdata/bad/bad0.go @@ -0,0 +1,24 @@ +//go:build go1.11 +// +build go1.11 + +package bad + +import _ "golang.org/lsptests/assign/internal/secret" //@diag("\"golang.org/lsptests/assign/internal/secret\"", "compiler", "could not import golang.org/lsptests/assign/internal/secret \\(invalid use of internal package \"golang.org/lsptests/assign/internal/secret\"\\)", "error") + +func stuff() { //@item(stuff, "stuff", "func()", "func") + x := "heeeeyyyy" + random2(x) //@diag("x", "compiler", "cannot use x \\(variable of type string\\) as int value in argument to random2", "error") + random2(1) //@complete("dom", random, random2, random3) + y := 3 //@diag("y", "compiler", "y declared (and|but) not used", "error") +} + +type bob struct { //@item(bob, "bob", "struct{...}", "struct") + x int +} + +func _() { + var q int + _ = &bob{ + f: q, //@diag("f: q", "compiler", "unknown field f in struct literal", "error") + } +} diff --git a/gopls/internal/lsp/testdata/bad/bad1.go b/gopls/internal/lsp/testdata/bad/bad1.go new file mode 100644 index 000000000..13b3d0af6 --- /dev/null +++ b/gopls/internal/lsp/testdata/bad/bad1.go @@ -0,0 +1,34 @@ +//go:build go1.11 +// +build go1.11 + +package bad + +// See #36637 +type stateFunc func() stateFunc //@item(stateFunc, "stateFunc", "func() stateFunc", "type") + +var a unknown //@item(global_a, "a", "unknown", "var"),diag("unknown", "compiler", "(undeclared name|undefined): unknown", "error") + +func random() int { //@item(random, "random", "func() int", "func") + //@complete("", global_a, bob, random, random2, random3, stateFunc, stuff) + return 0 +} + +func random2(y int) int { //@item(random2, "random2", "func(y int) int", "func"),item(bad_y_param, "y", "int", "var") + x := 6 //@item(x, "x", "int", "var"),diag("x", "compiler", "x declared (and|but) not used", "error") + var q blah //@item(q, "q", "blah", "var"),diag("q", "compiler", "q declared (and|but) not used", "error"),diag("blah", "compiler", "(undeclared name|undefined): blah", "error") + var t **blob //@item(t, "t", "**blob", "var"),diag("t", "compiler", "t declared (and|but) not used", "error"),diag("blob", "compiler", "(undeclared name|undefined): blob", "error") + //@complete("", q, t, x, bad_y_param, global_a, bob, random, random2, random3, stateFunc, stuff) + + return y +} + +func random3(y ...int) { //@item(random3, "random3", "func(y ...int)", "func"),item(y_variadic_param, "y", "[]int", "var") + //@complete("", y_variadic_param, global_a, bob, random, random2, random3, stateFunc, stuff) + + var ch chan (favType1) //@item(ch, "ch", "chan (favType1)", "var"),diag("ch", "compiler", "ch declared (and|but) not used", "error"),diag("favType1", "compiler", "(undeclared name|undefined): favType1", "error") + var m map[keyType]int //@item(m, "m", "map[keyType]int", "var"),diag("m", "compiler", "m declared (and|but) not used", "error"),diag("keyType", "compiler", "(undeclared name|undefined): keyType", "error") + var arr []favType2 //@item(arr, "arr", "[]favType2", "var"),diag("arr", "compiler", "arr declared (and|but) not used", "error"),diag("favType2", "compiler", "(undeclared name|undefined): favType2", "error") + var fn1 func() badResult //@item(fn1, "fn1", "func() badResult", "var"),diag("fn1", "compiler", "fn1 declared (and|but) not used", "error"),diag("badResult", "compiler", "(undeclared name|undefined): badResult", "error") + var fn2 func(badParam) //@item(fn2, "fn2", "func(badParam)", "var"),diag("fn2", "compiler", "fn2 declared (and|but) not used", "error"),diag("badParam", "compiler", "(undeclared name|undefined): badParam", "error") + //@complete("", arr, ch, fn1, fn2, m, y_variadic_param, global_a, bob, random, random2, random3, stateFunc, stuff) +} diff --git a/gopls/internal/lsp/testdata/badstmt/badstmt.go.in b/gopls/internal/lsp/testdata/badstmt/badstmt.go.in new file mode 100644 index 000000000..81aee201d --- /dev/null +++ b/gopls/internal/lsp/testdata/badstmt/badstmt.go.in @@ -0,0 +1,29 @@ +package badstmt + +import ( + "golang.org/lsptests/foo" +) + +// The nonewvars expectation asserts that the go/analysis framework ran. +// See comments in noparse. + +func _(x int) { + defer foo.F //@complete(" //", Foo),diag(" //", "syntax", "function must be invoked in defer statement|expression in defer must be function call", "error") + defer foo.F //@complete(" //", Foo) + x := 123 //@diag(":=", "nonewvars", "no new variables", "warning") +} + +func _() { + switch true { + case true: + go foo.F //@complete(" //", Foo) + } +} + +func _() { + defer func() { + foo.F //@complete(" //", Foo),snippet(" //", Foo, "Foo()", "Foo()") + + foo. //@rank(" //", Foo) + } +} diff --git a/gopls/internal/lsp/testdata/badstmt/badstmt_2.go.in b/gopls/internal/lsp/testdata/badstmt/badstmt_2.go.in new file mode 100644 index 000000000..6af9c35e3 --- /dev/null +++ b/gopls/internal/lsp/testdata/badstmt/badstmt_2.go.in @@ -0,0 +1,9 @@ +package badstmt + +import ( + "golang.org/lsptests/foo" +) + +func _() { + defer func() { foo. } //@rank(" }", Foo) +} diff --git a/gopls/internal/lsp/testdata/badstmt/badstmt_3.go.in b/gopls/internal/lsp/testdata/badstmt/badstmt_3.go.in new file mode 100644 index 000000000..d135e2015 --- /dev/null +++ b/gopls/internal/lsp/testdata/badstmt/badstmt_3.go.in @@ -0,0 +1,9 @@ +package badstmt + +import ( + "golang.org/lsptests/foo" +) + +func _() { + go foo. //@rank(" //", Foo, IntFoo),snippet(" //", Foo, "Foo()", "Foo()") +} diff --git a/gopls/internal/lsp/testdata/badstmt/badstmt_4.go.in b/gopls/internal/lsp/testdata/badstmt/badstmt_4.go.in new file mode 100644 index 000000000..6afd635ec --- /dev/null +++ b/gopls/internal/lsp/testdata/badstmt/badstmt_4.go.in @@ -0,0 +1,11 @@ +package badstmt + +import ( + "golang.org/lsptests/foo" +) + +func _() { + go func() { + defer foo. //@rank(" //", Foo, IntFoo) + } +} diff --git a/gopls/internal/lsp/testdata/bar/bar.go.in b/gopls/internal/lsp/testdata/bar/bar.go.in new file mode 100644 index 000000000..502bdf740 --- /dev/null +++ b/gopls/internal/lsp/testdata/bar/bar.go.in @@ -0,0 +1,47 @@ +// +build go1.11 + +package bar + +import ( + "golang.org/lsptests/foo" //@item(foo, "foo", "\"golang.org/lsptests/foo\"", "package") +) + +func helper(i foo.IntFoo) {} //@item(helper, "helper", "func(i foo.IntFoo)", "func") + +func _() { + help //@complete("l", helper) + _ = foo.StructFoo{} //@complete("S", IntFoo, StructFoo) +} + +// Bar is a function. +func Bar() { //@item(Bar, "Bar", "func()", "func", "Bar is a function.") + foo.Foo() //@complete("F", Foo, IntFoo, StructFoo) + var _ foo.IntFoo //@complete("I", IntFoo, StructFoo) + foo.() //@complete("(", Foo, IntFoo, StructFoo) +} + +func _() { + var Valentine int //@item(Valentine, "Valentine", "int", "var") + + _ = foo.StructFoo{ + Valu //@complete(" //", Value) + } + _ = foo.StructFoo{ + Va //@complete("a", Value, Valentine) + } + _ = foo.StructFoo{ + Value: 5, //@complete("a", Value) + } + _ = foo.StructFoo{ + //@complete("", Value, Valentine, foo, helper, Bar) + } + _ = foo.StructFoo{ + Value: Valen //@complete("le", Valentine) + } + _ = foo.StructFoo{ + Value: //@complete(" //", Valentine, foo, helper, Bar) + } + _ = foo.StructFoo{ + Value: //@complete(" ", Valentine, foo, helper, Bar) + } +} diff --git a/gopls/internal/lsp/testdata/basiclit/basiclit.go b/gopls/internal/lsp/testdata/basiclit/basiclit.go new file mode 100644 index 000000000..ab895dc01 --- /dev/null +++ b/gopls/internal/lsp/testdata/basiclit/basiclit.go @@ -0,0 +1,13 @@ +package basiclit + +func _() { + var a int // something for lexical completions + + _ = "hello." //@complete(".") + + _ = 1 //@complete(" //") + + _ = 1. //@complete(".") + + _ = 'a' //@complete("' ") +} diff --git a/gopls/internal/lsp/testdata/baz/baz.go.in b/gopls/internal/lsp/testdata/baz/baz.go.in new file mode 100644 index 000000000..94952e126 --- /dev/null +++ b/gopls/internal/lsp/testdata/baz/baz.go.in @@ -0,0 +1,33 @@ +// +build go1.11 + +package baz + +import ( + "golang.org/lsptests/bar" + + f "golang.org/lsptests/foo" +) + +var FooStruct f.StructFoo + +func Baz() { + defer bar.Bar() //@complete("B", Bar) + // TODO(rstambler): Test completion here. + defer bar.B + var x f.IntFoo //@complete("n", IntFoo),typdef("x", IntFoo) + bar.Bar() //@complete("B", Bar) +} + +func _() { + bob := f.StructFoo{Value: 5} + if x := bob. //@complete(" //", Value) + switch true == false { + case true: + if x := bob. //@complete(" //", Value) + case false: + } + if x := bob.Va //@complete("a", Value) + switch true == true { + default: + } +} diff --git a/gopls/internal/lsp/testdata/builtins/builtin_args.go b/gopls/internal/lsp/testdata/builtins/builtin_args.go new file mode 100644 index 000000000..052777fe9 --- /dev/null +++ b/gopls/internal/lsp/testdata/builtins/builtin_args.go @@ -0,0 +1,62 @@ +package builtins + +func _() { + var ( + aSlice []int //@item(builtinSlice, "aSlice", "[]int", "var") + aMap map[string]int //@item(builtinMap, "aMap", "map[string]int", "var") + aString string //@item(builtinString, "aString", "string", "var") + aArray [0]int //@item(builtinArray, "aArray", "[0]int", "var") + aArrayPtr *[0]int //@item(builtinArrayPtr, "aArrayPtr", "*[0]int", "var") + aChan chan int //@item(builtinChan, "aChan", "chan int", "var") + aPtr *int //@item(builtinPtr, "aPtr", "*int", "var") + aInt int //@item(builtinInt, "aInt", "int", "var") + ) + + type ( + aSliceType []int //@item(builtinSliceType, "aSliceType", "[]int", "type") + aChanType chan int //@item(builtinChanType, "aChanType", "chan int", "type") + aMapType map[string]int //@item(builtinMapType, "aMapType", "map[string]int", "type") + ) + + close() //@rank(")", builtinChan, builtinSlice) + + append() //@rank(")", builtinSlice, builtinChan) + + var _ []byte = append([]byte(nil), ""...) //@rank(") //") + + copy() //@rank(")", builtinSlice, builtinChan) + copy(aSlice, aS) //@rank(")", builtinSlice, builtinString) + copy(aS, aSlice) //@rank(",", builtinSlice, builtinString) + + delete() //@rank(")", builtinMap, builtinChan) + delete(aMap, aS) //@rank(")", builtinString, builtinSlice) + + aMapFunc := func() map[int]int { //@item(builtinMapFunc, "aMapFunc", "func() map[int]int", "var") + return nil + } + delete() //@rank(")", builtinMapFunc, builtinSlice) + + len() //@rank(")", builtinSlice, builtinInt),rank(")", builtinMap, builtinInt),rank(")", builtinString, builtinInt),rank(")", builtinArray, builtinInt),rank(")", builtinArrayPtr, builtinPtr),rank(")", builtinChan, builtinInt) + + cap() //@rank(")", builtinSlice, builtinMap),rank(")", builtinArray, builtinString),rank(")", builtinArrayPtr, builtinPtr),rank(")", builtinChan, builtinInt) + + make() //@rank(")", builtinMapType, int),rank(")", builtinChanType, int),rank(")", builtinSliceType, int),rank(")", builtinMapType, int) + make(aSliceType, a) //@rank(")", builtinInt, builtinSlice) + + type myInt int + var mi myInt //@item(builtinMyInt, "mi", "myInt", "var") + make(aSliceType, m) //@snippet(")", builtinMyInt, "mi", "mi") + + var _ []int = make() //@rank(")", builtinSliceType, builtinMapType) + + type myStruct struct{} //@item(builtinStructType, "myStruct", "struct{...}", "struct") + var _ *myStruct = new() //@rank(")", builtinStructType, int) + + for k := range a { //@rank(" {", builtinSlice, builtinInt),rank(" {", builtinString, builtinInt),rank(" {", builtinChan, builtinInt),rank(" {", builtinArray, builtinInt),rank(" {", builtinArrayPtr, builtinInt),rank(" {", builtinMap, builtinInt), + } + + for k, v := range a { //@rank(" {", builtinSlice, builtinChan) + } + + <-a //@rank(" //", builtinChan, builtinInt) +} diff --git a/gopls/internal/lsp/testdata/builtins/builtin_go117.go b/gopls/internal/lsp/testdata/builtins/builtin_go117.go new file mode 100644 index 000000000..57abcde15 --- /dev/null +++ b/gopls/internal/lsp/testdata/builtins/builtin_go117.go @@ -0,0 +1,8 @@ +//go:build !go1.18 +// +build !go1.18 + +package builtins + +func _() { + //@complete("", append, bool, byte, cap, close, complex, complex128, complex64, copy, delete, error, _false, float32, float64, imag, int, int16, int32, int64, int8, len, make, new, panic, print, println, real, recover, rune, string, _true, uint, uint16, uint32, uint64, uint8, uintptr, _nil) +} diff --git a/gopls/internal/lsp/testdata/builtins/builtin_go118.go b/gopls/internal/lsp/testdata/builtins/builtin_go118.go new file mode 100644 index 000000000..dabffcc67 --- /dev/null +++ b/gopls/internal/lsp/testdata/builtins/builtin_go118.go @@ -0,0 +1,8 @@ +//go:build go1.18 && !go1.21 +// +build go1.18,!go1.21 + +package builtins + +func _() { + //@complete("", any, append, bool, byte, cap, close, comparable, complex, complex128, complex64, copy, delete, error, _false, float32, float64, imag, int, int16, int32, int64, int8, len, make, new, panic, print, println, real, recover, rune, string, _true, uint, uint16, uint32, uint64, uint8, uintptr, _nil) +} diff --git a/gopls/internal/lsp/testdata/builtins/builtin_go121.go b/gopls/internal/lsp/testdata/builtins/builtin_go121.go new file mode 100644 index 000000000..cb8e8fae3 --- /dev/null +++ b/gopls/internal/lsp/testdata/builtins/builtin_go121.go @@ -0,0 +1,8 @@ +//go:build go1.21 +// +build go1.21 + +package builtins + +func _() { + //@complete("", any, append, bool, byte, cap, clear, close, comparable, complex, complex128, complex64, copy, delete, error, _false, float32, float64, imag, int, int16, int32, int64, int8, len, make, new, panic, print, println, real, recover, rune, string, _true, uint, uint16, uint32, uint64, uint8, uintptr, _nil) +} diff --git a/gopls/internal/lsp/testdata/builtins/builtin_types.go b/gopls/internal/lsp/testdata/builtins/builtin_types.go new file mode 100644 index 000000000..93a4a7095 --- /dev/null +++ b/gopls/internal/lsp/testdata/builtins/builtin_types.go @@ -0,0 +1,11 @@ +package builtins + +func _() { + var _ []bool //@item(builtinBoolSliceType, "[]bool", "[]bool", "type") + + var _ []bool = make() //@rank(")", builtinBoolSliceType, int) + + var _ []bool = make([], 0) //@rank(",", bool, int) + + var _ [][]bool = make([][], 0) //@rank(",", bool, int) +} diff --git a/gopls/internal/lsp/testdata/builtins/builtins.go b/gopls/internal/lsp/testdata/builtins/builtins.go new file mode 100644 index 000000000..75c6e4183 --- /dev/null +++ b/gopls/internal/lsp/testdata/builtins/builtins.go @@ -0,0 +1,47 @@ +package builtins + +// Definitions of builtin completion items. + +/* any */ //@item(any, "any", "", "interface") +/* Create markers for builtin types. Only for use by this test. +/* append(slice []Type, elems ...Type) []Type */ //@item(append, "append", "func(slice []Type, elems ...Type) []Type", "func") +/* bool */ //@item(bool, "bool", "", "type") +/* byte */ //@item(byte, "byte", "", "type") +/* cap(v Type) int */ //@item(cap, "cap", "func(v Type) int", "func") +/* clear[T interface{ ~[]Type | ~map[Type]Type1 }](t T) */ //@item(clear, "clear", "func(t T)", "func") +/* close(c chan<- Type) */ //@item(close, "close", "func(c chan<- Type)", "func") +/* comparable */ //@item(comparable, "comparable", "", "interface") +/* complex(r float64, i float64) */ //@item(complex, "complex", "func(r float64, i float64) complex128", "func") +/* complex128 */ //@item(complex128, "complex128", "", "type") +/* complex64 */ //@item(complex64, "complex64", "", "type") +/* copy(dst []Type, src []Type) int */ //@item(copy, "copy", "func(dst []Type, src []Type) int", "func") +/* delete(m map[Type]Type1, key Type) */ //@item(delete, "delete", "func(m map[Type]Type1, key Type)", "func") +/* error */ //@item(error, "error", "", "interface") +/* false */ //@item(_false, "false", "", "const") +/* float32 */ //@item(float32, "float32", "", "type") +/* float64 */ //@item(float64, "float64", "", "type") +/* imag(c complex128) float64 */ //@item(imag, "imag", "func(c complex128) float64", "func") +/* int */ //@item(int, "int", "", "type") +/* int16 */ //@item(int16, "int16", "", "type") +/* int32 */ //@item(int32, "int32", "", "type") +/* int64 */ //@item(int64, "int64", "", "type") +/* int8 */ //@item(int8, "int8", "", "type") +/* iota */ //@item(iota, "iota", "", "const") +/* len(v Type) int */ //@item(len, "len", "func(v Type) int", "func") +/* make(t Type, size ...int) Type */ //@item(make, "make", "func(t Type, size ...int) Type", "func") +/* new(Type) *Type */ //@item(new, "new", "func(Type) *Type", "func") +/* nil */ //@item(_nil, "nil", "", "var") +/* panic(v interface{}) */ //@item(panic, "panic", "func(v interface{})", "func") +/* print(args ...Type) */ //@item(print, "print", "func(args ...Type)", "func") +/* println(args ...Type) */ //@item(println, "println", "func(args ...Type)", "func") +/* real(c complex128) float64 */ //@item(real, "real", "func(c complex128) float64", "func") +/* recover() interface{} */ //@item(recover, "recover", "func() interface{}", "func") +/* rune */ //@item(rune, "rune", "", "type") +/* string */ //@item(string, "string", "", "type") +/* true */ //@item(_true, "true", "", "const") +/* uint */ //@item(uint, "uint", "", "type") +/* uint16 */ //@item(uint16, "uint16", "", "type") +/* uint32 */ //@item(uint32, "uint32", "", "type") +/* uint64 */ //@item(uint64, "uint64", "", "type") +/* uint8 */ //@item(uint8, "uint8", "", "type") +/* uintptr */ //@item(uintptr, "uintptr", "", "type") diff --git a/gopls/internal/lsp/testdata/builtins/constants.go b/gopls/internal/lsp/testdata/builtins/constants.go new file mode 100644 index 000000000..7ad07bd1f --- /dev/null +++ b/gopls/internal/lsp/testdata/builtins/constants.go @@ -0,0 +1,19 @@ +package builtins + +func _() { + const ( + foo = iota //@complete(" //", iota) + ) + + iota //@complete(" //") + + var iota int //@item(iotaVar, "iota", "int", "var") + + iota //@complete(" //", iotaVar) +} + +func _() { + var twoRedUpEnd bool //@item(TRUEVar, "twoRedUpEnd", "bool", "var") + + var _ bool = true //@rank(" //", _true, TRUEVar) +} diff --git a/gopls/internal/lsp/testdata/callhierarchy/callhierarchy.go b/gopls/internal/lsp/testdata/callhierarchy/callhierarchy.go new file mode 100644 index 000000000..252e8054f --- /dev/null +++ b/gopls/internal/lsp/testdata/callhierarchy/callhierarchy.go @@ -0,0 +1,70 @@ +// Copyright 2020 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 callhierarchy + +import "golang.org/lsptests/callhierarchy/outgoing" + +func a() { //@mark(hierarchyA, "a") + D() +} + +func b() { //@mark(hierarchyB, "b") + D() +} + +// C is an exported function +func C() { //@mark(hierarchyC, "C") + D() + D() +} + +// To test hierarchy across function literals +var x = func() { //@mark(hierarchyLiteral, "func"),mark(hierarchyLiteralOut, "x") + D() +} + +// D is exported to test incoming/outgoing calls across packages +func D() { //@mark(hierarchyD, "D"),incomingcalls(hierarchyD, hierarchyA, hierarchyB, hierarchyC, hierarchyLiteral, incomingA),outgoingcalls(hierarchyD, hierarchyE, hierarchyF, hierarchyG, hierarchyLiteralOut, outgoingB, hierarchyFoo, hierarchyH, hierarchyI, hierarchyJ, hierarchyK) + e() + x() + F() + outgoing.B() + foo := func() {} //@mark(hierarchyFoo, "foo"),incomingcalls(hierarchyFoo, hierarchyD),outgoingcalls(hierarchyFoo) + foo() + + func() { + g() + }() + + var i Interface = impl{} + i.H() + i.I() + + s := Struct{} + s.J() + s.K() +} + +func e() {} //@mark(hierarchyE, "e") + +// F is an exported function +func F() {} //@mark(hierarchyF, "F") + +func g() {} //@mark(hierarchyG, "g") + +type Interface interface { + H() //@mark(hierarchyH, "H") + I() //@mark(hierarchyI, "I") +} + +type impl struct{} + +func (i impl) H() {} +func (i impl) I() {} + +type Struct struct { + J func() //@mark(hierarchyJ, "J") + K func() //@mark(hierarchyK, "K") +} diff --git a/gopls/internal/lsp/testdata/callhierarchy/incoming/incoming.go b/gopls/internal/lsp/testdata/callhierarchy/incoming/incoming.go new file mode 100644 index 000000000..c629aa879 --- /dev/null +++ b/gopls/internal/lsp/testdata/callhierarchy/incoming/incoming.go @@ -0,0 +1,12 @@ +// Copyright 2020 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 incoming + +import "golang.org/lsptests/callhierarchy" + +// A is exported to test incoming calls across packages +func A() { //@mark(incomingA, "A") + callhierarchy.D() +} diff --git a/gopls/internal/lsp/testdata/callhierarchy/outgoing/outgoing.go b/gopls/internal/lsp/testdata/callhierarchy/outgoing/outgoing.go new file mode 100644 index 000000000..74362d419 --- /dev/null +++ b/gopls/internal/lsp/testdata/callhierarchy/outgoing/outgoing.go @@ -0,0 +1,9 @@ +// Copyright 2020 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 outgoing + +// B is exported to test outgoing calls across packages +func B() { //@mark(outgoingB, "B") +} diff --git a/gopls/internal/lsp/testdata/casesensitive/casesensitive.go b/gopls/internal/lsp/testdata/casesensitive/casesensitive.go new file mode 100644 index 000000000..6f49d36ff --- /dev/null +++ b/gopls/internal/lsp/testdata/casesensitive/casesensitive.go @@ -0,0 +1,16 @@ +// Copyright 2019 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 casesensitive + +func _() { + var lower int //@item(lower, "lower", "int", "var") + var Upper int //@item(upper, "Upper", "int", "var") + + l //@casesensitive(" //", lower) + U //@casesensitive(" //", upper) + + L //@casesensitive(" //") + u //@casesensitive(" //") +} diff --git a/gopls/internal/lsp/testdata/cast/cast.go.in b/gopls/internal/lsp/testdata/cast/cast.go.in new file mode 100644 index 000000000..7fe21903c --- /dev/null +++ b/gopls/internal/lsp/testdata/cast/cast.go.in @@ -0,0 +1,11 @@ +package cast + +func _() { + foo := struct{x int}{x: 1} //@item(x_field, "x", "int", "field") + _ = float64(foo.x) //@complete("x", x_field) +} + +func _() { + foo := struct{x int}{x: 1} + _ = float64(foo. //@complete(" /", x_field) +}
\ No newline at end of file diff --git a/gopls/internal/lsp/testdata/cgo/declarecgo.go b/gopls/internal/lsp/testdata/cgo/declarecgo.go new file mode 100644 index 000000000..c283cdfb2 --- /dev/null +++ b/gopls/internal/lsp/testdata/cgo/declarecgo.go @@ -0,0 +1,27 @@ +package cgo + +/* +#include <stdio.h> +#include <stdlib.h> + +void myprint(char* s) { + printf("%s\n", s); +} +*/ +import "C" + +import ( + "fmt" + "unsafe" +) + +func Example() { //@mark(funccgoexample, "Example"),item(funccgoexample, "Example", "func()", "func") + fmt.Println() + cs := C.CString("Hello from stdio\n") + C.myprint(cs) + C.free(unsafe.Pointer(cs)) +} + +func _() { + Example() //@godef("ample", funccgoexample),complete("ample", funccgoexample) +} diff --git a/gopls/internal/lsp/testdata/cgo/declarecgo.go.golden b/gopls/internal/lsp/testdata/cgo/declarecgo.go.golden new file mode 100644 index 000000000..0d6fbb0ff --- /dev/null +++ b/gopls/internal/lsp/testdata/cgo/declarecgo.go.golden @@ -0,0 +1,30 @@ +-- funccgoexample-definition -- +cgo/declarecgo.go:18:6-13: defined here as ```go +func Example() +``` + +[`cgo.Example` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/cgo#Example) +-- funccgoexample-definition-json -- +{ + "span": { + "uri": "file://cgo/declarecgo.go", + "start": { + "line": 18, + "column": 6, + "offset": 151 + }, + "end": { + "line": 18, + "column": 13, + "offset": 158 + } + }, + "description": "```go\nfunc Example()\n```\n\n[`cgo.Example` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/cgo#Example)" +} + +-- funccgoexample-hoverdef -- +```go +func Example() +``` + +[`cgo.Example` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/cgo#Example) diff --git a/gopls/internal/lsp/testdata/cgo/declarecgo_nocgo.go b/gopls/internal/lsp/testdata/cgo/declarecgo_nocgo.go new file mode 100644 index 000000000..a05c01257 --- /dev/null +++ b/gopls/internal/lsp/testdata/cgo/declarecgo_nocgo.go @@ -0,0 +1,6 @@ +//+build !cgo + +package cgo + +// Set a dummy marker to keep the test framework happy. The tests should be skipped. +var _ = "Example" //@mark(funccgoexample, "Example"),godef("ample", funccgoexample),complete("ample", funccgoexample) diff --git a/gopls/internal/lsp/testdata/cgoimport/usecgo.go.golden b/gopls/internal/lsp/testdata/cgoimport/usecgo.go.golden new file mode 100644 index 000000000..03fc22468 --- /dev/null +++ b/gopls/internal/lsp/testdata/cgoimport/usecgo.go.golden @@ -0,0 +1,30 @@ +-- funccgoexample-definition -- +cgo/declarecgo.go:18:6-13: defined here as ```go +func cgo.Example() +``` + +[`cgo.Example` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/cgo#Example) +-- funccgoexample-definition-json -- +{ + "span": { + "uri": "file://cgo/declarecgo.go", + "start": { + "line": 18, + "column": 6, + "offset": 151 + }, + "end": { + "line": 18, + "column": 13, + "offset": 158 + } + }, + "description": "```go\nfunc cgo.Example()\n```\n\n[`cgo.Example` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/cgo#Example)" +} + +-- funccgoexample-hoverdef -- +```go +func cgo.Example() +``` + +[`cgo.Example` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/cgo#Example) diff --git a/gopls/internal/lsp/testdata/cgoimport/usecgo.go.in b/gopls/internal/lsp/testdata/cgoimport/usecgo.go.in new file mode 100644 index 000000000..414a739da --- /dev/null +++ b/gopls/internal/lsp/testdata/cgoimport/usecgo.go.in @@ -0,0 +1,9 @@ +package cgoimport + +import ( + "golang.org/lsptests/cgo" +) + +func _() { + cgo.Example() //@godef("ample", funccgoexample),complete("ample", funccgoexample) +} diff --git a/gopls/internal/lsp/testdata/channel/channel.go b/gopls/internal/lsp/testdata/channel/channel.go new file mode 100644 index 000000000..d6bd311e3 --- /dev/null +++ b/gopls/internal/lsp/testdata/channel/channel.go @@ -0,0 +1,25 @@ +package channel + +func _() { + var ( + aa = "123" //@item(channelAA, "aa", "string", "var") + ab = 123 //@item(channelAB, "ab", "int", "var") + ) + + { + type myChan chan int + var mc myChan + mc <- a //@complete(" //", channelAB, channelAA) + } + + { + var ac chan int //@item(channelAC, "ac", "chan int", "var") + a <- a //@complete(" <-", channelAC, channelAA, channelAB) + } + + { + var foo chan int //@item(channelFoo, "foo", "chan int", "var") + wantsInt := func(int) {} //@item(channelWantsInt, "wantsInt", "func(int)", "var") + wantsInt(<-) //@rank(")", channelFoo, channelAB) + } +} diff --git a/gopls/internal/lsp/testdata/codelens/codelens_test.go b/gopls/internal/lsp/testdata/codelens/codelens_test.go new file mode 100644 index 000000000..f6c696416 --- /dev/null +++ b/gopls/internal/lsp/testdata/codelens/codelens_test.go @@ -0,0 +1,16 @@ +package codelens //@codelens("package codelens", "run file benchmarks", "test") + +import "testing" + +func TestMain(m *testing.M) {} // no code lens for TestMain + +func TestFuncWithCodeLens(t *testing.T) { //@codelens("func", "run test", "test") +} + +func thisShouldNotHaveACodeLens(t *testing.T) { +} + +func BenchmarkFuncWithCodeLens(b *testing.B) { //@codelens("func", "run benchmark", "test") +} + +func helper() {} // expect no code lens diff --git a/gopls/internal/lsp/testdata/comment_completion/comment_completion.go.in b/gopls/internal/lsp/testdata/comment_completion/comment_completion.go.in new file mode 100644 index 000000000..dbca0ff17 --- /dev/null +++ b/gopls/internal/lsp/testdata/comment_completion/comment_completion.go.in @@ -0,0 +1,70 @@ +package comment_completion + +var p bool + +//@complete(re"$") + +func _() { + var a int + + switch a { + case 1: + //@complete(re"$") + _ = a + } + + var b chan int + select { + case <-b: + //@complete(re"$") + _ = b + } + + var ( + //@complete(re"$") + _ = a + ) +} + +// //@complete(" ", variableC) +var C string //@item(variableC, "C", "string", "var") //@complete(" ", variableC) + +// //@complete(" ", constant) +const Constant = "example" //@item(constant, "Constant", "string", "const") //@complete(" ", constant) + +// //@complete(" ", structType, fieldB, fieldA) +type StructType struct { //@item(structType, "StructType", "struct{...}", "struct") //@complete(" ", structType, fieldA, fieldB) + // //@complete(" ", fieldA, structType, fieldB) + A string //@item(fieldA, "A", "string", "field") //@complete(" ", fieldA, structType, fieldB) + b int //@item(fieldB, "b", "int", "field") //@complete(" ", fieldB, structType, fieldA) +} + +// //@complete(" ", method, structRecv, paramX, resultY, fieldB, fieldA) +func (structType *StructType) Method(X int) (Y int) { //@item(structRecv, "structType", "*StructType", "var"),item(method, "Method", "func(X int) (Y int)", "method"),item(paramX, "X", "int", "var"),item(resultY, "Y", "int", "var") + // //@complete(" ", method, structRecv, paramX, resultY, fieldB, fieldA) + return +} + +// //@complete(" ", newType) +type NewType string //@item(newType, "NewType", "string", "type") //@complete(" ", newType) + +// //@complete(" ", testInterface, testA, testB) +type TestInterface interface { //@item(testInterface, "TestInterface", "interface{...}", "interface") + // //@complete(" ", testA, testInterface, testB) + TestA(L string) (M int) //@item(testA, "TestA", "func(L string) (M int)", "method"),item(paramL, "L", "var", "string"),item(resM, "M", "var", "int") //@complete(" ", testA, testInterface, testB) + TestB(N int) bool //@item(testB, "TestB", "func(N int) bool", "method"),item(paramN, "N", "var", "int") //@complete(" ", testB, testInterface, testA) +} + +// //@complete(" ", function) +func Function() int { //@item(function, "Function", "func() int", "func") //@complete(" ", function) + // //@complete(" ", function) + return 0 +} + +// This tests multiline block comments and completion with prefix +// Lorem Ipsum Multili//@complete("Multi", multiline) +// Lorem ipsum dolor sit ametom +func Multiline() int { //@item(multiline, "Multiline", "func() int", "func") + // //@complete(" ", multiline) + return 0 +} diff --git a/gopls/internal/lsp/testdata/complit/complit.go.in b/gopls/internal/lsp/testdata/complit/complit.go.in new file mode 100644 index 000000000..e819810d8 --- /dev/null +++ b/gopls/internal/lsp/testdata/complit/complit.go.in @@ -0,0 +1,90 @@ +package complit + +// general completions + +type position struct { //@item(structPosition, "position", "struct{...}", "struct") + X, Y int //@item(fieldX, "X", "int", "field"),item(fieldY, "Y", "int", "field") +} + +func _() { + _ = position{ + //@complete("", fieldX, fieldY, structPosition) + } + _ = position{ + X: 1, + //@complete("", fieldY) + } + _ = position{ + //@complete("", fieldX) + Y: 1, + } + _ = []*position{ + { + //@complete("", fieldX, fieldY, structPosition) + }, + } +} + +func _() { + var ( + aa string //@item(aaVar, "aa", "string", "var") + ab int //@item(abVar, "ab", "int", "var") + ) + + _ = map[int]int{ + a: a, //@complete(":", abVar, aaVar),complete(",", abVar, aaVar) + } + + _ = map[int]int{ + //@complete("", abVar, aaVar, structPosition) + } + + _ = []string{a: ""} //@complete(":", abVar, aaVar) + _ = [1]string{a: ""} //@complete(":", abVar, aaVar) + + _ = position{X: a} //@complete("}", abVar, aaVar) + _ = position{a} //@complete("}", abVar, aaVar) + _ = position{a, } //@complete("}", abVar, aaVar, structPosition) + + _ = []int{a} //@complete("}", abVar, aaVar) + _ = [1]int{a} //@complete("}", abVar, aaVar) + + type myStruct struct { + AA int //@item(fieldAA, "AA", "int", "field") + AB string //@item(fieldAB, "AB", "string", "field") + } + + _ = myStruct{ + AB: a, //@complete(",", aaVar, abVar) + } + + var s myStruct + + _ = map[int]string{1: "" + s.A} //@complete("}", fieldAB, fieldAA) + _ = map[int]string{1: (func(i int) string { return "" })(s.A)} //@complete(")}", fieldAA, fieldAB) + _ = map[int]string{1: func() string { s.A }} //@complete(" }", fieldAA, fieldAB) + + _ = position{s.A} //@complete("}", fieldAA, fieldAB) + + var X int //@item(varX, "X", "int", "var") + _ = position{X} //@complete("}", fieldX, varX) +} + +func _() { + type foo struct{} //@item(complitFoo, "foo", "struct{...}", "struct") + + var _ *foo = &fo{} //@snippet("{", complitFoo, "foo", "foo") + var _ *foo = fo{} //@snippet("{", complitFoo, "&foo", "&foo") + + struct { a, b *foo }{ + a: &fo{}, //@rank("{", complitFoo) + b: fo{}, //@snippet("{", complitFoo, "&foo", "&foo") + } +} + +func _() { + _ := position{ + X: 1, //@complete("X", fieldX),complete(" 1", structPosition) + Y: , //@complete(":", fieldY),complete(" ,", structPosition) + } +} diff --git a/gopls/internal/lsp/testdata/constant/constant.go b/gopls/internal/lsp/testdata/constant/constant.go new file mode 100644 index 000000000..c1c88e16e --- /dev/null +++ b/gopls/internal/lsp/testdata/constant/constant.go @@ -0,0 +1,14 @@ +package constant + +const x = 1 //@item(constX, "x", "int", "const") + +const ( + a int = iota << 2 //@item(constA, "a", "int", "const") + b //@item(constB, "b", "int", "const") + c //@item(constC, "c", "int", "const") +) + +func _() { + const y = "hi" //@item(constY, "y", "string", "const") + //@complete("", constY, constA, constB, constC, constX) +} diff --git a/gopls/internal/lsp/testdata/danglingstmt/dangling_for.go b/gopls/internal/lsp/testdata/danglingstmt/dangling_for.go new file mode 100644 index 000000000..a16d3bd88 --- /dev/null +++ b/gopls/internal/lsp/testdata/danglingstmt/dangling_for.go @@ -0,0 +1,9 @@ +package danglingstmt + +func _() { + for bar //@rank(" //", danglingBar) +} + +func bar() bool { //@item(danglingBar, "bar", "func() bool", "func") + return true +} diff --git a/gopls/internal/lsp/testdata/danglingstmt/dangling_for_init.go b/gopls/internal/lsp/testdata/danglingstmt/dangling_for_init.go new file mode 100644 index 000000000..e1130bc23 --- /dev/null +++ b/gopls/internal/lsp/testdata/danglingstmt/dangling_for_init.go @@ -0,0 +1,9 @@ +package danglingstmt + +func _() { + for i := bar //@rank(" //", danglingBar2) +} + +func bar2() int { //@item(danglingBar2, "bar2", "func() int", "func") + return 0 +} diff --git a/gopls/internal/lsp/testdata/danglingstmt/dangling_for_init_cond.go b/gopls/internal/lsp/testdata/danglingstmt/dangling_for_init_cond.go new file mode 100644 index 000000000..fb0269f16 --- /dev/null +++ b/gopls/internal/lsp/testdata/danglingstmt/dangling_for_init_cond.go @@ -0,0 +1,9 @@ +package danglingstmt + +func _() { + for i := bar3(); i > bar //@rank(" //", danglingBar3) +} + +func bar3() int { //@item(danglingBar3, "bar3", "func() int", "func") + return 0 +} diff --git a/gopls/internal/lsp/testdata/danglingstmt/dangling_for_init_cond_post.go b/gopls/internal/lsp/testdata/danglingstmt/dangling_for_init_cond_post.go new file mode 100644 index 000000000..14f78d392 --- /dev/null +++ b/gopls/internal/lsp/testdata/danglingstmt/dangling_for_init_cond_post.go @@ -0,0 +1,9 @@ +package danglingstmt + +func _() { + for i := bar4(); i > bar4(); i += bar //@rank(" //", danglingBar4) +} + +func bar4() int { //@item(danglingBar4, "bar4", "func() int", "func") + return 0 +} diff --git a/gopls/internal/lsp/testdata/danglingstmt/dangling_if.go b/gopls/internal/lsp/testdata/danglingstmt/dangling_if.go new file mode 100644 index 000000000..91f145ada --- /dev/null +++ b/gopls/internal/lsp/testdata/danglingstmt/dangling_if.go @@ -0,0 +1,9 @@ +package danglingstmt + +func _() { + if foo //@rank(" //", danglingFoo) +} + +func foo() bool { //@item(danglingFoo, "foo", "func() bool", "func") + return true +} diff --git a/gopls/internal/lsp/testdata/danglingstmt/dangling_if_eof.go b/gopls/internal/lsp/testdata/danglingstmt/dangling_if_eof.go new file mode 100644 index 000000000..3454c9fa6 --- /dev/null +++ b/gopls/internal/lsp/testdata/danglingstmt/dangling_if_eof.go @@ -0,0 +1,8 @@ +package danglingstmt + +func bar5() bool { //@item(danglingBar5, "bar5", "func() bool", "func") + return true +} + +func _() { + if b //@rank(" //", danglingBar5) diff --git a/gopls/internal/lsp/testdata/danglingstmt/dangling_if_init.go b/gopls/internal/lsp/testdata/danglingstmt/dangling_if_init.go new file mode 100644 index 000000000..887c31860 --- /dev/null +++ b/gopls/internal/lsp/testdata/danglingstmt/dangling_if_init.go @@ -0,0 +1,9 @@ +package danglingstmt + +func _() { + if i := foo //@rank(" //", danglingFoo2) +} + +func foo2() bool { //@item(danglingFoo2, "foo2", "func() bool", "func") + return true +} diff --git a/gopls/internal/lsp/testdata/danglingstmt/dangling_if_init_cond.go b/gopls/internal/lsp/testdata/danglingstmt/dangling_if_init_cond.go new file mode 100644 index 000000000..5371283e9 --- /dev/null +++ b/gopls/internal/lsp/testdata/danglingstmt/dangling_if_init_cond.go @@ -0,0 +1,9 @@ +package danglingstmt + +func _() { + if i := 123; foo //@rank(" //", danglingFoo3) +} + +func foo3() bool { //@item(danglingFoo3, "foo3", "func() bool", "func") + return true +} diff --git a/gopls/internal/lsp/testdata/danglingstmt/dangling_multiline_if.go b/gopls/internal/lsp/testdata/danglingstmt/dangling_multiline_if.go new file mode 100644 index 000000000..2213777e1 --- /dev/null +++ b/gopls/internal/lsp/testdata/danglingstmt/dangling_multiline_if.go @@ -0,0 +1,10 @@ +package danglingstmt + +func walrus() bool { //@item(danglingWalrus, "walrus", "func() bool", "func") + return true +} + +func _() { + if true && + walrus //@complete(" //", danglingWalrus) +} diff --git a/gopls/internal/lsp/testdata/danglingstmt/dangling_selector_1.go b/gopls/internal/lsp/testdata/danglingstmt/dangling_selector_1.go new file mode 100644 index 000000000..772152f7b --- /dev/null +++ b/gopls/internal/lsp/testdata/danglingstmt/dangling_selector_1.go @@ -0,0 +1,7 @@ +package danglingstmt + +func _() { + x. //@rank(" //", danglingI) +} + +var x struct { i int } //@item(danglingI, "i", "int", "field") diff --git a/gopls/internal/lsp/testdata/danglingstmt/dangling_selector_2.go b/gopls/internal/lsp/testdata/danglingstmt/dangling_selector_2.go new file mode 100644 index 000000000..8d4b15bff --- /dev/null +++ b/gopls/internal/lsp/testdata/danglingstmt/dangling_selector_2.go @@ -0,0 +1,8 @@ +package danglingstmt + +import "golang.org/lsptests/foo" + +func _() { + foo. //@rank(" //", Foo) + var _ = []string{foo.} //@rank("}", Foo) +} diff --git a/gopls/internal/lsp/testdata/danglingstmt/dangling_switch_init.go b/gopls/internal/lsp/testdata/danglingstmt/dangling_switch_init.go new file mode 100644 index 000000000..15da3ce10 --- /dev/null +++ b/gopls/internal/lsp/testdata/danglingstmt/dangling_switch_init.go @@ -0,0 +1,9 @@ +package danglingstmt + +func _() { + switch i := baz //@rank(" //", danglingBaz) +} + +func baz() int { //@item(danglingBaz, "baz", "func() int", "func") + return 0 +} diff --git a/gopls/internal/lsp/testdata/danglingstmt/dangling_switch_init_tag.go b/gopls/internal/lsp/testdata/danglingstmt/dangling_switch_init_tag.go new file mode 100644 index 000000000..20b825b2e --- /dev/null +++ b/gopls/internal/lsp/testdata/danglingstmt/dangling_switch_init_tag.go @@ -0,0 +1,9 @@ +package danglingstmt + +func _() { + switch i := 0; baz //@rank(" //", danglingBaz2) +} + +func baz2() int { //@item(danglingBaz2, "baz2", "func() int", "func") + return 0 +} diff --git a/gopls/internal/lsp/testdata/deep/deep.go b/gopls/internal/lsp/testdata/deep/deep.go new file mode 100644 index 000000000..6908824f8 --- /dev/null +++ b/gopls/internal/lsp/testdata/deep/deep.go @@ -0,0 +1,142 @@ +package deep + +import "context" + +type deepA struct { + b deepB //@item(deepBField, "b", "deepB", "field") +} + +type deepB struct { +} + +func wantsDeepB(deepB) {} + +func _() { + var a deepA //@item(deepAVar, "a", "deepA", "var") + a.b //@item(deepABField, "a.b", "deepB", "field") + wantsDeepB(a) //@deep(")", deepABField, deepAVar) + + deepA{a} //@snippet("}", deepABField, "a.b", "a.b") +} + +func wantsContext(context.Context) {} + +func _() { + context.Background() //@item(ctxBackground, "context.Background", "func() context.Context", "func", "Background returns a non-nil, empty Context.") + context.TODO() //@item(ctxTODO, "context.TODO", "func() context.Context", "func", "TODO returns a non-nil, empty Context.") + + wantsContext(c) //@rank(")", ctxBackground),rank(")", ctxTODO) +} + +func _() { + var cork struct{ err error } + cork.err //@item(deepCorkErr, "cork.err", "error", "field") + context //@item(deepContextPkg, "context", "\"context\"", "package") + var _ error = co //@rank(" //", deepCorkErr, deepContextPkg) +} + +func _() { + // deepCircle is circular. + type deepCircle struct { + *deepCircle + } + var circle deepCircle //@item(deepCircle, "circle", "deepCircle", "var") + circle.deepCircle //@item(deepCircleField, "circle.deepCircle", "*deepCircle", "field") + var _ deepCircle = circ //@deep(" //", deepCircle, deepCircleField),snippet(" //", deepCircleField, "*circle.deepCircle", "*circle.deepCircle") +} + +func _() { + type deepEmbedC struct { + } + type deepEmbedB struct { + deepEmbedC + } + type deepEmbedA struct { + deepEmbedB + } + + wantsC := func(deepEmbedC) {} + + var a deepEmbedA //@item(deepEmbedA, "a", "deepEmbedA", "var") + a.deepEmbedB //@item(deepEmbedB, "a.deepEmbedB", "deepEmbedB", "field") + a.deepEmbedC //@item(deepEmbedC, "a.deepEmbedC", "deepEmbedC", "field") + wantsC(a) //@deep(")", deepEmbedC, deepEmbedA, deepEmbedB) +} + +func _() { + type nested struct { + a int + n *nested //@item(deepNestedField, "n", "*nested", "field") + } + + nested{ + a: 123, //@deep(" //", deepNestedField) + } +} + +func _() { + var a struct { + b struct { + c int + } + d int + } + + a.d //@item(deepAD, "a.d", "int", "field") + a.b.c //@item(deepABC, "a.b.c", "int", "field") + a.b //@item(deepAB, "a.b", "struct{...}", "field") + a //@item(deepA, "a", "struct{...}", "var") + + // "a.d" should be ranked above the deeper "a.b.c" + var i int + i = a //@deep(" //", deepAD, deepABC, deepA, deepAB) +} + +type foo struct { + b bar +} + +func (f foo) bar() bar { + return f.b +} + +func (f foo) barPtr() *bar { + return &f.b +} + +type bar struct{} + +func (b bar) valueReceiver() int { + return 0 +} + +func (b *bar) ptrReceiver() int { + return 0 +} + +func _() { + var ( + i int + f foo + ) + + f.bar().valueReceiver //@item(deepBarValue, "f.bar().valueReceiver", "func() int", "method") + f.barPtr().ptrReceiver //@item(deepBarPtrPtr, "f.barPtr().ptrReceiver", "func() int", "method") + f.barPtr().valueReceiver //@item(deepBarPtrValue, "f.barPtr().valueReceiver", "func() int", "method") + + i = fbar //@fuzzy(" //", deepBarValue, deepBarPtrPtr, deepBarPtrValue) +} + +func (b baz) Thing() struct{ val int } { + return b.thing +} + +type baz struct { + thing struct{ val int } +} + +func (b baz) _() { + b.Thing().val //@item(deepBazMethVal, "b.Thing().val", "int", "field") + b.thing.val //@item(deepBazFieldVal, "b.thing.val", "int", "field") + var _ int = bval //@rank(" //", deepBazFieldVal, deepBazMethVal) +} diff --git a/gopls/internal/lsp/testdata/errors/errors.go b/gopls/internal/lsp/testdata/errors/errors.go new file mode 100644 index 000000000..e14cde69e --- /dev/null +++ b/gopls/internal/lsp/testdata/errors/errors.go @@ -0,0 +1,10 @@ +package errors + +import ( + "golang.org/lsptests/types" +) + +func _() { + bob.Bob() //@complete(".") + types.b //@complete(" //", Bob_interface) +} diff --git a/gopls/internal/lsp/testdata/extract/extract_function/extract_args_returns.go b/gopls/internal/lsp/testdata/extract/extract_function/extract_args_returns.go new file mode 100644 index 000000000..63d24df00 --- /dev/null +++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_args_returns.go @@ -0,0 +1,11 @@ +package extract + +func _() { + a := 1 + a = 5 //@mark(exSt0, "a") + a = a + 2 //@mark(exEn0, "2") + //@extractfunc(exSt0, exEn0) + b := a * 2 //@mark(exB, " b") + _ = 3 + 4 //@mark(exEnd, "4") + //@extractfunc(exB, exEnd) +} diff --git a/gopls/internal/lsp/testdata/extract/extract_function/extract_args_returns.go.golden b/gopls/internal/lsp/testdata/extract/extract_function/extract_args_returns.go.golden new file mode 100644 index 000000000..b15345e23 --- /dev/null +++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_args_returns.go.golden @@ -0,0 +1,37 @@ +-- functionextraction_extract_args_returns_5_2 -- +package extract + +func _() { + a := 1 + //@mark(exSt0, "a") + a = newFunction(a) //@mark(exEn0, "2") + //@extractfunc(exSt0, exEn0) + b := a * 2 //@mark(exB, " b") + _ = 3 + 4 //@mark(exEnd, "4") + //@extractfunc(exB, exEnd) +} + +func newFunction(a int) int { + a = 5 + a = a + 2 + return a +} + +-- functionextraction_extract_args_returns_8_1 -- +package extract + +func _() { + a := 1 + a = 5 //@mark(exSt0, "a") + a = a + 2 //@mark(exEn0, "2") + //@extractfunc(exSt0, exEn0) + //@mark(exB, " b") + newFunction(a) //@mark(exEnd, "4") + //@extractfunc(exB, exEnd) +} + +func newFunction(a int) { + b := a * 2 + _ = 3 + 4 +} + diff --git a/gopls/internal/lsp/testdata/extract/extract_function/extract_basic.go b/gopls/internal/lsp/testdata/extract/extract_function/extract_basic.go new file mode 100644 index 000000000..5e44de26f --- /dev/null +++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_basic.go @@ -0,0 +1,8 @@ +package extract + +func _() { //@mark(exSt25, "{") + a := 1 //@mark(exSt1, "a") + _ = 3 + 4 //@mark(exEn1, "4") + //@extractfunc(exSt1, exEn1) + //@extractfunc(exSt25, exEn25) +} //@mark(exEn25, "}") diff --git a/gopls/internal/lsp/testdata/extract/extract_function/extract_basic.go.golden b/gopls/internal/lsp/testdata/extract/extract_function/extract_basic.go.golden new file mode 100644 index 000000000..18adc4db4 --- /dev/null +++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_basic.go.golden @@ -0,0 +1,30 @@ +-- functionextraction_extract_basic_3_10 -- +package extract + +func _() { //@mark(exSt25, "{") + //@mark(exSt1, "a") + newFunction() //@mark(exEn1, "4") + //@extractfunc(exSt1, exEn1) + //@extractfunc(exSt25, exEn25) +} + +func newFunction() { + a := 1 + _ = 3 + 4 +} //@mark(exEn25, "}") + +-- functionextraction_extract_basic_4_2 -- +package extract + +func _() { //@mark(exSt25, "{") + //@mark(exSt1, "a") + newFunction() //@mark(exEn1, "4") + //@extractfunc(exSt1, exEn1) + //@extractfunc(exSt25, exEn25) +} + +func newFunction() { + a := 1 + _ = 3 + 4 +} //@mark(exEn25, "}") + diff --git a/gopls/internal/lsp/testdata/extract/extract_function/extract_basic_comment.go b/gopls/internal/lsp/testdata/extract/extract_function/extract_basic_comment.go new file mode 100644 index 000000000..71f969e48 --- /dev/null +++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_basic_comment.go @@ -0,0 +1,12 @@ +package extract + +func _() { + a := /* comment in the middle of a line */ 1 //@mark(exSt18, "a") + // Comment on its own line //@mark(exSt19, "Comment") + _ = 3 + 4 //@mark(exEn18, "4"),mark(exEn19, "4"),mark(exSt20, "_") + // Comment right after 3 + 4 + + // Comment after with space //@mark(exEn20, "Comment") + + //@extractfunc(exSt18, exEn18),extractfunc(exSt19, exEn19),extractfunc(exSt20, exEn20) +} diff --git a/gopls/internal/lsp/testdata/extract/extract_function/extract_basic_comment.go.golden b/gopls/internal/lsp/testdata/extract/extract_function/extract_basic_comment.go.golden new file mode 100644 index 000000000..1b2869ef7 --- /dev/null +++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_basic_comment.go.golden @@ -0,0 +1,57 @@ +-- functionextraction_extract_basic_comment_4_2 -- +package extract + +func _() { + /* comment in the middle of a line */ + //@mark(exSt18, "a") + // Comment on its own line //@mark(exSt19, "Comment") + newFunction() //@mark(exEn18, "4"),mark(exEn19, "4"),mark(exSt20, "_") + // Comment right after 3 + 4 + + // Comment after with space //@mark(exEn20, "Comment") + + //@extractfunc(exSt18, exEn18),extractfunc(exSt19, exEn19),extractfunc(exSt20, exEn20) +} + +func newFunction() { + a := 1 + + _ = 3 + 4 +} + +-- functionextraction_extract_basic_comment_5_5 -- +package extract + +func _() { + a := /* comment in the middle of a line */ 1 //@mark(exSt18, "a") + // Comment on its own line //@mark(exSt19, "Comment") + newFunction() //@mark(exEn18, "4"),mark(exEn19, "4"),mark(exSt20, "_") + // Comment right after 3 + 4 + + // Comment after with space //@mark(exEn20, "Comment") + + //@extractfunc(exSt18, exEn18),extractfunc(exSt19, exEn19),extractfunc(exSt20, exEn20) +} + +func newFunction() { + _ = 3 + 4 +} + +-- functionextraction_extract_basic_comment_6_2 -- +package extract + +func _() { + a := /* comment in the middle of a line */ 1 //@mark(exSt18, "a") + // Comment on its own line //@mark(exSt19, "Comment") + newFunction() //@mark(exEn18, "4"),mark(exEn19, "4"),mark(exSt20, "_") + // Comment right after 3 + 4 + + // Comment after with space //@mark(exEn20, "Comment") + + //@extractfunc(exSt18, exEn18),extractfunc(exSt19, exEn19),extractfunc(exSt20, exEn20) +} + +func newFunction() { + _ = 3 + 4 +} + diff --git a/gopls/internal/lsp/testdata/extract/extract_function/extract_issue_44813.go b/gopls/internal/lsp/testdata/extract/extract_function/extract_issue_44813.go new file mode 100644 index 000000000..9713b9101 --- /dev/null +++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_issue_44813.go @@ -0,0 +1,13 @@ +package extract + +import "fmt" + +func main() { + x := []rune{} //@mark(exSt9, "x") + s := "HELLO" + for _, c := range s { + x = append(x, c) + } //@mark(exEn9, "}") + //@extractfunc(exSt9, exEn9) + fmt.Printf("%x\n", x) +} diff --git a/gopls/internal/lsp/testdata/extract/extract_function/extract_issue_44813.go.golden b/gopls/internal/lsp/testdata/extract/extract_function/extract_issue_44813.go.golden new file mode 100644 index 000000000..3198c9fa2 --- /dev/null +++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_issue_44813.go.golden @@ -0,0 +1,21 @@ +-- functionextraction_extract_issue_44813_6_2 -- +package extract + +import "fmt" + +func main() { + //@mark(exSt9, "x") + x := newFunction() //@mark(exEn9, "}") + //@extractfunc(exSt9, exEn9) + fmt.Printf("%x\n", x) +} + +func newFunction() []rune { + x := []rune{} + s := "HELLO" + for _, c := range s { + x = append(x, c) + } + return x +} + diff --git a/gopls/internal/lsp/testdata/extract/extract_function/extract_redefine.go b/gopls/internal/lsp/testdata/extract/extract_function/extract_redefine.go new file mode 100644 index 000000000..604f4757c --- /dev/null +++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_redefine.go @@ -0,0 +1,11 @@ +package extract + +import "strconv" + +func _() { + i, err := strconv.Atoi("1") + u, err := strconv.Atoi("2") //@extractfunc("u", ")") + if i == u || err == nil { + return + } +} diff --git a/gopls/internal/lsp/testdata/extract/extract_function/extract_redefine.go.golden b/gopls/internal/lsp/testdata/extract/extract_function/extract_redefine.go.golden new file mode 100644 index 000000000..e2ee217d1 --- /dev/null +++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_redefine.go.golden @@ -0,0 +1,18 @@ +-- functionextraction_extract_redefine_7_2 -- +package extract + +import "strconv" + +func _() { + i, err := strconv.Atoi("1") + u, err := newFunction() //@extractfunc("u", ")") + if i == u || err == nil { + return + } +} + +func newFunction() (int, error) { + u, err := strconv.Atoi("2") + return u, err +} + diff --git a/gopls/internal/lsp/testdata/extract/extract_function/extract_return_basic.go b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_basic.go new file mode 100644 index 000000000..1ff24daeb --- /dev/null +++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_basic.go @@ -0,0 +1,10 @@ +package extract + +func _() bool { + x := 1 + if x == 0 { //@mark(exSt2, "if") + return true + } //@mark(exEn2, "}") + return false + //@extractfunc(exSt2, exEn2) +} diff --git a/gopls/internal/lsp/testdata/extract/extract_function/extract_return_basic.go.golden b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_basic.go.golden new file mode 100644 index 000000000..6103d1ee9 --- /dev/null +++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_basic.go.golden @@ -0,0 +1,21 @@ +-- functionextraction_extract_return_basic_5_2 -- +package extract + +func _() bool { + x := 1 + //@mark(exSt2, "if") + shouldReturn, returnValue := newFunction(x) + if shouldReturn { + return returnValue + } //@mark(exEn2, "}") + return false + //@extractfunc(exSt2, exEn2) +} + +func newFunction(x int) (bool, bool) { + if x == 0 { + return true, true + } + return false, false +} + diff --git a/gopls/internal/lsp/testdata/extract/extract_function/extract_return_basic_nonnested.go b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_basic_nonnested.go new file mode 100644 index 000000000..08573acdd --- /dev/null +++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_basic_nonnested.go @@ -0,0 +1,10 @@ +package extract + +func _() bool { + x := 1 //@mark(exSt13, "x") + if x == 0 { + return true + } + return false //@mark(exEn13, "false") + //@extractfunc(exSt13, exEn13) +} diff --git a/gopls/internal/lsp/testdata/extract/extract_function/extract_return_basic_nonnested.go.golden b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_basic_nonnested.go.golden new file mode 100644 index 000000000..19e48da01 --- /dev/null +++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_basic_nonnested.go.golden @@ -0,0 +1,17 @@ +-- functionextraction_extract_return_basic_nonnested_4_2 -- +package extract + +func _() bool { + //@mark(exSt13, "x") + return newFunction() //@mark(exEn13, "false") + //@extractfunc(exSt13, exEn13) +} + +func newFunction() bool { + x := 1 + if x == 0 { + return true + } + return false +} + diff --git a/gopls/internal/lsp/testdata/extract/extract_function/extract_return_complex.go b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_complex.go new file mode 100644 index 000000000..605c5ec2e --- /dev/null +++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_complex.go @@ -0,0 +1,17 @@ +package extract + +import "fmt" + +func _() (int, string, error) { + x := 1 + y := "hello" + z := "bye" //@mark(exSt3, "z") + if y == z { + return x, y, fmt.Errorf("same") + } else { + z = "hi" + return x, z, nil + } //@mark(exEn3, "}") + return x, z, nil + //@extractfunc(exSt3, exEn3) +} diff --git a/gopls/internal/lsp/testdata/extract/extract_function/extract_return_complex.go.golden b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_complex.go.golden new file mode 100644 index 000000000..4d201227a --- /dev/null +++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_complex.go.golden @@ -0,0 +1,28 @@ +-- functionextraction_extract_return_complex_8_2 -- +package extract + +import "fmt" + +func _() (int, string, error) { + x := 1 + y := "hello" + //@mark(exSt3, "z") + z, shouldReturn, returnValue, returnValue1, returnValue2 := newFunction(y, x) + if shouldReturn { + return returnValue, returnValue1, returnValue2 + } //@mark(exEn3, "}") + return x, z, nil + //@extractfunc(exSt3, exEn3) +} + +func newFunction(y string, x int) (string, bool, int, string, error) { + z := "bye" + if y == z { + return "", true, x, y, fmt.Errorf("same") + } else { + z = "hi" + return "", true, x, z, nil + } + return z, false, 0, "", nil +} + diff --git a/gopls/internal/lsp/testdata/extract/extract_function/extract_return_complex_nonnested.go b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_complex_nonnested.go new file mode 100644 index 000000000..6b2a4d8c0 --- /dev/null +++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_complex_nonnested.go @@ -0,0 +1,17 @@ +package extract + +import "fmt" + +func _() (int, string, error) { + x := 1 + y := "hello" + z := "bye" //@mark(exSt10, "z") + if y == z { + return x, y, fmt.Errorf("same") + } else { + z = "hi" + return x, z, nil + } + return x, z, nil //@mark(exEn10, "nil") + //@extractfunc(exSt10, exEn10) +} diff --git a/gopls/internal/lsp/testdata/extract/extract_function/extract_return_complex_nonnested.go.golden b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_complex_nonnested.go.golden new file mode 100644 index 000000000..de54b1534 --- /dev/null +++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_complex_nonnested.go.golden @@ -0,0 +1,24 @@ +-- functionextraction_extract_return_complex_nonnested_8_2 -- +package extract + +import "fmt" + +func _() (int, string, error) { + x := 1 + y := "hello" + //@mark(exSt10, "z") + return newFunction(y, x) //@mark(exEn10, "nil") + //@extractfunc(exSt10, exEn10) +} + +func newFunction(y string, x int) (int, string, error) { + z := "bye" + if y == z { + return x, y, fmt.Errorf("same") + } else { + z = "hi" + return x, z, nil + } + return x, z, nil +} + diff --git a/gopls/internal/lsp/testdata/extract/extract_function/extract_return_func_lit.go b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_func_lit.go new file mode 100644 index 000000000..b3fb4fd21 --- /dev/null +++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_func_lit.go @@ -0,0 +1,13 @@ +package extract + +import "go/ast" + +func _() { + ast.Inspect(ast.NewIdent("a"), func(n ast.Node) bool { + if n == nil { //@mark(exSt4, "if") + return true + } //@mark(exEn4, "}") + return false + }) + //@extractfunc(exSt4, exEn4) +} diff --git a/gopls/internal/lsp/testdata/extract/extract_function/extract_return_func_lit.go.golden b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_func_lit.go.golden new file mode 100644 index 000000000..3af747c22 --- /dev/null +++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_func_lit.go.golden @@ -0,0 +1,24 @@ +-- functionextraction_extract_return_func_lit_7_3 -- +package extract + +import "go/ast" + +func _() { + ast.Inspect(ast.NewIdent("a"), func(n ast.Node) bool { + //@mark(exSt4, "if") + shouldReturn, returnValue := newFunction(n) + if shouldReturn { + return returnValue + } //@mark(exEn4, "}") + return false + }) + //@extractfunc(exSt4, exEn4) +} + +func newFunction(n ast.Node) (bool, bool) { + if n == nil { + return true, true + } + return false, false +} + diff --git a/gopls/internal/lsp/testdata/extract/extract_function/extract_return_func_lit_nonnested.go b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_func_lit_nonnested.go new file mode 100644 index 000000000..c22db2a6d --- /dev/null +++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_func_lit_nonnested.go @@ -0,0 +1,13 @@ +package extract + +import "go/ast" + +func _() { + ast.Inspect(ast.NewIdent("a"), func(n ast.Node) bool { + if n == nil { //@mark(exSt11, "if") + return true + } + return false //@mark(exEn11, "false") + }) + //@extractfunc(exSt11, exEn11) +} diff --git a/gopls/internal/lsp/testdata/extract/extract_function/extract_return_func_lit_nonnested.go.golden b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_func_lit_nonnested.go.golden new file mode 100644 index 000000000..efa22ba2b --- /dev/null +++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_func_lit_nonnested.go.golden @@ -0,0 +1,20 @@ +-- functionextraction_extract_return_func_lit_nonnested_7_3 -- +package extract + +import "go/ast" + +func _() { + ast.Inspect(ast.NewIdent("a"), func(n ast.Node) bool { + //@mark(exSt11, "if") + return newFunction(n) //@mark(exEn11, "false") + }) + //@extractfunc(exSt11, exEn11) +} + +func newFunction(n ast.Node) bool { + if n == nil { + return true + } + return false +} + diff --git a/gopls/internal/lsp/testdata/extract/extract_function/extract_return_init.go b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_init.go new file mode 100644 index 000000000..c1994c1c1 --- /dev/null +++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_init.go @@ -0,0 +1,12 @@ +package extract + +func _() string { + x := 1 + if x == 0 { //@mark(exSt5, "if") + x = 3 + return "a" + } //@mark(exEn5, "}") + x = 2 + return "b" + //@extractfunc(exSt5, exEn5) +} diff --git a/gopls/internal/lsp/testdata/extract/extract_function/extract_return_init.go.golden b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_init.go.golden new file mode 100644 index 000000000..31d1b2ddf --- /dev/null +++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_init.go.golden @@ -0,0 +1,23 @@ +-- functionextraction_extract_return_init_5_2 -- +package extract + +func _() string { + x := 1 + //@mark(exSt5, "if") + shouldReturn, returnValue := newFunction(x) + if shouldReturn { + return returnValue + } //@mark(exEn5, "}") + x = 2 + return "b" + //@extractfunc(exSt5, exEn5) +} + +func newFunction(x int) (bool, string) { + if x == 0 { + x = 3 + return true, "a" + } + return false, "" +} + diff --git a/gopls/internal/lsp/testdata/extract/extract_function/extract_return_init_nonnested.go b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_init_nonnested.go new file mode 100644 index 000000000..bb5ed083c --- /dev/null +++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_init_nonnested.go @@ -0,0 +1,12 @@ +package extract + +func _() string { + x := 1 + if x == 0 { //@mark(exSt12, "if") + x = 3 + return "a" + } + x = 2 + return "b" //@mark(exEn12, "\"b\"") + //@extractfunc(exSt12, exEn12) +} diff --git a/gopls/internal/lsp/testdata/extract/extract_function/extract_return_init_nonnested.go.golden b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_init_nonnested.go.golden new file mode 100644 index 000000000..58bb57325 --- /dev/null +++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_init_nonnested.go.golden @@ -0,0 +1,19 @@ +-- functionextraction_extract_return_init_nonnested_5_2 -- +package extract + +func _() string { + x := 1 + //@mark(exSt12, "if") + return newFunction(x) //@mark(exEn12, "\"b\"") + //@extractfunc(exSt12, exEn12) +} + +func newFunction(x int) string { + if x == 0 { + x = 3 + return "a" + } + x = 2 + return "b" +} + diff --git a/gopls/internal/lsp/testdata/extract/extract_function/extract_scope.go b/gopls/internal/lsp/testdata/extract/extract_function/extract_scope.go new file mode 100644 index 000000000..6cc141fd1 --- /dev/null +++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_scope.go @@ -0,0 +1,10 @@ +package extract + +func _() { + newFunction := 1 + a := newFunction //@extractfunc("a", "newFunction") +} + +func newFunction1() int { + return 1 +} diff --git a/gopls/internal/lsp/testdata/extract/extract_function/extract_scope.go.golden b/gopls/internal/lsp/testdata/extract/extract_function/extract_scope.go.golden new file mode 100644 index 000000000..a4803b4fe --- /dev/null +++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_scope.go.golden @@ -0,0 +1,16 @@ +-- functionextraction_extract_scope_5_2 -- +package extract + +func _() { + newFunction := 1 + newFunction2(newFunction) //@extractfunc("a", "newFunction") +} + +func newFunction2(newFunction int) { + a := newFunction +} + +func newFunction1() int { + return 1 +} + diff --git a/gopls/internal/lsp/testdata/extract/extract_function/extract_smart_initialization.go b/gopls/internal/lsp/testdata/extract/extract_function/extract_smart_initialization.go new file mode 100644 index 000000000..da2c669a8 --- /dev/null +++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_smart_initialization.go @@ -0,0 +1,9 @@ +package extract + +func _() { + var a []int + a = append(a, 2) //@mark(exSt6, "a") + b := 4 //@mark(exEn6, "4") + //@extractfunc(exSt6, exEn6) + a = append(a, b) +} diff --git a/gopls/internal/lsp/testdata/extract/extract_function/extract_smart_initialization.go.golden b/gopls/internal/lsp/testdata/extract/extract_function/extract_smart_initialization.go.golden new file mode 100644 index 000000000..8be5040c4 --- /dev/null +++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_smart_initialization.go.golden @@ -0,0 +1,17 @@ +-- functionextraction_extract_smart_initialization_5_2 -- +package extract + +func _() { + var a []int + //@mark(exSt6, "a") + a, b := newFunction(a) //@mark(exEn6, "4") + //@extractfunc(exSt6, exEn6) + a = append(a, b) +} + +func newFunction(a []int) ([]int, int) { + a = append(a, 2) + b := 4 + return a, b +} + diff --git a/gopls/internal/lsp/testdata/extract/extract_function/extract_smart_return.go b/gopls/internal/lsp/testdata/extract/extract_function/extract_smart_return.go new file mode 100644 index 000000000..264d680e2 --- /dev/null +++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_smart_return.go @@ -0,0 +1,11 @@ +package extract + +func _() { + var b []int + var a int + a = 2 //@mark(exSt7, "a") + b = []int{} + b = append(b, a) //@mark(exEn7, ")") + b[0] = 1 + //@extractfunc(exSt7, exEn7) +} diff --git a/gopls/internal/lsp/testdata/extract/extract_function/extract_smart_return.go.golden b/gopls/internal/lsp/testdata/extract/extract_function/extract_smart_return.go.golden new file mode 100644 index 000000000..fdf55ae6d --- /dev/null +++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_smart_return.go.golden @@ -0,0 +1,19 @@ +-- functionextraction_extract_smart_return_6_2 -- +package extract + +func _() { + var b []int + var a int + //@mark(exSt7, "a") + b = newFunction(a, b) //@mark(exEn7, ")") + b[0] = 1 + //@extractfunc(exSt7, exEn7) +} + +func newFunction(a int, b []int) []int { + a = 2 + b = []int{} + b = append(b, a) + return b +} + diff --git a/gopls/internal/lsp/testdata/extract/extract_function/extract_unnecessary_param.go b/gopls/internal/lsp/testdata/extract/extract_function/extract_unnecessary_param.go new file mode 100644 index 000000000..a6eb1f872 --- /dev/null +++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_unnecessary_param.go @@ -0,0 +1,14 @@ +package extract + +func _() { + var b []int + var a int + a := 2 //@mark(exSt8, "a") + b = []int{} + b = append(b, a) //@mark(exEn8, ")") + b[0] = 1 + if a == 2 { + return + } + //@extractfunc(exSt8, exEn8) +} diff --git a/gopls/internal/lsp/testdata/extract/extract_function/extract_unnecessary_param.go.golden b/gopls/internal/lsp/testdata/extract/extract_function/extract_unnecessary_param.go.golden new file mode 100644 index 000000000..4374f3728 --- /dev/null +++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_unnecessary_param.go.golden @@ -0,0 +1,22 @@ +-- functionextraction_extract_unnecessary_param_6_2 -- +package extract + +func _() { + var b []int + var a int + //@mark(exSt8, "a") + a, b = newFunction(b) //@mark(exEn8, ")") + b[0] = 1 + if a == 2 { + return + } + //@extractfunc(exSt8, exEn8) +} + +func newFunction(b []int) (int, []int) { + a := 2 + b = []int{} + b = append(b, a) + return a, b +} + diff --git a/gopls/internal/lsp/testdata/extract/extract_method/extract_basic.go b/gopls/internal/lsp/testdata/extract/extract_method/extract_basic.go new file mode 100644 index 000000000..c9a8d9dce --- /dev/null +++ b/gopls/internal/lsp/testdata/extract/extract_method/extract_basic.go @@ -0,0 +1,24 @@ +package extract + +type A struct { + x int + y int +} + +func (a *A) XLessThanYP() bool { + return a.x < a.y //@extractmethod("return", "a.y"),extractfunc("return", "a.y") +} + +func (a *A) AddP() int { + sum := a.x + a.y //@extractmethod("sum", "a.y"),extractfunc("sum", "a.y") + return sum //@extractmethod("return", "sum"),extractfunc("return", "sum") +} + +func (a A) XLessThanY() bool { + return a.x < a.y //@extractmethod("return", "a.y"),extractfunc("return", "a.y") +} + +func (a A) Add() int { + sum := a.x + a.y //@extractmethod("sum", "a.y"),extractfunc("sum", "a.y") + return sum //@extractmethod("return", "sum"),extractfunc("return", "sum") +} diff --git a/gopls/internal/lsp/testdata/extract/extract_method/extract_basic.go.golden b/gopls/internal/lsp/testdata/extract/extract_method/extract_basic.go.golden new file mode 100644 index 000000000..3310d973e --- /dev/null +++ b/gopls/internal/lsp/testdata/extract/extract_method/extract_basic.go.golden @@ -0,0 +1,364 @@ +-- functionextraction_extract_basic_13_2 -- +package extract + +type A struct { + x int + y int +} + +func (a *A) XLessThanYP() bool { + return a.x < a.y //@extractmethod("return", "a.y"),extractfunc("return", "a.y") +} + +func (a *A) AddP() int { + sum := newFunction(a) //@extractmethod("sum", "a.y"),extractfunc("sum", "a.y") + return sum //@extractmethod("return", "sum"),extractfunc("return", "sum") +} + +func newFunction(a *A) int { + sum := a.x + a.y + return sum +} + +func (a A) XLessThanY() bool { + return a.x < a.y //@extractmethod("return", "a.y"),extractfunc("return", "a.y") +} + +func (a A) Add() int { + sum := a.x + a.y //@extractmethod("sum", "a.y"),extractfunc("sum", "a.y") + return sum //@extractmethod("return", "sum"),extractfunc("return", "sum") +} + +-- functionextraction_extract_basic_14_2 -- +package extract + +type A struct { + x int + y int +} + +func (a *A) XLessThanYP() bool { + return a.x < a.y //@extractmethod("return", "a.y"),extractfunc("return", "a.y") +} + +func (a *A) AddP() int { + sum := a.x + a.y //@extractmethod("sum", "a.y"),extractfunc("sum", "a.y") + return newFunction(sum) //@extractmethod("return", "sum"),extractfunc("return", "sum") +} + +func newFunction(sum int) int { + return sum +} + +func (a A) XLessThanY() bool { + return a.x < a.y //@extractmethod("return", "a.y"),extractfunc("return", "a.y") +} + +func (a A) Add() int { + sum := a.x + a.y //@extractmethod("sum", "a.y"),extractfunc("sum", "a.y") + return sum //@extractmethod("return", "sum"),extractfunc("return", "sum") +} + +-- functionextraction_extract_basic_18_2 -- +package extract + +type A struct { + x int + y int +} + +func (a *A) XLessThanYP() bool { + return a.x < a.y //@extractmethod("return", "a.y"),extractfunc("return", "a.y") +} + +func (a *A) AddP() int { + sum := a.x + a.y //@extractmethod("sum", "a.y"),extractfunc("sum", "a.y") + return sum //@extractmethod("return", "sum"),extractfunc("return", "sum") +} + +func (a A) XLessThanY() bool { + return newFunction(a) //@extractmethod("return", "a.y"),extractfunc("return", "a.y") +} + +func newFunction(a A) bool { + return a.x < a.y +} + +func (a A) Add() int { + sum := a.x + a.y //@extractmethod("sum", "a.y"),extractfunc("sum", "a.y") + return sum //@extractmethod("return", "sum"),extractfunc("return", "sum") +} + +-- functionextraction_extract_basic_22_2 -- +package extract + +type A struct { + x int + y int +} + +func (a *A) XLessThanYP() bool { + return a.x < a.y //@extractmethod("return", "a.y"),extractfunc("return", "a.y") +} + +func (a *A) AddP() int { + sum := a.x + a.y //@extractmethod("sum", "a.y"),extractfunc("sum", "a.y") + return sum //@extractmethod("return", "sum"),extractfunc("return", "sum") +} + +func (a A) XLessThanY() bool { + return a.x < a.y //@extractmethod("return", "a.y"),extractfunc("return", "a.y") +} + +func (a A) Add() int { + sum := newFunction(a) //@extractmethod("sum", "a.y"),extractfunc("sum", "a.y") + return sum //@extractmethod("return", "sum"),extractfunc("return", "sum") +} + +func newFunction(a A) int { + sum := a.x + a.y + return sum +} + +-- functionextraction_extract_basic_23_2 -- +package extract + +type A struct { + x int + y int +} + +func (a *A) XLessThanYP() bool { + return a.x < a.y //@extractmethod("return", "a.y"),extractfunc("return", "a.y") +} + +func (a *A) AddP() int { + sum := a.x + a.y //@extractmethod("sum", "a.y"),extractfunc("sum", "a.y") + return sum //@extractmethod("return", "sum"),extractfunc("return", "sum") +} + +func (a A) XLessThanY() bool { + return a.x < a.y //@extractmethod("return", "a.y"),extractfunc("return", "a.y") +} + +func (a A) Add() int { + sum := a.x + a.y //@extractmethod("sum", "a.y"),extractfunc("sum", "a.y") + return newFunction(sum) //@extractmethod("return", "sum"),extractfunc("return", "sum") +} + +func newFunction(sum int) int { + return sum +} + +-- functionextraction_extract_basic_9_2 -- +package extract + +type A struct { + x int + y int +} + +func (a *A) XLessThanYP() bool { + return newFunction(a) //@extractmethod("return", "a.y"),extractfunc("return", "a.y") +} + +func newFunction(a *A) bool { + return a.x < a.y +} + +func (a *A) AddP() int { + sum := a.x + a.y //@extractmethod("sum", "a.y"),extractfunc("sum", "a.y") + return sum //@extractmethod("return", "sum"),extractfunc("return", "sum") +} + +func (a A) XLessThanY() bool { + return a.x < a.y //@extractmethod("return", "a.y"),extractfunc("return", "a.y") +} + +func (a A) Add() int { + sum := a.x + a.y //@extractmethod("sum", "a.y"),extractfunc("sum", "a.y") + return sum //@extractmethod("return", "sum"),extractfunc("return", "sum") +} + +-- methodextraction_extract_basic_13_2 -- +package extract + +type A struct { + x int + y int +} + +func (a *A) XLessThanYP() bool { + return a.x < a.y //@extractmethod("return", "a.y"),extractfunc("return", "a.y") +} + +func (a *A) AddP() int { + sum := a.newMethod() //@extractmethod("sum", "a.y"),extractfunc("sum", "a.y") + return sum //@extractmethod("return", "sum"),extractfunc("return", "sum") +} + +func (a *A) newMethod() int { + sum := a.x + a.y + return sum +} + +func (a A) XLessThanY() bool { + return a.x < a.y //@extractmethod("return", "a.y"),extractfunc("return", "a.y") +} + +func (a A) Add() int { + sum := a.x + a.y //@extractmethod("sum", "a.y"),extractfunc("sum", "a.y") + return sum //@extractmethod("return", "sum"),extractfunc("return", "sum") +} + +-- methodextraction_extract_basic_14_2 -- +package extract + +type A struct { + x int + y int +} + +func (a *A) XLessThanYP() bool { + return a.x < a.y //@extractmethod("return", "a.y"),extractfunc("return", "a.y") +} + +func (a *A) AddP() int { + sum := a.x + a.y //@extractmethod("sum", "a.y"),extractfunc("sum", "a.y") + return a.newMethod(sum) //@extractmethod("return", "sum"),extractfunc("return", "sum") +} + +func (*A) newMethod(sum int) int { + return sum +} + +func (a A) XLessThanY() bool { + return a.x < a.y //@extractmethod("return", "a.y"),extractfunc("return", "a.y") +} + +func (a A) Add() int { + sum := a.x + a.y //@extractmethod("sum", "a.y"),extractfunc("sum", "a.y") + return sum //@extractmethod("return", "sum"),extractfunc("return", "sum") +} + +-- methodextraction_extract_basic_18_2 -- +package extract + +type A struct { + x int + y int +} + +func (a *A) XLessThanYP() bool { + return a.x < a.y //@extractmethod("return", "a.y"),extractfunc("return", "a.y") +} + +func (a *A) AddP() int { + sum := a.x + a.y //@extractmethod("sum", "a.y"),extractfunc("sum", "a.y") + return sum //@extractmethod("return", "sum"),extractfunc("return", "sum") +} + +func (a A) XLessThanY() bool { + return a.newMethod() //@extractmethod("return", "a.y"),extractfunc("return", "a.y") +} + +func (a A) newMethod() bool { + return a.x < a.y +} + +func (a A) Add() int { + sum := a.x + a.y //@extractmethod("sum", "a.y"),extractfunc("sum", "a.y") + return sum //@extractmethod("return", "sum"),extractfunc("return", "sum") +} + +-- methodextraction_extract_basic_22_2 -- +package extract + +type A struct { + x int + y int +} + +func (a *A) XLessThanYP() bool { + return a.x < a.y //@extractmethod("return", "a.y"),extractfunc("return", "a.y") +} + +func (a *A) AddP() int { + sum := a.x + a.y //@extractmethod("sum", "a.y"),extractfunc("sum", "a.y") + return sum //@extractmethod("return", "sum"),extractfunc("return", "sum") +} + +func (a A) XLessThanY() bool { + return a.x < a.y //@extractmethod("return", "a.y"),extractfunc("return", "a.y") +} + +func (a A) Add() int { + sum := a.newMethod() //@extractmethod("sum", "a.y"),extractfunc("sum", "a.y") + return sum //@extractmethod("return", "sum"),extractfunc("return", "sum") +} + +func (a A) newMethod() int { + sum := a.x + a.y + return sum +} + +-- methodextraction_extract_basic_23_2 -- +package extract + +type A struct { + x int + y int +} + +func (a *A) XLessThanYP() bool { + return a.x < a.y //@extractmethod("return", "a.y"),extractfunc("return", "a.y") +} + +func (a *A) AddP() int { + sum := a.x + a.y //@extractmethod("sum", "a.y"),extractfunc("sum", "a.y") + return sum //@extractmethod("return", "sum"),extractfunc("return", "sum") +} + +func (a A) XLessThanY() bool { + return a.x < a.y //@extractmethod("return", "a.y"),extractfunc("return", "a.y") +} + +func (a A) Add() int { + sum := a.x + a.y //@extractmethod("sum", "a.y"),extractfunc("sum", "a.y") + return a.newMethod(sum) //@extractmethod("return", "sum"),extractfunc("return", "sum") +} + +func (A) newMethod(sum int) int { + return sum +} + +-- methodextraction_extract_basic_9_2 -- +package extract + +type A struct { + x int + y int +} + +func (a *A) XLessThanYP() bool { + return a.newMethod() //@extractmethod("return", "a.y"),extractfunc("return", "a.y") +} + +func (a *A) newMethod() bool { + return a.x < a.y +} + +func (a *A) AddP() int { + sum := a.x + a.y //@extractmethod("sum", "a.y"),extractfunc("sum", "a.y") + return sum //@extractmethod("return", "sum"),extractfunc("return", "sum") +} + +func (a A) XLessThanY() bool { + return a.x < a.y //@extractmethod("return", "a.y"),extractfunc("return", "a.y") +} + +func (a A) Add() int { + sum := a.x + a.y //@extractmethod("sum", "a.y"),extractfunc("sum", "a.y") + return sum //@extractmethod("return", "sum"),extractfunc("return", "sum") +} + diff --git a/gopls/internal/lsp/testdata/extract/extract_variable/extract_basic_lit.go b/gopls/internal/lsp/testdata/extract/extract_variable/extract_basic_lit.go new file mode 100644 index 000000000..cbb70a04c --- /dev/null +++ b/gopls/internal/lsp/testdata/extract/extract_variable/extract_basic_lit.go @@ -0,0 +1,6 @@ +package extract + +func _() { + var _ = 1 + 2 //@suggestedfix("1", "refactor.extract", "") + var _ = 3 + 4 //@suggestedfix("3 + 4", "refactor.extract", "") +} diff --git a/gopls/internal/lsp/testdata/extract/extract_variable/extract_basic_lit.go.golden b/gopls/internal/lsp/testdata/extract/extract_variable/extract_basic_lit.go.golden new file mode 100644 index 000000000..3fd9b3287 --- /dev/null +++ b/gopls/internal/lsp/testdata/extract/extract_variable/extract_basic_lit.go.golden @@ -0,0 +1,18 @@ +-- suggestedfix_extract_basic_lit_4_10 -- +package extract + +func _() { + x := 1 + var _ = x + 2 //@suggestedfix("1", "refactor.extract", "") + var _ = 3 + 4 //@suggestedfix("3 + 4", "refactor.extract", "") +} + +-- suggestedfix_extract_basic_lit_5_10 -- +package extract + +func _() { + var _ = 1 + 2 //@suggestedfix("1", "refactor.extract", "") + x := 3 + 4 + var _ = x //@suggestedfix("3 + 4", "refactor.extract", "") +} + diff --git a/gopls/internal/lsp/testdata/extract/extract_variable/extract_func_call.go b/gopls/internal/lsp/testdata/extract/extract_variable/extract_func_call.go new file mode 100644 index 000000000..a20b45f58 --- /dev/null +++ b/gopls/internal/lsp/testdata/extract/extract_variable/extract_func_call.go @@ -0,0 +1,9 @@ +package extract + +import "strconv" + +func _() { + x0 := append([]int{}, 1) //@suggestedfix("append([]int{}, 1)", "refactor.extract", "") + str := "1" + b, err := strconv.Atoi(str) //@suggestedfix("strconv.Atoi(str)", "refactor.extract", "") +} diff --git a/gopls/internal/lsp/testdata/extract/extract_variable/extract_func_call.go.golden b/gopls/internal/lsp/testdata/extract/extract_variable/extract_func_call.go.golden new file mode 100644 index 000000000..d59c0ee99 --- /dev/null +++ b/gopls/internal/lsp/testdata/extract/extract_variable/extract_func_call.go.golden @@ -0,0 +1,24 @@ +-- suggestedfix_extract_func_call_6_8 -- +package extract + +import "strconv" + +func _() { + x := append([]int{}, 1) + x0 := x //@suggestedfix("append([]int{}, 1)", "refactor.extract", "") + str := "1" + b, err := strconv.Atoi(str) //@suggestedfix("strconv.Atoi(str)", "refactor.extract", "") +} + +-- suggestedfix_extract_func_call_8_12 -- +package extract + +import "strconv" + +func _() { + x0 := append([]int{}, 1) //@suggestedfix("append([]int{}, 1)", "refactor.extract", "") + str := "1" + x, x1 := strconv.Atoi(str) + b, err := x, x1 //@suggestedfix("strconv.Atoi(str)", "refactor.extract", "") +} + diff --git a/gopls/internal/lsp/testdata/extract/extract_variable/extract_scope.go b/gopls/internal/lsp/testdata/extract/extract_variable/extract_scope.go new file mode 100644 index 000000000..c14ad7092 --- /dev/null +++ b/gopls/internal/lsp/testdata/extract/extract_variable/extract_scope.go @@ -0,0 +1,13 @@ +package extract + +import "go/ast" + +func _() { + x0 := 0 + if true { + y := ast.CompositeLit{} //@suggestedfix("ast.CompositeLit{}", "refactor.extract", "") + } + if true { + x1 := !false //@suggestedfix("!false", "refactor.extract", "") + } +} diff --git a/gopls/internal/lsp/testdata/extract/extract_variable/extract_scope.go.golden b/gopls/internal/lsp/testdata/extract/extract_variable/extract_scope.go.golden new file mode 100644 index 000000000..1c2f64b7d --- /dev/null +++ b/gopls/internal/lsp/testdata/extract/extract_variable/extract_scope.go.golden @@ -0,0 +1,32 @@ +-- suggestedfix_extract_scope_11_9 -- +package extract + +import "go/ast" + +func _() { + x0 := 0 + if true { + y := ast.CompositeLit{} //@suggestedfix("ast.CompositeLit{}", "refactor.extract", "") + } + if true { + x := !false + x1 := x //@suggestedfix("!false", "refactor.extract", "") + } +} + +-- suggestedfix_extract_scope_8_8 -- +package extract + +import "go/ast" + +func _() { + x0 := 0 + if true { + x := ast.CompositeLit{} + y := x //@suggestedfix("ast.CompositeLit{}", "refactor.extract", "") + } + if true { + x1 := !false //@suggestedfix("!false", "refactor.extract", "") + } +} + diff --git a/gopls/internal/lsp/testdata/fieldlist/field_list.go b/gopls/internal/lsp/testdata/fieldlist/field_list.go new file mode 100644 index 000000000..e687defb1 --- /dev/null +++ b/gopls/internal/lsp/testdata/fieldlist/field_list.go @@ -0,0 +1,27 @@ +package fieldlist + +var myInt int //@item(flVar, "myInt", "int", "var") +type myType int //@item(flType, "myType", "int", "type") + +func (my) _() {} //@complete(") _", flType) +func (my my) _() {} //@complete(" my)"),complete(") _", flType) + +func (myType) _() {} //@complete(") {", flType) + +func (myType) _(my my) {} //@complete(" my)"),complete(") {", flType) + +func (myType) _() my {} //@complete(" {", flType) + +func (myType) _() (my my) {} //@complete(" my"),complete(") {", flType) + +func _() { + var _ struct { + //@complete("", flType) + m my //@complete(" my"),complete(" //", flType) + } + + var _ interface { + //@complete("", flType) + m() my //@complete("("),complete(" //", flType) + } +} diff --git a/gopls/internal/lsp/testdata/fillstruct/a.go b/gopls/internal/lsp/testdata/fillstruct/a.go new file mode 100644 index 000000000..e1add2d47 --- /dev/null +++ b/gopls/internal/lsp/testdata/fillstruct/a.go @@ -0,0 +1,27 @@ +package fillstruct + +import ( + "golang.org/lsptests/fillstruct/data" +) + +type basicStruct struct { + foo int +} + +var _ = basicStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill") + +type twoArgStruct struct { + foo int + bar string +} + +var _ = twoArgStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill") + +type nestedStruct struct { + bar string + basic basicStruct +} + +var _ = nestedStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill") + +var _ = data.B{} //@suggestedfix("}", "refactor.rewrite", "Fill") diff --git a/gopls/internal/lsp/testdata/fillstruct/a.go.golden b/gopls/internal/lsp/testdata/fillstruct/a.go.golden new file mode 100644 index 000000000..ca1db04ea --- /dev/null +++ b/gopls/internal/lsp/testdata/fillstruct/a.go.golden @@ -0,0 +1,126 @@ +-- suggestedfix_a_11_21 -- +package fillstruct + +import ( + "golang.org/lsptests/fillstruct/data" +) + +type basicStruct struct { + foo int +} + +var _ = basicStruct{ + foo: 0, +} //@suggestedfix("}", "refactor.rewrite", "Fill") + +type twoArgStruct struct { + foo int + bar string +} + +var _ = twoArgStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill") + +type nestedStruct struct { + bar string + basic basicStruct +} + +var _ = nestedStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill") + +var _ = data.B{} //@suggestedfix("}", "refactor.rewrite", "Fill") + +-- suggestedfix_a_18_22 -- +package fillstruct + +import ( + "golang.org/lsptests/fillstruct/data" +) + +type basicStruct struct { + foo int +} + +var _ = basicStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill") + +type twoArgStruct struct { + foo int + bar string +} + +var _ = twoArgStruct{ + foo: 0, + bar: "", +} //@suggestedfix("}", "refactor.rewrite", "Fill") + +type nestedStruct struct { + bar string + basic basicStruct +} + +var _ = nestedStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill") + +var _ = data.B{} //@suggestedfix("}", "refactor.rewrite", "Fill") + +-- suggestedfix_a_25_22 -- +package fillstruct + +import ( + "golang.org/lsptests/fillstruct/data" +) + +type basicStruct struct { + foo int +} + +var _ = basicStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill") + +type twoArgStruct struct { + foo int + bar string +} + +var _ = twoArgStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill") + +type nestedStruct struct { + bar string + basic basicStruct +} + +var _ = nestedStruct{ + bar: "", + basic: basicStruct{}, +} //@suggestedfix("}", "refactor.rewrite", "Fill") + +var _ = data.B{} //@suggestedfix("}", "refactor.rewrite", "Fill") + +-- suggestedfix_a_27_16 -- +package fillstruct + +import ( + "golang.org/lsptests/fillstruct/data" +) + +type basicStruct struct { + foo int +} + +var _ = basicStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill") + +type twoArgStruct struct { + foo int + bar string +} + +var _ = twoArgStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill") + +type nestedStruct struct { + bar string + basic basicStruct +} + +var _ = nestedStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill") + +var _ = data.B{ + ExportedInt: 0, +} //@suggestedfix("}", "refactor.rewrite", "Fill") + diff --git a/gopls/internal/lsp/testdata/fillstruct/a2.go b/gopls/internal/lsp/testdata/fillstruct/a2.go new file mode 100644 index 000000000..b5e30a84f --- /dev/null +++ b/gopls/internal/lsp/testdata/fillstruct/a2.go @@ -0,0 +1,29 @@ +package fillstruct + +type typedStruct struct { + m map[string]int + s []int + c chan int + c1 <-chan int + a [2]string +} + +var _ = typedStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill") + +type funStruct struct { + fn func(i int) int +} + +var _ = funStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill") + +type funStructCompex struct { + fn func(i int, s string) (string, int) +} + +var _ = funStructCompex{} //@suggestedfix("}", "refactor.rewrite", "Fill") + +type funStructEmpty struct { + fn func() +} + +var _ = funStructEmpty{} //@suggestedfix("}", "refactor.rewrite", "Fill") diff --git a/gopls/internal/lsp/testdata/fillstruct/a2.go.golden b/gopls/internal/lsp/testdata/fillstruct/a2.go.golden new file mode 100644 index 000000000..2eca3e349 --- /dev/null +++ b/gopls/internal/lsp/testdata/fillstruct/a2.go.golden @@ -0,0 +1,139 @@ +-- suggestedfix_a2_11_21 -- +package fillstruct + +type typedStruct struct { + m map[string]int + s []int + c chan int + c1 <-chan int + a [2]string +} + +var _ = typedStruct{ + m: map[string]int{}, + s: []int{}, + c: make(chan int), + c1: make(<-chan int), + a: [2]string{}, +} //@suggestedfix("}", "refactor.rewrite", "Fill") + +type funStruct struct { + fn func(i int) int +} + +var _ = funStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill") + +type funStructCompex struct { + fn func(i int, s string) (string, int) +} + +var _ = funStructCompex{} //@suggestedfix("}", "refactor.rewrite", "Fill") + +type funStructEmpty struct { + fn func() +} + +var _ = funStructEmpty{} //@suggestedfix("}", "refactor.rewrite", "Fill") + +-- suggestedfix_a2_17_19 -- +package fillstruct + +type typedStruct struct { + m map[string]int + s []int + c chan int + c1 <-chan int + a [2]string +} + +var _ = typedStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill") + +type funStruct struct { + fn func(i int) int +} + +var _ = funStruct{ + fn: func(i int) int { + }, +} //@suggestedfix("}", "refactor.rewrite", "Fill") + +type funStructCompex struct { + fn func(i int, s string) (string, int) +} + +var _ = funStructCompex{} //@suggestedfix("}", "refactor.rewrite", "Fill") + +type funStructEmpty struct { + fn func() +} + +var _ = funStructEmpty{} //@suggestedfix("}", "refactor.rewrite", "Fill") + +-- suggestedfix_a2_23_25 -- +package fillstruct + +type typedStruct struct { + m map[string]int + s []int + c chan int + c1 <-chan int + a [2]string +} + +var _ = typedStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill") + +type funStruct struct { + fn func(i int) int +} + +var _ = funStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill") + +type funStructCompex struct { + fn func(i int, s string) (string, int) +} + +var _ = funStructCompex{ + fn: func(i int, s string) (string, int) { + }, +} //@suggestedfix("}", "refactor.rewrite", "Fill") + +type funStructEmpty struct { + fn func() +} + +var _ = funStructEmpty{} //@suggestedfix("}", "refactor.rewrite", "Fill") + +-- suggestedfix_a2_29_24 -- +package fillstruct + +type typedStruct struct { + m map[string]int + s []int + c chan int + c1 <-chan int + a [2]string +} + +var _ = typedStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill") + +type funStruct struct { + fn func(i int) int +} + +var _ = funStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill") + +type funStructCompex struct { + fn func(i int, s string) (string, int) +} + +var _ = funStructCompex{} //@suggestedfix("}", "refactor.rewrite", "Fill") + +type funStructEmpty struct { + fn func() +} + +var _ = funStructEmpty{ + fn: func() { + }, +} //@suggestedfix("}", "refactor.rewrite", "Fill") + diff --git a/gopls/internal/lsp/testdata/fillstruct/a3.go b/gopls/internal/lsp/testdata/fillstruct/a3.go new file mode 100644 index 000000000..59cd9fa28 --- /dev/null +++ b/gopls/internal/lsp/testdata/fillstruct/a3.go @@ -0,0 +1,42 @@ +package fillstruct + +import ( + "go/ast" + "go/token" +) + +type Foo struct { + A int +} + +type Bar struct { + X *Foo + Y *Foo +} + +var _ = Bar{} //@suggestedfix("}", "refactor.rewrite", "Fill") + +type importedStruct struct { + m map[*ast.CompositeLit]ast.Field + s []ast.BadExpr + a [3]token.Token + c chan ast.EmptyStmt + fn func(ast_decl ast.DeclStmt) ast.Ellipsis + st ast.CompositeLit +} + +var _ = importedStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill") + +type pointerBuiltinStruct struct { + b *bool + s *string + i *int +} + +var _ = pointerBuiltinStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill") + +var _ = []ast.BasicLit{ + {}, //@suggestedfix("}", "refactor.rewrite", "Fill") +} + +var _ = []ast.BasicLit{{}} //@suggestedfix("}", "refactor.rewrite", "Fill") diff --git a/gopls/internal/lsp/testdata/fillstruct/a3.go.golden b/gopls/internal/lsp/testdata/fillstruct/a3.go.golden new file mode 100644 index 000000000..a7c7baa8d --- /dev/null +++ b/gopls/internal/lsp/testdata/fillstruct/a3.go.golden @@ -0,0 +1,243 @@ +-- suggestedfix_a3_17_13 -- +package fillstruct + +import ( + "go/ast" + "go/token" +) + +type Foo struct { + A int +} + +type Bar struct { + X *Foo + Y *Foo +} + +var _ = Bar{ + X: &Foo{}, + Y: &Foo{}, +} //@suggestedfix("}", "refactor.rewrite", "Fill") + +type importedStruct struct { + m map[*ast.CompositeLit]ast.Field + s []ast.BadExpr + a [3]token.Token + c chan ast.EmptyStmt + fn func(ast_decl ast.DeclStmt) ast.Ellipsis + st ast.CompositeLit +} + +var _ = importedStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill") + +type pointerBuiltinStruct struct { + b *bool + s *string + i *int +} + +var _ = pointerBuiltinStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill") + +var _ = []ast.BasicLit{ + {}, //@suggestedfix("}", "refactor.rewrite", "Fill") +} + +var _ = []ast.BasicLit{{}} //@suggestedfix("}", "refactor.rewrite", "Fill") + +-- suggestedfix_a3_28_24 -- +package fillstruct + +import ( + "go/ast" + "go/token" +) + +type Foo struct { + A int +} + +type Bar struct { + X *Foo + Y *Foo +} + +var _ = Bar{} //@suggestedfix("}", "refactor.rewrite", "Fill") + +type importedStruct struct { + m map[*ast.CompositeLit]ast.Field + s []ast.BadExpr + a [3]token.Token + c chan ast.EmptyStmt + fn func(ast_decl ast.DeclStmt) ast.Ellipsis + st ast.CompositeLit +} + +var _ = importedStruct{ + m: map[*ast.CompositeLit]ast.Field{}, + s: []ast.BadExpr{}, + a: [3]token.Token{}, + c: make(chan ast.EmptyStmt), + fn: func(ast_decl ast.DeclStmt) ast.Ellipsis { + }, + st: ast.CompositeLit{}, +} //@suggestedfix("}", "refactor.rewrite", "Fill") + +type pointerBuiltinStruct struct { + b *bool + s *string + i *int +} + +var _ = pointerBuiltinStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill") + +var _ = []ast.BasicLit{ + {}, //@suggestedfix("}", "refactor.rewrite", "Fill") +} + +var _ = []ast.BasicLit{{}} //@suggestedfix("}", "refactor.rewrite", "Fill") + +-- suggestedfix_a3_36_30 -- +package fillstruct + +import ( + "go/ast" + "go/token" +) + +type Foo struct { + A int +} + +type Bar struct { + X *Foo + Y *Foo +} + +var _ = Bar{} //@suggestedfix("}", "refactor.rewrite", "Fill") + +type importedStruct struct { + m map[*ast.CompositeLit]ast.Field + s []ast.BadExpr + a [3]token.Token + c chan ast.EmptyStmt + fn func(ast_decl ast.DeclStmt) ast.Ellipsis + st ast.CompositeLit +} + +var _ = importedStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill") + +type pointerBuiltinStruct struct { + b *bool + s *string + i *int +} + +var _ = pointerBuiltinStruct{ + b: new(bool), + s: new(string), + i: new(int), +} //@suggestedfix("}", "refactor.rewrite", "Fill") + +var _ = []ast.BasicLit{ + {}, //@suggestedfix("}", "refactor.rewrite", "Fill") +} + +var _ = []ast.BasicLit{{}} //@suggestedfix("}", "refactor.rewrite", "Fill") + +-- suggestedfix_a3_39_3 -- +package fillstruct + +import ( + "go/ast" + "go/token" +) + +type Foo struct { + A int +} + +type Bar struct { + X *Foo + Y *Foo +} + +var _ = Bar{} //@suggestedfix("}", "refactor.rewrite", "Fill") + +type importedStruct struct { + m map[*ast.CompositeLit]ast.Field + s []ast.BadExpr + a [3]token.Token + c chan ast.EmptyStmt + fn func(ast_decl ast.DeclStmt) ast.Ellipsis + st ast.CompositeLit +} + +var _ = importedStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill") + +type pointerBuiltinStruct struct { + b *bool + s *string + i *int +} + +var _ = pointerBuiltinStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill") + +var _ = []ast.BasicLit{ + { + ValuePos: 0, + Kind: 0, + Value: "", + }, //@suggestedfix("}", "refactor.rewrite", "Fill") +} + +var _ = []ast.BasicLit{{}} //@suggestedfix("}", "refactor.rewrite", "Fill") + +-- suggestedfix_a3_42_25 -- +package fillstruct + +import ( + "go/ast" + "go/token" +) + +type Foo struct { + A int +} + +type Bar struct { + X *Foo + Y *Foo +} + +var _ = Bar{} //@suggestedfix("}", "refactor.rewrite", "Fill") + +type importedStruct struct { + m map[*ast.CompositeLit]ast.Field + s []ast.BadExpr + a [3]token.Token + c chan ast.EmptyStmt + fn func(ast_decl ast.DeclStmt) ast.Ellipsis + st ast.CompositeLit +} + +var _ = importedStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill") + +type pointerBuiltinStruct struct { + b *bool + s *string + i *int +} + +var _ = pointerBuiltinStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill") + +var _ = []ast.BasicLit{ + {}, //@suggestedfix("}", "refactor.rewrite", "Fill") +} + +var _ = []ast.BasicLit{{ + ValuePos: 0, + Kind: 0, + Value: "", +}} //@suggestedfix("}", "refactor.rewrite", "Fill") + diff --git a/gopls/internal/lsp/testdata/fillstruct/a4.go b/gopls/internal/lsp/testdata/fillstruct/a4.go new file mode 100644 index 000000000..5f52a55fa --- /dev/null +++ b/gopls/internal/lsp/testdata/fillstruct/a4.go @@ -0,0 +1,39 @@ +package fillstruct + +import "go/ast" + +type iStruct struct { + X int +} + +type sStruct struct { + str string +} + +type multiFill struct { + num int + strin string + arr []int +} + +type assignStruct struct { + n ast.Node +} + +func fill() { + var x int + var _ = iStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill") + + var s string + var _ = sStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill") + + var n int + _ = []int{} + if true { + arr := []int{1, 2} + } + var _ = multiFill{} //@suggestedfix("}", "refactor.rewrite", "Fill") + + var node *ast.CompositeLit + var _ = assignStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill") +} diff --git a/gopls/internal/lsp/testdata/fillstruct/a4.go.golden b/gopls/internal/lsp/testdata/fillstruct/a4.go.golden new file mode 100644 index 000000000..b1e376f05 --- /dev/null +++ b/gopls/internal/lsp/testdata/fillstruct/a4.go.golden @@ -0,0 +1,174 @@ +-- suggestedfix_a4_25_18 -- +package fillstruct + +import "go/ast" + +type iStruct struct { + X int +} + +type sStruct struct { + str string +} + +type multiFill struct { + num int + strin string + arr []int +} + +type assignStruct struct { + n ast.Node +} + +func fill() { + var x int + var _ = iStruct{ + X: x, + } //@suggestedfix("}", "refactor.rewrite", "Fill") + + var s string + var _ = sStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill") + + var n int + _ = []int{} + if true { + arr := []int{1, 2} + } + var _ = multiFill{} //@suggestedfix("}", "refactor.rewrite", "Fill") + + var node *ast.CompositeLit + var _ = assignStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill") +} + +-- suggestedfix_a4_28_18 -- +package fillstruct + +import "go/ast" + +type iStruct struct { + X int +} + +type sStruct struct { + str string +} + +type multiFill struct { + num int + strin string + arr []int +} + +type assignStruct struct { + n ast.Node +} + +func fill() { + var x int + var _ = iStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill") + + var s string + var _ = sStruct{ + str: s, + } //@suggestedfix("}", "refactor.rewrite", "Fill") + + var n int + _ = []int{} + if true { + arr := []int{1, 2} + } + var _ = multiFill{} //@suggestedfix("}", "refactor.rewrite", "Fill") + + var node *ast.CompositeLit + var _ = assignStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill") +} + +-- suggestedfix_a4_35_20 -- +package fillstruct + +import "go/ast" + +type iStruct struct { + X int +} + +type sStruct struct { + str string +} + +type multiFill struct { + num int + strin string + arr []int +} + +type assignStruct struct { + n ast.Node +} + +func fill() { + var x int + var _ = iStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill") + + var s string + var _ = sStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill") + + var n int + _ = []int{} + if true { + arr := []int{1, 2} + } + var _ = multiFill{ + num: n, + strin: s, + arr: []int{}, + } //@suggestedfix("}", "refactor.rewrite", "Fill") + + var node *ast.CompositeLit + var _ = assignStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill") +} + +-- suggestedfix_a4_38_23 -- +package fillstruct + +import "go/ast" + +type iStruct struct { + X int +} + +type sStruct struct { + str string +} + +type multiFill struct { + num int + strin string + arr []int +} + +type assignStruct struct { + n ast.Node +} + +func fill() { + var x int + var _ = iStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill") + + var s string + var _ = sStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill") + + var n int + _ = []int{} + if true { + arr := []int{1, 2} + } + var _ = multiFill{} //@suggestedfix("}", "refactor.rewrite", "Fill") + + var node *ast.CompositeLit + var _ = assignStruct{ + n: node, + } //@suggestedfix("}", "refactor.rewrite", "Fill") +} + diff --git a/gopls/internal/lsp/testdata/fillstruct/data/a.go b/gopls/internal/lsp/testdata/fillstruct/data/a.go new file mode 100644 index 000000000..7ca37736b --- /dev/null +++ b/gopls/internal/lsp/testdata/fillstruct/data/a.go @@ -0,0 +1,6 @@ +package data
+
+type B struct {
+ ExportedInt int
+ unexportedInt int
+}
diff --git a/gopls/internal/lsp/testdata/fillstruct/fill_struct.go b/gopls/internal/lsp/testdata/fillstruct/fill_struct.go new file mode 100644 index 000000000..3da904741 --- /dev/null +++ b/gopls/internal/lsp/testdata/fillstruct/fill_struct.go @@ -0,0 +1,26 @@ +package fillstruct + +type StructA struct { + unexportedIntField int + ExportedIntField int + MapA map[int]string + Array []int + StructB +} + +type StructA2 struct { + B *StructB +} + +type StructA3 struct { + B StructB +} + +func fill() { + a := StructA{} //@suggestedfix("}", "refactor.rewrite", "Fill") + b := StructA2{} //@suggestedfix("}", "refactor.rewrite", "Fill") + c := StructA3{} //@suggestedfix("}", "refactor.rewrite", "Fill") + if true { + _ = StructA3{} //@suggestedfix("}", "refactor.rewrite", "Fill") + } +} diff --git a/gopls/internal/lsp/testdata/fillstruct/fill_struct.go.golden b/gopls/internal/lsp/testdata/fillstruct/fill_struct.go.golden new file mode 100644 index 000000000..de01a40f0 --- /dev/null +++ b/gopls/internal/lsp/testdata/fillstruct/fill_struct.go.golden @@ -0,0 +1,124 @@ +-- suggestedfix_fill_struct_20_15 -- +package fillstruct + +type StructA struct { + unexportedIntField int + ExportedIntField int + MapA map[int]string + Array []int + StructB +} + +type StructA2 struct { + B *StructB +} + +type StructA3 struct { + B StructB +} + +func fill() { + a := StructA{ + unexportedIntField: 0, + ExportedIntField: 0, + MapA: map[int]string{}, + Array: []int{}, + StructB: StructB{}, + } //@suggestedfix("}", "refactor.rewrite", "Fill") + b := StructA2{} //@suggestedfix("}", "refactor.rewrite", "Fill") + c := StructA3{} //@suggestedfix("}", "refactor.rewrite", "Fill") + if true { + _ = StructA3{} //@suggestedfix("}", "refactor.rewrite", "Fill") + } +} + +-- suggestedfix_fill_struct_21_16 -- +package fillstruct + +type StructA struct { + unexportedIntField int + ExportedIntField int + MapA map[int]string + Array []int + StructB +} + +type StructA2 struct { + B *StructB +} + +type StructA3 struct { + B StructB +} + +func fill() { + a := StructA{} //@suggestedfix("}", "refactor.rewrite", "Fill") + b := StructA2{ + B: &StructB{}, + } //@suggestedfix("}", "refactor.rewrite", "Fill") + c := StructA3{} //@suggestedfix("}", "refactor.rewrite", "Fill") + if true { + _ = StructA3{} //@suggestedfix("}", "refactor.rewrite", "Fill") + } +} + +-- suggestedfix_fill_struct_22_16 -- +package fillstruct + +type StructA struct { + unexportedIntField int + ExportedIntField int + MapA map[int]string + Array []int + StructB +} + +type StructA2 struct { + B *StructB +} + +type StructA3 struct { + B StructB +} + +func fill() { + a := StructA{} //@suggestedfix("}", "refactor.rewrite", "Fill") + b := StructA2{} //@suggestedfix("}", "refactor.rewrite", "Fill") + c := StructA3{ + B: StructB{}, + } //@suggestedfix("}", "refactor.rewrite", "Fill") + if true { + _ = StructA3{} //@suggestedfix("}", "refactor.rewrite", "Fill") + } +} + +-- suggestedfix_fill_struct_24_16 -- +package fillstruct + +type StructA struct { + unexportedIntField int + ExportedIntField int + MapA map[int]string + Array []int + StructB +} + +type StructA2 struct { + B *StructB +} + +type StructA3 struct { + B StructB +} + +func fill() { + a := StructA{} //@suggestedfix("}", "refactor.rewrite", "Fill") + b := StructA2{} //@suggestedfix("}", "refactor.rewrite", "Fill") + c := StructA3{} //@suggestedfix("}", "refactor.rewrite", "Fill") + if true { + _ = StructA3{ + B: StructB{}, + } //@suggestedfix("}", "refactor.rewrite", "Fill") + } +} + diff --git a/gopls/internal/lsp/testdata/fillstruct/fill_struct_anon.go b/gopls/internal/lsp/testdata/fillstruct/fill_struct_anon.go new file mode 100644 index 000000000..2c099a80e --- /dev/null +++ b/gopls/internal/lsp/testdata/fillstruct/fill_struct_anon.go @@ -0,0 +1,14 @@ +package fillstruct + +type StructAnon struct { + a struct{} + b map[string]interface{} + c map[string]struct { + d int + e bool + } +} + +func fill() { + _ := StructAnon{} //@suggestedfix("}", "refactor.rewrite", "Fill") +} diff --git a/gopls/internal/lsp/testdata/fillstruct/fill_struct_anon.go.golden b/gopls/internal/lsp/testdata/fillstruct/fill_struct_anon.go.golden new file mode 100644 index 000000000..7cc9ac23d --- /dev/null +++ b/gopls/internal/lsp/testdata/fillstruct/fill_struct_anon.go.golden @@ -0,0 +1,20 @@ +-- suggestedfix_fill_struct_anon_13_18 -- +package fillstruct + +type StructAnon struct { + a struct{} + b map[string]interface{} + c map[string]struct { + d int + e bool + } +} + +func fill() { + _ := StructAnon{ + a: struct{}{}, + b: map[string]interface{}{}, + c: map[string]struct{d int; e bool}{}, + } //@suggestedfix("}", "refactor.rewrite", "Fill") +} + diff --git a/gopls/internal/lsp/testdata/fillstruct/fill_struct_nested.go b/gopls/internal/lsp/testdata/fillstruct/fill_struct_nested.go new file mode 100644 index 000000000..ab7be5a7b --- /dev/null +++ b/gopls/internal/lsp/testdata/fillstruct/fill_struct_nested.go @@ -0,0 +1,15 @@ +package fillstruct + +type StructB struct { + StructC +} + +type StructC struct { + unexportedInt int +} + +func nested() { + c := StructB{ + StructC: StructC{}, //@suggestedfix("}", "refactor.rewrite", "Fill") + } +} diff --git a/gopls/internal/lsp/testdata/fillstruct/fill_struct_nested.go.golden b/gopls/internal/lsp/testdata/fillstruct/fill_struct_nested.go.golden new file mode 100644 index 000000000..c902ee7f1 --- /dev/null +++ b/gopls/internal/lsp/testdata/fillstruct/fill_struct_nested.go.golden @@ -0,0 +1,19 @@ +-- suggestedfix_fill_struct_nested_13_20 -- +package fillstruct + +type StructB struct { + StructC +} + +type StructC struct { + unexportedInt int +} + +func nested() { + c := StructB{ + StructC: StructC{ + unexportedInt: 0, + }, //@suggestedfix("}", "refactor.rewrite", "Fill") + } +} + diff --git a/gopls/internal/lsp/testdata/fillstruct/fill_struct_package.go b/gopls/internal/lsp/testdata/fillstruct/fill_struct_package.go new file mode 100644 index 000000000..ef35627c8 --- /dev/null +++ b/gopls/internal/lsp/testdata/fillstruct/fill_struct_package.go @@ -0,0 +1,12 @@ +package fillstruct + +import ( + h2 "net/http" + + "golang.org/lsptests/fillstruct/data" +) + +func unexported() { + a := data.B{} //@suggestedfix("}", "refactor.rewrite", "Fill") + _ = h2.Client{} //@suggestedfix("}", "refactor.rewrite", "Fill") +} diff --git a/gopls/internal/lsp/testdata/fillstruct/fill_struct_package.go.golden b/gopls/internal/lsp/testdata/fillstruct/fill_struct_package.go.golden new file mode 100644 index 000000000..0cdbfc820 --- /dev/null +++ b/gopls/internal/lsp/testdata/fillstruct/fill_struct_package.go.golden @@ -0,0 +1,36 @@ +-- suggestedfix_fill_struct_package_10_14 -- +package fillstruct + +import ( + h2 "net/http" + + "golang.org/lsptests/fillstruct/data" +) + +func unexported() { + a := data.B{ + ExportedInt: 0, + } //@suggestedfix("}", "refactor.rewrite", "Fill") + _ = h2.Client{} //@suggestedfix("}", "refactor.rewrite", "Fill") +} + +-- suggestedfix_fill_struct_package_11_16 -- +package fillstruct + +import ( + h2 "net/http" + + "golang.org/lsptests/fillstruct/data" +) + +func unexported() { + a := data.B{} //@suggestedfix("}", "refactor.rewrite", "Fill") + _ = h2.Client{ + Transport: nil, + CheckRedirect: func(req *h2.Request, via []*h2.Request) error { + }, + Jar: nil, + Timeout: 0, + } //@suggestedfix("}", "refactor.rewrite", "Fill") +} + diff --git a/gopls/internal/lsp/testdata/fillstruct/fill_struct_partial.go b/gopls/internal/lsp/testdata/fillstruct/fill_struct_partial.go new file mode 100644 index 000000000..5de1722c7 --- /dev/null +++ b/gopls/internal/lsp/testdata/fillstruct/fill_struct_partial.go @@ -0,0 +1,24 @@ +package fillstruct + +type StructPartialA struct { + PrefilledInt int + UnfilledInt int + StructPartialB +} + +type StructPartialB struct { + PrefilledInt int + UnfilledInt int +} + +func fill() { + a := StructPartialA{ + PrefilledInt: 5, + } //@suggestedfix("}", "refactor.rewrite", "Fill") + b := StructPartialB{ + /* this comment should disappear */ + PrefilledInt: 7, // This comment should be blown away. + /* As should + this one */ + } //@suggestedfix("}", "refactor.rewrite", "Fill") +} diff --git a/gopls/internal/lsp/testdata/fillstruct/fill_struct_partial.go.golden b/gopls/internal/lsp/testdata/fillstruct/fill_struct_partial.go.golden new file mode 100644 index 000000000..3aa437a03 --- /dev/null +++ b/gopls/internal/lsp/testdata/fillstruct/fill_struct_partial.go.golden @@ -0,0 +1,52 @@ +-- suggestedfix_fill_struct_partial_17_2 -- +package fillstruct + +type StructPartialA struct { + PrefilledInt int + UnfilledInt int + StructPartialB +} + +type StructPartialB struct { + PrefilledInt int + UnfilledInt int +} + +func fill() { + a := StructPartialA{ + PrefilledInt: 5, + UnfilledInt: 0, + StructPartialB: StructPartialB{}, + } //@suggestedfix("}", "refactor.rewrite", "Fill") + b := StructPartialB{ + /* this comment should disappear */ + PrefilledInt: 7, // This comment should be blown away. + /* As should + this one */ + } //@suggestedfix("}", "refactor.rewrite", "Fill") +} + +-- suggestedfix_fill_struct_partial_23_2 -- +package fillstruct + +type StructPartialA struct { + PrefilledInt int + UnfilledInt int + StructPartialB +} + +type StructPartialB struct { + PrefilledInt int + UnfilledInt int +} + +func fill() { + a := StructPartialA{ + PrefilledInt: 5, + } //@suggestedfix("}", "refactor.rewrite", "Fill") + b := StructPartialB{ + PrefilledInt: 7, + UnfilledInt: 0, + } //@suggestedfix("}", "refactor.rewrite", "Fill") +} + diff --git a/gopls/internal/lsp/testdata/fillstruct/fill_struct_spaces.go b/gopls/internal/lsp/testdata/fillstruct/fill_struct_spaces.go new file mode 100644 index 000000000..6a468cd54 --- /dev/null +++ b/gopls/internal/lsp/testdata/fillstruct/fill_struct_spaces.go @@ -0,0 +1,9 @@ +package fillstruct + +type StructD struct { + ExportedIntField int +} + +func spaces() { + d := StructD{} //@suggestedfix("}", "refactor.rewrite", "Fill") +} diff --git a/gopls/internal/lsp/testdata/fillstruct/fill_struct_spaces.go.golden b/gopls/internal/lsp/testdata/fillstruct/fill_struct_spaces.go.golden new file mode 100644 index 000000000..590c91611 --- /dev/null +++ b/gopls/internal/lsp/testdata/fillstruct/fill_struct_spaces.go.golden @@ -0,0 +1,13 @@ +-- suggestedfix_fill_struct_spaces_8_15 -- +package fillstruct + +type StructD struct { + ExportedIntField int +} + +func spaces() { + d := StructD{ + ExportedIntField: 0, + } //@suggestedfix("}", "refactor.rewrite", "Fill") +} + diff --git a/gopls/internal/lsp/testdata/fillstruct/fill_struct_unsafe.go b/gopls/internal/lsp/testdata/fillstruct/fill_struct_unsafe.go new file mode 100644 index 000000000..f5e42a4f2 --- /dev/null +++ b/gopls/internal/lsp/testdata/fillstruct/fill_struct_unsafe.go @@ -0,0 +1,12 @@ +package fillstruct + +import "unsafe" + +type unsafeStruct struct { + x int + p unsafe.Pointer +} + +func fill() { + _ := unsafeStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill") +} diff --git a/gopls/internal/lsp/testdata/fillstruct/fill_struct_unsafe.go.golden b/gopls/internal/lsp/testdata/fillstruct/fill_struct_unsafe.go.golden new file mode 100644 index 000000000..7e8e1952f --- /dev/null +++ b/gopls/internal/lsp/testdata/fillstruct/fill_struct_unsafe.go.golden @@ -0,0 +1,17 @@ +-- suggestedfix_fill_struct_unsafe_11_20 -- +package fillstruct + +import "unsafe" + +type unsafeStruct struct { + x int + p unsafe.Pointer +} + +func fill() { + _ := unsafeStruct{ + x: 0, + p: nil, + } //@suggestedfix("}", "refactor.rewrite", "Fill") +} + diff --git a/gopls/internal/lsp/testdata/fillstruct/typeparams.go b/gopls/internal/lsp/testdata/fillstruct/typeparams.go new file mode 100644 index 000000000..c0b702f57 --- /dev/null +++ b/gopls/internal/lsp/testdata/fillstruct/typeparams.go @@ -0,0 +1,37 @@ +//go:build go1.18 +// +build go1.18 + +package fillstruct + +type emptyStructWithTypeParams[A any] struct{} + +var _ = emptyStructWithTypeParams[int]{} // no suggested fix + +type basicStructWithTypeParams[T any] struct { + foo T +} + +var _ = basicStructWithTypeParams[int]{} //@suggestedfix("}", "refactor.rewrite", "Fill") + +type twoArgStructWithTypeParams[F, B any] struct { + foo F + bar B +} + +var _ = twoArgStructWithTypeParams[string, int]{} //@suggestedfix("}", "refactor.rewrite", "Fill") + +var _ = twoArgStructWithTypeParams[int, string]{ + bar: "bar", +} //@suggestedfix("}", "refactor.rewrite", "Fill") + +type nestedStructWithTypeParams struct { + bar string + basic basicStructWithTypeParams[int] +} + +var _ = nestedStructWithTypeParams{} //@suggestedfix("}", "refactor.rewrite", "Fill") + +func _[T any]() { + type S struct{ t T } + _ = S{} //@suggestedfix("}", "refactor.rewrite", "Fill") +} diff --git a/gopls/internal/lsp/testdata/fillstruct/typeparams.go.golden b/gopls/internal/lsp/testdata/fillstruct/typeparams.go.golden new file mode 100644 index 000000000..625df7577 --- /dev/null +++ b/gopls/internal/lsp/testdata/fillstruct/typeparams.go.golden @@ -0,0 +1,206 @@ +-- suggestedfix_typeparams_14_40 -- +//go:build go1.18 +// +build go1.18 + +package fillstruct + +type emptyStructWithTypeParams[A any] struct{} + +var _ = emptyStructWithTypeParams[int]{} // no suggested fix + +type basicStructWithTypeParams[T any] struct { + foo T +} + +var _ = basicStructWithTypeParams[int]{ + foo: 0, +} //@suggestedfix("}", "refactor.rewrite", "Fill") + +type twoArgStructWithTypeParams[F, B any] struct { + foo F + bar B +} + +var _ = twoArgStructWithTypeParams[string, int]{} //@suggestedfix("}", "refactor.rewrite", "Fill") + +var _ = twoArgStructWithTypeParams[int, string]{ + bar: "bar", +} //@suggestedfix("}", "refactor.rewrite", "Fill") + +type nestedStructWithTypeParams struct { + bar string + basic basicStructWithTypeParams[int] +} + +var _ = nestedStructWithTypeParams{} //@suggestedfix("}", "refactor.rewrite", "Fill") + +func _[T any]() { + type S struct{ t T } + _ = S{} //@suggestedfix("}", "refactor.rewrite", "Fill") +} + +-- suggestedfix_typeparams_21_49 -- +//go:build go1.18 +// +build go1.18 + +package fillstruct + +type emptyStructWithTypeParams[A any] struct{} + +var _ = emptyStructWithTypeParams[int]{} // no suggested fix + +type basicStructWithTypeParams[T any] struct { + foo T +} + +var _ = basicStructWithTypeParams[int]{} //@suggestedfix("}", "refactor.rewrite", "Fill") + +type twoArgStructWithTypeParams[F, B any] struct { + foo F + bar B +} + +var _ = twoArgStructWithTypeParams[string, int]{ + foo: "", + bar: 0, +} //@suggestedfix("}", "refactor.rewrite", "Fill") + +var _ = twoArgStructWithTypeParams[int, string]{ + bar: "bar", +} //@suggestedfix("}", "refactor.rewrite", "Fill") + +type nestedStructWithTypeParams struct { + bar string + basic basicStructWithTypeParams[int] +} + +var _ = nestedStructWithTypeParams{} //@suggestedfix("}", "refactor.rewrite", "Fill") + +func _[T any]() { + type S struct{ t T } + _ = S{} //@suggestedfix("}", "refactor.rewrite", "Fill") +} + +-- suggestedfix_typeparams_25_1 -- +//go:build go1.18 +// +build go1.18 + +package fillstruct + +type emptyStructWithTypeParams[A any] struct{} + +var _ = emptyStructWithTypeParams[int]{} // no suggested fix + +type basicStructWithTypeParams[T any] struct { + foo T +} + +var _ = basicStructWithTypeParams[int]{} //@suggestedfix("}", "refactor.rewrite", "Fill") + +type twoArgStructWithTypeParams[F, B any] struct { + foo F + bar B +} + +var _ = twoArgStructWithTypeParams[string, int]{} //@suggestedfix("}", "refactor.rewrite", "Fill") + +var _ = twoArgStructWithTypeParams[int, string]{ + foo: 0, + bar: "bar", +} //@suggestedfix("}", "refactor.rewrite", "Fill") + +type nestedStructWithTypeParams struct { + bar string + basic basicStructWithTypeParams[int] +} + +var _ = nestedStructWithTypeParams{} //@suggestedfix("}", "refactor.rewrite", "Fill") + +func _[T any]() { + type S struct{ t T } + _ = S{} //@suggestedfix("}", "refactor.rewrite", "Fill") +} + +-- suggestedfix_typeparams_32_36 -- +//go:build go1.18 +// +build go1.18 + +package fillstruct + +type emptyStructWithTypeParams[A any] struct{} + +var _ = emptyStructWithTypeParams[int]{} // no suggested fix + +type basicStructWithTypeParams[T any] struct { + foo T +} + +var _ = basicStructWithTypeParams[int]{} //@suggestedfix("}", "refactor.rewrite", "Fill") + +type twoArgStructWithTypeParams[F, B any] struct { + foo F + bar B +} + +var _ = twoArgStructWithTypeParams[string, int]{} //@suggestedfix("}", "refactor.rewrite", "Fill") + +var _ = twoArgStructWithTypeParams[int, string]{ + bar: "bar", +} //@suggestedfix("}", "refactor.rewrite", "Fill") + +type nestedStructWithTypeParams struct { + bar string + basic basicStructWithTypeParams[int] +} + +var _ = nestedStructWithTypeParams{ + bar: "", + basic: basicStructWithTypeParams{}, +} //@suggestedfix("}", "refactor.rewrite", "Fill") + +func _[T any]() { + type S struct{ t T } + _ = S{} //@suggestedfix("}", "refactor.rewrite", "Fill") +} + +-- suggestedfix_typeparams_36_8 -- +//go:build go1.18 +// +build go1.18 + +package fillstruct + +type emptyStructWithTypeParams[A any] struct{} + +var _ = emptyStructWithTypeParams[int]{} // no suggested fix + +type basicStructWithTypeParams[T any] struct { + foo T +} + +var _ = basicStructWithTypeParams[int]{} //@suggestedfix("}", "refactor.rewrite", "Fill") + +type twoArgStructWithTypeParams[F, B any] struct { + foo F + bar B +} + +var _ = twoArgStructWithTypeParams[string, int]{} //@suggestedfix("}", "refactor.rewrite", "Fill") + +var _ = twoArgStructWithTypeParams[int, string]{ + bar: "bar", +} //@suggestedfix("}", "refactor.rewrite", "Fill") + +type nestedStructWithTypeParams struct { + bar string + basic basicStructWithTypeParams[int] +} + +var _ = nestedStructWithTypeParams{} //@suggestedfix("}", "refactor.rewrite", "Fill") + +func _[T any]() { + type S struct{ t T } + _ = S{ + t: *new(T), + } //@suggestedfix("}", "refactor.rewrite", "Fill") +} + diff --git a/gopls/internal/lsp/testdata/folding/a.go b/gopls/internal/lsp/testdata/folding/a.go new file mode 100644 index 000000000..e07d7e0bf --- /dev/null +++ b/gopls/internal/lsp/testdata/folding/a.go @@ -0,0 +1,75 @@ +package folding //@fold("package") + +import ( + "fmt" + _ "log" +) + +import _ "os" + +// bar is a function. +// With a multiline doc comment. +func bar() string { + /* This is a single line comment */ + switch { + case true: + if true { + fmt.Println("true") + } else { + fmt.Println("false") + } + case false: + fmt.Println("false") + default: + fmt.Println("default") + } + /* This is a multiline + block + comment */ + + /* This is a multiline + block + comment */ + // Followed by another comment. + _ = []int{ + 1, + 2, + 3, + } + _ = [2]string{"d", + "e", + } + _ = map[string]int{ + "a": 1, + "b": 2, + "c": 3, + } + type T struct { + f string + g int + h string + } + _ = T{ + f: "j", + g: 4, + h: "i", + } + x, y := make(chan bool), make(chan bool) + select { + case val := <-x: + if val { + fmt.Println("true from x") + } else { + fmt.Println("false from x") + } + case <-y: + fmt.Println("y") + default: + fmt.Println("default") + } + // This is a multiline comment + // that is not a doc comment. + return ` +this string +is not indented` +} diff --git a/gopls/internal/lsp/testdata/folding/a.go.golden b/gopls/internal/lsp/testdata/folding/a.go.golden new file mode 100644 index 000000000..b04ca4dab --- /dev/null +++ b/gopls/internal/lsp/testdata/folding/a.go.golden @@ -0,0 +1,722 @@ +-- foldingRange-0 -- +package folding //@fold("package") + +import (<>) + +import _ "os" + +// bar is a function.<> +func bar(<>) string {<>} + +-- foldingRange-1 -- +package folding //@fold("package") + +import ( + "fmt" + _ "log" +) + +import _ "os" + +// bar is a function. +// With a multiline doc comment. +func bar() string { + /* This is a single line comment */ + switch {<>} + /* This is a multiline<> + + /* This is a multiline<> + _ = []int{<>} + _ = [2]string{<>} + _ = map[string]int{<>} + type T struct {<>} + _ = T{<>} + x, y := make(<>), make(<>) + select {<>} + // This is a multiline comment<> + return <> +} + +-- foldingRange-2 -- +package folding //@fold("package") + +import ( + "fmt" + _ "log" +) + +import _ "os" + +// bar is a function. +// With a multiline doc comment. +func bar() string { + /* This is a single line comment */ + switch { + case true:<> + case false:<> + default:<> + } + /* This is a multiline + block + comment */ + + /* This is a multiline + block + comment */ + // Followed by another comment. + _ = []int{ + 1, + 2, + 3, + } + _ = [2]string{"d", + "e", + } + _ = map[string]int{ + "a": 1, + "b": 2, + "c": 3, + } + type T struct { + f string + g int + h string + } + _ = T{ + f: "j", + g: 4, + h: "i", + } + x, y := make(chan bool), make(chan bool) + select { + case val := <-x:<> + case <-y:<> + default:<> + } + // This is a multiline comment + // that is not a doc comment. + return ` +this string +is not indented` +} + +-- foldingRange-3 -- +package folding //@fold("package") + +import ( + "fmt" + _ "log" +) + +import _ "os" + +// bar is a function. +// With a multiline doc comment. +func bar() string { + /* This is a single line comment */ + switch { + case true: + if true {<>} else {<>} + case false: + fmt.Println(<>) + default: + fmt.Println(<>) + } + /* This is a multiline + block + comment */ + + /* This is a multiline + block + comment */ + // Followed by another comment. + _ = []int{ + 1, + 2, + 3, + } + _ = [2]string{"d", + "e", + } + _ = map[string]int{ + "a": 1, + "b": 2, + "c": 3, + } + type T struct { + f string + g int + h string + } + _ = T{ + f: "j", + g: 4, + h: "i", + } + x, y := make(chan bool), make(chan bool) + select { + case val := <-x: + if val {<>} else {<>} + case <-y: + fmt.Println(<>) + default: + fmt.Println(<>) + } + // This is a multiline comment + // that is not a doc comment. + return ` +this string +is not indented` +} + +-- foldingRange-4 -- +package folding //@fold("package") + +import ( + "fmt" + _ "log" +) + +import _ "os" + +// bar is a function. +// With a multiline doc comment. +func bar() string { + /* This is a single line comment */ + switch { + case true: + if true { + fmt.Println(<>) + } else { + fmt.Println(<>) + } + case false: + fmt.Println("false") + default: + fmt.Println("default") + } + /* This is a multiline + block + comment */ + + /* This is a multiline + block + comment */ + // Followed by another comment. + _ = []int{ + 1, + 2, + 3, + } + _ = [2]string{"d", + "e", + } + _ = map[string]int{ + "a": 1, + "b": 2, + "c": 3, + } + type T struct { + f string + g int + h string + } + _ = T{ + f: "j", + g: 4, + h: "i", + } + x, y := make(chan bool), make(chan bool) + select { + case val := <-x: + if val { + fmt.Println(<>) + } else { + fmt.Println(<>) + } + case <-y: + fmt.Println("y") + default: + fmt.Println("default") + } + // This is a multiline comment + // that is not a doc comment. + return ` +this string +is not indented` +} + +-- foldingRange-comment-0 -- +package folding //@fold("package") + +import ( + "fmt" + _ "log" +) + +import _ "os" + +// bar is a function.<> +func bar() string { + /* This is a single line comment */ + switch { + case true: + if true { + fmt.Println("true") + } else { + fmt.Println("false") + } + case false: + fmt.Println("false") + default: + fmt.Println("default") + } + /* This is a multiline<> + + /* This is a multiline<> + _ = []int{ + 1, + 2, + 3, + } + _ = [2]string{"d", + "e", + } + _ = map[string]int{ + "a": 1, + "b": 2, + "c": 3, + } + type T struct { + f string + g int + h string + } + _ = T{ + f: "j", + g: 4, + h: "i", + } + x, y := make(chan bool), make(chan bool) + select { + case val := <-x: + if val { + fmt.Println("true from x") + } else { + fmt.Println("false from x") + } + case <-y: + fmt.Println("y") + default: + fmt.Println("default") + } + // This is a multiline comment<> + return ` +this string +is not indented` +} + +-- foldingRange-imports-0 -- +package folding //@fold("package") + +import (<>) + +import _ "os" + +// bar is a function. +// With a multiline doc comment. +func bar() string { + /* This is a single line comment */ + switch { + case true: + if true { + fmt.Println("true") + } else { + fmt.Println("false") + } + case false: + fmt.Println("false") + default: + fmt.Println("default") + } + /* This is a multiline + block + comment */ + + /* This is a multiline + block + comment */ + // Followed by another comment. + _ = []int{ + 1, + 2, + 3, + } + _ = [2]string{"d", + "e", + } + _ = map[string]int{ + "a": 1, + "b": 2, + "c": 3, + } + type T struct { + f string + g int + h string + } + _ = T{ + f: "j", + g: 4, + h: "i", + } + x, y := make(chan bool), make(chan bool) + select { + case val := <-x: + if val { + fmt.Println("true from x") + } else { + fmt.Println("false from x") + } + case <-y: + fmt.Println("y") + default: + fmt.Println("default") + } + // This is a multiline comment + // that is not a doc comment. + return ` +this string +is not indented` +} + +-- foldingRange-lineFolding-0 -- +package folding //@fold("package") + +import (<> +) + +import _ "os" + +// bar is a function.<> +func bar() string {<> +} + +-- foldingRange-lineFolding-1 -- +package folding //@fold("package") + +import ( + "fmt" + _ "log" +) + +import _ "os" + +// bar is a function. +// With a multiline doc comment. +func bar() string { + /* This is a single line comment */ + switch {<> + } + /* This is a multiline<> + + /* This is a multiline<> + _ = []int{<>, + } + _ = [2]string{"d", + "e", + } + _ = map[string]int{<>, + } + type T struct {<> + } + _ = T{<>, + } + x, y := make(chan bool), make(chan bool) + select {<> + } + // This is a multiline comment<> + return <> +} + +-- foldingRange-lineFolding-2 -- +package folding //@fold("package") + +import ( + "fmt" + _ "log" +) + +import _ "os" + +// bar is a function. +// With a multiline doc comment. +func bar() string { + /* This is a single line comment */ + switch { + case true:<> + case false:<> + default:<> + } + /* This is a multiline + block + comment */ + + /* This is a multiline + block + comment */ + // Followed by another comment. + _ = []int{ + 1, + 2, + 3, + } + _ = [2]string{"d", + "e", + } + _ = map[string]int{ + "a": 1, + "b": 2, + "c": 3, + } + type T struct { + f string + g int + h string + } + _ = T{ + f: "j", + g: 4, + h: "i", + } + x, y := make(chan bool), make(chan bool) + select { + case val := <-x:<> + case <-y:<> + default:<> + } + // This is a multiline comment + // that is not a doc comment. + return ` +this string +is not indented` +} + +-- foldingRange-lineFolding-3 -- +package folding //@fold("package") + +import ( + "fmt" + _ "log" +) + +import _ "os" + +// bar is a function. +// With a multiline doc comment. +func bar() string { + /* This is a single line comment */ + switch { + case true: + if true {<> + } else {<> + } + case false: + fmt.Println("false") + default: + fmt.Println("default") + } + /* This is a multiline + block + comment */ + + /* This is a multiline + block + comment */ + // Followed by another comment. + _ = []int{ + 1, + 2, + 3, + } + _ = [2]string{"d", + "e", + } + _ = map[string]int{ + "a": 1, + "b": 2, + "c": 3, + } + type T struct { + f string + g int + h string + } + _ = T{ + f: "j", + g: 4, + h: "i", + } + x, y := make(chan bool), make(chan bool) + select { + case val := <-x: + if val {<> + } else {<> + } + case <-y: + fmt.Println("y") + default: + fmt.Println("default") + } + // This is a multiline comment + // that is not a doc comment. + return ` +this string +is not indented` +} + +-- foldingRange-lineFolding-comment-0 -- +package folding //@fold("package") + +import ( + "fmt" + _ "log" +) + +import _ "os" + +// bar is a function.<> +func bar() string { + /* This is a single line comment */ + switch { + case true: + if true { + fmt.Println("true") + } else { + fmt.Println("false") + } + case false: + fmt.Println("false") + default: + fmt.Println("default") + } + /* This is a multiline<> + + /* This is a multiline<> + _ = []int{ + 1, + 2, + 3, + } + _ = [2]string{"d", + "e", + } + _ = map[string]int{ + "a": 1, + "b": 2, + "c": 3, + } + type T struct { + f string + g int + h string + } + _ = T{ + f: "j", + g: 4, + h: "i", + } + x, y := make(chan bool), make(chan bool) + select { + case val := <-x: + if val { + fmt.Println("true from x") + } else { + fmt.Println("false from x") + } + case <-y: + fmt.Println("y") + default: + fmt.Println("default") + } + // This is a multiline comment<> + return ` +this string +is not indented` +} + +-- foldingRange-lineFolding-imports-0 -- +package folding //@fold("package") + +import (<> +) + +import _ "os" + +// bar is a function. +// With a multiline doc comment. +func bar() string { + /* This is a single line comment */ + switch { + case true: + if true { + fmt.Println("true") + } else { + fmt.Println("false") + } + case false: + fmt.Println("false") + default: + fmt.Println("default") + } + /* This is a multiline + block + comment */ + + /* This is a multiline + block + comment */ + // Followed by another comment. + _ = []int{ + 1, + 2, + 3, + } + _ = [2]string{"d", + "e", + } + _ = map[string]int{ + "a": 1, + "b": 2, + "c": 3, + } + type T struct { + f string + g int + h string + } + _ = T{ + f: "j", + g: 4, + h: "i", + } + x, y := make(chan bool), make(chan bool) + select { + case val := <-x: + if val { + fmt.Println("true from x") + } else { + fmt.Println("false from x") + } + case <-y: + fmt.Println("y") + default: + fmt.Println("default") + } + // This is a multiline comment + // that is not a doc comment. + return ` +this string +is not indented` +} + diff --git a/gopls/internal/lsp/testdata/folding/bad.go.golden b/gopls/internal/lsp/testdata/folding/bad.go.golden new file mode 100644 index 000000000..ab274f75a --- /dev/null +++ b/gopls/internal/lsp/testdata/folding/bad.go.golden @@ -0,0 +1,81 @@ +-- foldingRange-0 -- +package folding //@fold("package") + +import (<>) + +import (<>) + +// badBar is a function. +func badBar(<>) string {<>} + +-- foldingRange-1 -- +package folding //@fold("package") + +import ( "fmt" + _ "log" +) + +import ( + _ "os" ) + +// badBar is a function. +func badBar() string { x := true + if x {<>} else {<>} + return +} + +-- foldingRange-2 -- +package folding //@fold("package") + +import ( "fmt" + _ "log" +) + +import ( + _ "os" ) + +// badBar is a function. +func badBar() string { x := true + if x { + // This is the only foldable thing in this file when lineFoldingOnly + fmt.Println(<>) + } else { + fmt.Println(<>) } + return +} + +-- foldingRange-imports-0 -- +package folding //@fold("package") + +import (<>) + +import (<>) + +// badBar is a function. +func badBar() string { x := true + if x { + // This is the only foldable thing in this file when lineFoldingOnly + fmt.Println("true") + } else { + fmt.Println("false") } + return +} + +-- foldingRange-lineFolding-0 -- +package folding //@fold("package") + +import ( "fmt" + _ "log" +) + +import ( + _ "os" ) + +// badBar is a function. +func badBar() string { x := true + if x {<> + } else { + fmt.Println("false") } + return +} + diff --git a/gopls/internal/lsp/testdata/folding/bad.go.in b/gopls/internal/lsp/testdata/folding/bad.go.in new file mode 100644 index 000000000..84fcb740f --- /dev/null +++ b/gopls/internal/lsp/testdata/folding/bad.go.in @@ -0,0 +1,18 @@ +package folding //@fold("package") + +import ( "fmt" + _ "log" +) + +import ( + _ "os" ) + +// badBar is a function. +func badBar() string { x := true + if x { + // This is the only foldable thing in this file when lineFoldingOnly + fmt.Println("true") + } else { + fmt.Println("false") } + return +} diff --git a/gopls/internal/lsp/testdata/foo/foo.go b/gopls/internal/lsp/testdata/foo/foo.go new file mode 100644 index 000000000..66631c58c --- /dev/null +++ b/gopls/internal/lsp/testdata/foo/foo.go @@ -0,0 +1,30 @@ +package foo //@mark(PackageFoo, "foo"),item(PackageFoo, "foo", "\"golang.org/lsptests/foo\"", "package") + +type StructFoo struct { //@item(StructFoo, "StructFoo", "struct{...}", "struct") + Value int //@item(Value, "Value", "int", "field") +} + +// Pre-set this marker, as we don't have a "source" for it in this package. +/* Error() */ //@item(Error, "Error", "func() string", "method") + +func Foo() { //@item(Foo, "Foo", "func()", "func") + var err error + err.Error() //@complete("E", Error) +} + +func _() { + var sFoo StructFoo //@mark(sFoo1, "sFoo"),complete("t", StructFoo) + if x := sFoo; x.Value == 1 { //@mark(sFoo2, "sFoo"),complete("V", Value),typdef("sFoo", StructFoo),refs("sFo", sFoo1, sFoo2) + return + } +} + +func _() { + shadowed := 123 + { + shadowed := "hi" //@item(shadowed, "shadowed", "string", "var"),refs("shadowed", shadowed) + sha //@complete("a", shadowed) + } +} + +type IntFoo int //@item(IntFoo, "IntFoo", "int", "type") diff --git a/gopls/internal/lsp/testdata/format/bad_format.go.golden b/gopls/internal/lsp/testdata/format/bad_format.go.golden new file mode 100644 index 000000000..f0c24d635 --- /dev/null +++ b/gopls/internal/lsp/testdata/format/bad_format.go.golden @@ -0,0 +1,21 @@ +-- gofmt -- +package format //@format("package") + +import ( + "fmt" + "log" + "runtime" +) + +func hello() { + + var x int //@diag("x", "compiler", "x declared (and|but) not used", "error") +} + +func hi() { + runtime.GOROOT() + fmt.Printf("") + + log.Printf("") +} + diff --git a/gopls/internal/lsp/testdata/format/bad_format.go.in b/gopls/internal/lsp/testdata/format/bad_format.go.in new file mode 100644 index 000000000..995ec399a --- /dev/null +++ b/gopls/internal/lsp/testdata/format/bad_format.go.in @@ -0,0 +1,22 @@ +package format //@format("package") + +import ( + "runtime" + "fmt" + "log" +) + +func hello() { + + + + + var x int //@diag("x", "compiler", "x declared (and|but) not used", "error") +} + +func hi() { + runtime.GOROOT() + fmt.Printf("") + + log.Printf("") +} diff --git a/gopls/internal/lsp/testdata/format/good_format.go b/gopls/internal/lsp/testdata/format/good_format.go new file mode 100644 index 000000000..01cb1610c --- /dev/null +++ b/gopls/internal/lsp/testdata/format/good_format.go @@ -0,0 +1,9 @@ +package format //@format("package") + +import ( + "log" +) + +func goodbye() { + log.Printf("byeeeee") +} diff --git a/gopls/internal/lsp/testdata/format/good_format.go.golden b/gopls/internal/lsp/testdata/format/good_format.go.golden new file mode 100644 index 000000000..99f47e2e8 --- /dev/null +++ b/gopls/internal/lsp/testdata/format/good_format.go.golden @@ -0,0 +1,11 @@ +-- gofmt -- +package format //@format("package") + +import ( + "log" +) + +func goodbye() { + log.Printf("byeeeee") +} + diff --git a/gopls/internal/lsp/testdata/format/newline_format.go.golden b/gopls/internal/lsp/testdata/format/newline_format.go.golden new file mode 100644 index 000000000..7c76afdd5 --- /dev/null +++ b/gopls/internal/lsp/testdata/format/newline_format.go.golden @@ -0,0 +1,4 @@ +-- gofmt -- +package format //@format("package") +func _() {} + diff --git a/gopls/internal/lsp/testdata/format/newline_format.go.in b/gopls/internal/lsp/testdata/format/newline_format.go.in new file mode 100644 index 000000000..fe597b90b --- /dev/null +++ b/gopls/internal/lsp/testdata/format/newline_format.go.in @@ -0,0 +1,2 @@ +package format //@format("package") +func _() {}
\ No newline at end of file diff --git a/gopls/internal/lsp/testdata/format/one_line.go.golden b/gopls/internal/lsp/testdata/format/one_line.go.golden new file mode 100644 index 000000000..4d11f84cb --- /dev/null +++ b/gopls/internal/lsp/testdata/format/one_line.go.golden @@ -0,0 +1,3 @@ +-- gofmt -- +package format //@format("package") + diff --git a/gopls/internal/lsp/testdata/format/one_line.go.in b/gopls/internal/lsp/testdata/format/one_line.go.in new file mode 100644 index 000000000..30f413755 --- /dev/null +++ b/gopls/internal/lsp/testdata/format/one_line.go.in @@ -0,0 +1 @@ +package format //@format("package")
\ No newline at end of file diff --git a/gopls/internal/lsp/testdata/func_rank/func_rank.go.in b/gopls/internal/lsp/testdata/func_rank/func_rank.go.in new file mode 100644 index 000000000..905010b3d --- /dev/null +++ b/gopls/internal/lsp/testdata/func_rank/func_rank.go.in @@ -0,0 +1,70 @@ +package func_rank + +import "net/http" + +var stringAVar = "var" //@item(stringAVar, "stringAVar", "string", "var") +func stringBFunc() string { return "str" } //@item(stringBFunc, "stringBFunc", "func() string", "func") +type stringer struct{} //@item(stringer, "stringer", "struct{...}", "struct") + +func _() stringer //@complete("tr", stringer) + +func _(val stringer) {} //@complete("tr", stringer) + +func (stringer) _() {} //@complete("tr", stringer) + +func _() { + var s struct { + AA int //@item(rankAA, "AA", "int", "field") + AB string //@item(rankAB, "AB", "string", "field") + AC int //@item(rankAC, "AC", "int", "field") + } + fnStr := func(string) {} + fnStr(s.A) //@complete(")", rankAB, rankAA, rankAC) + fnStr("" + s.A) //@complete(")", rankAB, rankAA, rankAC) + + fnInt := func(int) {} + fnInt(-s.A) //@complete(")", rankAA, rankAC, rankAB) + + // no expected type + fnInt(func() int { s.A }) //@complete(" }", rankAA, rankAB, rankAC) + fnInt(s.A()) //@complete("()", rankAA, rankAC, rankAB) + fnInt([]int{}[s.A]) //@complete("])", rankAA, rankAC, rankAB) + fnInt([]int{}[:s.A]) //@complete("])", rankAA, rankAC, rankAB) + + fnInt(s.A.(int)) //@complete(".(", rankAA, rankAC, rankAB) + + fnPtr := func(*string) {} + fnPtr(&s.A) //@complete(")", rankAB, rankAA, rankAC) + + var aaPtr *string //@item(rankAAPtr, "aaPtr", "*string", "var") + var abPtr *int //@item(rankABPtr, "abPtr", "*int", "var") + fnInt(*a) //@complete(")", rankABPtr, rankAAPtr) + + _ = func() string { + return s.A //@complete(" //", rankAB, rankAA, rankAC) + } +} + +type foo struct { + fooPrivateField int //@item(rankFooPrivField, "fooPrivateField", "int", "field") + FooPublicField int //@item(rankFooPubField, "FooPublicField", "int", "field") +} + +func (foo) fooPrivateMethod() int { //@item(rankFooPrivMeth, "fooPrivateMethod", "func() int", "method") + return 0 +} + +func (foo) FooPublicMethod() int { //@item(rankFooPubMeth, "FooPublicMethod", "func() int", "method") + return 0 +} + +func _() { + var _ int = foo{}. //@rank(" //", rankFooPrivField, rankFooPubField),rank(" //", rankFooPrivMeth, rankFooPubMeth),rank(" //", rankFooPrivField, rankFooPrivMeth) +} + +func _() { + HandleFunc //@item(httpHandleFunc, "HandleFunc", "func(pattern string, handler func(http.ResponseWriter, *http.Request))", "func") + HandlerFunc //@item(httpHandlerFunc, "HandlerFunc", "func(http.ResponseWriter, *http.Request)", "type") + + http.HandleFunc //@rank(" //", httpHandleFunc, httpHandlerFunc) +} diff --git a/gopls/internal/lsp/testdata/funcsig/func_sig.go b/gopls/internal/lsp/testdata/funcsig/func_sig.go new file mode 100644 index 000000000..00f9b575d --- /dev/null +++ b/gopls/internal/lsp/testdata/funcsig/func_sig.go @@ -0,0 +1,9 @@ +package funcsig + +type someType int //@item(sigSomeType, "someType", "int", "type") + +// Don't complete "foo" in signature. +func (foo someType) _() { //@item(sigFoo, "foo", "someType", "var"),complete(") {", sigSomeType) + + //@complete("", sigFoo, sigSomeType) +} diff --git a/gopls/internal/lsp/testdata/funcvalue/func_value.go b/gopls/internal/lsp/testdata/funcvalue/func_value.go new file mode 100644 index 000000000..913fcbcfe --- /dev/null +++ b/gopls/internal/lsp/testdata/funcvalue/func_value.go @@ -0,0 +1,27 @@ +package funcvalue + +func fooFunc() int { //@item(fvFooFunc, "fooFunc", "func() int", "func") + return 0 +} + +var _ = fooFunc() //@item(fvFooFuncCall, "fooFunc", "func() int", "func") + +var fooVar = func() int { //@item(fvFooVar, "fooVar", "func() int", "var") + return 0 +} + +var _ = fooVar() //@item(fvFooVarCall, "fooVar", "func() int", "var") + +type myFunc func() int + +var fooType myFunc = fooVar //@item(fvFooType, "fooType", "myFunc", "var") + +var _ = fooType() //@item(fvFooTypeCall, "fooType", "func() int", "var") + +func _() { + var f func() int + f = foo //@complete(" //", fvFooFunc, fvFooType, fvFooVar) + + var i int + i = foo //@complete(" //", fvFooFuncCall, fvFooTypeCall, fvFooVarCall) +} diff --git a/gopls/internal/lsp/testdata/fuzzymatch/fuzzymatch.go b/gopls/internal/lsp/testdata/fuzzymatch/fuzzymatch.go new file mode 100644 index 000000000..73268f553 --- /dev/null +++ b/gopls/internal/lsp/testdata/fuzzymatch/fuzzymatch.go @@ -0,0 +1,48 @@ +// Copyright 2019 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 fuzzy + +func _() { + var a struct { + fabar int + fooBar string + } + + a.fabar //@item(fuzzFabarField, "a.fabar", "int", "field") + a.fooBar //@item(fuzzFooBarField, "a.fooBar", "string", "field") + + afa //@fuzzy(" //", fuzzFabarField, fuzzFooBarField) + afb //@fuzzy(" //", fuzzFooBarField, fuzzFabarField) + + fab //@fuzzy(" //", fuzzFabarField) + + var myString string + myString = af //@fuzzy(" //", fuzzFooBarField, fuzzFabarField) + + var b struct { + c struct { + d struct { + e struct { + abc string + } + abc float32 + } + abc bool + } + abc int + } + + b.abc //@item(fuzzABCInt, "b.abc", "int", "field") + b.c.abc //@item(fuzzABCbool, "b.c.abc", "bool", "field") + b.c.d.abc //@item(fuzzABCfloat, "b.c.d.abc", "float32", "field") + b.c.d.e.abc //@item(fuzzABCstring, "b.c.d.e.abc", "string", "field") + + // in depth order by default + abc //@fuzzy(" //", fuzzABCInt, fuzzABCbool, fuzzABCfloat) + + // deep candidate that matches expected type should still ranked first + var s string + s = abc //@fuzzy(" //", fuzzABCstring, fuzzABCInt, fuzzABCbool) +} diff --git a/gopls/internal/lsp/testdata/generate/generate.go b/gopls/internal/lsp/testdata/generate/generate.go new file mode 100644 index 000000000..ae5e90d1a --- /dev/null +++ b/gopls/internal/lsp/testdata/generate/generate.go @@ -0,0 +1,4 @@ +package generate + +//go:generate echo Hi //@ codelens("//go:generate", "run go generate", "generate"), codelens("//go:generate", "run go generate ./...", "generate") +//go:generate echo I shall have no CodeLens diff --git a/gopls/internal/lsp/testdata/generated/generated.go b/gopls/internal/lsp/testdata/generated/generated.go new file mode 100644 index 000000000..c7adc1804 --- /dev/null +++ b/gopls/internal/lsp/testdata/generated/generated.go @@ -0,0 +1,7 @@ +package generated + +// Code generated by generator.go. DO NOT EDIT. + +func _() { + var y int //@diag("y", "compiler", "y declared (and|but) not used", "error") +} diff --git a/gopls/internal/lsp/testdata/generated/generator.go b/gopls/internal/lsp/testdata/generated/generator.go new file mode 100644 index 000000000..8e2a4fab7 --- /dev/null +++ b/gopls/internal/lsp/testdata/generated/generator.go @@ -0,0 +1,5 @@ +package generated + +func _() { + var x int //@diag("x", "compiler", "x declared (and|but) not used", "error") +} diff --git a/gopls/internal/lsp/testdata/godef/a/a_x_test.go b/gopls/internal/lsp/testdata/godef/a/a_x_test.go new file mode 100644 index 000000000..f166f0550 --- /dev/null +++ b/gopls/internal/lsp/testdata/godef/a/a_x_test.go @@ -0,0 +1,9 @@ +package a_test + +import ( + "testing" +) + +func TestA2(t *testing.T) { //@TestA2,godef(TestA2, TestA2) + Nonexistant() //@diag("Nonexistant", "compiler", "(undeclared name|undefined): Nonexistant", "error") +} diff --git a/gopls/internal/lsp/testdata/godef/a/a_x_test.go.golden b/gopls/internal/lsp/testdata/godef/a/a_x_test.go.golden new file mode 100644 index 000000000..2e3064794 --- /dev/null +++ b/gopls/internal/lsp/testdata/godef/a/a_x_test.go.golden @@ -0,0 +1,26 @@ +-- TestA2-definition -- +godef/a/a_x_test.go:7:6-12: defined here as ```go +func TestA2(t *testing.T) +``` +-- TestA2-definition-json -- +{ + "span": { + "uri": "file://godef/a/a_x_test.go", + "start": { + "line": 7, + "column": 6, + "offset": 44 + }, + "end": { + "line": 7, + "column": 12, + "offset": 50 + } + }, + "description": "```go\nfunc TestA2(t *testing.T)\n```" +} + +-- TestA2-hoverdef -- +```go +func TestA2(t *testing.T) +``` diff --git a/gopls/internal/lsp/testdata/godef/a/d.go b/gopls/internal/lsp/testdata/godef/a/d.go new file mode 100644 index 000000000..a1d17ad0d --- /dev/null +++ b/gopls/internal/lsp/testdata/godef/a/d.go @@ -0,0 +1,69 @@ +package a //@mark(a, "a "),hoverdef("a ", a) + +import "fmt" + +type Thing struct { //@Thing + Member string //@Member +} + +var Other Thing //@Other + +func Things(val []string) []Thing { //@Things + return nil +} + +func (t Thing) Method(i int) string { //@Method + return t.Member +} + +func (t Thing) Method3() { +} + +func (t *Thing) Method2(i int, j int) (error, string) { + return nil, t.Member +} + +func (t *Thing) private() { +} + +func useThings() { + t := Thing{ //@mark(aStructType, "ing") + Member: "string", //@mark(fMember, "ember") + } + fmt.Print(t.Member) //@mark(aMember, "ember") + fmt.Print(Other) //@mark(aVar, "ther") + Things() //@mark(aFunc, "ings") + t.Method() //@mark(aMethod, "eth") +} + +type NextThing struct { //@NextThing + Thing + Value int +} + +func (n NextThing) another() string { + return n.Member +} + +// Shadows Thing.Method3 +func (n *NextThing) Method3() int { + return n.Value +} + +var nextThing NextThing //@hoverdef("NextThing", NextThing) + +/*@ +godef(aStructType, Thing) +godef(aMember, Member) +godef(aVar, Other) +godef(aFunc, Things) +godef(aMethod, Method) +godef(fMember, Member) +godef(Member, Member) + +//param +//package name +//const +//anon field + +*/ diff --git a/gopls/internal/lsp/testdata/godef/a/d.go.golden b/gopls/internal/lsp/testdata/godef/a/d.go.golden new file mode 100644 index 000000000..ee687750c --- /dev/null +++ b/gopls/internal/lsp/testdata/godef/a/d.go.golden @@ -0,0 +1,191 @@ +-- Member-definition -- +godef/a/d.go:6:2-8: defined here as ```go +field Member string +``` + +@Member + + +[`(a.Thing).Member` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/godef/a#Thing.Member) +-- Member-definition-json -- +{ + "span": { + "uri": "file://godef/a/d.go", + "start": { + "line": 6, + "column": 2, + "offset": 90 + }, + "end": { + "line": 6, + "column": 8, + "offset": 96 + } + }, + "description": "```go\nfield Member string\n```\n\n@Member\n\n\n[`(a.Thing).Member` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/godef/a#Thing.Member)" +} + +-- Member-hoverdef -- +```go +field Member string +``` + +@Member + + +[`(a.Thing).Member` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/godef/a#Thing.Member) +-- Method-definition -- +godef/a/d.go:15:16-22: defined here as ```go +func (Thing).Method(i int) string +``` + +[`(a.Thing).Method` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/godef/a#Thing.Method) +-- Method-definition-json -- +{ + "span": { + "uri": "file://godef/a/d.go", + "start": { + "line": 15, + "column": 16, + "offset": 219 + }, + "end": { + "line": 15, + "column": 22, + "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/lsptests/godef/a#Thing.Method)" +} + +-- Method-hoverdef -- +```go +func (Thing).Method(i int) string +``` + +[`(a.Thing).Method` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/godef/a#Thing.Method) +-- NextThing-hoverdef -- +```go +type NextThing struct { + Thing + Value int +} + +func (*NextThing).Method3() int +func (NextThing).another() string +``` + +[`a.NextThing` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/godef/a#NextThing) +-- Other-definition -- +godef/a/d.go:9:5-10: defined here as ```go +var Other Thing +``` + +@Other + + +[`a.Other` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/godef/a#Other) +-- Other-definition-json -- +{ + "span": { + "uri": "file://godef/a/d.go", + "start": { + "line": 9, + "column": 5, + "offset": 121 + }, + "end": { + "line": 9, + "column": 10, + "offset": 126 + } + }, + "description": "```go\nvar Other Thing\n```\n\n@Other\n\n\n[`a.Other` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/godef/a#Other)" +} + +-- Other-hoverdef -- +```go +var Other Thing +``` + +@Other + + +[`a.Other` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/godef/a#Other) +-- Thing-definition -- +godef/a/d.go:5:6-11: defined here as ```go +type Thing struct { + Member string //@Member +} + +func (Thing).Method(i int) string +func (*Thing).Method2(i int, j int) (error, string) +func (Thing).Method3() +func (*Thing).private() +``` + +[`a.Thing` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/godef/a#Thing) +-- Thing-definition-json -- +{ + "span": { + "uri": "file://godef/a/d.go", + "start": { + "line": 5, + "column": 6, + "offset": 65 + }, + "end": { + "line": 5, + "column": 11, + "offset": 70 + } + }, + "description": "```go\ntype Thing struct {\n\tMember string //@Member\n}\n\nfunc (Thing).Method(i int) string\nfunc (*Thing).Method2(i int, j int) (error, string)\nfunc (Thing).Method3()\nfunc (*Thing).private()\n```\n\n[`a.Thing` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/godef/a#Thing)" +} + +-- Thing-hoverdef -- +```go +type Thing struct { + Member string //@Member +} + +func (Thing).Method(i int) string +func (*Thing).Method2(i int, j int) (error, string) +func (Thing).Method3() +func (*Thing).private() +``` + +[`a.Thing` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/godef/a#Thing) +-- Things-definition -- +godef/a/d.go:11:6-12: defined here as ```go +func Things(val []string) []Thing +``` + +[`a.Things` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/godef/a#Things) +-- Things-definition-json -- +{ + "span": { + "uri": "file://godef/a/d.go", + "start": { + "line": 11, + "column": 6, + "offset": 148 + }, + "end": { + "line": 11, + "column": 12, + "offset": 154 + } + }, + "description": "```go\nfunc Things(val []string) []Thing\n```\n\n[`a.Things` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/godef/a#Things)" +} + +-- Things-hoverdef -- +```go +func Things(val []string) []Thing +``` + +[`a.Things` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/godef/a#Things) +-- a-hoverdef -- +Package a is a package for testing go to definition. + diff --git a/gopls/internal/lsp/testdata/godef/a/f.go b/gopls/internal/lsp/testdata/godef/a/f.go new file mode 100644 index 000000000..10f88262a --- /dev/null +++ b/gopls/internal/lsp/testdata/godef/a/f.go @@ -0,0 +1,16 @@ +// Package a is a package for testing go to definition. +package a + +import "fmt" + +func TypeStuff() { //@Stuff + var x string + + switch y := interface{}(x).(type) { //@mark(switchY, "y"),godef("y", switchY) + case int: //@mark(intY, "int") + fmt.Printf("%v", y) //@hoverdef("y", intY) + case string: //@mark(stringY, "string") + fmt.Printf("%v", y) //@hoverdef("y", stringY) + } + +} diff --git a/gopls/internal/lsp/testdata/godef/a/f.go.golden b/gopls/internal/lsp/testdata/godef/a/f.go.golden new file mode 100644 index 000000000..a084356c0 --- /dev/null +++ b/gopls/internal/lsp/testdata/godef/a/f.go.golden @@ -0,0 +1,34 @@ +-- intY-hoverdef -- +```go +var y int +``` +-- stringY-hoverdef -- +```go +var y string +``` +-- switchY-definition -- +godef/a/f.go:8:9-10: defined here as ```go +var y interface{} +``` +-- switchY-definition-json -- +{ + "span": { + "uri": "file://godef/a/f.go", + "start": { + "line": 8, + "column": 9, + "offset": 76 + }, + "end": { + "line": 8, + "column": 10, + "offset": 77 + } + }, + "description": "```go\nvar y interface{}\n```" +} + +-- switchY-hoverdef -- +```go +var y interface{} +``` diff --git a/gopls/internal/lsp/testdata/godef/a/g.go b/gopls/internal/lsp/testdata/godef/a/g.go new file mode 100644 index 000000000..dfef2fb80 --- /dev/null +++ b/gopls/internal/lsp/testdata/godef/a/g.go @@ -0,0 +1,6 @@ +package a + +import "time" + +// dur is a constant of type time.Duration. +const dur = 15*time.Minute + 10*time.Second + 350*time.Millisecond //@dur,hoverdef("dur", dur) diff --git a/gopls/internal/lsp/testdata/godef/a/g.go.golden b/gopls/internal/lsp/testdata/godef/a/g.go.golden new file mode 100644 index 000000000..f7a2e1b07 --- /dev/null +++ b/gopls/internal/lsp/testdata/godef/a/g.go.golden @@ -0,0 +1,7 @@ +-- dur-hoverdef -- +```go +const dur time.Duration = 910350000000 // 15m10.35s +``` + +dur is a constant of type time.Duration. + diff --git a/gopls/internal/lsp/testdata/godef/a/h.go b/gopls/internal/lsp/testdata/godef/a/h.go new file mode 100644 index 000000000..5a5dcc678 --- /dev/null +++ b/gopls/internal/lsp/testdata/godef/a/h.go @@ -0,0 +1,147 @@ +package a + +func _() { + type s struct { + nested struct { + // nested number + number int64 //@mark(nestedNumber, "number") + } + nested2 []struct { + // nested string + str string //@mark(nestedString, "str") + } + x struct { + x struct { + x struct { + x struct { + x struct { + // nested map + m map[string]float64 //@mark(nestedMap, "m") + } + } + } + } + } + } + + var t s + _ = t.nested.number //@hoverdef("number", nestedNumber) + _ = t.nested2[0].str //@hoverdef("str", nestedString) + _ = t.x.x.x.x.x.m //@hoverdef("m", nestedMap) +} + +func _() { + var s struct { + // a field + a int //@mark(structA, "a") + // b nested struct + b struct { //@mark(structB, "b") + // c field of nested struct + c int //@mark(structC, "c") + } + } + _ = s.a //@hoverdef("a", structA) + _ = s.b //@hoverdef("b", structB) + _ = s.b.c //@hoverdef("c", structC) + + var arr []struct { + // d field + d int //@mark(arrD, "d") + // e nested struct + e struct { //@mark(arrE, "e") + // f field of nested struct + f int //@mark(arrF, "f") + } + } + _ = 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 { + // h field + h int //@mark(complexH, "h") + // i nested struct + i struct { //@mark(complexI, "i") + // j field of nested struct + j int //@mark(complexJ, "j") + } + } + } + _ = (<-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 //@hoverdef("x", mapStructKeyX) + } + + var mapWithStructKeyAndValue map[struct { + // Y key field + y string //@mark(mapStructKeyY, "y") + }]struct { + // X value field + x string //@mark(mapStructValueX, "x") + } + 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 //@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() //@hoverdef("open", openMethod) +} + +func _() { + test := struct { + // test description + desc string //@mark(testDescription, "desc") + }{} + _ = test.desc //@hoverdef("desc", testDescription) + + for _, tt := range []struct { + // test input + in map[string][]struct { //@mark(testInput, "in") + // test key + key string //@mark(testInputKey, "key") + // test value + value interface{} //@mark(testInputValue, "value") + } + result struct { + v <-chan struct { + // expected test value + value int //@mark(testResultValue, "value") + } + } + }{} { + _ = 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 //@hoverdef("value", testResultValue) + } +} + +func _() { + getPoints := func() []struct { + // X coord + x int //@mark(returnX, "x") + // Y coord + y int //@mark(returnY, "y") + } { + return nil + } + + r := getPoints() + r[0].x //@hoverdef("x", returnX) + r[0].y //@hoverdef("y", returnY) +} diff --git a/gopls/internal/lsp/testdata/godef/a/h.go.golden b/gopls/internal/lsp/testdata/godef/a/h.go.golden new file mode 100644 index 000000000..7cef9ee96 --- /dev/null +++ b/gopls/internal/lsp/testdata/godef/a/h.go.golden @@ -0,0 +1,161 @@ +-- arrD-hoverdef -- +```go +field d int +``` + +d field + +-- arrE-hoverdef -- +```go +field e struct{f int} +``` + +e nested struct + +-- arrF-hoverdef -- +```go +field f int +``` + +f field of nested struct + +-- complexH-hoverdef -- +```go +field h int +``` + +h field + +-- complexI-hoverdef -- +```go +field i struct{j int} +``` + +i nested struct + +-- complexJ-hoverdef -- +```go +field j int +``` + +j field of nested struct + +-- mapStructKeyX-hoverdef -- +```go +field x []string +``` + +X key field + +-- mapStructKeyY-hoverdef -- +```go +field y string +``` + +Y key field + +-- mapStructValueX-hoverdef -- +```go +field x string +``` + +X value field + +-- nestedMap-hoverdef -- +```go +field m map[string]float64 +``` + +nested map + +-- nestedNumber-hoverdef -- +```go +field number int64 +``` + +nested number + +-- nestedString-hoverdef -- +```go +field str string +``` + +nested string + +-- openMethod-hoverdef -- +```go +func (interface).open() error +``` + +open method comment + +-- returnX-hoverdef -- +```go +field x int +``` + +X coord + +-- returnY-hoverdef -- +```go +field y int +``` + +Y coord + +-- structA-hoverdef -- +```go +field a int +``` + +a field + +-- structB-hoverdef -- +```go +field b struct{c int} +``` + +b nested struct + +-- structC-hoverdef -- +```go +field c int +``` + +c field of nested struct + +-- testDescription-hoverdef -- +```go +field desc string +``` + +test description + +-- testInput-hoverdef -- +```go +field in map[string][]struct{key string; value interface{}} +``` + +test input + +-- testInputKey-hoverdef -- +```go +field key string +``` + +test key + +-- testInputValue-hoverdef -- +```go +field value interface{} +``` + +test value + +-- testResultValue-hoverdef -- +```go +field value int +``` + +expected test value + diff --git a/gopls/internal/lsp/testdata/godef/b/e.go b/gopls/internal/lsp/testdata/godef/b/e.go new file mode 100644 index 000000000..9c81cad31 --- /dev/null +++ b/gopls/internal/lsp/testdata/godef/b/e.go @@ -0,0 +1,31 @@ +package b + +import ( + "fmt" + + "golang.org/lsptests/godef/a" +) + +func useThings() { + t := a.Thing{} //@mark(bStructType, "ing") + fmt.Print(t.Member) //@mark(bMember, "ember") + fmt.Print(a.Other) //@mark(bVar, "ther") + a.Things() //@mark(bFunc, "ings") +} + +/*@ +godef(bStructType, Thing) +godef(bMember, Member) +godef(bVar, Other) +godef(bFunc, Things) +*/ + +func _() { + var x interface{} //@mark(eInterface, "interface{}") + switch x := x.(type) { //@hoverdef("x", eInterface) + case string: //@mark(eString, "string") + fmt.Println(x) //@hoverdef("x", eString) + case int: //@mark(eInt, "int") + fmt.Println(x) //@hoverdef("x", eInt) + } +} diff --git a/gopls/internal/lsp/testdata/godef/b/e.go.golden b/gopls/internal/lsp/testdata/godef/b/e.go.golden new file mode 100644 index 000000000..3d7d89797 --- /dev/null +++ b/gopls/internal/lsp/testdata/godef/b/e.go.golden @@ -0,0 +1,156 @@ +-- Member-definition -- +godef/a/d.go:6:2-8: defined here as ```go +field Member string +``` + +@Member + + +[`(a.Thing).Member` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/godef/a#Thing.Member) +-- Member-definition-json -- +{ + "span": { + "uri": "file://godef/a/d.go", + "start": { + "line": 6, + "column": 2, + "offset": 90 + }, + "end": { + "line": 6, + "column": 8, + "offset": 96 + } + }, + "description": "```go\nfield Member string\n```\n\n@Member\n\n\n[`(a.Thing).Member` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/godef/a#Thing.Member)" +} + +-- Member-hoverdef -- +```go +field Member string +``` + +@Member + + +[`(a.Thing).Member` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/godef/a#Thing.Member) +-- Other-definition -- +godef/a/d.go:9:5-10: defined here as ```go +var a.Other a.Thing +``` + +@Other + + +[`a.Other` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/godef/a#Other) +-- Other-definition-json -- +{ + "span": { + "uri": "file://godef/a/d.go", + "start": { + "line": 9, + "column": 5, + "offset": 121 + }, + "end": { + "line": 9, + "column": 10, + "offset": 126 + } + }, + "description": "```go\nvar a.Other a.Thing\n```\n\n@Other\n\n\n[`a.Other` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/godef/a#Other)" +} + +-- Other-hoverdef -- +```go +var a.Other a.Thing +``` + +@Other + + +[`a.Other` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/godef/a#Other) +-- Thing-definition -- +godef/a/d.go:5:6-11: defined here as ```go +type Thing struct { + Member string //@Member +} + +func (a.Thing).Method(i int) string +func (*a.Thing).Method2(i int, j int) (error, string) +func (a.Thing).Method3() +``` + +[`a.Thing` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/godef/a#Thing) +-- Thing-definition-json -- +{ + "span": { + "uri": "file://godef/a/d.go", + "start": { + "line": 5, + "column": 6, + "offset": 65 + }, + "end": { + "line": 5, + "column": 11, + "offset": 70 + } + }, + "description": "```go\ntype Thing struct {\n\tMember string //@Member\n}\n\nfunc (a.Thing).Method(i int) string\nfunc (*a.Thing).Method2(i int, j int) (error, string)\nfunc (a.Thing).Method3()\n```\n\n[`a.Thing` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/godef/a#Thing)" +} + +-- Thing-hoverdef -- +```go +type Thing struct { + Member string //@Member +} + +func (a.Thing).Method(i int) string +func (*a.Thing).Method2(i int, j int) (error, string) +func (a.Thing).Method3() +``` + +[`a.Thing` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/godef/a#Thing) +-- Things-definition -- +godef/a/d.go:11:6-12: defined here as ```go +func a.Things(val []string) []a.Thing +``` + +[`a.Things` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/godef/a#Things) +-- Things-definition-json -- +{ + "span": { + "uri": "file://godef/a/d.go", + "start": { + "line": 11, + "column": 6, + "offset": 148 + }, + "end": { + "line": 11, + "column": 12, + "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/lsptests/godef/a#Things)" +} + +-- Things-hoverdef -- +```go +func a.Things(val []string) []a.Thing +``` + +[`a.Things` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/godef/a#Things) +-- eInt-hoverdef -- +```go +var x int +``` +-- eInterface-hoverdef -- +```go +var x interface{} +``` +-- eString-hoverdef -- +```go +var x string +``` diff --git a/gopls/internal/lsp/testdata/godef/broken/unclosedIf.go.golden b/gopls/internal/lsp/testdata/godef/broken/unclosedIf.go.golden new file mode 100644 index 000000000..9ce869848 --- /dev/null +++ b/gopls/internal/lsp/testdata/godef/broken/unclosedIf.go.golden @@ -0,0 +1,31 @@ +-- myUnclosedIf-definition -- +godef/broken/unclosedIf.go:7:7-19: defined here as ```go +var myUnclosedIf string +``` + +@myUnclosedIf +-- myUnclosedIf-definition-json -- +{ + "span": { + "uri": "file://godef/broken/unclosedIf.go", + "start": { + "line": 7, + "column": 7, + "offset": 68 + }, + "end": { + "line": 7, + "column": 19, + "offset": 80 + } + }, + "description": "```go\nvar myUnclosedIf string\n```\n\n@myUnclosedIf" +} + +-- myUnclosedIf-hoverdef -- +```go +var myUnclosedIf string +``` + +@myUnclosedIf + diff --git a/gopls/internal/lsp/testdata/godef/broken/unclosedIf.go.in b/gopls/internal/lsp/testdata/godef/broken/unclosedIf.go.in new file mode 100644 index 000000000..0f2cf1b1e --- /dev/null +++ b/gopls/internal/lsp/testdata/godef/broken/unclosedIf.go.in @@ -0,0 +1,9 @@ +package broken + +import "fmt" + +func unclosedIf() { + if false { + var myUnclosedIf string //@myUnclosedIf + fmt.Printf("s = %v\n", myUnclosedIf) //@godef("my", myUnclosedIf) +} diff --git a/gopls/internal/lsp/testdata/good/good0.go b/gopls/internal/lsp/testdata/good/good0.go new file mode 100644 index 000000000..89450a845 --- /dev/null +++ b/gopls/internal/lsp/testdata/good/good0.go @@ -0,0 +1,6 @@ +package good //@diag("package", "no_diagnostics", "", "error") + +func stuff() { //@item(good_stuff, "stuff", "func()", "func"),prepare("stu", "stuff", "stuff") + x := 5 + random2(x) //@prepare("dom", "random2", "random2") +} diff --git a/gopls/internal/lsp/testdata/good/good1.go b/gopls/internal/lsp/testdata/good/good1.go new file mode 100644 index 000000000..624d8147a --- /dev/null +++ b/gopls/internal/lsp/testdata/good/good1.go @@ -0,0 +1,21 @@ +package good //@diag("package", "no_diagnostics", "", "error") + +import ( + "golang.org/lsptests/types" //@item(types_import, "types", "\"golang.org/lsptests/types\"", "package") +) + +func random() int { //@item(good_random, "random", "func() int", "func") + _ = "random() int" //@prepare("random", "", "") + y := 6 + 7 //@prepare("7", "", "") + return y //@prepare("return", "","") +} + +func random2(y int) int { //@item(good_random2, "random2", "func(y int) int", "func"),item(good_y_param, "y", "int", "var") + //@complete("", good_y_param, types_import, good_random, good_random2, good_stuff) + var b types.Bob = &types.X{} //@prepare("ypes","types", "types") + if _, ok := b.(*types.X); ok { //@complete("X", X_struct, Y_struct, Bob_interface, CoolAlias) + _ = 0 // suppress "empty branch" diagnostic + } + + return y +} diff --git a/gopls/internal/lsp/testdata/highlights/highlights.go b/gopls/internal/lsp/testdata/highlights/highlights.go new file mode 100644 index 000000000..55ae68aa1 --- /dev/null +++ b/gopls/internal/lsp/testdata/highlights/highlights.go @@ -0,0 +1,151 @@ +package highlights + +import ( + "fmt" //@mark(fmtImp, "\"fmt\""),highlight(fmtImp, fmtImp, fmt1, fmt2, fmt3, fmt4) + h2 "net/http" //@mark(hImp, "h2"),highlight(hImp, hImp, hUse) + "sort" +) + +type F struct{ bar int } //@mark(barDeclaration, "bar"),highlight(barDeclaration, barDeclaration, bar1, bar2, bar3) + +func _() F { + return F{ + bar: 123, //@mark(bar1, "bar"),highlight(bar1, barDeclaration, bar1, bar2, bar3) + } +} + +var foo = F{bar: 52} //@mark(fooDeclaration, "foo"),mark(bar2, "bar"),highlight(fooDeclaration, fooDeclaration, fooUse),highlight(bar2, barDeclaration, bar1, bar2, bar3) + +func Print() { //@mark(printFunc, "Print"),highlight(printFunc, printFunc, printTest) + _ = h2.Client{} //@mark(hUse, "h2"),highlight(hUse, hImp, hUse) + + fmt.Println(foo) //@mark(fooUse, "foo"),highlight(fooUse, fooDeclaration, fooUse),mark(fmt1, "fmt"),highlight(fmt1, fmtImp, fmt1, fmt2, fmt3, fmt4) + fmt.Print("yo") //@mark(printSep, "Print"),highlight(printSep, printSep, print1, print2),mark(fmt2, "fmt"),highlight(fmt2, fmtImp, fmt1, fmt2, fmt3, fmt4) +} + +func (x *F) Inc() { //@mark(xRightDecl, "x"),mark(xLeftDecl, " *"),highlight(xRightDecl, xRightDecl, xUse),highlight(xLeftDecl, xRightDecl, xUse) + x.bar++ //@mark(xUse, "x"),mark(bar3, "bar"),highlight(xUse, xRightDecl, xUse),highlight(bar3, barDeclaration, bar1, bar2, bar3) +} + +func testFunctions() { + fmt.Print("main start") //@mark(print1, "Print"),highlight(print1, printSep, print1, print2),mark(fmt3, "fmt"),highlight(fmt3, fmtImp, fmt1, fmt2, fmt3, fmt4) + fmt.Print("ok") //@mark(print2, "Print"),highlight(print2, printSep, print1, print2),mark(fmt4, "fmt"),highlight(fmt4, fmtImp, fmt1, fmt2, fmt3, fmt4) + Print() //@mark(printTest, "Print"),highlight(printTest, printFunc, printTest) +} + +func toProtocolHighlight(rngs []int) []DocumentHighlight { //@mark(doc1, "DocumentHighlight"),mark(docRet1, "[]DocumentHighlight"),highlight(doc1, docRet1, doc1, doc2, doc3, result) + result := make([]DocumentHighlight, 0, len(rngs)) //@mark(doc2, "DocumentHighlight"),highlight(doc2, doc1, doc2, doc3) + for _, rng := range rngs { + result = append(result, DocumentHighlight{ //@mark(doc3, "DocumentHighlight"),highlight(doc3, doc1, doc2, doc3) + Range: rng, + }) + } + return result //@mark(result, "result") +} + +func testForLoops() { + for i := 0; i < 10; i++ { //@mark(forDecl1, "for"),highlight(forDecl1, forDecl1, brk1, cont1) + if i > 8 { + break //@mark(brk1, "break"),highlight(brk1, forDecl1, brk1, cont1) + } + if i < 2 { + for j := 1; j < 10; j++ { //@mark(forDecl2, "for"),highlight(forDecl2, forDecl2, cont2) + if j < 3 { + for k := 1; k < 10; k++ { //@mark(forDecl3, "for"),highlight(forDecl3, forDecl3, cont3) + if k < 3 { + continue //@mark(cont3, "continue"),highlight(cont3, forDecl3, cont3) + } + } + continue //@mark(cont2, "continue"),highlight(cont2, forDecl2, cont2) + } + } + continue //@mark(cont1, "continue"),highlight(cont1, forDecl1, brk1, cont1) + } + } + + arr := []int{} + for i := range arr { //@mark(forDecl4, "for"),highlight(forDecl4, forDecl4, brk4, cont4) + if i > 8 { + break //@mark(brk4, "break"),highlight(brk4, forDecl4, brk4, cont4) + } + if i < 4 { + continue //@mark(cont4, "continue"),highlight(cont4, forDecl4, brk4, cont4) + } + } + +Outer: + for i := 0; i < 10; i++ { //@mark(forDecl5, "for"),highlight(forDecl5, forDecl5, brk5, brk6, brk8) + break //@mark(brk5, "break"),highlight(brk5, forDecl5, brk5, brk6, brk8) + for { //@mark(forDecl6, "for"),highlight(forDecl6, forDecl6, cont5) + if i == 1 { + break Outer //@mark(brk6, "break Outer"),highlight(brk6, forDecl5, brk5, brk6, brk8) + } + switch i { //@mark(switch1, "switch"),highlight(switch1, switch1, brk7) + case 5: + break //@mark(brk7, "break"),highlight(brk7, switch1, brk7) + case 6: + continue //@mark(cont5, "continue"),highlight(cont5, forDecl6, cont5) + case 7: + break Outer //@mark(brk8, "break Outer"),highlight(brk8, forDecl5, brk5, brk6, brk8) + } + } + } +} + +func testSwitch() { + var i, j int + +L1: + for { //@mark(forDecl7, "for"),highlight(forDecl7, forDecl7, brk10, cont6) + L2: + switch i { //@mark(switch2, "switch"),highlight(switch2, switch2, brk11, brk12, brk13) + case 1: + switch j { //@mark(switch3, "switch"),highlight(switch3, switch3, brk9) + case 1: + break //@mark(brk9, "break"),highlight(brk9, switch3, brk9) + case 2: + break L1 //@mark(brk10, "break L1"),highlight(brk10, forDecl7, brk10, cont6) + case 3: + break L2 //@mark(brk11, "break L2"),highlight(brk11, switch2, brk11, brk12, brk13) + default: + continue //@mark(cont6, "continue"),highlight(cont6, forDecl7, brk10, cont6) + } + case 2: + break //@mark(brk12, "break"),highlight(brk12, switch2, brk11, brk12, brk13) + default: + break L2 //@mark(brk13, "break L2"),highlight(brk13, switch2, brk11, brk12, brk13) + } + } +} + +func testReturn() bool { //@mark(func1, "func"),mark(bool1, "bool"),highlight(func1, func1, fullRet11, fullRet12),highlight(bool1, bool1, false1, bool2, true1) + if 1 < 2 { + return false //@mark(ret11, "return"),mark(fullRet11, "return false"),mark(false1, "false"),highlight(ret11, func1, fullRet11, fullRet12) + } + candidates := []int{} + sort.SliceStable(candidates, func(i, j int) bool { //@mark(func2, "func"),mark(bool2, "bool"),highlight(func2, func2, fullRet2) + return candidates[i] > candidates[j] //@mark(ret2, "return"),mark(fullRet2, "return candidates[i] > candidates[j]"),highlight(ret2, func2, fullRet2) + }) + return true //@mark(ret12, "return"),mark(fullRet12, "return true"),mark(true1, "true"),highlight(ret12, func1, fullRet11, fullRet12) +} + +func testReturnFields() float64 { //@mark(retVal1, "float64"),highlight(retVal1, retVal1, retVal11, retVal21) + if 1 < 2 { + return 20.1 //@mark(retVal11, "20.1"),highlight(retVal11, retVal1, retVal11, retVal21) + } + z := 4.3 //@mark(zDecl, "z") + return z //@mark(retVal21, "z"),highlight(retVal21, retVal1, retVal11, zDecl, retVal21) +} + +func testReturnMultipleFields() (float32, string) { //@mark(retVal31, "float32"),mark(retVal32, "string"),highlight(retVal31, retVal31, retVal41, retVal51),highlight(retVal32, retVal32, retVal42, retVal52) + y := "im a var" //@mark(yDecl, "y"), + if 1 < 2 { + return 20.1, y //@mark(retVal41, "20.1"),mark(retVal42, "y"),highlight(retVal41, retVal31, retVal41, retVal51),highlight(retVal42, retVal32, yDecl, retVal42, retVal52) + } + return 4.9, "test" //@mark(retVal51, "4.9"),mark(retVal52, "\"test\""),highlight(retVal51, retVal31, retVal41, retVal51),highlight(retVal52, retVal32, retVal42, retVal52) +} + +func testReturnFunc() int32 { //@mark(retCall, "int32") + mulch := 1 //@mark(mulchDec, "mulch"),highlight(mulchDec, mulchDec, mulchRet) + return int32(mulch) //@mark(mulchRet, "mulch"),mark(retFunc, "int32"),mark(retTotal, "int32(mulch)"),highlight(mulchRet, mulchDec, mulchRet),highlight(retFunc, retCall, retFunc, retTotal) +} diff --git a/gopls/internal/lsp/testdata/implementation/implementation.go b/gopls/internal/lsp/testdata/implementation/implementation.go new file mode 100644 index 000000000..4c1a22dd4 --- /dev/null +++ b/gopls/internal/lsp/testdata/implementation/implementation.go @@ -0,0 +1,37 @@ +package implementation + +import "golang.org/lsptests/implementation/other" + +type ImpP struct{} //@ImpP,implementations("ImpP", Laugher, OtherLaugher) + +func (*ImpP) Laugh() { //@mark(LaughP, "Laugh"),implementations("Laugh", Laugh, OtherLaugh) +} + +type ImpS struct{} //@ImpS,implementations("ImpS", Laugher, OtherLaugher) + +func (ImpS) Laugh() { //@mark(LaughS, "Laugh"),implementations("Laugh", Laugh, OtherLaugh) +} + +type Laugher interface { //@Laugher,implementations("Laugher", ImpP, OtherImpP, ImpS, OtherImpS, embedsImpP) + Laugh() //@Laugh,implementations("Laugh", LaughP, OtherLaughP, LaughS, OtherLaughS) +} + +type Foo struct { //@implementations("Foo", Joker) + other.Foo +} + +type Joker interface { //@Joker + Joke() //@Joke,implementations("Joke", ImpJoker) +} + +type cryer int //@implementations("cryer", Cryer) + +func (cryer) Cry(other.CryType) {} //@mark(CryImpl, "Cry"),implementations("Cry", Cry) + +type Empty interface{} //@implementations("Empty") + +var _ interface{ Joke() } //@implementations("Joke", ImpJoker) + +type embedsImpP struct { //@embedsImpP + ImpP //@implementations("ImpP", Laugher, OtherLaugher) +} diff --git a/gopls/internal/lsp/testdata/implementation/implementation_generics.go b/gopls/internal/lsp/testdata/implementation/implementation_generics.go new file mode 100644 index 000000000..1f02d166b --- /dev/null +++ b/gopls/internal/lsp/testdata/implementation/implementation_generics.go @@ -0,0 +1,16 @@ +//go:build go1.18 +// +build go1.18 + +package implementation + +// -- generics -- + +type GenIface[T any] interface { //@mark(GenIface, "GenIface"),implementations("GenIface", GC) + F(int, string, T) //@mark(GenIfaceF, "F"),implementations("F", GCF) +} + +type GenConc[U any] int //@mark(GenConc, "GenConc"),implementations("GenConc", GI) + +func (GenConc[V]) F(int, string, V) {} //@mark(GenConcF, "F"),implementations("F", GIF) + +type GenConcString struct{ GenConc[string] } //@mark(GenConcString, "GenConcString"),implementations(GenConcString, GIString) diff --git a/gopls/internal/lsp/testdata/implementation/other/other.go b/gopls/internal/lsp/testdata/implementation/other/other.go new file mode 100644 index 000000000..aff825e91 --- /dev/null +++ b/gopls/internal/lsp/testdata/implementation/other/other.go @@ -0,0 +1,27 @@ +package other + +type ImpP struct{} //@mark(OtherImpP, "ImpP") + +func (*ImpP) Laugh() { //@mark(OtherLaughP, "Laugh") +} + +type ImpS struct{} //@mark(OtherImpS, "ImpS") + +func (ImpS) Laugh() { //@mark(OtherLaughS, "Laugh") +} + +type ImpI interface { //@mark(OtherLaugher, "ImpI") + Laugh() //@mark(OtherLaugh, "Laugh") +} + +type Foo struct { //@implementations("Foo", Joker) +} + +func (Foo) Joke() { //@mark(ImpJoker, "Joke"),implementations("Joke", Joke) +} + +type CryType int + +type Cryer interface { //@Cryer + Cry(CryType) //@Cry,implementations("Cry", CryImpl) +} diff --git a/gopls/internal/lsp/testdata/implementation/other/other_generics.go b/gopls/internal/lsp/testdata/implementation/other/other_generics.go new file mode 100644 index 000000000..4b4c29f7d --- /dev/null +++ b/gopls/internal/lsp/testdata/implementation/other/other_generics.go @@ -0,0 +1,16 @@ +//go:build go1.18 +// +build go1.18 + +package other + +// -- generics (limited support) -- + +type GI[T any] interface { //@mark(GI, "GI"),implementations("GI", GenConc) + F(int, string, T) //@mark(GIF, "F"),implementations("F", GenConcF) +} + +type GIString GI[string] //@mark(GIString, "GIString"),implementations("GIString", GenConcString) + +type GC[U any] int //@mark(GC, "GC"),implementations("GC", GenIface) + +func (GC[V]) F(int, string, V) {} //@mark(GCF, "F"),implementations("F", GenIfaceF) diff --git a/gopls/internal/lsp/testdata/implementation/other/other_test.go b/gopls/internal/lsp/testdata/implementation/other/other_test.go new file mode 100644 index 000000000..846e0d591 --- /dev/null +++ b/gopls/internal/lsp/testdata/implementation/other/other_test.go @@ -0,0 +1,10 @@ +package other + +import ( + "testing" +) + +// This exists so the other.test package comes into existence. + +func TestOther(t *testing.T) { +} diff --git a/gopls/internal/lsp/testdata/importedcomplit/imported_complit.go.in b/gopls/internal/lsp/testdata/importedcomplit/imported_complit.go.in new file mode 100644 index 000000000..2f4cbada1 --- /dev/null +++ b/gopls/internal/lsp/testdata/importedcomplit/imported_complit.go.in @@ -0,0 +1,42 @@ +package importedcomplit + +import ( + "golang.org/lsptests/foo" + + // import completions + "fm" //@complete("\" //", fmtImport) + "go/pars" //@complete("\" //", parserImport) + "golang.org/lsptests/signa" //@complete("na\" //", signatureImport) + "golang.org/lspte" //@complete("\" //", lsptestsImport) + "crypto/elli" //@complete("\" //", cryptoImport) + "golang.org/lsptests/sign" //@complete("\" //", signatureImport) + "golang.org/lsptests/sign" //@complete("ests", lsptestsImport) + namedParser "go/pars" //@complete("\" //", parserImport) +) + +func _() { + var V int //@item(icVVar, "V", "int", "var") + _ = foo.StructFoo{V} //@complete("}", Value, icVVar) +} + +func _() { + var ( + aa string //@item(icAAVar, "aa", "string", "var") + ab int //@item(icABVar, "ab", "int", "var") + ) + + _ = foo.StructFoo{a} //@complete("}", abVar, aaVar) + + var s struct { + AA string //@item(icFieldAA, "AA", "string", "field") + AB int //@item(icFieldAB, "AB", "int", "field") + } + + _ = foo.StructFoo{s.} //@complete("}", icFieldAB, icFieldAA) +} + +/* "fmt" */ //@item(fmtImport, "fmt", "\"fmt\"", "package") +/* "go/parser" */ //@item(parserImport, "parser", "\"go/parser\"", "package") +/* "golang.org/lsptests/signature" */ //@item(signatureImport, "signature", "\"golang.org/lsptests/signature\"", "package") +/* "golang.org/lsptests/" */ //@item(lsptestsImport, "lsptests/", "\"golang.org/lsptests/\"", "package") +/* "crypto/elliptic" */ //@item(cryptoImport, "elliptic", "\"crypto/elliptic\"", "package") diff --git a/gopls/internal/lsp/testdata/imports/add_import.go.golden b/gopls/internal/lsp/testdata/imports/add_import.go.golden new file mode 100644 index 000000000..16af110a0 --- /dev/null +++ b/gopls/internal/lsp/testdata/imports/add_import.go.golden @@ -0,0 +1,13 @@ +-- goimports -- +package imports //@import("package") + +import ( + "bytes" + "fmt" +) + +func _() { + fmt.Println("") + bytes.NewBuffer(nil) +} + diff --git a/gopls/internal/lsp/testdata/imports/add_import.go.in b/gopls/internal/lsp/testdata/imports/add_import.go.in new file mode 100644 index 000000000..7928e6f71 --- /dev/null +++ b/gopls/internal/lsp/testdata/imports/add_import.go.in @@ -0,0 +1,10 @@ +package imports //@import("package") + +import ( + "fmt" +) + +func _() { + fmt.Println("") + bytes.NewBuffer(nil) +} diff --git a/gopls/internal/lsp/testdata/imports/good_imports.go.golden b/gopls/internal/lsp/testdata/imports/good_imports.go.golden new file mode 100644 index 000000000..2abdae4d7 --- /dev/null +++ b/gopls/internal/lsp/testdata/imports/good_imports.go.golden @@ -0,0 +1,9 @@ +-- goimports -- +package imports //@import("package") + +import "fmt" + +func _() { +fmt.Println("") +} + diff --git a/gopls/internal/lsp/testdata/imports/good_imports.go.in b/gopls/internal/lsp/testdata/imports/good_imports.go.in new file mode 100644 index 000000000..a03c06c6d --- /dev/null +++ b/gopls/internal/lsp/testdata/imports/good_imports.go.in @@ -0,0 +1,7 @@ +package imports //@import("package") + +import "fmt" + +func _() { +fmt.Println("") +} diff --git a/gopls/internal/lsp/testdata/imports/issue35458.go.golden b/gopls/internal/lsp/testdata/imports/issue35458.go.golden new file mode 100644 index 000000000..f0772606b --- /dev/null +++ b/gopls/internal/lsp/testdata/imports/issue35458.go.golden @@ -0,0 +1,20 @@ +-- goimports -- +// package doc +package imports //@import("package") + + + + + + +func _() { + println("Hello, world!") +} + + + + + + + + diff --git a/gopls/internal/lsp/testdata/imports/issue35458.go.in b/gopls/internal/lsp/testdata/imports/issue35458.go.in new file mode 100644 index 000000000..7420c212c --- /dev/null +++ b/gopls/internal/lsp/testdata/imports/issue35458.go.in @@ -0,0 +1,23 @@ + + + + + +// package doc +package imports //@import("package") + + + + + + +func _() { + println("Hello, world!") +} + + + + + + + diff --git a/gopls/internal/lsp/testdata/imports/multiple_blocks.go.golden b/gopls/internal/lsp/testdata/imports/multiple_blocks.go.golden new file mode 100644 index 000000000..d37a6c751 --- /dev/null +++ b/gopls/internal/lsp/testdata/imports/multiple_blocks.go.golden @@ -0,0 +1,9 @@ +-- goimports -- +package imports //@import("package") + +import "fmt" + +func _() { + fmt.Println("") +} + diff --git a/gopls/internal/lsp/testdata/imports/multiple_blocks.go.in b/gopls/internal/lsp/testdata/imports/multiple_blocks.go.in new file mode 100644 index 000000000..3f2fb99ea --- /dev/null +++ b/gopls/internal/lsp/testdata/imports/multiple_blocks.go.in @@ -0,0 +1,9 @@ +package imports //@import("package") + +import "fmt" + +import "bytes" + +func _() { + fmt.Println("") +} diff --git a/gopls/internal/lsp/testdata/imports/needs_imports.go.golden b/gopls/internal/lsp/testdata/imports/needs_imports.go.golden new file mode 100644 index 000000000..fd6032874 --- /dev/null +++ b/gopls/internal/lsp/testdata/imports/needs_imports.go.golden @@ -0,0 +1,13 @@ +-- goimports -- +package imports //@import("package") + +import ( + "fmt" + "log" +) + +func goodbye() { + fmt.Printf("HI") + log.Printf("byeeeee") +} + diff --git a/gopls/internal/lsp/testdata/imports/needs_imports.go.in b/gopls/internal/lsp/testdata/imports/needs_imports.go.in new file mode 100644 index 000000000..949d56a64 --- /dev/null +++ b/gopls/internal/lsp/testdata/imports/needs_imports.go.in @@ -0,0 +1,6 @@ +package imports //@import("package") + +func goodbye() { + fmt.Printf("HI") + log.Printf("byeeeee") +} diff --git a/gopls/internal/lsp/testdata/imports/remove_import.go.golden b/gopls/internal/lsp/testdata/imports/remove_import.go.golden new file mode 100644 index 000000000..3df80882c --- /dev/null +++ b/gopls/internal/lsp/testdata/imports/remove_import.go.golden @@ -0,0 +1,11 @@ +-- goimports -- +package imports //@import("package") + +import ( + "fmt" +) + +func _() { + fmt.Println("") +} + diff --git a/gopls/internal/lsp/testdata/imports/remove_import.go.in b/gopls/internal/lsp/testdata/imports/remove_import.go.in new file mode 100644 index 000000000..09060bada --- /dev/null +++ b/gopls/internal/lsp/testdata/imports/remove_import.go.in @@ -0,0 +1,10 @@ +package imports //@import("package") + +import ( + "bytes" + "fmt" +) + +func _() { + fmt.Println("") +} diff --git a/gopls/internal/lsp/testdata/imports/remove_imports.go.golden b/gopls/internal/lsp/testdata/imports/remove_imports.go.golden new file mode 100644 index 000000000..530c8c09f --- /dev/null +++ b/gopls/internal/lsp/testdata/imports/remove_imports.go.golden @@ -0,0 +1,6 @@ +-- goimports -- +package imports //@import("package") + +func _() { +} + diff --git a/gopls/internal/lsp/testdata/imports/remove_imports.go.in b/gopls/internal/lsp/testdata/imports/remove_imports.go.in new file mode 100644 index 000000000..44d065f25 --- /dev/null +++ b/gopls/internal/lsp/testdata/imports/remove_imports.go.in @@ -0,0 +1,9 @@ +package imports //@import("package") + +import ( + "bytes" + "fmt" +) + +func _() { +} diff --git a/gopls/internal/lsp/testdata/imports/two_lines.go.golden b/gopls/internal/lsp/testdata/imports/two_lines.go.golden new file mode 100644 index 000000000..ec118a4dd --- /dev/null +++ b/gopls/internal/lsp/testdata/imports/two_lines.go.golden @@ -0,0 +1,4 @@ +-- goimports -- +package main +func main() {} //@import("main") + diff --git a/gopls/internal/lsp/testdata/imports/two_lines.go.in b/gopls/internal/lsp/testdata/imports/two_lines.go.in new file mode 100644 index 000000000..eee534569 --- /dev/null +++ b/gopls/internal/lsp/testdata/imports/two_lines.go.in @@ -0,0 +1,2 @@ +package main +func main() {} //@import("main") diff --git a/gopls/internal/lsp/testdata/index/index.go b/gopls/internal/lsp/testdata/index/index.go new file mode 100644 index 000000000..a2656893c --- /dev/null +++ b/gopls/internal/lsp/testdata/index/index.go @@ -0,0 +1,25 @@ +package index + +func _() { + var ( + aa = "123" //@item(indexAA, "aa", "string", "var") + ab = 123 //@item(indexAB, "ab", "int", "var") + ) + + var foo [1]int + foo[a] //@complete("]", indexAB, indexAA) + foo[:a] //@complete("]", indexAB, indexAA) + a[:a] //@complete("[", indexAA, indexAB) + a[a] //@complete("[", indexAA, indexAB) + + var bar map[string]int + bar[a] //@complete("]", indexAA, indexAB) + + type myMap map[string]int + var baz myMap + baz[a] //@complete("]", indexAA, indexAB) + + type myInt int + var mi myInt //@item(indexMyInt, "mi", "myInt", "var") + foo[m] //@snippet("]", indexMyInt, "mi", "mi") +} diff --git a/gopls/internal/lsp/testdata/inlay_hint/composite_literals.go b/gopls/internal/lsp/testdata/inlay_hint/composite_literals.go new file mode 100644 index 000000000..b05c95ec8 --- /dev/null +++ b/gopls/internal/lsp/testdata/inlay_hint/composite_literals.go @@ -0,0 +1,27 @@ +package inlayHint //@inlayHint("package") + +import "fmt" + +func fieldNames() { + for _, c := range []struct { + in, want string + }{ + struct{ in, want string }{"Hello, world", "dlrow ,olleH"}, + {"Hello, 世界", "界世 ,olleH"}, + {"", ""}, + } { + fmt.Println(c.in == c.want) + } +} + +func fieldNamesPointers() { + for _, c := range []*struct { + in, want string + }{ + &struct{ in, want string }{"Hello, world", "dlrow ,olleH"}, + {"Hello, 世界", "界世 ,olleH"}, + {"", ""}, + } { + fmt.Println(c.in == c.want) + } +} diff --git a/gopls/internal/lsp/testdata/inlay_hint/composite_literals.go.golden b/gopls/internal/lsp/testdata/inlay_hint/composite_literals.go.golden new file mode 100644 index 000000000..eb2febdb6 --- /dev/null +++ b/gopls/internal/lsp/testdata/inlay_hint/composite_literals.go.golden @@ -0,0 +1,29 @@ +-- inlayHint -- +package inlayHint //@inlayHint("package") + +import "fmt" + +func fieldNames() { + for _< int>, c< struct{in string; want string}> := range []struct { + in, want string + }{ + struct{ in, want string }{<in: >"Hello, world", <want: >"dlrow ,olleH"}, + <struct{in string; want string}>{<in: >"Hello, 世界", <want: >"界世 ,olleH"}, + <struct{in string; want string}>{<in: >"", <want: >""}, + } { + fmt.Println(<a...: >c.in == c.want) + } +} + +func fieldNamesPointers() { + for _< int>, c< *struct{in string; want string}> := range []*struct { + in, want string + }{ + &struct{ in, want string }{<in: >"Hello, world", <want: >"dlrow ,olleH"}, + <&struct{in string; want string}>{<in: >"Hello, 世界", <want: >"界世 ,olleH"}, + <&struct{in string; want string}>{<in: >"", <want: >""}, + } { + fmt.Println(<a...: >c.in == c.want) + } +} + diff --git a/gopls/internal/lsp/testdata/inlay_hint/constant_values.go b/gopls/internal/lsp/testdata/inlay_hint/constant_values.go new file mode 100644 index 000000000..e3339b0f3 --- /dev/null +++ b/gopls/internal/lsp/testdata/inlay_hint/constant_values.go @@ -0,0 +1,45 @@ +package inlayHint //@inlayHint("package") + +const True = true + +type Kind int + +const ( + KindNone Kind = iota + KindPrint + KindPrintf + KindErrorf +) + +const ( + u = iota * 4 + v float64 = iota * 42 + w = iota * 42 +) + +const ( + a, b = 1, 2 + c, d + e, f = 5 * 5, "hello" + "world" + g, h + i, j = true, f +) + +// No hint +const ( + Int = 3 + Float = 3.14 + Bool = true + Rune = '3' + Complex = 2.7i + String = "Hello, world!" +) + +var ( + varInt = 3 + varFloat = 3.14 + varBool = true + varRune = '3' + '4' + varComplex = 2.7i + varString = "Hello, world!" +) diff --git a/gopls/internal/lsp/testdata/inlay_hint/constant_values.go.golden b/gopls/internal/lsp/testdata/inlay_hint/constant_values.go.golden new file mode 100644 index 000000000..edc46debc --- /dev/null +++ b/gopls/internal/lsp/testdata/inlay_hint/constant_values.go.golden @@ -0,0 +1,47 @@ +-- inlayHint -- +package inlayHint //@inlayHint("package") + +const True = true + +type Kind int + +const ( + KindNone Kind = iota< = 0> + KindPrint< = 1> + KindPrintf< = 2> + KindErrorf< = 3> +) + +const ( + u = iota * 4< = 0> + v float64 = iota * 42< = 42> + w = iota * 42< = 84> +) + +const ( + a, b = 1, 2 + c, d< = 1, 2> + e, f = 5 * 5, "hello" + "world"< = 25, "helloworld"> + g, h< = 25, "helloworld"> + i, j = true, f< = true, "helloworld"> +) + +// No hint +const ( + Int = 3 + Float = 3.14 + Bool = true + Rune = '3' + Complex = 2.7i + String = "Hello, world!" +) + +var ( + varInt = 3 + varFloat = 3.14 + varBool = true + varRune = '3' + '4' + varComplex = 2.7i + varString = "Hello, world!" +) + diff --git a/gopls/internal/lsp/testdata/inlay_hint/parameter_names.go b/gopls/internal/lsp/testdata/inlay_hint/parameter_names.go new file mode 100644 index 000000000..0d930e5d4 --- /dev/null +++ b/gopls/internal/lsp/testdata/inlay_hint/parameter_names.go @@ -0,0 +1,50 @@ +package inlayHint //@inlayHint("package") + +import "fmt" + +func hello(name string) string { + return "Hello " + name +} + +func helloWorld() string { + return hello("World") +} + +type foo struct{} + +func (*foo) bar(baz string, qux int) int { + if baz != "" { + return qux + 1 + } + return qux +} + +func kase(foo int, bar bool, baz ...string) { + fmt.Println(foo, bar, baz) +} + +func kipp(foo string, bar, baz string) { + fmt.Println(foo, bar, baz) +} + +func plex(foo, bar string, baz string) { + fmt.Println(foo, bar, baz) +} + +func tars(foo string, bar, baz string) { + fmt.Println(foo, bar, baz) +} + +func foobar() { + var x foo + x.bar("", 1) + kase(0, true, "c", "d", "e") + kipp("a", "b", "c") + plex("a", "b", "c") + tars("a", "b", "c") + foo, bar, baz := "a", "b", "c" + kipp(foo, bar, baz) + plex("a", bar, baz) + tars(foo+foo, (bar), "c") + +} diff --git a/gopls/internal/lsp/testdata/inlay_hint/parameter_names.go.golden b/gopls/internal/lsp/testdata/inlay_hint/parameter_names.go.golden new file mode 100644 index 000000000..4e93a4f92 --- /dev/null +++ b/gopls/internal/lsp/testdata/inlay_hint/parameter_names.go.golden @@ -0,0 +1,52 @@ +-- inlayHint -- +package inlayHint //@inlayHint("package") + +import "fmt" + +func hello(name string) string { + return "Hello " + name +} + +func helloWorld() string { + return hello(<name: >"World") +} + +type foo struct{} + +func (*foo) bar(baz string, qux int) int { + if baz != "" { + return qux + 1 + } + return qux +} + +func kase(foo int, bar bool, baz ...string) { + fmt.Println(<a...: >foo, bar, baz) +} + +func kipp(foo string, bar, baz string) { + fmt.Println(<a...: >foo, bar, baz) +} + +func plex(foo, bar string, baz string) { + fmt.Println(<a...: >foo, bar, baz) +} + +func tars(foo string, bar, baz string) { + fmt.Println(<a...: >foo, bar, baz) +} + +func foobar() { + var x foo + x.bar(<baz: >"", <qux: >1) + kase(<foo: >0, <bar: >true, <baz...: >"c", "d", "e") + kipp(<foo: >"a", <bar: >"b", <baz: >"c") + plex(<foo: >"a", <bar: >"b", <baz: >"c") + tars(<foo: >"a", <bar: >"b", <baz: >"c") + foo< string>, bar< string>, baz< string> := "a", "b", "c" + kipp(foo, bar, baz) + plex(<foo: >"a", bar, baz) + tars(<foo: >foo+foo, <bar: >(bar), <baz: >"c") + +} + diff --git a/gopls/internal/lsp/testdata/inlay_hint/type_params.go b/gopls/internal/lsp/testdata/inlay_hint/type_params.go new file mode 100644 index 000000000..3a3c7e537 --- /dev/null +++ b/gopls/internal/lsp/testdata/inlay_hint/type_params.go @@ -0,0 +1,45 @@ +//go:build go1.18 +// +build go1.18 + +package inlayHint //@inlayHint("package") + +func main() { + ints := map[string]int64{ + "first": 34, + "second": 12, + } + + floats := map[string]float64{ + "first": 35.98, + "second": 26.99, + } + + SumIntsOrFloats[string, int64](ints) + SumIntsOrFloats[string, float64](floats) + + SumIntsOrFloats(ints) + SumIntsOrFloats(floats) + + SumNumbers(ints) + SumNumbers(floats) +} + +type Number interface { + int64 | float64 +} + +func SumIntsOrFloats[K comparable, V int64 | float64](m map[K]V) V { + var s V + for _, v := range m { + s += v + } + return s +} + +func SumNumbers[K comparable, V Number](m map[K]V) V { + var s V + for _, v := range m { + s += v + } + return s +} diff --git a/gopls/internal/lsp/testdata/inlay_hint/type_params.go.golden b/gopls/internal/lsp/testdata/inlay_hint/type_params.go.golden new file mode 100644 index 000000000..4819963b7 --- /dev/null +++ b/gopls/internal/lsp/testdata/inlay_hint/type_params.go.golden @@ -0,0 +1,47 @@ +-- inlayHint -- +//go:build go1.18 +// +build go1.18 + +package inlayHint //@inlayHint("package") + +func main() { + ints< map[string]int64> := map[string]int64{ + "first": 34, + "second": 12, + } + + floats< map[string]float64> := map[string]float64{ + "first": 35.98, + "second": 26.99, + } + + SumIntsOrFloats[string, int64](<m: >ints) + SumIntsOrFloats[string, float64](<m: >floats) + + SumIntsOrFloats<[string, int64]>(<m: >ints) + SumIntsOrFloats<[string, float64]>(<m: >floats) + + SumNumbers<[string, int64]>(<m: >ints) + SumNumbers<[string, float64]>(<m: >floats) +} + +type Number interface { + int64 | float64 +} + +func SumIntsOrFloats[K comparable, V int64 | float64](m map[K]V) V { + var s V + for _< K>, v< V> := range m { + s += v + } + return s +} + +func SumNumbers[K comparable, V Number](m map[K]V) V { + var s V + for _< K>, v< V> := range m { + s += v + } + return s +} + diff --git a/gopls/internal/lsp/testdata/inlay_hint/variable_types.go b/gopls/internal/lsp/testdata/inlay_hint/variable_types.go new file mode 100644 index 000000000..219af7059 --- /dev/null +++ b/gopls/internal/lsp/testdata/inlay_hint/variable_types.go @@ -0,0 +1,20 @@ +package inlayHint //@inlayHint("package") + +func assignTypes() { + i, j := 0, len([]string{})-1 + println(i, j) +} + +func rangeTypes() { + for k, v := range []string{} { + println(k, v) + } +} + +func funcLitType() { + myFunc := func(a string) string { return "" } +} + +func compositeLitType() { + foo := map[string]interface{}{"": ""} +} diff --git a/gopls/internal/lsp/testdata/inlay_hint/variable_types.go.golden b/gopls/internal/lsp/testdata/inlay_hint/variable_types.go.golden new file mode 100644 index 000000000..6039950d5 --- /dev/null +++ b/gopls/internal/lsp/testdata/inlay_hint/variable_types.go.golden @@ -0,0 +1,22 @@ +-- inlayHint -- +package inlayHint //@inlayHint("package") + +func assignTypes() { + i< int>, j< int> := 0, len([]string{})-1 + println(i, j) +} + +func rangeTypes() { + for k< int>, v< string> := range []string{} { + println(k, v) + } +} + +func funcLitType() { + myFunc< func(a string) string> := func(a string) string { return "" } +} + +func compositeLitType() { + foo< map[string]interface{}> := map[string]interface{}{"": ""} +} + diff --git a/gopls/internal/lsp/testdata/interfacerank/interface_rank.go b/gopls/internal/lsp/testdata/interfacerank/interface_rank.go new file mode 100644 index 000000000..acb5a42e0 --- /dev/null +++ b/gopls/internal/lsp/testdata/interfacerank/interface_rank.go @@ -0,0 +1,23 @@ +package interfacerank + +type foo interface { + foo() +} + +type fooImpl int + +func (*fooImpl) foo() {} + +func wantsFoo(foo) {} + +func _() { + var ( + aa string //@item(irAA, "aa", "string", "var") + ab *fooImpl //@item(irAB, "ab", "*fooImpl", "var") + ) + + wantsFoo(a) //@complete(")", irAB, irAA) + + var ac fooImpl //@item(irAC, "ac", "fooImpl", "var") + wantsFoo(&a) //@complete(")", irAC, irAA, irAB) +} diff --git a/gopls/internal/lsp/testdata/issues/issue56505.go b/gopls/internal/lsp/testdata/issues/issue56505.go new file mode 100644 index 000000000..8c641bfb8 --- /dev/null +++ b/gopls/internal/lsp/testdata/issues/issue56505.go @@ -0,0 +1,8 @@ +package issues + +// Test for golang/go#56505: completion on variables of type *error should not +// panic. +func _() { + var e *error + e.x //@complete(" //") +} diff --git a/gopls/internal/lsp/testdata/keywords/accidental_keywords.go.in b/gopls/internal/lsp/testdata/keywords/accidental_keywords.go.in new file mode 100644 index 000000000..3833081c4 --- /dev/null +++ b/gopls/internal/lsp/testdata/keywords/accidental_keywords.go.in @@ -0,0 +1,31 @@ +package keywords + +// non-matching candidate - shouldn't show up as completion +var apple = "apple" + +func _() { + foo.bar() // insert some extra statements to exercise our AST surgery + variance := 123 //@item(kwVariance, "variance", "int", "var") + foo.bar() + println(var) //@complete(")", kwVariance) +} + +func _() { + foo.bar() + var s struct { variance int } //@item(kwVarianceField, "variance", "int", "field") + foo.bar() + s.var //@complete(" //", kwVarianceField) +} + +func _() { + channel := 123 //@item(kwChannel, "channel", "int", "var") + chan //@complete(" //", kwChannel) + foo.bar() +} + +func _() { + foo.bar() + var typeName string //@item(kwTypeName, "typeName", "string", "var") + foo.bar() + type //@complete(" //", kwTypeName) +} diff --git a/gopls/internal/lsp/testdata/keywords/empty_select.go b/gopls/internal/lsp/testdata/keywords/empty_select.go new file mode 100644 index 000000000..17ca3ec9d --- /dev/null +++ b/gopls/internal/lsp/testdata/keywords/empty_select.go @@ -0,0 +1,7 @@ +package keywords + +func _() { + select { + c //@complete(" //", case) + } +} diff --git a/gopls/internal/lsp/testdata/keywords/empty_switch.go b/gopls/internal/lsp/testdata/keywords/empty_switch.go new file mode 100644 index 000000000..2004d5541 --- /dev/null +++ b/gopls/internal/lsp/testdata/keywords/empty_switch.go @@ -0,0 +1,11 @@ +package keywords + +func _() { + switch { + //@complete("", case, default) + } + + switch test.(type) { + d //@complete(" //", default) + } +} diff --git a/gopls/internal/lsp/testdata/keywords/keywords.go b/gopls/internal/lsp/testdata/keywords/keywords.go new file mode 100644 index 000000000..0bcaa63bf --- /dev/null +++ b/gopls/internal/lsp/testdata/keywords/keywords.go @@ -0,0 +1,100 @@ +package keywords + +//@rank("", type),rank("", func),rank("", var),rank("", const),rank("", import) + +func _() { + var test int //@rank(" //", int, interface) + var tChan chan int + var _ m //@complete(" //", map) + var _ f //@complete(" //", func) + var _ c //@complete(" //", chan) + + var _ str //@rank(" //", string, struct) + + type _ int //@rank(" //", interface, int) + + type _ str //@rank(" //", struct, string) + + switch test { + case 1: // TODO: trying to complete case here will break because the parser won't return *ast.Ident + b //@complete(" //", break) + case 2: + f //@complete(" //", fallthrough, for) + r //@complete(" //", return) + d //@complete(" //", default, defer) + c //@complete(" //", case, const) + } + + switch test.(type) { + case fo: //@complete(":") + case int: + b //@complete(" //", break) + case int32: + f //@complete(" //", for) + d //@complete(" //", default, defer) + r //@complete(" //", return) + c //@complete(" //", case, const) + } + + select { + case <-tChan: + b //@complete(" //", break) + c //@complete(" //", case, const) + } + + for index := 0; index < test; index++ { + c //@complete(" //", const, continue) + b //@complete(" //", break) + } + + for range []int{} { + c //@complete(" //", const, continue) + b //@complete(" //", break) + } + + // Test function level keywords + + //Using 2 characters to test because map output order is random + sw //@complete(" //", switch) + se //@complete(" //", select) + + f //@complete(" //", for) + d //@complete(" //", defer) + g //@rank(" //", go),rank(" //", goto) + r //@complete(" //", return) + i //@complete(" //", if) + e //@complete(" //", else) + v //@complete(" //", var) + c //@complete(" //", const) + + for i := r //@complete(" //", range) +} + +/* package */ //@item(package, "package", "", "keyword") +/* import */ //@item(import, "import", "", "keyword") +/* func */ //@item(func, "func", "", "keyword") +/* type */ //@item(type, "type", "", "keyword") +/* var */ //@item(var, "var", "", "keyword") +/* const */ //@item(const, "const", "", "keyword") +/* break */ //@item(break, "break", "", "keyword") +/* default */ //@item(default, "default", "", "keyword") +/* case */ //@item(case, "case", "", "keyword") +/* defer */ //@item(defer, "defer", "", "keyword") +/* go */ //@item(go, "go", "", "keyword") +/* for */ //@item(for, "for", "", "keyword") +/* if */ //@item(if, "if", "", "keyword") +/* else */ //@item(else, "else", "", "keyword") +/* switch */ //@item(switch, "switch", "", "keyword") +/* select */ //@item(select, "select", "", "keyword") +/* fallthrough */ //@item(fallthrough, "fallthrough", "", "keyword") +/* continue */ //@item(continue, "continue", "", "keyword") +/* return */ //@item(return, "return", "", "keyword") +/* var */ //@item(var, "var", "", "keyword") +/* const */ //@item(const, "const", "", "keyword") +/* goto */ //@item(goto, "goto", "", "keyword") +/* struct */ //@item(struct, "struct", "", "keyword") +/* interface */ //@item(interface, "interface", "", "keyword") +/* map */ //@item(map, "map", "", "keyword") +/* func */ //@item(func, "func", "", "keyword") +/* chan */ //@item(chan, "chan", "", "keyword") +/* range */ //@item(range, "range", "", "keyword") diff --git a/gopls/internal/lsp/testdata/labels/labels.go b/gopls/internal/lsp/testdata/labels/labels.go new file mode 100644 index 000000000..b9effb6d0 --- /dev/null +++ b/gopls/internal/lsp/testdata/labels/labels.go @@ -0,0 +1,49 @@ +package labels + +func _() { + goto F //@complete(" //", label1, label5) + +Foo1: //@item(label1, "Foo1", "label", "const") + for a, b := range []int{} { + Foo2: //@item(label2, "Foo2", "label", "const") + switch { + case true: + break F //@complete(" //", label2, label1) + + continue F //@complete(" //", label1) + + { + FooUnjumpable: + } + + goto F //@complete(" //", label1, label2, label4, label5) + + func() { + goto F //@complete(" //", label3) + + break F //@complete(" //") + + continue F //@complete(" //") + + Foo3: //@item(label3, "Foo3", "label", "const") + }() + } + + Foo4: //@item(label4, "Foo4", "label", "const") + switch interface{}(a).(type) { + case int: + break F //@complete(" //", label4, label1) + } + } + + break F //@complete(" //") + + continue F //@complete(" //") + +Foo5: //@item(label5, "Foo5", "label", "const") + for { + break F //@complete(" //", label5) + } + + return +} diff --git a/gopls/internal/lsp/testdata/links/links.go b/gopls/internal/lsp/testdata/links/links.go new file mode 100644 index 000000000..378134341 --- /dev/null +++ b/gopls/internal/lsp/testdata/links/links.go @@ -0,0 +1,26 @@ +package links + +import ( + "fmt" //@link(`fmt`,"https://pkg.go.dev/fmt") + + "golang.org/lsptests/foo" //@link(`golang.org/lsptests/foo`,`https://pkg.go.dev/golang.org/lsptests/foo`) + + _ "database/sql" //@link(`database/sql`, `https://pkg.go.dev/database/sql`) +) + +var ( + _ fmt.Formatter + _ foo.StructFoo + _ errors.Formatter +) + +// Foo function +func Foo() string { + /*https://example.com/comment */ //@link("https://example.com/comment","https://example.com/comment") + + url := "https://example.com/string_literal" //@link("https://example.com/string_literal","https://example.com/string_literal") + return url + + // TODO(golang/go#1234): Link the relevant issue. //@link("golang/go#1234", "https://github.com/golang/go/issues/1234") + // TODO(microsoft/vscode-go#12): Another issue. //@link("microsoft/vscode-go#12", "https://github.com/microsoft/vscode-go/issues/12") +} diff --git a/gopls/internal/lsp/testdata/maps/maps.go.in b/gopls/internal/lsp/testdata/maps/maps.go.in new file mode 100644 index 000000000..eeb5576b0 --- /dev/null +++ b/gopls/internal/lsp/testdata/maps/maps.go.in @@ -0,0 +1,18 @@ +package maps + +func _() { + var aVar int //@item(mapVar, "aVar", "int", "var") + + // not comparabale + type aSlice []int //@item(mapSliceType, "aSlice", "[]int", "type") + + *aSlice //@item(mapSliceTypePtr, "*aSlice", "[]int", "type") + + // comparable + type aStruct struct{} //@item(mapStructType, "aStruct", "struct{...}", "struct") + + map[]a{} //@complete("]", mapSliceType, mapStructType),snippet("]", mapSliceType, "*aSlice", "*aSlice") + + map[a]a{} //@complete("]", mapSliceType, mapStructType) + map[a]a{} //@complete("{", mapSliceType, mapStructType) +} diff --git a/gopls/internal/lsp/testdata/missingfunction/channels.go b/gopls/internal/lsp/testdata/missingfunction/channels.go new file mode 100644 index 000000000..303770cd7 --- /dev/null +++ b/gopls/internal/lsp/testdata/missingfunction/channels.go @@ -0,0 +1,9 @@ +package missingfunction + +func channels(s string) { + undefinedChannels(c()) //@suggestedfix("undefinedChannels", "quickfix", "") +} + +func c() (<-chan string, chan string) { + return make(<-chan string), make(chan string) +} diff --git a/gopls/internal/lsp/testdata/missingfunction/channels.go.golden b/gopls/internal/lsp/testdata/missingfunction/channels.go.golden new file mode 100644 index 000000000..998ce589e --- /dev/null +++ b/gopls/internal/lsp/testdata/missingfunction/channels.go.golden @@ -0,0 +1,15 @@ +-- suggestedfix_channels_4_2 -- +package missingfunction + +func channels(s string) { + undefinedChannels(c()) //@suggestedfix("undefinedChannels", "quickfix", "") +} + +func undefinedChannels(ch1 <-chan string, ch2 chan string) { + panic("unimplemented") +} + +func c() (<-chan string, chan string) { + return make(<-chan string), make(chan string) +} + diff --git a/gopls/internal/lsp/testdata/missingfunction/consecutive_params.go b/gopls/internal/lsp/testdata/missingfunction/consecutive_params.go new file mode 100644 index 000000000..f2fb3c041 --- /dev/null +++ b/gopls/internal/lsp/testdata/missingfunction/consecutive_params.go @@ -0,0 +1,6 @@ +package missingfunction + +func consecutiveParams() { + var s string + undefinedConsecutiveParams(s, s) //@suggestedfix("undefinedConsecutiveParams", "quickfix", "") +} diff --git a/gopls/internal/lsp/testdata/missingfunction/consecutive_params.go.golden b/gopls/internal/lsp/testdata/missingfunction/consecutive_params.go.golden new file mode 100644 index 000000000..4b852ce14 --- /dev/null +++ b/gopls/internal/lsp/testdata/missingfunction/consecutive_params.go.golden @@ -0,0 +1,12 @@ +-- suggestedfix_consecutive_params_5_2 -- +package missingfunction + +func consecutiveParams() { + var s string + undefinedConsecutiveParams(s, s) //@suggestedfix("undefinedConsecutiveParams", "quickfix", "") +} + +func undefinedConsecutiveParams(s1, s2 string) { + panic("unimplemented") +} + diff --git a/gopls/internal/lsp/testdata/missingfunction/error_param.go b/gopls/internal/lsp/testdata/missingfunction/error_param.go new file mode 100644 index 000000000..d0484f0ff --- /dev/null +++ b/gopls/internal/lsp/testdata/missingfunction/error_param.go @@ -0,0 +1,6 @@ +package missingfunction + +func errorParam() { + var err error + undefinedErrorParam(err) //@suggestedfix("undefinedErrorParam", "quickfix", "") +} diff --git a/gopls/internal/lsp/testdata/missingfunction/error_param.go.golden b/gopls/internal/lsp/testdata/missingfunction/error_param.go.golden new file mode 100644 index 000000000..de78646a5 --- /dev/null +++ b/gopls/internal/lsp/testdata/missingfunction/error_param.go.golden @@ -0,0 +1,12 @@ +-- suggestedfix_error_param_5_2 -- +package missingfunction + +func errorParam() { + var err error + undefinedErrorParam(err) //@suggestedfix("undefinedErrorParam", "quickfix", "") +} + +func undefinedErrorParam(err error) { + panic("unimplemented") +} + diff --git a/gopls/internal/lsp/testdata/missingfunction/literals.go b/gopls/internal/lsp/testdata/missingfunction/literals.go new file mode 100644 index 000000000..0099b1a08 --- /dev/null +++ b/gopls/internal/lsp/testdata/missingfunction/literals.go @@ -0,0 +1,7 @@ +package missingfunction + +type T struct{} + +func literals() { + undefinedLiterals("hey compiler", T{}, &T{}) //@suggestedfix("undefinedLiterals", "quickfix", "") +} diff --git a/gopls/internal/lsp/testdata/missingfunction/literals.go.golden b/gopls/internal/lsp/testdata/missingfunction/literals.go.golden new file mode 100644 index 000000000..cb85de4eb --- /dev/null +++ b/gopls/internal/lsp/testdata/missingfunction/literals.go.golden @@ -0,0 +1,13 @@ +-- suggestedfix_literals_6_2 -- +package missingfunction + +type T struct{} + +func literals() { + undefinedLiterals("hey compiler", T{}, &T{}) //@suggestedfix("undefinedLiterals", "quickfix", "") +} + +func undefinedLiterals(s string, t1 T, t2 *T) { + panic("unimplemented") +} + diff --git a/gopls/internal/lsp/testdata/missingfunction/operation.go b/gopls/internal/lsp/testdata/missingfunction/operation.go new file mode 100644 index 000000000..a4913ec10 --- /dev/null +++ b/gopls/internal/lsp/testdata/missingfunction/operation.go @@ -0,0 +1,7 @@ +package missingfunction + +import "time" + +func operation() { + undefinedOperation(10 * time.Second) //@suggestedfix("undefinedOperation", "quickfix", "") +} diff --git a/gopls/internal/lsp/testdata/missingfunction/operation.go.golden b/gopls/internal/lsp/testdata/missingfunction/operation.go.golden new file mode 100644 index 000000000..6f9e6ffab --- /dev/null +++ b/gopls/internal/lsp/testdata/missingfunction/operation.go.golden @@ -0,0 +1,13 @@ +-- suggestedfix_operation_6_2 -- +package missingfunction + +import "time" + +func operation() { + undefinedOperation(10 * time.Second) //@suggestedfix("undefinedOperation", "quickfix", "") +} + +func undefinedOperation(duration time.Duration) { + panic("unimplemented") +} + diff --git a/gopls/internal/lsp/testdata/missingfunction/selector.go b/gopls/internal/lsp/testdata/missingfunction/selector.go new file mode 100644 index 000000000..93a040271 --- /dev/null +++ b/gopls/internal/lsp/testdata/missingfunction/selector.go @@ -0,0 +1,6 @@ +package missingfunction + +func selector() { + m := map[int]bool{} + undefinedSelector(m[1]) //@suggestedfix("undefinedSelector", "quickfix", "") +} diff --git a/gopls/internal/lsp/testdata/missingfunction/selector.go.golden b/gopls/internal/lsp/testdata/missingfunction/selector.go.golden new file mode 100644 index 000000000..44e2dde3a --- /dev/null +++ b/gopls/internal/lsp/testdata/missingfunction/selector.go.golden @@ -0,0 +1,12 @@ +-- suggestedfix_selector_5_2 -- +package missingfunction + +func selector() { + m := map[int]bool{} + undefinedSelector(m[1]) //@suggestedfix("undefinedSelector", "quickfix", "") +} + +func undefinedSelector(b bool) { + panic("unimplemented") +} + diff --git a/gopls/internal/lsp/testdata/missingfunction/slice.go b/gopls/internal/lsp/testdata/missingfunction/slice.go new file mode 100644 index 000000000..48b1a52b3 --- /dev/null +++ b/gopls/internal/lsp/testdata/missingfunction/slice.go @@ -0,0 +1,5 @@ +package missingfunction + +func slice() { + undefinedSlice([]int{1, 2}) //@suggestedfix("undefinedSlice", "quickfix", "") +} diff --git a/gopls/internal/lsp/testdata/missingfunction/slice.go.golden b/gopls/internal/lsp/testdata/missingfunction/slice.go.golden new file mode 100644 index 000000000..2a05d9a0f --- /dev/null +++ b/gopls/internal/lsp/testdata/missingfunction/slice.go.golden @@ -0,0 +1,11 @@ +-- suggestedfix_slice_4_2 -- +package missingfunction + +func slice() { + undefinedSlice([]int{1, 2}) //@suggestedfix("undefinedSlice", "quickfix", "") +} + +func undefinedSlice(i []int) { + panic("unimplemented") +} + diff --git a/gopls/internal/lsp/testdata/missingfunction/tuple.go b/gopls/internal/lsp/testdata/missingfunction/tuple.go new file mode 100644 index 000000000..4059ced98 --- /dev/null +++ b/gopls/internal/lsp/testdata/missingfunction/tuple.go @@ -0,0 +1,9 @@ +package missingfunction + +func tuple() { + undefinedTuple(b()) //@suggestedfix("undefinedTuple", "quickfix", "") +} + +func b() (string, error) { + return "", nil +} diff --git a/gopls/internal/lsp/testdata/missingfunction/tuple.go.golden b/gopls/internal/lsp/testdata/missingfunction/tuple.go.golden new file mode 100644 index 000000000..e1118a3f3 --- /dev/null +++ b/gopls/internal/lsp/testdata/missingfunction/tuple.go.golden @@ -0,0 +1,15 @@ +-- suggestedfix_tuple_4_2 -- +package missingfunction + +func tuple() { + undefinedTuple(b()) //@suggestedfix("undefinedTuple", "quickfix", "") +} + +func undefinedTuple(s string, err error) { + panic("unimplemented") +} + +func b() (string, error) { + return "", nil +} + diff --git a/gopls/internal/lsp/testdata/missingfunction/unique_params.go b/gopls/internal/lsp/testdata/missingfunction/unique_params.go new file mode 100644 index 000000000..00479bf75 --- /dev/null +++ b/gopls/internal/lsp/testdata/missingfunction/unique_params.go @@ -0,0 +1,7 @@ +package missingfunction + +func uniqueArguments() { + var s string + var i int + undefinedUniqueArguments(s, i, s) //@suggestedfix("undefinedUniqueArguments", "quickfix", "") +} diff --git a/gopls/internal/lsp/testdata/missingfunction/unique_params.go.golden b/gopls/internal/lsp/testdata/missingfunction/unique_params.go.golden new file mode 100644 index 000000000..8d6352cde --- /dev/null +++ b/gopls/internal/lsp/testdata/missingfunction/unique_params.go.golden @@ -0,0 +1,13 @@ +-- suggestedfix_unique_params_6_2 -- +package missingfunction + +func uniqueArguments() { + var s string + var i int + undefinedUniqueArguments(s, i, s) //@suggestedfix("undefinedUniqueArguments", "quickfix", "") +} + +func undefinedUniqueArguments(s1 string, i int, s2 string) { + panic("unimplemented") +} + diff --git a/gopls/internal/lsp/testdata/multireturn/multi_return.go.in b/gopls/internal/lsp/testdata/multireturn/multi_return.go.in new file mode 100644 index 000000000..c302f3815 --- /dev/null +++ b/gopls/internal/lsp/testdata/multireturn/multi_return.go.in @@ -0,0 +1,48 @@ +package multireturn + +func f0() {} //@item(multiF0, "f0", "func()", "func") + +func f1(int) int { return 0 } //@item(multiF1, "f1", "func(int) int", "func") + +func f2(int, int) (int, int) { return 0, 0 } //@item(multiF2, "f2", "func(int, int) (int, int)", "func") + +func f2Str(string, string) (string, string) { return "", "" } //@item(multiF2Str, "f2Str", "func(string, string) (string, string)", "func") + +func f3(int, int, int) (int, int, int) { return 0, 0, 0 } //@item(multiF3, "f3", "func(int, int, int) (int, int, int)", "func") + +func _() { + _ := f //@rank(" //", multiF1, multiF2) + + _, _ := f //@rank(" //", multiF2, multiF0),rank(" //", multiF1, multiF0) + + _, _ := _, f //@rank(" //", multiF1, multiF2),rank(" //", multiF1, multiF0) + + _, _ := f, abc //@rank(", abc", multiF1, multiF2) + + f1() //@rank(")", multiF1, multiF0) + f1(f) //@rank(")", multiF1, multiF2) + f2(f) //@rank(")", multiF2, multiF3),rank(")", multiF1, multiF3) + f2(1, f) //@rank(")", multiF1, multiF2),rank(")", multiF1, multiF0) + f2(1, ) //@rank(")", multiF1, multiF2),rank(")", multiF1, multiF0) + f2Str() //@rank(")", multiF2Str, multiF2) + + var i int + i, _ := f //@rank(" //", multiF2, multiF2Str) + + var s string + _, s := f //@rank(" //", multiF2Str, multiF2) + + banana, s = f //@rank(" //", multiF2, multiF3) + + var variadic func(int, ...int) + variadic() //@rank(")", multiF1, multiF0),rank(")", multiF2, multiF0),rank(")", multiF3, multiF0) +} + +func _() { + var baz func(...interface{}) + + var otterNap func() (int, int) //@item(multiTwo, "otterNap", "func() (int, int)", "var") + var one int //@item(multiOne, "one", "int", "var") + + baz(on) //@rank(")", multiOne, multiTwo) +} diff --git a/gopls/internal/lsp/testdata/nested_complit/nested_complit.go.in b/gopls/internal/lsp/testdata/nested_complit/nested_complit.go.in new file mode 100644 index 000000000..3ad2d213e --- /dev/null +++ b/gopls/internal/lsp/testdata/nested_complit/nested_complit.go.in @@ -0,0 +1,15 @@ +package nested_complit + +type ncFoo struct {} //@item(structNCFoo, "ncFoo", "struct{...}", "struct") + +type ncBar struct { //@item(structNCBar, "ncBar", "struct{...}", "struct") + baz []ncFoo +} + +func _() { + []ncFoo{} //@item(litNCFoo, "[]ncFoo{}", "", "var") + _ := ncBar{ + // disabled - see issue #54822 + baz: [] // complete(" //", structNCFoo, structNCBar) + } +} diff --git a/gopls/internal/lsp/testdata/nodisk/empty b/gopls/internal/lsp/testdata/nodisk/empty new file mode 100644 index 000000000..0c10a42f9 --- /dev/null +++ b/gopls/internal/lsp/testdata/nodisk/empty @@ -0,0 +1 @@ +an empty file so that this directory exists
\ No newline at end of file diff --git a/gopls/internal/lsp/testdata/nodisk/nodisk.overlay.go b/gopls/internal/lsp/testdata/nodisk/nodisk.overlay.go new file mode 100644 index 000000000..08aebd12f --- /dev/null +++ b/gopls/internal/lsp/testdata/nodisk/nodisk.overlay.go @@ -0,0 +1,9 @@ +package nodisk + +import ( + "golang.org/lsptests/foo" +) + +func _() { + foo.Foo() //@complete("F", Foo, IntFoo, StructFoo) +} diff --git a/gopls/internal/lsp/testdata/noparse/noparse.go.in b/gopls/internal/lsp/testdata/noparse/noparse.go.in new file mode 100644 index 000000000..8b0bfaa03 --- /dev/null +++ b/gopls/internal/lsp/testdata/noparse/noparse.go.in @@ -0,0 +1,24 @@ +package noparse + +// The type error was chosen carefully to exercise a type-error analyzer. +// We use the 'nonewvars' analyzer because the other candidates are tricky: +// +// - The 'unusedvariable' analyzer is disabled by default, so it is not +// consistently enabled across Test{LSP,CommandLine} tests, which +// both process this file. +// - The 'undeclaredname' analyzer depends on the text of the go/types +// "undeclared name" error, which changed in go1.20. +// - The 'noresultvalues' analyzer produces a diagnostic containing newlines, +// which breaks the parser used by TestCommandLine. +// +// This comment is all that remains of my afternoon. + +func bye(x int) { + x := 123 //@diag(":=", "nonewvars", "no new variables", "warning") +} + +func stuff() { + +} + +func .() {} //@diag(".", "syntax", "expected 'IDENT', found '.'", "error") diff --git a/gopls/internal/lsp/testdata/noparse_format/noparse_format.go.golden b/gopls/internal/lsp/testdata/noparse_format/noparse_format.go.golden new file mode 100644 index 000000000..0060c5c92 --- /dev/null +++ b/gopls/internal/lsp/testdata/noparse_format/noparse_format.go.golden @@ -0,0 +1,2 @@ +-- gofmt -- + diff --git a/gopls/internal/lsp/testdata/noparse_format/noparse_format.go.in b/gopls/internal/lsp/testdata/noparse_format/noparse_format.go.in new file mode 100644 index 000000000..311a99aaf --- /dev/null +++ b/gopls/internal/lsp/testdata/noparse_format/noparse_format.go.in @@ -0,0 +1,14 @@ +// +build go1.11 + +package noparse_format //@format("package") + +// The nonewvars expectation asserts that the go/analysis framework ran. +// See comments in badstmt. + +func what() { + var hi func() + if { hi() //@diag("{", "syntax", "missing condition in if statement", "error") + } + hi := nil //@diag(":=", "nonewvars", "no new variables", "warning") +} + diff --git a/gopls/internal/lsp/testdata/noparse_format/parse_format.go.golden b/gopls/internal/lsp/testdata/noparse_format/parse_format.go.golden new file mode 100644 index 000000000..667c90b22 --- /dev/null +++ b/gopls/internal/lsp/testdata/noparse_format/parse_format.go.golden @@ -0,0 +1,7 @@ +-- gofmt -- +package noparse_format //@format("package") + +func _() { + f() +} + diff --git a/gopls/internal/lsp/testdata/noparse_format/parse_format.go.in b/gopls/internal/lsp/testdata/noparse_format/parse_format.go.in new file mode 100644 index 000000000..4b98cf8d0 --- /dev/null +++ b/gopls/internal/lsp/testdata/noparse_format/parse_format.go.in @@ -0,0 +1,5 @@ +package noparse_format //@format("package") + +func _() { +f() +}
\ No newline at end of file diff --git a/gopls/internal/lsp/testdata/printf/printf.go b/gopls/internal/lsp/testdata/printf/printf.go new file mode 100644 index 000000000..6e56549c1 --- /dev/null +++ b/gopls/internal/lsp/testdata/printf/printf.go @@ -0,0 +1,33 @@ +package printf + +import "fmt" + +func myPrintf(string, ...interface{}) {} + +func _() { + var ( + aInt int //@item(printfInt, "aInt", "int", "var") + aFloat float64 //@item(printfFloat, "aFloat", "float64", "var") + aString string //@item(printfString, "aString", "string", "var") + aBytes []byte //@item(printfBytes, "aBytes", "[]byte", "var") + aStringer fmt.Stringer //@item(printfStringer, "aStringer", "fmt.Stringer", "var") + aError error //@item(printfError, "aError", "error", "var") + aBool bool //@item(printfBool, "aBool", "bool", "var") + ) + + myPrintf("%d", a) //@rank(")", printfInt, printfFloat) + myPrintf("%s", a) //@rank(")", printfString, printfInt),rank(")", printfBytes, printfInt),rank(")", printfStringer, printfInt),rank(")", printfError, printfInt) + myPrintf("%w", a) //@rank(")", printfError, printfInt) + myPrintf("%x %[1]b", a) //@rank(")", printfInt, printfString) + + fmt.Printf("%t", a) //@rank(")", printfBool, printfInt) + + fmt.Fprintf(nil, "%f", a) //@rank(")", printfFloat, printfInt) + + fmt.Sprintf("%[2]q %[1]*.[3]*[4]f", + a, //@rank(",", printfInt, printfFloat) + a, //@rank(",", printfString, printfFloat) + a, //@rank(",", printfInt, printfFloat) + a, //@rank(",", printfFloat, printfInt) + ) +} diff --git a/gopls/internal/lsp/testdata/rank/assign_rank.go.in b/gopls/internal/lsp/testdata/rank/assign_rank.go.in new file mode 100644 index 000000000..5c51910d4 --- /dev/null +++ b/gopls/internal/lsp/testdata/rank/assign_rank.go.in @@ -0,0 +1,19 @@ +package rank + +var ( + apple int = 3 //@item(apple, "apple", "int", "var") + pear string = "hello" //@item(pear, "pear", "string", "var") +) + +func _() { + orange := 1 //@item(orange, "orange", "int", "var") + grape := "hello" //@item(grape, "grape", "string", "var") + orange, grape = 2, "hello" //@complete(" \"", grape, pear, orange, apple) +} + +func _() { + var pineapple int //@item(pineapple, "pineapple", "int", "var") + pineapple = 1 //@complete(" 1", pineapple, apple, pear) + + y := //@complete(" /", pineapple, apple, pear) +} diff --git a/gopls/internal/lsp/testdata/rank/binexpr_rank.go.in b/gopls/internal/lsp/testdata/rank/binexpr_rank.go.in new file mode 100644 index 000000000..60b2cc1bc --- /dev/null +++ b/gopls/internal/lsp/testdata/rank/binexpr_rank.go.in @@ -0,0 +1,8 @@ +package rank + +func _() { + _ = 5 + ; //@complete(" ;", apple, pear) + y := + 5; //@complete(" +", apple, pear) + + if 6 == {} //@complete(" {", apple, pear) +} diff --git a/gopls/internal/lsp/testdata/rank/boolexpr_rank.go b/gopls/internal/lsp/testdata/rank/boolexpr_rank.go new file mode 100644 index 000000000..fe512eee1 --- /dev/null +++ b/gopls/internal/lsp/testdata/rank/boolexpr_rank.go @@ -0,0 +1,11 @@ +package rank + +func _() { + someRandomBoolFunc := func() bool { //@item(boolExprFunc, "someRandomBoolFunc", "func() bool", "var") + return true + } + + var foo, bar int //@item(boolExprBar, "bar", "int", "var") + if foo == 123 && b { //@rank(" {", boolExprBar, boolExprFunc) + } +} diff --git a/gopls/internal/lsp/testdata/rank/convert_rank.go.in b/gopls/internal/lsp/testdata/rank/convert_rank.go.in new file mode 100644 index 000000000..c43004833 --- /dev/null +++ b/gopls/internal/lsp/testdata/rank/convert_rank.go.in @@ -0,0 +1,54 @@ +package rank + +import "time" + +func _() { + type strList []string + wantsStrList := func(strList) {} + + var ( + convA string //@item(convertA, "convA", "string", "var") + convB []string //@item(convertB, "convB", "[]string", "var") + ) + wantsStrList(strList(conv)) //@complete("))", convertB, convertA) +} + +func _() { + type myInt int + + const ( + convC = "hi" //@item(convertC, "convC", "string", "const") + convD = 123 //@item(convertD, "convD", "int", "const") + convE int = 123 //@item(convertE, "convE", "int", "const") + convF string = "there" //@item(convertF, "convF", "string", "const") + convG myInt = 123 //@item(convertG, "convG", "myInt", "const") + ) + + var foo int + foo = conv //@rank(" //", convertE, convertD) + + var mi myInt + mi = conv //@rank(" //", convertG, convertD, convertE) + mi + conv //@rank(" //", convertG, convertD, convertE) + + 1 + conv //@rank(" //", convertD, convertC),rank(" //", convertE, convertC),rank(" //", convertG, convertC) + + type myString string + var ms myString + ms = conv //@rank(" //", convertC, convertF) + + type myUint uint32 + var mu myUint + mu = conv //@rank(" //", convertD, convertE) + + // don't downrank constants when assigning to interface{} + var _ interface{} = c //@rank(" //", convertD, complex) + + var _ time.Duration = conv //@rank(" //", convertD, convertE),snippet(" //", convertE, "time.Duration(convE)", "time.Duration(convE)") + + var convP myInt //@item(convertP, "convP", "myInt", "var") + var _ *int = conv //@snippet(" //", convertP, "(*int)(&convP)", "(*int)(&convP)") + + var ff float64 //@item(convertFloat, "ff", "float64", "var") + f == convD //@snippet(" =", convertFloat, "ff", "ff") +} diff --git a/gopls/internal/lsp/testdata/rank/struct/struct_rank.go b/gopls/internal/lsp/testdata/rank/struct/struct_rank.go new file mode 100644 index 000000000..e0bdd38a8 --- /dev/null +++ b/gopls/internal/lsp/testdata/rank/struct/struct_rank.go @@ -0,0 +1,11 @@ +package struct_rank + +type foo struct { + c int //@item(c_rank, "c", "int", "field") + b int //@item(b_rank, "b", "int", "field") + a int //@item(a_rank, "a", "int", "field") +} + +func f() { + foo := foo{} //@rank("}", c_rank, b_rank, a_rank) +} diff --git a/gopls/internal/lsp/testdata/rank/switch_rank.go.in b/gopls/internal/lsp/testdata/rank/switch_rank.go.in new file mode 100644 index 000000000..b828528da --- /dev/null +++ b/gopls/internal/lsp/testdata/rank/switch_rank.go.in @@ -0,0 +1,29 @@ +package rank + +import "time" + +func _() { + switch pear { + case _: //@rank("_", pear, apple) + } + + time.Monday //@item(timeMonday, "time.Monday", "time.Weekday", "const"),item(monday ,"Monday", "time.Weekday", "const") + time.Friday //@item(timeFriday, "time.Friday", "time.Weekday", "const"),item(friday ,"Friday", "time.Weekday", "const") + + now := time.Now() + now.Weekday //@item(nowWeekday, "now.Weekday", "func() time.Weekday", "method") + + then := time.Now() + then.Weekday //@item(thenWeekday, "then.Weekday", "func() time.Weekday", "method") + + switch time.Weekday(0) { + case time.Monday, time.Tuesday: + case time.Wednesday, time.Thursday: + case time.Saturday, time.Sunday: + case t: //@rank(":", timeFriday, timeMonday) + case time.: //@rank(":", friday, monday) + + case now.Weekday(): + case week: //@rank(":", thenWeekday, nowWeekday) + } +} diff --git a/gopls/internal/lsp/testdata/rank/type_assert_rank.go.in b/gopls/internal/lsp/testdata/rank/type_assert_rank.go.in new file mode 100644 index 000000000..416541cdd --- /dev/null +++ b/gopls/internal/lsp/testdata/rank/type_assert_rank.go.in @@ -0,0 +1,8 @@ +package rank + +func _() { + type flower int //@item(flower, "flower", "int", "type") + var fig string //@item(fig, "fig", "string", "var") + + _ = interface{}(nil).(f) //@complete(") //", flower) +} diff --git a/gopls/internal/lsp/testdata/rank/type_switch_rank.go.in b/gopls/internal/lsp/testdata/rank/type_switch_rank.go.in new file mode 100644 index 000000000..1ed12b7c1 --- /dev/null +++ b/gopls/internal/lsp/testdata/rank/type_switch_rank.go.in @@ -0,0 +1,31 @@ +package rank + +import ( + "fmt" + "go/ast" +) + +func _() { + type basket int //@item(basket, "basket", "int", "type") + var banana string //@item(banana, "banana", "string", "var") + + switch interface{}(pear).(type) { + case b: //@complete(":", basket) + b //@complete(" //", banana, basket) + } + + Ident //@item(astIdent, "Ident", "struct{...}", "struct") + IfStmt //@item(astIfStmt, "IfStmt", "struct{...}", "struct") + + switch ast.Node(nil).(type) { + case *ast.Ident: + case *ast.I: //@rank(":", astIfStmt, astIdent) + } + + Stringer //@item(fmtStringer, "Stringer", "interface{...}", "interface") + GoStringer //@item(fmtGoStringer, "GoStringer", "interface{...}", "interface") + + switch interface{}(nil).(type) { + case fmt.Stringer: //@rank(":", fmtStringer, fmtGoStringer) + } +} diff --git a/gopls/internal/lsp/testdata/references/another/another.go b/gopls/internal/lsp/testdata/references/another/another.go new file mode 100644 index 000000000..20e3ebca1 --- /dev/null +++ b/gopls/internal/lsp/testdata/references/another/another.go @@ -0,0 +1,13 @@ +// Package another has another type. +package another + +import ( + other "golang.org/lsptests/references/other" +) + +func _() { + xes := other.GetXes() + for _, x := range xes { //@mark(defX, "x") + _ = x.Y //@mark(useX, "x"),mark(anotherXY, "Y"),refs("Y", typeXY, anotherXY, GetXesY),refs(".", defX, useX),refs("x", defX, useX) + } +} diff --git a/gopls/internal/lsp/testdata/references/interfaces/interfaces.go b/gopls/internal/lsp/testdata/references/interfaces/interfaces.go new file mode 100644 index 000000000..6661dcc5d --- /dev/null +++ b/gopls/internal/lsp/testdata/references/interfaces/interfaces.go @@ -0,0 +1,34 @@ +package interfaces + +type first interface { + common() //@mark(firCommon, "common"),refs("common", firCommon, xCommon, zCommon) + firstMethod() //@mark(firMethod, "firstMethod"),refs("firstMethod", firMethod, xfMethod, zfMethod) +} + +type second interface { + common() //@mark(secCommon, "common"),refs("common", secCommon, yCommon, zCommon) + secondMethod() //@mark(secMethod, "secondMethod"),refs("secondMethod", secMethod, ysMethod, zsMethod) +} + +type s struct {} + +func (*s) common() {} //@mark(sCommon, "common"),refs("common", sCommon, xCommon, yCommon, zCommon) + +func (*s) firstMethod() {} //@mark(sfMethod, "firstMethod"),refs("firstMethod", sfMethod, xfMethod, zfMethod) + +func (*s) secondMethod() {} //@mark(ssMethod, "secondMethod"),refs("secondMethod", ssMethod, ysMethod, zsMethod) + +func main() { + var x first = &s{} + var y second = &s{} + + x.common() //@mark(xCommon, "common"),refs("common", firCommon, xCommon, zCommon) + x.firstMethod() //@mark(xfMethod, "firstMethod"),refs("firstMethod", firMethod, xfMethod, zfMethod) + y.common() //@mark(yCommon, "common"),refs("common", secCommon, yCommon, zCommon) + y.secondMethod() //@mark(ysMethod, "secondMethod"),refs("secondMethod", secMethod, ysMethod, zsMethod) + + var z *s = &s{} + z.firstMethod() //@mark(zfMethod, "firstMethod"),refs("firstMethod", sfMethod, xfMethod, zfMethod) + z.secondMethod() //@mark(zsMethod, "secondMethod"),refs("secondMethod", ssMethod, ysMethod, zsMethod) + z.common() //@mark(zCommon, "common"),refs("common", sCommon, xCommon, yCommon, zCommon) +} diff --git a/gopls/internal/lsp/testdata/references/other/other.go b/gopls/internal/lsp/testdata/references/other/other.go new file mode 100644 index 000000000..daac1a028 --- /dev/null +++ b/gopls/internal/lsp/testdata/references/other/other.go @@ -0,0 +1,19 @@ +package other + +import ( + references "golang.org/lsptests/references" +) + +func GetXes() []references.X { + return []references.X{ + { + Y: 1, //@mark(GetXesY, "Y"),refs("Y", typeXY, GetXesY, anotherXY) + }, + } +} + +func _() { + references.Q = "hello" //@mark(assignExpQ, "Q") + bob := func(_ string) {} + bob(references.Q) //@mark(bobExpQ, "Q") +} diff --git a/gopls/internal/lsp/testdata/references/refs.go b/gopls/internal/lsp/testdata/references/refs.go new file mode 100644 index 000000000..e7ff50494 --- /dev/null +++ b/gopls/internal/lsp/testdata/references/refs.go @@ -0,0 +1,53 @@ +// Package refs is a package used to test find references. +package refs + +import "os" //@mark(osDecl, `"os"`),refs("os", osDecl, osUse) + +type i int //@mark(typeI, "i"),refs("i", typeI, argI, returnI, embeddedI) + +type X struct { + Y int //@mark(typeXY, "Y") +} + +func _(_ i) []bool { //@mark(argI, "i") + return nil +} + +func _(_ []byte) i { //@mark(returnI, "i") + return 0 +} + +var q string //@mark(declQ, "q"),refs("q", declQ, assignQ, bobQ) + +var Q string //@mark(declExpQ, "Q"),refs("Q", declExpQ, assignExpQ, bobExpQ) + +func _() { + q = "hello" //@mark(assignQ, "q") + bob := func(_ string) {} + bob(q) //@mark(bobQ, "q") +} + +type e struct { + i //@mark(embeddedI, "i"),refs("i", embeddedI, embeddedIUse) +} + +func _() { + _ = e{}.i //@mark(embeddedIUse, "i") +} + +const ( + foo = iota //@refs("iota") +) + +func _(x interface{}) { + // We use the _ prefix because the markers inhabit a single + // namespace and yDecl is already used in ../highlights/highlights.go. + switch _y := x.(type) { //@mark(_yDecl, "_y"),refs("_y", _yDecl, _yInt, _yDefault) + case int: + println(_y) //@mark(_yInt, "_y"),refs("_y", _yDecl, _yInt, _yDefault) + default: + println(_y) //@mark(_yDefault, "_y") + } + + os.Getwd() //@mark(osUse, "os") +} diff --git a/gopls/internal/lsp/testdata/references/refs_test.go b/gopls/internal/lsp/testdata/references/refs_test.go new file mode 100644 index 000000000..08c0db1f0 --- /dev/null +++ b/gopls/internal/lsp/testdata/references/refs_test.go @@ -0,0 +1,10 @@ +package references + +import ( + "testing" +) + +// This test exists to bring the test package into existence. + +func TestReferences(t *testing.T) { +} diff --git a/gopls/internal/lsp/testdata/rename/a/random.go.golden b/gopls/internal/lsp/testdata/rename/a/random.go.golden new file mode 100644 index 000000000..7459863ec --- /dev/null +++ b/gopls/internal/lsp/testdata/rename/a/random.go.golden @@ -0,0 +1,616 @@ +-- GetSum-rename -- +package a + +import ( + lg "log" + "fmt" //@rename("fmt", "fmty") + f2 "fmt" //@rename("f2", "f2name"),rename("fmt","f2y") +) + +func Random() int { + y := 6 + 7 + return y +} + +func Random2(y int) int { //@rename("y", "z") + return y +} + +type Pos struct { + x, y int +} + +func (p *Pos) GetSum() int { + return p.x + p.y //@rename("x", "myX") +} + +func _() { + var p Pos //@rename("p", "pos") + _ = p.GetSum() //@rename("Sum", "GetSum") +} + +func sw() { + var x interface{} + + switch y := x.(type) { //@rename("y", "y0") + case int: + fmt.Printf("%d", y) //@rename("y", "y1"),rename("fmt", "format") + case string: + lg.Printf("%s", y) //@rename("y", "y2"),rename("lg","log") + default: + f2.Printf("%v", y) //@rename("y", "y3"),rename("f2","fmt2") + } +} + +-- f2name-rename -- +package a + +import ( + lg "log" + "fmt" //@rename("fmt", "fmty") + f2name "fmt" //@rename("f2", "f2name"),rename("fmt","f2y") +) + +func Random() int { + y := 6 + 7 + return y +} + +func Random2(y int) int { //@rename("y", "z") + return y +} + +type Pos struct { + x, y int +} + +func (p *Pos) Sum() int { + return p.x + p.y //@rename("x", "myX") +} + +func _() { + var p Pos //@rename("p", "pos") + _ = p.Sum() //@rename("Sum", "GetSum") +} + +func sw() { + var x interface{} + + switch y := x.(type) { //@rename("y", "y0") + case int: + fmt.Printf("%d", y) //@rename("y", "y1"),rename("fmt", "format") + case string: + lg.Printf("%s", y) //@rename("y", "y2"),rename("lg","log") + default: + f2name.Printf("%v", y) //@rename("y", "y3"),rename("f2","fmt2") + } +} + +-- f2y-rename -- +package a + +import ( + lg "log" + "fmt" //@rename("fmt", "fmty") + f2y "fmt" //@rename("f2", "f2name"),rename("fmt","f2y") +) + +func Random() int { + y := 6 + 7 + return y +} + +func Random2(y int) int { //@rename("y", "z") + return y +} + +type Pos struct { + x, y int +} + +func (p *Pos) Sum() int { + return p.x + p.y //@rename("x", "myX") +} + +func _() { + var p Pos //@rename("p", "pos") + _ = p.Sum() //@rename("Sum", "GetSum") +} + +func sw() { + var x interface{} + + switch y := x.(type) { //@rename("y", "y0") + case int: + fmt.Printf("%d", y) //@rename("y", "y1"),rename("fmt", "format") + case string: + lg.Printf("%s", y) //@rename("y", "y2"),rename("lg","log") + default: + f2y.Printf("%v", y) //@rename("y", "y3"),rename("f2","fmt2") + } +} + +-- fmt2-rename -- +package a + +import ( + lg "log" + "fmt" //@rename("fmt", "fmty") + fmt2 "fmt" //@rename("f2", "f2name"),rename("fmt","f2y") +) + +func Random() int { + y := 6 + 7 + return y +} + +func Random2(y int) int { //@rename("y", "z") + return y +} + +type Pos struct { + x, y int +} + +func (p *Pos) Sum() int { + return p.x + p.y //@rename("x", "myX") +} + +func _() { + var p Pos //@rename("p", "pos") + _ = p.Sum() //@rename("Sum", "GetSum") +} + +func sw() { + var x interface{} + + switch y := x.(type) { //@rename("y", "y0") + case int: + fmt.Printf("%d", y) //@rename("y", "y1"),rename("fmt", "format") + case string: + lg.Printf("%s", y) //@rename("y", "y2"),rename("lg","log") + default: + fmt2.Printf("%v", y) //@rename("y", "y3"),rename("f2","fmt2") + } +} + +-- fmty-rename -- +package a + +import ( + lg "log" + fmty "fmt" //@rename("fmt", "fmty") + f2 "fmt" //@rename("f2", "f2name"),rename("fmt","f2y") +) + +func Random() int { + y := 6 + 7 + return y +} + +func Random2(y int) int { //@rename("y", "z") + return y +} + +type Pos struct { + x, y int +} + +func (p *Pos) Sum() int { + return p.x + p.y //@rename("x", "myX") +} + +func _() { + var p Pos //@rename("p", "pos") + _ = p.Sum() //@rename("Sum", "GetSum") +} + +func sw() { + var x interface{} + + switch y := x.(type) { //@rename("y", "y0") + case int: + fmty.Printf("%d", y) //@rename("y", "y1"),rename("fmt", "format") + case string: + lg.Printf("%s", y) //@rename("y", "y2"),rename("lg","log") + default: + f2.Printf("%v", y) //@rename("y", "y3"),rename("f2","fmt2") + } +} + +-- format-rename -- +package a + +import ( + lg "log" + format "fmt" //@rename("fmt", "fmty") + f2 "fmt" //@rename("f2", "f2name"),rename("fmt","f2y") +) + +func Random() int { + y := 6 + 7 + return y +} + +func Random2(y int) int { //@rename("y", "z") + return y +} + +type Pos struct { + x, y int +} + +func (p *Pos) Sum() int { + return p.x + p.y //@rename("x", "myX") +} + +func _() { + var p Pos //@rename("p", "pos") + _ = p.Sum() //@rename("Sum", "GetSum") +} + +func sw() { + var x interface{} + + switch y := x.(type) { //@rename("y", "y0") + case int: + format.Printf("%d", y) //@rename("y", "y1"),rename("fmt", "format") + case string: + lg.Printf("%s", y) //@rename("y", "y2"),rename("lg","log") + default: + f2.Printf("%v", y) //@rename("y", "y3"),rename("f2","fmt2") + } +} + +-- log-rename -- +package a + +import ( + "log" + "fmt" //@rename("fmt", "fmty") + f2 "fmt" //@rename("f2", "f2name"),rename("fmt","f2y") +) + +func Random() int { + y := 6 + 7 + return y +} + +func Random2(y int) int { //@rename("y", "z") + return y +} + +type Pos struct { + x, y int +} + +func (p *Pos) Sum() int { + return p.x + p.y //@rename("x", "myX") +} + +func _() { + var p Pos //@rename("p", "pos") + _ = p.Sum() //@rename("Sum", "GetSum") +} + +func sw() { + var x interface{} + + switch y := x.(type) { //@rename("y", "y0") + case int: + fmt.Printf("%d", y) //@rename("y", "y1"),rename("fmt", "format") + case string: + log.Printf("%s", y) //@rename("y", "y2"),rename("lg","log") + default: + f2.Printf("%v", y) //@rename("y", "y3"),rename("f2","fmt2") + } +} + +-- myX-rename -- +package a + +import ( + lg "log" + "fmt" //@rename("fmt", "fmty") + f2 "fmt" //@rename("f2", "f2name"),rename("fmt","f2y") +) + +func Random() int { + y := 6 + 7 + return y +} + +func Random2(y int) int { //@rename("y", "z") + return y +} + +type Pos struct { + myX, y int +} + +func (p *Pos) Sum() int { + return p.myX + p.y //@rename("x", "myX") +} + +func _() { + var p Pos //@rename("p", "pos") + _ = p.Sum() //@rename("Sum", "GetSum") +} + +func sw() { + var x interface{} + + switch y := x.(type) { //@rename("y", "y0") + case int: + fmt.Printf("%d", y) //@rename("y", "y1"),rename("fmt", "format") + case string: + lg.Printf("%s", y) //@rename("y", "y2"),rename("lg","log") + default: + f2.Printf("%v", y) //@rename("y", "y3"),rename("f2","fmt2") + } +} + +-- pos-rename -- +package a + +import ( + lg "log" + "fmt" //@rename("fmt", "fmty") + f2 "fmt" //@rename("f2", "f2name"),rename("fmt","f2y") +) + +func Random() int { + y := 6 + 7 + return y +} + +func Random2(y int) int { //@rename("y", "z") + return y +} + +type Pos struct { + x, y int +} + +func (p *Pos) Sum() int { + return p.x + p.y //@rename("x", "myX") +} + +func _() { + var pos Pos //@rename("p", "pos") + _ = pos.Sum() //@rename("Sum", "GetSum") +} + +func sw() { + var x interface{} + + switch y := x.(type) { //@rename("y", "y0") + case int: + fmt.Printf("%d", y) //@rename("y", "y1"),rename("fmt", "format") + case string: + lg.Printf("%s", y) //@rename("y", "y2"),rename("lg","log") + default: + f2.Printf("%v", y) //@rename("y", "y3"),rename("f2","fmt2") + } +} + +-- y0-rename -- +package a + +import ( + lg "log" + "fmt" //@rename("fmt", "fmty") + f2 "fmt" //@rename("f2", "f2name"),rename("fmt","f2y") +) + +func Random() int { + y := 6 + 7 + return y +} + +func Random2(y int) int { //@rename("y", "z") + return y +} + +type Pos struct { + x, y int +} + +func (p *Pos) Sum() int { + return p.x + p.y //@rename("x", "myX") +} + +func _() { + var p Pos //@rename("p", "pos") + _ = p.Sum() //@rename("Sum", "GetSum") +} + +func sw() { + var x interface{} + + switch y0 := x.(type) { //@rename("y", "y0") + case int: + fmt.Printf("%d", y0) //@rename("y", "y1"),rename("fmt", "format") + case string: + lg.Printf("%s", y0) //@rename("y", "y2"),rename("lg","log") + default: + f2.Printf("%v", y0) //@rename("y", "y3"),rename("f2","fmt2") + } +} + +-- y1-rename -- +package a + +import ( + lg "log" + "fmt" //@rename("fmt", "fmty") + f2 "fmt" //@rename("f2", "f2name"),rename("fmt","f2y") +) + +func Random() int { + y := 6 + 7 + return y +} + +func Random2(y int) int { //@rename("y", "z") + return y +} + +type Pos struct { + x, y int +} + +func (p *Pos) Sum() int { + return p.x + p.y //@rename("x", "myX") +} + +func _() { + var p Pos //@rename("p", "pos") + _ = p.Sum() //@rename("Sum", "GetSum") +} + +func sw() { + var x interface{} + + switch y1 := x.(type) { //@rename("y", "y0") + case int: + fmt.Printf("%d", y1) //@rename("y", "y1"),rename("fmt", "format") + case string: + lg.Printf("%s", y1) //@rename("y", "y2"),rename("lg","log") + default: + f2.Printf("%v", y1) //@rename("y", "y3"),rename("f2","fmt2") + } +} + +-- y2-rename -- +package a + +import ( + lg "log" + "fmt" //@rename("fmt", "fmty") + f2 "fmt" //@rename("f2", "f2name"),rename("fmt","f2y") +) + +func Random() int { + y := 6 + 7 + return y +} + +func Random2(y int) int { //@rename("y", "z") + return y +} + +type Pos struct { + x, y int +} + +func (p *Pos) Sum() int { + return p.x + p.y //@rename("x", "myX") +} + +func _() { + var p Pos //@rename("p", "pos") + _ = p.Sum() //@rename("Sum", "GetSum") +} + +func sw() { + var x interface{} + + switch y2 := x.(type) { //@rename("y", "y0") + case int: + fmt.Printf("%d", y2) //@rename("y", "y1"),rename("fmt", "format") + case string: + lg.Printf("%s", y2) //@rename("y", "y2"),rename("lg","log") + default: + f2.Printf("%v", y2) //@rename("y", "y3"),rename("f2","fmt2") + } +} + +-- y3-rename -- +package a + +import ( + lg "log" + "fmt" //@rename("fmt", "fmty") + f2 "fmt" //@rename("f2", "f2name"),rename("fmt","f2y") +) + +func Random() int { + y := 6 + 7 + return y +} + +func Random2(y int) int { //@rename("y", "z") + return y +} + +type Pos struct { + x, y int +} + +func (p *Pos) Sum() int { + return p.x + p.y //@rename("x", "myX") +} + +func _() { + var p Pos //@rename("p", "pos") + _ = p.Sum() //@rename("Sum", "GetSum") +} + +func sw() { + var x interface{} + + switch y3 := x.(type) { //@rename("y", "y0") + case int: + fmt.Printf("%d", y3) //@rename("y", "y1"),rename("fmt", "format") + case string: + lg.Printf("%s", y3) //@rename("y", "y2"),rename("lg","log") + default: + f2.Printf("%v", y3) //@rename("y", "y3"),rename("f2","fmt2") + } +} + +-- z-rename -- +package a + +import ( + lg "log" + "fmt" //@rename("fmt", "fmty") + f2 "fmt" //@rename("f2", "f2name"),rename("fmt","f2y") +) + +func Random() int { + y := 6 + 7 + return y +} + +func Random2(z int) int { //@rename("y", "z") + return z +} + +type Pos struct { + x, y int +} + +func (p *Pos) Sum() int { + return p.x + p.y //@rename("x", "myX") +} + +func _() { + var p Pos //@rename("p", "pos") + _ = p.Sum() //@rename("Sum", "GetSum") +} + +func sw() { + var x interface{} + + switch y := x.(type) { //@rename("y", "y0") + case int: + fmt.Printf("%d", y) //@rename("y", "y1"),rename("fmt", "format") + case string: + lg.Printf("%s", y) //@rename("y", "y2"),rename("lg","log") + default: + f2.Printf("%v", y) //@rename("y", "y3"),rename("f2","fmt2") + } +} + diff --git a/gopls/internal/lsp/testdata/rename/a/random.go.in b/gopls/internal/lsp/testdata/rename/a/random.go.in new file mode 100644 index 000000000..069db27ba --- /dev/null +++ b/gopls/internal/lsp/testdata/rename/a/random.go.in @@ -0,0 +1,42 @@ +package a + +import ( + lg "log" + "fmt" //@rename("fmt", "fmty") + f2 "fmt" //@rename("f2", "f2name"),rename("fmt","f2y") +) + +func Random() int { + y := 6 + 7 + return y +} + +func Random2(y int) int { //@rename("y", "z") + return y +} + +type Pos struct { + x, y int +} + +func (p *Pos) Sum() int { + return p.x + p.y //@rename("x", "myX") +} + +func _() { + var p Pos //@rename("p", "pos") + _ = p.Sum() //@rename("Sum", "GetSum") +} + +func sw() { + var x interface{} + + switch y := x.(type) { //@rename("y", "y0") + case int: + fmt.Printf("%d", y) //@rename("y", "y1"),rename("fmt", "format") + case string: + lg.Printf("%s", y) //@rename("y", "y2"),rename("lg","log") + default: + f2.Printf("%v", y) //@rename("y", "y3"),rename("f2","fmt2") + } +} diff --git a/gopls/internal/lsp/testdata/rename/b/b.go b/gopls/internal/lsp/testdata/rename/b/b.go new file mode 100644 index 000000000..8455f035b --- /dev/null +++ b/gopls/internal/lsp/testdata/rename/b/b.go @@ -0,0 +1,20 @@ +package b + +var c int //@rename("int", "uint") + +func _() { + a := 1 //@rename("a", "error") + a = 2 + _ = a +} + +var ( + // Hello there. + // Foo does the thing. + Foo int //@rename("Foo", "Bob") +) + +/* +Hello description +*/ +func Hello() {} //@rename("Hello", "Goodbye") diff --git a/gopls/internal/lsp/testdata/rename/b/b.go.golden b/gopls/internal/lsp/testdata/rename/b/b.go.golden new file mode 100644 index 000000000..add4049cd --- /dev/null +++ b/gopls/internal/lsp/testdata/rename/b/b.go.golden @@ -0,0 +1,78 @@ +-- Bob-rename -- +package b + +var c int //@rename("int", "uint") + +func _() { + a := 1 //@rename("a", "error") + a = 2 + _ = a +} + +var ( + // Hello there. + // Bob does the thing. + Bob int //@rename("Foo", "Bob") +) + +/* +Hello description +*/ +func Hello() {} //@rename("Hello", "Goodbye") + +-- Goodbye-rename -- +b.go: +package b + +var c int //@rename("int", "uint") + +func _() { + a := 1 //@rename("a", "error") + a = 2 + _ = a +} + +var ( + // Hello there. + // Foo does the thing. + Foo int //@rename("Foo", "Bob") +) + +/* +Goodbye description +*/ +func Goodbye() {} //@rename("Hello", "Goodbye") + +c.go: +package c + +import "golang.org/lsptests/rename/b" + +func _() { + b.Goodbye() //@rename("Hello", "Goodbye") +} + +-- error-rename -- +package b + +var c int //@rename("int", "uint") + +func _() { + error := 1 //@rename("a", "error") + error = 2 + _ = error +} + +var ( + // Hello there. + // Foo does the thing. + Foo int //@rename("Foo", "Bob") +) + +/* +Hello description +*/ +func Hello() {} //@rename("Hello", "Goodbye") + +-- uint-rename -- +int is built in and cannot be renamed diff --git a/gopls/internal/lsp/testdata/rename/bad/bad.go.golden b/gopls/internal/lsp/testdata/rename/bad/bad.go.golden new file mode 100644 index 000000000..1b27e1782 --- /dev/null +++ b/gopls/internal/lsp/testdata/rename/bad/bad.go.golden @@ -0,0 +1,2 @@ +-- rFunc-rename -- +renaming "sFunc" to "rFunc" not possible because "golang.org/lsptests/rename/bad" has errors diff --git a/gopls/internal/lsp/testdata/rename/bad/bad.go.in b/gopls/internal/lsp/testdata/rename/bad/bad.go.in new file mode 100644 index 000000000..56dbee74e --- /dev/null +++ b/gopls/internal/lsp/testdata/rename/bad/bad.go.in @@ -0,0 +1,8 @@ +package bad + +type myStruct struct { +} + +func (s *myStruct) sFunc() bool { //@rename("sFunc", "rFunc") + return s.Bad +} diff --git a/gopls/internal/lsp/testdata/rename/bad/bad_test.go.in b/gopls/internal/lsp/testdata/rename/bad/bad_test.go.in new file mode 100644 index 000000000..e695db14b --- /dev/null +++ b/gopls/internal/lsp/testdata/rename/bad/bad_test.go.in @@ -0,0 +1 @@ +package bad
\ No newline at end of file diff --git a/gopls/internal/lsp/testdata/rename/c/c.go b/gopls/internal/lsp/testdata/rename/c/c.go new file mode 100644 index 000000000..6332c78f3 --- /dev/null +++ b/gopls/internal/lsp/testdata/rename/c/c.go @@ -0,0 +1,7 @@ +package c + +import "golang.org/lsptests/rename/b" + +func _() { + b.Hello() //@rename("Hello", "Goodbye") +} diff --git a/gopls/internal/lsp/testdata/rename/c/c.go.golden b/gopls/internal/lsp/testdata/rename/c/c.go.golden new file mode 100644 index 000000000..d56250693 --- /dev/null +++ b/gopls/internal/lsp/testdata/rename/c/c.go.golden @@ -0,0 +1,32 @@ +-- Goodbye-rename -- +b.go: +package b + +var c int //@rename("int", "uint") + +func _() { + a := 1 //@rename("a", "error") + a = 2 + _ = a +} + +var ( + // Hello there. + // Foo does the thing. + Foo int //@rename("Foo", "Bob") +) + +/* +Goodbye description +*/ +func Goodbye() {} //@rename("Hello", "Goodbye") + +c.go: +package c + +import "golang.org/lsptests/rename/b" + +func _() { + b.Goodbye() //@rename("Hello", "Goodbye") +} + diff --git a/gopls/internal/lsp/testdata/rename/c/c2.go b/gopls/internal/lsp/testdata/rename/c/c2.go new file mode 100644 index 000000000..4fc484a1a --- /dev/null +++ b/gopls/internal/lsp/testdata/rename/c/c2.go @@ -0,0 +1,4 @@ +package c + +//go:embed Static/* +var Static embed.FS //@rename("Static", "static")
\ No newline at end of file diff --git a/gopls/internal/lsp/testdata/rename/c/c2.go.golden b/gopls/internal/lsp/testdata/rename/c/c2.go.golden new file mode 100644 index 000000000..e509227a9 --- /dev/null +++ b/gopls/internal/lsp/testdata/rename/c/c2.go.golden @@ -0,0 +1,5 @@ +-- static-rename -- +package c + +//go:embed Static/* +var static embed.FS //@rename("Static", "static") diff --git a/gopls/internal/lsp/testdata/rename/crosspkg/another/another.go b/gopls/internal/lsp/testdata/rename/crosspkg/another/another.go new file mode 100644 index 000000000..9b50af2cb --- /dev/null +++ b/gopls/internal/lsp/testdata/rename/crosspkg/another/another.go @@ -0,0 +1,13 @@ +package another + +type ( + I interface{ F() } + C struct{ I } +) + +func (C) g() + +func _() { + var x I = C{} + x.F() //@rename("F", "G") +} diff --git a/gopls/internal/lsp/testdata/rename/crosspkg/another/another.go.golden b/gopls/internal/lsp/testdata/rename/crosspkg/another/another.go.golden new file mode 100644 index 000000000..d3fccdaf1 --- /dev/null +++ b/gopls/internal/lsp/testdata/rename/crosspkg/another/another.go.golden @@ -0,0 +1,15 @@ +-- G-rename -- +package another + +type ( + I interface{ G() } + C struct{ I } +) + +func (C) g() + +func _() { + var x I = C{} + x.G() //@rename("F", "G") +} + diff --git a/gopls/internal/lsp/testdata/rename/crosspkg/crosspkg.go b/gopls/internal/lsp/testdata/rename/crosspkg/crosspkg.go new file mode 100644 index 000000000..8510bcfe0 --- /dev/null +++ b/gopls/internal/lsp/testdata/rename/crosspkg/crosspkg.go @@ -0,0 +1,7 @@ +package crosspkg + +func Foo() { //@rename("Foo", "Dolphin") + +} + +var Bar int //@rename("Bar", "Tomato") diff --git a/gopls/internal/lsp/testdata/rename/crosspkg/crosspkg.go.golden b/gopls/internal/lsp/testdata/rename/crosspkg/crosspkg.go.golden new file mode 100644 index 000000000..49ff7f841 --- /dev/null +++ b/gopls/internal/lsp/testdata/rename/crosspkg/crosspkg.go.golden @@ -0,0 +1,40 @@ +-- Dolphin-rename -- +crosspkg.go: +package crosspkg + +func Dolphin() { //@rename("Foo", "Dolphin") + +} + +var Bar int //@rename("Bar", "Tomato") + +other.go: +package other + +import "golang.org/lsptests/rename/crosspkg" + +func Other() { + crosspkg.Bar + crosspkg.Dolphin() //@rename("Foo", "Flamingo") +} + +-- Tomato-rename -- +crosspkg.go: +package crosspkg + +func Foo() { //@rename("Foo", "Dolphin") + +} + +var Tomato int //@rename("Bar", "Tomato") + +other.go: +package other + +import "golang.org/lsptests/rename/crosspkg" + +func Other() { + crosspkg.Tomato + crosspkg.Foo() //@rename("Foo", "Flamingo") +} + diff --git a/gopls/internal/lsp/testdata/rename/crosspkg/other/other.go b/gopls/internal/lsp/testdata/rename/crosspkg/other/other.go new file mode 100644 index 000000000..5fd147da6 --- /dev/null +++ b/gopls/internal/lsp/testdata/rename/crosspkg/other/other.go @@ -0,0 +1,8 @@ +package other + +import "golang.org/lsptests/rename/crosspkg" + +func Other() { + crosspkg.Bar + crosspkg.Foo() //@rename("Foo", "Flamingo") +} diff --git a/gopls/internal/lsp/testdata/rename/crosspkg/other/other.go.golden b/gopls/internal/lsp/testdata/rename/crosspkg/other/other.go.golden new file mode 100644 index 000000000..f7b4aaad4 --- /dev/null +++ b/gopls/internal/lsp/testdata/rename/crosspkg/other/other.go.golden @@ -0,0 +1,20 @@ +-- Flamingo-rename -- +crosspkg.go: +package crosspkg + +func Flamingo() { //@rename("Foo", "Dolphin") + +} + +var Bar int //@rename("Bar", "Tomato") + +other.go: +package other + +import "golang.org/lsptests/rename/crosspkg" + +func Other() { + crosspkg.Bar + crosspkg.Flamingo() //@rename("Foo", "Flamingo") +} + diff --git a/gopls/internal/lsp/testdata/rename/generics/embedded.go b/gopls/internal/lsp/testdata/rename/generics/embedded.go new file mode 100644 index 000000000..b44bab880 --- /dev/null +++ b/gopls/internal/lsp/testdata/rename/generics/embedded.go @@ -0,0 +1,10 @@ +//go:build go1.18 +// +build go1.18 + +package generics + +type foo[P any] int //@rename("foo","bar") + +var x struct{ foo[int] } + +var _ = x.foo diff --git a/gopls/internal/lsp/testdata/rename/generics/embedded.go.golden b/gopls/internal/lsp/testdata/rename/generics/embedded.go.golden new file mode 100644 index 000000000..faa9afb69 --- /dev/null +++ b/gopls/internal/lsp/testdata/rename/generics/embedded.go.golden @@ -0,0 +1,12 @@ +-- bar-rename -- +//go:build go1.18 +// +build go1.18 + +package generics + +type bar[P any] int //@rename("foo","bar") + +var x struct{ bar[int] } + +var _ = x.bar + diff --git a/gopls/internal/lsp/testdata/rename/generics/generics.go b/gopls/internal/lsp/testdata/rename/generics/generics.go new file mode 100644 index 000000000..977589c0c --- /dev/null +++ b/gopls/internal/lsp/testdata/rename/generics/generics.go @@ -0,0 +1,25 @@ +//go:build go1.18 +// +build go1.18 + +package generics + +type G[P any] struct { + F int +} + +func (G[_]) M() {} + +func F[P any](P) { + var p P //@rename("P", "Q") + _ = p +} + +func _() { + var x G[int] //@rename("G", "H") + _ = x.F //@rename("F", "K") + x.M() //@rename("M", "N") + + var y G[string] + _ = y.F + y.M() +} diff --git a/gopls/internal/lsp/testdata/rename/generics/generics.go.golden b/gopls/internal/lsp/testdata/rename/generics/generics.go.golden new file mode 100644 index 000000000..7d39813e1 --- /dev/null +++ b/gopls/internal/lsp/testdata/rename/generics/generics.go.golden @@ -0,0 +1,108 @@ +-- H-rename -- +//go:build go1.18 +// +build go1.18 + +package generics + +type H[P any] struct { + F int +} + +func (H[_]) M() {} + +func F[P any](P) { + var p P //@rename("P", "Q") + _ = p +} + +func _() { + var x H[int] //@rename("G", "H") + _ = x.F //@rename("F", "K") + x.M() //@rename("M", "N") + + var y H[string] + _ = y.F + y.M() +} + +-- K-rename -- +//go:build go1.18 +// +build go1.18 + +package generics + +type G[P any] struct { + K int +} + +func (G[_]) M() {} + +func F[P any](P) { + var p P //@rename("P", "Q") + _ = p +} + +func _() { + var x G[int] //@rename("G", "H") + _ = x.K //@rename("F", "K") + x.M() //@rename("M", "N") + + var y G[string] + _ = y.K + y.M() +} + +-- N-rename -- +//go:build go1.18 +// +build go1.18 + +package generics + +type G[P any] struct { + F int +} + +func (G[_]) N() {} + +func F[P any](P) { + var p P //@rename("P", "Q") + _ = p +} + +func _() { + var x G[int] //@rename("G", "H") + _ = x.F //@rename("F", "K") + x.N() //@rename("M", "N") + + var y G[string] + _ = y.F + y.N() +} + +-- Q-rename -- +//go:build go1.18 +// +build go1.18 + +package generics + +type G[P any] struct { + F int +} + +func (G[_]) M() {} + +func F[Q any](Q) { + var p Q //@rename("P", "Q") + _ = p +} + +func _() { + var x G[int] //@rename("G", "H") + _ = x.F //@rename("F", "K") + x.M() //@rename("M", "N") + + var y G[string] + _ = y.F + y.M() +} + diff --git a/gopls/internal/lsp/testdata/rename/generics/unions.go b/gopls/internal/lsp/testdata/rename/generics/unions.go new file mode 100644 index 000000000..c737b5c27 --- /dev/null +++ b/gopls/internal/lsp/testdata/rename/generics/unions.go @@ -0,0 +1,10 @@ +//go:build go1.18 +// +build go1.18 + +package generics + +type T string //@rename("T", "R") + +type C interface { + T | ~int //@rename("T", "S") +} diff --git a/gopls/internal/lsp/testdata/rename/generics/unions.go.golden b/gopls/internal/lsp/testdata/rename/generics/unions.go.golden new file mode 100644 index 000000000..463289629 --- /dev/null +++ b/gopls/internal/lsp/testdata/rename/generics/unions.go.golden @@ -0,0 +1,24 @@ +-- R-rename -- +//go:build go1.18 +// +build go1.18 + +package generics + +type R string //@rename("T", "R") + +type C interface { + R | ~int //@rename("T", "S") +} + +-- S-rename -- +//go:build go1.18 +// +build go1.18 + +package generics + +type S string //@rename("T", "R") + +type C interface { + S | ~int //@rename("T", "S") +} + diff --git a/gopls/internal/lsp/testdata/rename/issue39614/issue39614.go.golden b/gopls/internal/lsp/testdata/rename/issue39614/issue39614.go.golden new file mode 100644 index 000000000..d87c58e83 --- /dev/null +++ b/gopls/internal/lsp/testdata/rename/issue39614/issue39614.go.golden @@ -0,0 +1,10 @@ +-- bar-rename -- +package issue39614 + +func fn() { + var bar bool //@rename("foo","bar") + make(map[string]bool + if true { + } +} + diff --git a/gopls/internal/lsp/testdata/rename/issue39614/issue39614.go.in b/gopls/internal/lsp/testdata/rename/issue39614/issue39614.go.in new file mode 100644 index 000000000..8222db2c4 --- /dev/null +++ b/gopls/internal/lsp/testdata/rename/issue39614/issue39614.go.in @@ -0,0 +1,8 @@ +package issue39614 + +func fn() { + var foo bool //@rename("foo","bar") + make(map[string]bool + if true { + } +} diff --git a/gopls/internal/lsp/testdata/rename/issue42134/1.go b/gopls/internal/lsp/testdata/rename/issue42134/1.go new file mode 100644 index 000000000..056f8476a --- /dev/null +++ b/gopls/internal/lsp/testdata/rename/issue42134/1.go @@ -0,0 +1,8 @@ +package issue42134 + +func _() { + // foo computes things. + foo := func() {} + + foo() //@rename("foo", "bar") +} diff --git a/gopls/internal/lsp/testdata/rename/issue42134/1.go.golden b/gopls/internal/lsp/testdata/rename/issue42134/1.go.golden new file mode 100644 index 000000000..266aeef4b --- /dev/null +++ b/gopls/internal/lsp/testdata/rename/issue42134/1.go.golden @@ -0,0 +1,10 @@ +-- bar-rename -- +package issue42134 + +func _() { + // bar computes things. + bar := func() {} + + bar() //@rename("foo", "bar") +} + diff --git a/gopls/internal/lsp/testdata/rename/issue42134/2.go b/gopls/internal/lsp/testdata/rename/issue42134/2.go new file mode 100644 index 000000000..e9f639575 --- /dev/null +++ b/gopls/internal/lsp/testdata/rename/issue42134/2.go @@ -0,0 +1,12 @@ +package issue42134 + +import "fmt" + +func _() { + // minNumber is a min number. + // Second line. + minNumber := min(1, 2) + fmt.Println(minNumber) //@rename("minNumber", "res") +} + +func min(a, b int) int { return a } diff --git a/gopls/internal/lsp/testdata/rename/issue42134/2.go.golden b/gopls/internal/lsp/testdata/rename/issue42134/2.go.golden new file mode 100644 index 000000000..406a3833c --- /dev/null +++ b/gopls/internal/lsp/testdata/rename/issue42134/2.go.golden @@ -0,0 +1,14 @@ +-- res-rename -- +package issue42134 + +import "fmt" + +func _() { + // res is a min number. + // Second line. + res := min(1, 2) + fmt.Println(res) //@rename("minNumber", "res") +} + +func min(a, b int) int { return a } + diff --git a/gopls/internal/lsp/testdata/rename/issue42134/3.go b/gopls/internal/lsp/testdata/rename/issue42134/3.go new file mode 100644 index 000000000..7666f57d3 --- /dev/null +++ b/gopls/internal/lsp/testdata/rename/issue42134/3.go @@ -0,0 +1,11 @@ +package issue42134 + +func _() { + /* + tests contains test cases + */ + tests := []struct { //@rename("tests", "testCases") + in, out string + }{} + _ = tests +} diff --git a/gopls/internal/lsp/testdata/rename/issue42134/3.go.golden b/gopls/internal/lsp/testdata/rename/issue42134/3.go.golden new file mode 100644 index 000000000..cdcae1808 --- /dev/null +++ b/gopls/internal/lsp/testdata/rename/issue42134/3.go.golden @@ -0,0 +1,13 @@ +-- testCases-rename -- +package issue42134 + +func _() { + /* + testCases contains test cases + */ + testCases := []struct { //@rename("tests", "testCases") + in, out string + }{} + _ = testCases +} + diff --git a/gopls/internal/lsp/testdata/rename/issue42134/4.go b/gopls/internal/lsp/testdata/rename/issue42134/4.go new file mode 100644 index 000000000..c953520bc --- /dev/null +++ b/gopls/internal/lsp/testdata/rename/issue42134/4.go @@ -0,0 +1,8 @@ +package issue42134 + +func _() { + // a is equal to 5. Comment must stay the same + + a := 5 + _ = a //@rename("a", "b") +} diff --git a/gopls/internal/lsp/testdata/rename/issue42134/4.go.golden b/gopls/internal/lsp/testdata/rename/issue42134/4.go.golden new file mode 100644 index 000000000..2086cf74c --- /dev/null +++ b/gopls/internal/lsp/testdata/rename/issue42134/4.go.golden @@ -0,0 +1,10 @@ +-- b-rename -- +package issue42134 + +func _() { + // a is equal to 5. Comment must stay the same + + b := 5 + _ = b //@rename("a", "b") +} + diff --git a/gopls/internal/lsp/testdata/rename/issue43616/issue43616.go.golden b/gopls/internal/lsp/testdata/rename/issue43616/issue43616.go.golden new file mode 100644 index 000000000..34d03ba7a --- /dev/null +++ b/gopls/internal/lsp/testdata/rename/issue43616/issue43616.go.golden @@ -0,0 +1,13 @@ +-- bar-rename -- +package issue43616 + +type bar int //@rename("foo","bar"),prepare("oo","foo","foo") + +var x struct{ bar } //@rename("foo","baz") + +var _ = x.bar //@rename("foo","quux") + +-- baz-rename -- +can't rename embedded fields: rename the type directly or name the field +-- quux-rename -- +can't rename embedded fields: rename the type directly or name the field diff --git a/gopls/internal/lsp/testdata/rename/issue43616/issue43616.go.in b/gopls/internal/lsp/testdata/rename/issue43616/issue43616.go.in new file mode 100644 index 000000000..aaad531b7 --- /dev/null +++ b/gopls/internal/lsp/testdata/rename/issue43616/issue43616.go.in @@ -0,0 +1,7 @@ +package issue43616 + +type foo int //@rename("foo","bar"),prepare("oo","foo","foo") + +var x struct{ foo } //@rename("foo","baz") + +var _ = x.foo //@rename("foo","quux") diff --git a/gopls/internal/lsp/testdata/rename/shadow/shadow.go b/gopls/internal/lsp/testdata/rename/shadow/shadow.go new file mode 100644 index 000000000..38329b4fe --- /dev/null +++ b/gopls/internal/lsp/testdata/rename/shadow/shadow.go @@ -0,0 +1,20 @@ +package shadow + +func _() { + a := true + b, c, _ := A(), B(), D() //@rename("A", "a"),rename("B", "b"),rename("b", "c"),rename("D", "d") + d := false + _, _, _, _ = a, b, c, d +} + +func A() int { + return 0 +} + +func B() int { + return 0 +} + +func D() int { + return 0 +} diff --git a/gopls/internal/lsp/testdata/rename/shadow/shadow.go.golden b/gopls/internal/lsp/testdata/rename/shadow/shadow.go.golden new file mode 100644 index 000000000..a34b5c0fe --- /dev/null +++ b/gopls/internal/lsp/testdata/rename/shadow/shadow.go.golden @@ -0,0 +1,51 @@ +-- a-rename -- +shadow/shadow.go:10:6: renaming this func "A" to "a" +shadow/shadow.go:5:13: would cause this reference to become shadowed +shadow/shadow.go:4:2: by this intervening var definition +-- b-rename -- +package shadow + +func _() { + a := true + b, c, _ := A(), b(), D() //@rename("A", "a"),rename("B", "b"),rename("b", "c"),rename("D", "d") + d := false + _, _, _, _ = a, b, c, d +} + +func A() int { + return 0 +} + +func b() int { + return 0 +} + +func D() int { + return 0 +} + +-- c-rename -- +shadow/shadow.go:5:2: renaming this var "b" to "c" +shadow/shadow.go:5:5: conflicts with var in same block +-- d-rename -- +package shadow + +func _() { + a := true + b, c, _ := A(), B(), d() //@rename("A", "a"),rename("B", "b"),rename("b", "c"),rename("D", "d") + d := false + _, _, _, _ = a, b, c, d +} + +func A() int { + return 0 +} + +func B() int { + return 0 +} + +func d() int { + return 0 +} + diff --git a/gopls/internal/lsp/testdata/rename/testy/testy.go b/gopls/internal/lsp/testdata/rename/testy/testy.go new file mode 100644 index 000000000..e46dc06cd --- /dev/null +++ b/gopls/internal/lsp/testdata/rename/testy/testy.go @@ -0,0 +1,7 @@ +package testy + +type tt int //@rename("tt", "testyType") + +func a() { + foo := 42 //@rename("foo", "bar") +} diff --git a/gopls/internal/lsp/testdata/rename/testy/testy.go.golden b/gopls/internal/lsp/testdata/rename/testy/testy.go.golden new file mode 100644 index 000000000..288dfee96 --- /dev/null +++ b/gopls/internal/lsp/testdata/rename/testy/testy.go.golden @@ -0,0 +1,18 @@ +-- bar-rename -- +package testy + +type tt int //@rename("tt", "testyType") + +func a() { + bar := 42 //@rename("foo", "bar") +} + +-- testyType-rename -- +package testy + +type testyType int //@rename("tt", "testyType") + +func a() { + foo := 42 //@rename("foo", "bar") +} + diff --git a/gopls/internal/lsp/testdata/rename/testy/testy_test.go b/gopls/internal/lsp/testdata/rename/testy/testy_test.go new file mode 100644 index 000000000..3d86e8455 --- /dev/null +++ b/gopls/internal/lsp/testdata/rename/testy/testy_test.go @@ -0,0 +1,8 @@ +package testy + +import "testing" + +func TestSomething(t *testing.T) { + var x int //@rename("x", "testyX") + a() //@rename("a", "b") +} diff --git a/gopls/internal/lsp/testdata/rename/testy/testy_test.go.golden b/gopls/internal/lsp/testdata/rename/testy/testy_test.go.golden new file mode 100644 index 000000000..480c8e995 --- /dev/null +++ b/gopls/internal/lsp/testdata/rename/testy/testy_test.go.golden @@ -0,0 +1,30 @@ +-- b-rename -- +testy.go: +package testy + +type tt int //@rename("tt", "testyType") + +func b() { + foo := 42 //@rename("foo", "bar") +} + +testy_test.go: +package testy + +import "testing" + +func TestSomething(t *testing.T) { + var x int //@rename("x", "testyX") + b() //@rename("a", "b") +} + +-- testyX-rename -- +package testy + +import "testing" + +func TestSomething(t *testing.T) { + var testyX int //@rename("x", "testyX") + a() //@rename("a", "b") +} + diff --git a/gopls/internal/lsp/testdata/rundespiteerrors/rundespiteerrors.go b/gopls/internal/lsp/testdata/rundespiteerrors/rundespiteerrors.go new file mode 100644 index 000000000..783e9a55f --- /dev/null +++ b/gopls/internal/lsp/testdata/rundespiteerrors/rundespiteerrors.go @@ -0,0 +1,14 @@ +package rundespiteerrors + +// This test verifies that analyzers without RunDespiteErrors are not +// executed on a package containing type errors (see issue #54762). +func _() { + // A type error. + _ = 1 + "" //@diag("1", "compiler", "mismatched types|cannot convert", "error") + + // A violation of an analyzer for which RunDespiteErrors=false: + // no diagnostic is produced; the diag comment is merely illustrative. + for _ = range "" { //diag("for _", "simplifyrange", "simplify range expression", "warning") + + } +} diff --git a/gopls/internal/lsp/testdata/selectionrange/foo.go b/gopls/internal/lsp/testdata/selectionrange/foo.go new file mode 100644 index 000000000..1bf41340c --- /dev/null +++ b/gopls/internal/lsp/testdata/selectionrange/foo.go @@ -0,0 +1,13 @@ +package foo + +import "time" + +func Bar(x, y int, t time.Time) int { + zs := []int{1, 2, 3} //@selectionrange("1") + + for _, z := range zs { + x = x + z + y + zs[1] //@selectionrange("1") + } + + return x + y //@selectionrange("+") +} diff --git a/gopls/internal/lsp/testdata/selectionrange/foo.go.golden b/gopls/internal/lsp/testdata/selectionrange/foo.go.golden new file mode 100644 index 000000000..fe70b30b7 --- /dev/null +++ b/gopls/internal/lsp/testdata/selectionrange/foo.go.golden @@ -0,0 +1,29 @@ +-- selectionrange_foo_12_11 -- +Ranges 0: + 11:8-11:13 "x + y" + 11:1-11:13 "return x + y" + 4:36-12:1 "{\\n\tzs := []int{...ionrange(\"+\")\\n}" + 4:0-12:1 "func Bar(x, y i...ionrange(\"+\")\\n}" + 0:0-12:1 "package foo\\n\\nim...ionrange(\"+\")\\n}" + +-- selectionrange_foo_6_14 -- +Ranges 0: + 5:13-5:14 "1" + 5:7-5:21 "[]int{1, 2, 3}" + 5:1-5:21 "zs := []int{1, 2, 3}" + 4:36-12:1 "{\\n\tzs := []int{...ionrange(\"+\")\\n}" + 4:0-12:1 "func Bar(x, y i...ionrange(\"+\")\\n}" + 0:0-12:1 "package foo\\n\\nim...ionrange(\"+\")\\n}" + +-- selectionrange_foo_9_22 -- +Ranges 0: + 8:21-8:22 "1" + 8:18-8:23 "zs[1]" + 8:6-8:23 "x + z + y + zs[1]" + 8:2-8:23 "x = x + z + y + zs[1]" + 7:22-9:2 "{\\n\t\tx = x + z +...onrange(\"1\")\\n\t}" + 7:1-9:2 "for _, z := ran...onrange(\"1\")\\n\t}" + 4:36-12:1 "{\\n\tzs := []int{...ionrange(\"+\")\\n}" + 4:0-12:1 "func Bar(x, y i...ionrange(\"+\")\\n}" + 0:0-12:1 "package foo\\n\\nim...ionrange(\"+\")\\n}" + diff --git a/gopls/internal/lsp/testdata/selector/selector.go.in b/gopls/internal/lsp/testdata/selector/selector.go.in new file mode 100644 index 000000000..b1498a08c --- /dev/null +++ b/gopls/internal/lsp/testdata/selector/selector.go.in @@ -0,0 +1,66 @@ +// +build go1.11 + +package selector + +import ( + "golang.org/lsptests/bar" +) + +type S struct { + B, A, C int //@item(Bf, "B", "int", "field"),item(Af, "A", "int", "field"),item(Cf, "C", "int", "field") +} + +func _() { + _ = S{}.; //@complete(";", Af, Bf, Cf) +} + +type bob struct { a int } //@item(a, "a", "int", "field") +type george struct { b int } +type jack struct { c int } //@item(c, "c", "int", "field") +type jill struct { d int } + +func (b *bob) george() *george {} //@item(george, "george", "func() *george", "method") +func (g *george) jack() *jack {} +func (j *jack) jill() *jill {} //@item(jill, "jill", "func() *jill", "method") + +func _() { + b := &bob{} + y := b.george(). + jack(); + y.; //@complete(";", c, jill) +} + +func _() { + bar. //@complete(" /", Bar) + x := 5 + + var b *bob + b. //@complete(" /", a, george) + y, z := 5, 6 + + b. //@complete(" /", a, george) + y, z, a, b, c := 5, 6 +} + +func _() { + bar. //@complete(" /", Bar) + bar.Bar() + + bar. //@complete(" /", Bar) + go f() +} + +func _() { + var b *bob + if y != b. //@complete(" /", a, george) + z := 5 + + if z + y + 1 + b. //@complete(" /", a, george) + r, s, t := 4, 5 + + if y != b. //@complete(" /", a, george) + z = 5 + + if z + y + 1 + b. //@complete(" /", a, george) + r = 4 +} diff --git a/gopls/internal/lsp/testdata/semantic/README.md b/gopls/internal/lsp/testdata/semantic/README.md new file mode 100644 index 000000000..00ec19af1 --- /dev/null +++ b/gopls/internal/lsp/testdata/semantic/README.md @@ -0,0 +1,2 @@ +The golden files are the output of `gopls semtok <src-file>`, with `-- semantic --` +inserted as the first line (the spaces are mandatory) and an extra newline at the end. diff --git a/gopls/internal/lsp/testdata/semantic/a.go b/gopls/internal/lsp/testdata/semantic/a.go new file mode 100644 index 000000000..54d6c8a62 --- /dev/null +++ b/gopls/internal/lsp/testdata/semantic/a.go @@ -0,0 +1,81 @@ +package semantictokens //@ semantic("") + +import ( + _ "encoding/utf8" + utf "encoding/utf8" + "fmt" //@ semantic("fmt") + . "fmt" + "unicode/utf8" +) + +var ( + a = fmt.Print + b []string = []string{"foo"} + c1 chan int + c2 <-chan int + c3 = make([]chan<- int) + b = A{X: 23} + m map[bool][3]*float64 +) + +const ( + xx F = iota + yy = xx + 3 + zz = "" + ww = "not " + zz +) + +type A struct { + X int `foof` +} +type B interface { + A + sad(int) bool +} + +type F int + +func (a *A) f() bool { + var z string + x := "foo" + a(x) + y := "bar" + x + switch z { + case "xx": + default: + } + select { + case z := <-c3[0]: + default: + } + for k, v := range m { + return (!k) && v[0] == nil + } + c2 <- A.X + w := b[4:] + j := len(x) + j-- + q := []interface{}{j, 23i, &y} + g(q...) + return true +} + +func g(vv ...interface{}) { + ff := func() {} + defer ff() + go utf.RuneCount("") + go utf8.RuneCount(vv.(string)) + if true { + } else { + } +Never: + for i := 0; i < 10; { + break Never + } + _, ok := vv[0].(A) + if !ok { + switch x := vv[0].(type) { + } + goto Never + } +} diff --git a/gopls/internal/lsp/testdata/semantic/a.go.golden b/gopls/internal/lsp/testdata/semantic/a.go.golden new file mode 100644 index 000000000..047a031a7 --- /dev/null +++ b/gopls/internal/lsp/testdata/semantic/a.go.golden @@ -0,0 +1,83 @@ +-- semantic -- +/*⇒7,keyword,[]*/package /*⇒14,namespace,[]*/semantictokens /*⇒16,comment,[]*///@ semantic("") + +/*⇒6,keyword,[]*/import ( + _ "encoding/utf8" + /*⇒3,namespace,[]*/utf "encoding/utf8" + "fmt"/*⇐3,namespace,[]*/ /*⇒19,comment,[]*///@ semantic("fmt") + . "fmt" + "unicode/utf8"/*⇐4,namespace,[]*/ +) + +/*⇒3,keyword,[]*/var ( + /*⇒1,variable,[definition]*/a = /*⇒3,namespace,[]*/fmt./*⇒5,function,[]*/Print + /*⇒1,variable,[definition]*/b []/*⇒6,type,[defaultLibrary]*/string = []/*⇒6,type,[defaultLibrary]*/string{/*⇒5,string,[]*/"foo"} + /*⇒2,variable,[definition]*/c1 /*⇒4,keyword,[]*/chan /*⇒3,type,[defaultLibrary]*/int + /*⇒2,variable,[definition]*/c2 /*⇒2,operator,[]*/<-/*⇒4,keyword,[]*/chan /*⇒3,type,[defaultLibrary]*/int + /*⇒2,variable,[definition]*/c3 = /*⇒4,function,[defaultLibrary]*/make([]/*⇒4,keyword,[]*/chan/*⇒2,operator,[]*/<- /*⇒3,type,[defaultLibrary]*/int) + /*⇒1,variable,[definition]*/b = /*⇒1,type,[]*/A{/*⇒1,variable,[]*/X: /*⇒2,number,[]*/23} + /*⇒1,variable,[definition]*/m /*⇒3,keyword,[]*/map[/*⇒4,type,[defaultLibrary]*/bool][/*⇒1,number,[]*/3]/*⇒1,operator,[]*/*/*⇒7,type,[defaultLibrary]*/float64 +) + +/*⇒5,keyword,[]*/const ( + /*⇒2,variable,[definition readonly]*/xx /*⇒1,type,[]*/F = /*⇒4,variable,[readonly]*/iota + /*⇒2,variable,[definition readonly]*/yy = /*⇒2,variable,[readonly]*/xx /*⇒1,operator,[]*/+ /*⇒1,number,[]*/3 + /*⇒2,variable,[definition readonly]*/zz = /*⇒2,string,[]*/"" + /*⇒2,variable,[definition readonly]*/ww = /*⇒6,string,[]*/"not " /*⇒1,operator,[]*/+ /*⇒2,variable,[readonly]*/zz +) + +/*⇒4,keyword,[]*/type /*⇒1,type,[definition]*/A /*⇒6,keyword,[]*/struct { + /*⇒1,variable,[definition]*/X /*⇒3,type,[defaultLibrary]*/int /*⇒6,string,[]*/`foof` +} +/*⇒4,keyword,[]*/type /*⇒1,type,[definition]*/B /*⇒9,keyword,[]*/interface { + /*⇒1,type,[]*/A + /*⇒3,method,[definition]*/sad(/*⇒3,type,[defaultLibrary]*/int) /*⇒4,type,[defaultLibrary]*/bool +} + +/*⇒4,keyword,[]*/type /*⇒1,type,[definition]*/F /*⇒3,type,[defaultLibrary]*/int + +/*⇒4,keyword,[]*/func (/*⇒1,variable,[]*/a /*⇒1,operator,[]*/*/*⇒1,type,[]*/A) /*⇒1,method,[definition]*/f() /*⇒4,type,[defaultLibrary]*/bool { + /*⇒3,keyword,[]*/var /*⇒1,variable,[definition]*/z /*⇒6,type,[defaultLibrary]*/string + /*⇒1,variable,[definition]*/x /*⇒2,operator,[]*/:= /*⇒5,string,[]*/"foo" + /*⇒1,variable,[]*/a(/*⇒1,variable,[]*/x) + /*⇒1,variable,[definition]*/y /*⇒2,operator,[]*/:= /*⇒5,string,[]*/"bar" /*⇒1,operator,[]*/+ /*⇒1,variable,[]*/x + /*⇒6,keyword,[]*/switch /*⇒1,variable,[]*/z { + /*⇒4,keyword,[]*/case /*⇒4,string,[]*/"xx": + /*⇒7,keyword,[]*/default: + } + /*⇒6,keyword,[]*/select { + /*⇒4,keyword,[]*/case /*⇒1,variable,[definition]*/z /*⇒2,operator,[]*/:= /*⇒2,operator,[]*/<-/*⇒2,variable,[]*/c3[/*⇒1,number,[]*/0]: + /*⇒7,keyword,[]*/default: + } + /*⇒3,keyword,[]*/for /*⇒1,variable,[definition]*/k, /*⇒1,variable,[definition]*/v := /*⇒5,keyword,[]*/range /*⇒1,variable,[]*/m { + /*⇒6,keyword,[]*/return (/*⇒1,operator,[]*/!/*⇒1,variable,[]*/k) /*⇒2,operator,[]*/&& /*⇒1,variable,[]*/v[/*⇒1,number,[]*/0] /*⇒2,operator,[]*/== /*⇒3,variable,[readonly defaultLibrary]*/nil + } + /*⇒2,variable,[]*/c2 /*⇒2,operator,[]*/<- /*⇒1,type,[]*/A./*⇒1,variable,[]*/X + /*⇒1,variable,[definition]*/w /*⇒2,operator,[]*/:= /*⇒1,variable,[]*/b[/*⇒1,number,[]*/4:] + /*⇒1,variable,[definition]*/j /*⇒2,operator,[]*/:= /*⇒3,function,[defaultLibrary]*/len(/*⇒1,variable,[]*/x) + /*⇒1,variable,[]*/j/*⇒2,operator,[]*/-- + /*⇒1,variable,[definition]*/q /*⇒2,operator,[]*/:= []/*⇒9,keyword,[]*/interface{}{/*⇒1,variable,[]*/j, /*⇒3,number,[]*/23i, /*⇒1,operator,[]*/&/*⇒1,variable,[]*/y} + /*⇒1,function,[]*/g(/*⇒1,variable,[]*/q/*⇒3,operator,[]*/...) + /*⇒6,keyword,[]*/return /*⇒4,variable,[readonly]*/true +} + +/*⇒4,keyword,[]*/func /*⇒1,function,[definition]*/g(/*⇒2,parameter,[definition]*/vv /*⇒3,operator,[]*/.../*⇒9,keyword,[]*/interface{}) { + /*⇒2,variable,[definition]*/ff /*⇒2,operator,[]*/:= /*⇒4,keyword,[]*/func() {} + /*⇒5,keyword,[]*/defer /*⇒2,function,[]*/ff() + /*⇒2,keyword,[]*/go /*⇒3,namespace,[]*/utf./*⇒9,function,[]*/RuneCount(/*⇒2,string,[]*/"") + /*⇒2,keyword,[]*/go /*⇒4,namespace,[]*/utf8./*⇒9,function,[]*/RuneCount(/*⇒2,parameter,[]*/vv.(/*⇒6,type,[]*/string)) + /*⇒2,keyword,[]*/if /*⇒4,variable,[readonly]*/true { + } /*⇒4,keyword,[]*/else { + } +/*⇒5,parameter,[definition]*/Never: + /*⇒3,keyword,[]*/for /*⇒1,variable,[definition]*/i /*⇒2,operator,[]*/:= /*⇒1,number,[]*/0; /*⇒1,variable,[]*/i /*⇒1,operator,[]*/< /*⇒2,number,[]*/10; { + /*⇒5,keyword,[]*/break Never + } + _, /*⇒2,variable,[definition]*/ok /*⇒2,operator,[]*/:= /*⇒2,parameter,[]*/vv[/*⇒1,number,[]*/0].(/*⇒1,type,[]*/A) + /*⇒2,keyword,[]*/if /*⇒1,operator,[]*/!/*⇒2,variable,[]*/ok { + /*⇒6,keyword,[]*/switch /*⇒1,variable,[definition]*/x /*⇒2,operator,[]*/:= /*⇒2,parameter,[]*/vv[/*⇒1,number,[]*/0].(/*⇒4,keyword,[]*/type) { + } + /*⇒4,keyword,[]*/goto Never + } +} + diff --git a/gopls/internal/lsp/testdata/semantic/b.go b/gopls/internal/lsp/testdata/semantic/b.go new file mode 100644 index 000000000..496b0863d --- /dev/null +++ b/gopls/internal/lsp/testdata/semantic/b.go @@ -0,0 +1,38 @@ +package semantictokens //@ semantic("") + +func f(x ...interface{}) { +} + +func weirⰀd() { /*😀*/ // comment + const ( + snil = nil + nil = true + true = false + false = snil + cmd = `foof` + double = iota + iota = copy + four = (len(cmd)/2 < 5) + five = four + ) + f(cmd, nil, double, iota) +} + +/* + +multiline */ /* +multiline +*/ +type AA int +type BB struct { + AA +} +type CC struct { + AA int +} +type D func(aa AA) (BB error) +type E func(AA) BB + +var a chan<- chan int +var b chan<- <-chan int +var c <-chan <-chan int diff --git a/gopls/internal/lsp/testdata/semantic/b.go.golden b/gopls/internal/lsp/testdata/semantic/b.go.golden new file mode 100644 index 000000000..59071374b --- /dev/null +++ b/gopls/internal/lsp/testdata/semantic/b.go.golden @@ -0,0 +1,40 @@ +-- semantic -- +/*⇒7,keyword,[]*/package /*⇒14,namespace,[]*/semantictokens /*⇒16,comment,[]*///@ semantic("") + +/*⇒4,keyword,[]*/func /*⇒1,function,[definition]*/f(/*⇒1,parameter,[definition]*/x /*⇒3,operator,[]*/.../*⇒9,keyword,[]*/interface{}) { +} + +/*⇒4,keyword,[]*/func /*⇒6,function,[definition]*/weirⰀd() { /*⇒5,comment,[]*//*😀*/ /*⇒10,comment,[]*/// comment + /*⇒5,keyword,[]*/const ( + /*⇒4,variable,[definition readonly]*/snil = /*⇒3,variable,[readonly defaultLibrary]*/nil + /*⇒3,variable,[definition readonly]*/nil = /*⇒4,variable,[readonly]*/true + /*⇒4,variable,[definition readonly]*/true = /*⇒5,variable,[readonly]*/false + /*⇒5,variable,[definition readonly]*/false = /*⇒4,variable,[readonly]*/snil + /*⇒3,variable,[definition readonly]*/cmd = /*⇒6,string,[]*/`foof` + /*⇒6,variable,[definition readonly]*/double = /*⇒4,variable,[readonly]*/iota + /*⇒4,variable,[definition readonly]*/iota = /*⇒4,function,[defaultLibrary]*/copy + /*⇒4,variable,[definition readonly]*/four = (/*⇒3,function,[defaultLibrary]*/len(/*⇒3,variable,[readonly]*/cmd)/*⇒1,operator,[]*// /*⇒1,number,[]*/2 /*⇒1,operator,[]*/< /*⇒1,number,[]*/5) + /*⇒4,variable,[definition readonly]*/five = /*⇒4,variable,[readonly]*/four + ) + /*⇒1,function,[]*/f(/*⇒3,variable,[readonly]*/cmd, /*⇒3,variable,[readonly]*/nil, /*⇒6,variable,[readonly]*/double, /*⇒4,variable,[readonly]*/iota) +} + +/*⇒2,comment,[]*//* +/*⇒0,comment,[]*/ +/*⇒12,comment,[]*/multiline */ /*⇒2,comment,[]*//* +/*⇒9,comment,[]*/multiline +/*⇒2,comment,[]*/*/ +/*⇒4,keyword,[]*/type /*⇒2,type,[definition]*/AA /*⇒3,type,[defaultLibrary]*/int +/*⇒4,keyword,[]*/type /*⇒2,type,[definition]*/BB /*⇒6,keyword,[]*/struct { + /*⇒2,type,[]*/AA +} +/*⇒4,keyword,[]*/type /*⇒2,type,[definition]*/CC /*⇒6,keyword,[]*/struct { + /*⇒2,variable,[definition]*/AA /*⇒3,type,[defaultLibrary]*/int +} +/*⇒4,keyword,[]*/type /*⇒1,type,[definition]*/D /*⇒4,keyword,[]*/func(/*⇒2,parameter,[definition]*/aa /*⇒2,type,[]*/AA) (/*⇒2,parameter,[definition]*/BB /*⇒5,type,[]*/error) +/*⇒4,keyword,[]*/type /*⇒1,type,[definition]*/E /*⇒4,keyword,[]*/func(/*⇒2,type,[]*/AA) /*⇒2,type,[]*/BB + +/*⇒3,keyword,[]*/var /*⇒1,variable,[definition]*/a /*⇒4,keyword,[]*/chan/*⇒2,operator,[]*/<- /*⇒4,keyword,[]*/chan /*⇒3,type,[defaultLibrary]*/int +/*⇒3,keyword,[]*/var /*⇒1,variable,[definition]*/b /*⇒4,keyword,[]*/chan/*⇒2,operator,[]*/<- /*⇒2,operator,[]*/<-/*⇒4,keyword,[]*/chan /*⇒3,type,[defaultLibrary]*/int +/*⇒3,keyword,[]*/var /*⇒1,variable,[definition]*/c /*⇒2,operator,[]*/<-/*⇒4,keyword,[]*/chan /*⇒2,operator,[]*/<-/*⇒4,keyword,[]*/chan /*⇒3,type,[defaultLibrary]*/int + diff --git a/gopls/internal/lsp/testdata/semantic/semantic_test.go b/gopls/internal/lsp/testdata/semantic/semantic_test.go new file mode 100644 index 000000000..63d59f666 --- /dev/null +++ b/gopls/internal/lsp/testdata/semantic/semantic_test.go @@ -0,0 +1,13 @@ +package semantictokens + +import ( + "os" + "testing" +) + +func TestSemanticTokens(t *testing.T) { + a, _ := os.Getwd() + // climb up to find internal/lsp + // find all the .go files + +} diff --git a/gopls/internal/lsp/testdata/signature/signature.go b/gopls/internal/lsp/testdata/signature/signature.go new file mode 100644 index 000000000..4e2b12bc4 --- /dev/null +++ b/gopls/internal/lsp/testdata/signature/signature.go @@ -0,0 +1,85 @@ +// Package signature has tests for signature help. +package signature + +import ( + "bytes" + "encoding/json" + "math/big" +) + +func Foo(a string, b int) (c bool) { + return +} + +func Bar(float64, ...byte) { +} + +type myStruct struct{} + +func (*myStruct) foo(e *json.Decoder) (*big.Int, error) { + return nil, nil +} + +type MyType struct{} + +type MyFunc func(foo int) string + +type Alias = int +type OtherAlias = int +type StringAlias = string + +func AliasSlice(a []*Alias) (b Alias) { return 0 } +func AliasMap(a map[*Alias]StringAlias) (b, c map[*Alias]StringAlias) { return nil, nil } +func OtherAliasMap(a, b map[Alias]OtherAlias) map[Alias]OtherAlias { return nil } + +func Qux() { + Foo("foo", 123) //@signature("(", "Foo(a string, b int) (c bool)", 0) + Foo("foo", 123) //@signature("123", "Foo(a string, b int) (c bool)", 1) + Foo("foo", 123) //@signature(",", "Foo(a string, b int) (c bool)", 0) + Foo("foo", 123) //@signature(" 1", "Foo(a string, b int) (c bool)", 1) + Foo("foo", 123) //@signature(")", "Foo(a string, b int) (c bool)", 1) + + Bar(13.37, 0x13) //@signature("13.37", "Bar(float64, ...byte)", 0) + Bar(13.37, 0x37) //@signature("0x37", "Bar(float64, ...byte)", 1) + Bar(13.37, 1, 2, 3, 4) //@signature("4", "Bar(float64, ...byte)", 1) + + fn := func(hi, there string) func(i int) rune { + return func(int) rune { return 0 } + } + + fn("hi", "there") //@signature("hi", "", 0) + fn("hi", "there") //@signature(",", "fn(hi string, there string) func(i int) rune", 0) + fn("hi", "there")(1) //@signature("1", "func(i int) rune", 0) + + fnPtr := &fn + (*fnPtr)("hi", "there") //@signature(",", "func(hi string, there string) func(i int) rune", 0) + + var fnIntf interface{} = Foo + fnIntf.(func(string, int) bool)("hi", 123) //@signature("123", "func(string, int) bool", 1) + + (&bytes.Buffer{}).Next(2) //@signature("2", "Next(n int) []byte", 0) + + myFunc := MyFunc(func(n int) string { return "" }) + myFunc(123) //@signature("123", "myFunc(foo int) string", 0) + + var ms myStruct + ms.foo(nil) //@signature("nil", "foo(e *json.Decoder) (*big.Int, error)", 0) + + _ = make([]int, 1, 2) //@signature("2", "make(t Type, size ...int) Type", 1) + + Foo(myFunc(123), 456) //@signature("myFunc", "Foo(a string, b int) (c bool)", 0) + Foo(myFunc(123), 456) //@signature("123", "myFunc(foo int) string", 0) + + panic("oops!") //@signature(")", "panic(v interface{})", 0) + println("hello", "world") //@signature(",", "println(args ...Type)", 0) + + Hello(func() { + //@signature("//", "", 0) + }) + + AliasSlice() //@signature(")", "AliasSlice(a []*Alias) (b Alias)", 0) + AliasMap() //@signature(")", "AliasMap(a map[*Alias]StringAlias) (b map[*Alias]StringAlias, c map[*Alias]StringAlias)", 0) + OtherAliasMap() //@signature(")", "OtherAliasMap(a map[Alias]OtherAlias, b map[Alias]OtherAlias) map[Alias]OtherAlias", 0) +} + +func Hello(func()) {} diff --git a/gopls/internal/lsp/testdata/signature/signature.go.golden b/gopls/internal/lsp/testdata/signature/signature.go.golden new file mode 100644 index 000000000..90a4facf9 --- /dev/null +++ b/gopls/internal/lsp/testdata/signature/signature.go.golden @@ -0,0 +1,53 @@ +-- AliasMap(a map[*Alias]StringAlias) (b map[*Alias]StringAlias, c map[*Alias]StringAlias)-signature -- +AliasMap(a map[*Alias]StringAlias) (b map[*Alias]StringAlias, c map[*Alias]StringAlias) + +-- AliasSlice(a []*Alias) (b Alias)-signature -- +AliasSlice(a []*Alias) (b Alias) + +-- Bar(float64, ...byte)-signature -- +Bar(float64, ...byte) + +-- Foo(a string, b int) (c bool)-signature -- +Foo(a string, b int) (c bool) + +-- Next(n int) []byte-signature -- +Next(n int) []byte + +Next returns a slice containing the next n bytes from the buffer, advancing the buffer as if the bytes had been returned by Read. + +-- OtherAliasMap(a map[Alias]OtherAlias, b map[Alias]OtherAlias) map[Alias]OtherAlias-signature -- +OtherAliasMap(a map[Alias]OtherAlias, b map[Alias]OtherAlias) map[Alias]OtherAlias + +-- fn(hi string, there string) func(i int) rune-signature -- +fn(hi string, there string) func(i int) rune + +-- foo(e *json.Decoder) (*big.Int, error)-signature -- +foo(e *json.Decoder) (*big.Int, error) + +-- func(hi string, there string) func(i int) rune-signature -- +func(hi string, there string) func(i int) rune + +-- func(i int) rune-signature -- +func(i int) rune + +-- func(string, int) bool-signature -- +func(string, int) bool + +-- make(t Type, size ...int) Type-signature -- +make(t Type, size ...int) Type + +The make built-in function allocates and initializes an object of type slice, map, or chan (only). + +-- myFunc(foo int) string-signature -- +myFunc(foo int) string + +-- panic(v interface{})-signature -- +panic(v any) + +The panic built-in function stops normal execution of the current goroutine. + +-- println(args ...Type)-signature -- +println(args ...Type) + +The println built-in function formats its arguments in an implementation-specific way and writes the result to standard error. + diff --git a/gopls/internal/lsp/testdata/signature/signature2.go.golden b/gopls/internal/lsp/testdata/signature/signature2.go.golden new file mode 100644 index 000000000..e8102584f --- /dev/null +++ b/gopls/internal/lsp/testdata/signature/signature2.go.golden @@ -0,0 +1,3 @@ +-- Foo(a string, b int) (c bool)-signature -- +Foo(a string, b int) (c bool) + diff --git a/gopls/internal/lsp/testdata/signature/signature2.go.in b/gopls/internal/lsp/testdata/signature/signature2.go.in new file mode 100644 index 000000000..16355ffc0 --- /dev/null +++ b/gopls/internal/lsp/testdata/signature/signature2.go.in @@ -0,0 +1,5 @@ +package signature + +func _() { + Foo(//@signature("//", "Foo(a string, b int) (c bool)", 0) +} diff --git a/gopls/internal/lsp/testdata/signature/signature3.go.golden b/gopls/internal/lsp/testdata/signature/signature3.go.golden new file mode 100644 index 000000000..e8102584f --- /dev/null +++ b/gopls/internal/lsp/testdata/signature/signature3.go.golden @@ -0,0 +1,3 @@ +-- Foo(a string, b int) (c bool)-signature -- +Foo(a string, b int) (c bool) + diff --git a/gopls/internal/lsp/testdata/signature/signature3.go.in b/gopls/internal/lsp/testdata/signature/signature3.go.in new file mode 100644 index 000000000..032be1304 --- /dev/null +++ b/gopls/internal/lsp/testdata/signature/signature3.go.in @@ -0,0 +1,5 @@ +package signature + +func _() { + Foo("hello",//@signature("//", "Foo(a string, b int) (c bool)", 1) +}
\ No newline at end of file diff --git a/gopls/internal/lsp/testdata/signature/signature_test.go b/gopls/internal/lsp/testdata/signature/signature_test.go new file mode 100644 index 000000000..500247dbd --- /dev/null +++ b/gopls/internal/lsp/testdata/signature/signature_test.go @@ -0,0 +1,13 @@ +package signature_test + +import ( + "testing" + + sig "golang.org/lsptests/signature" +) + +func TestSignature(t *testing.T) { + sig.AliasSlice() //@signature(")", "AliasSlice(a []*sig.Alias) (b sig.Alias)", 0) + sig.AliasMap() //@signature(")", "AliasMap(a map[*sig.Alias]sig.StringAlias) (b map[*sig.Alias]sig.StringAlias, c map[*sig.Alias]sig.StringAlias)", 0) + sig.OtherAliasMap() //@signature(")", "OtherAliasMap(a map[sig.Alias]sig.OtherAlias, b map[sig.Alias]sig.OtherAlias) map[sig.Alias]sig.OtherAlias", 0) +} diff --git a/gopls/internal/lsp/testdata/signature/signature_test.go.golden b/gopls/internal/lsp/testdata/signature/signature_test.go.golden new file mode 100644 index 000000000..9e6561ac5 --- /dev/null +++ b/gopls/internal/lsp/testdata/signature/signature_test.go.golden @@ -0,0 +1,9 @@ +-- AliasMap(a map[*sig.Alias]sig.StringAlias) (b map[*sig.Alias]sig.StringAlias, c map[*sig.Alias]sig.StringAlias)-signature -- +AliasMap(a map[*sig.Alias]sig.StringAlias) (b map[*sig.Alias]sig.StringAlias, c map[*sig.Alias]sig.StringAlias) + +-- AliasSlice(a []*sig.Alias) (b sig.Alias)-signature -- +AliasSlice(a []*sig.Alias) (b sig.Alias) + +-- OtherAliasMap(a map[sig.Alias]sig.OtherAlias, b map[sig.Alias]sig.OtherAlias) map[sig.Alias]sig.OtherAlias-signature -- +OtherAliasMap(a map[sig.Alias]sig.OtherAlias, b map[sig.Alias]sig.OtherAlias) map[sig.Alias]sig.OtherAlias + diff --git a/gopls/internal/lsp/testdata/snippets/func_snippets118.go.in b/gopls/internal/lsp/testdata/snippets/func_snippets118.go.in new file mode 100644 index 000000000..d4933689d --- /dev/null +++ b/gopls/internal/lsp/testdata/snippets/func_snippets118.go.in @@ -0,0 +1,19 @@ +// +build go1.18 +//go:build go1.18 + +package snippets + +type SyncMap[K comparable, V any] struct{} + +func NewSyncMap[K comparable, V any]() (result *SyncMap[K, V]) { //@item(NewSyncMap, "NewSyncMap", "", "") + return +} + +func Identity[P ~int](p P) P { //@item(Identity, "Identity", "", "") + return p +} + +func _() { + _ = NewSyncM //@snippet(" //", NewSyncMap, "NewSyncMap[${1:}]()", "NewSyncMap[${1:K comparable}, ${2:V any}]()") + _ = Identi //@snippet(" //", Identity, "Identity[${1:}](${2:})", "Identity[${1:P ~int}](${2:p P})") +} diff --git a/gopls/internal/lsp/testdata/snippets/literal.go b/gopls/internal/lsp/testdata/snippets/literal.go new file mode 100644 index 000000000..fbb642f08 --- /dev/null +++ b/gopls/internal/lsp/testdata/snippets/literal.go @@ -0,0 +1,22 @@ +package snippets + +import ( + "golang.org/lsptests/signature" + t "golang.org/lsptests/types" +) + +type structy struct { + x signature.MyType +} + +func X(_ map[signature.Alias]t.CoolAlias) (map[signature.Alias]t.CoolAlias) { + return nil +} + +func _() { + X() //@signature(")", "X(_ map[signature.Alias]t.CoolAlias) map[signature.Alias]t.CoolAlias", 0) + _ = signature.MyType{} //@item(literalMyType, "signature.MyType{}", "", "var") + s := structy{ + x: //@snippet(" //", literalMyType, "signature.MyType{\\}", "signature.MyType{\\}") + } +}
\ No newline at end of file diff --git a/gopls/internal/lsp/testdata/snippets/literal.go.golden b/gopls/internal/lsp/testdata/snippets/literal.go.golden new file mode 100644 index 000000000..c91e5e9e0 --- /dev/null +++ b/gopls/internal/lsp/testdata/snippets/literal.go.golden @@ -0,0 +1,3 @@ +-- X(_ map[signature.Alias]t.CoolAlias) map[signature.Alias]t.CoolAlias-signature -- +X(_ map[signature.Alias]t.CoolAlias) map[signature.Alias]t.CoolAlias + diff --git a/gopls/internal/lsp/testdata/snippets/literal_snippets.go.in b/gopls/internal/lsp/testdata/snippets/literal_snippets.go.in new file mode 100644 index 000000000..c6e6c0fbd --- /dev/null +++ b/gopls/internal/lsp/testdata/snippets/literal_snippets.go.in @@ -0,0 +1,233 @@ +package snippets + +import ( + "bytes" + "context" + "go/ast" + "net/http" + "sort" + + "golang.org/lsptests/foo" +) + +func _() { + []int{} //@item(litIntSlice, "[]int{}", "", "var") + &[]int{} //@item(litIntSliceAddr, "&[]int{}", "", "var") + make([]int, 0) //@item(makeIntSlice, "make([]int, 0)", "", "func") + + var _ *[]int = in //@snippet(" //", litIntSliceAddr, "&[]int{$0\\}", "&[]int{$0\\}") + var _ **[]int = in //@complete(" //") + + var slice []int + slice = i //@snippet(" //", litIntSlice, "[]int{$0\\}", "[]int{$0\\}") + slice = m //@snippet(" //", makeIntSlice, "make([]int, ${1:})", "make([]int, ${1:0})") +} + +func _() { + type namedInt []int + + namedInt{} //@item(litNamedSlice, "namedInt{}", "", "var") + make(namedInt, 0) //@item(makeNamedSlice, "make(namedInt, 0)", "", "func") + + var namedSlice namedInt + namedSlice = n //@snippet(" //", litNamedSlice, "namedInt{$0\\}", "namedInt{$0\\}") + namedSlice = m //@snippet(" //", makeNamedSlice, "make(namedInt, ${1:})", "make(namedInt, ${1:0})") +} + +func _() { + make(chan int) //@item(makeChan, "make(chan int)", "", "func") + + var ch chan int + ch = m //@snippet(" //", makeChan, "make(chan int)", "make(chan int)") +} + +func _() { + map[string]struct{}{} //@item(litMap, "map[string]struct{}{}", "", "var") + make(map[string]struct{}) //@item(makeMap, "make(map[string]struct{})", "", "func") + + var m map[string]struct{} + m = m //@snippet(" //", litMap, "map[string]struct{\\}{$0\\}", "map[string]struct{\\}{$0\\}") + m = m //@snippet(" //", makeMap, "make(map[string]struct{\\})", "make(map[string]struct{\\})") + + struct{}{} //@item(litEmptyStruct, "struct{}{}", "", "var") + + m["hi"] = s //@snippet(" //", litEmptyStruct, "struct{\\}{\\}", "struct{\\}{\\}") +} + +func _() { + type myStruct struct{ i int } //@item(myStructType, "myStruct", "struct{...}", "struct") + + myStruct{} //@item(litStruct, "myStruct{}", "", "var") + &myStruct{} //@item(litStructPtr, "&myStruct{}", "", "var") + + var ms myStruct + ms = m //@snippet(" //", litStruct, "myStruct{$0\\}", "myStruct{$0\\}") + + var msPtr *myStruct + msPtr = m //@snippet(" //", litStructPtr, "&myStruct{$0\\}", "&myStruct{$0\\}") + + msPtr = &m //@snippet(" //", litStruct, "myStruct{$0\\}", "myStruct{$0\\}") + + type myStructCopy struct { i int } //@item(myStructCopyType, "myStructCopy", "struct{...}", "struct") + + // Don't offer literal completion for convertible structs. + ms = myStruct //@complete(" //", litStruct, myStructType, myStructCopyType) +} + +type myImpl struct{} + +func (myImpl) foo() {} + +func (*myImpl) bar() {} + +type myBasicImpl string + +func (myBasicImpl) foo() {} + +func _() { + type myIntf interface { + foo() + } + + myImpl{} //@item(litImpl, "myImpl{}", "", "var") + + var mi myIntf + mi = m //@snippet(" //", litImpl, "myImpl{\\}", "myImpl{\\}") + + myBasicImpl() //@item(litBasicImpl, "myBasicImpl()", "string", "var") + + mi = m //@snippet(" //", litBasicImpl, "myBasicImpl($0)", "myBasicImpl($0)") + + // only satisfied by pointer to myImpl + type myPtrIntf interface { + bar() + } + + &myImpl{} //@item(litImplPtr, "&myImpl{}", "", "var") + + var mpi myPtrIntf + mpi = m //@snippet(" //", litImplPtr, "&myImpl{\\}", "&myImpl{\\}") +} + +func _() { + var s struct{ i []int } //@item(litSliceField, "i", "[]int", "field") + var foo []int + // no literal completions after selector + foo = s.i //@complete(" //", litSliceField) +} + +func _() { + type myStruct struct{ i int } //@item(litMyStructType, "myStruct", "struct{...}", "struct") + myStruct{} //@item(litMyStruct, "myStruct{}", "", "var") + + foo := func(s string, args ...myStruct) {} + // Don't give literal slice candidate for variadic arg. + // Do give literal candidates for variadic element. + foo("", myStruct) //@complete(")", litMyStruct, litMyStructType) +} + +func _() { + Buffer{} //@item(litBuffer, "Buffer{}", "", "var") + + var b *bytes.Buffer + b = bytes.Bu //@snippet(" //", litBuffer, "Buffer{\\}", "Buffer{\\}") +} + +func _() { + _ = "func(...) {}" //@item(litFunc, "func(...) {}", "", "var") + + sort.Slice(nil, fun) //@complete(")", litFunc),snippet(")", litFunc, "func(i, j int) bool {$0\\}", "func(i, j int) bool {$0\\}") + + http.HandleFunc("", f) //@snippet(")", litFunc, "func(w http.ResponseWriter, r *http.Request) {$0\\}", "func(${1:w} http.ResponseWriter, ${2:r} *http.Request) {$0\\}") + + // no literal "func" completions + http.Handle("", fun) //@complete(")") + + http.HandlerFunc() //@item(handlerFunc, "http.HandlerFunc()", "", "var") + http.Handle("", h) //@snippet(")", handlerFunc, "http.HandlerFunc($0)", "http.HandlerFunc($0)") + http.Handle("", http.HandlerFunc()) //@snippet("))", litFunc, "func(w http.ResponseWriter, r *http.Request) {$0\\}", "func(${1:w} http.ResponseWriter, ${2:r} *http.Request) {$0\\}") + + var namedReturn func(s string) (b bool) + namedReturn = f //@snippet(" //", litFunc, "func(s string) (b bool) {$0\\}", "func(s string) (b bool) {$0\\}") + + var multiReturn func() (bool, int) + multiReturn = f //@snippet(" //", litFunc, "func() (bool, int) {$0\\}", "func() (bool, int) {$0\\}") + + var multiNamedReturn func() (b bool, i int) + multiNamedReturn = f //@snippet(" //", litFunc, "func() (b bool, i int) {$0\\}", "func() (b bool, i int) {$0\\}") + + var duplicateParams func(myImpl, int, myImpl) + duplicateParams = f //@snippet(" //", litFunc, "func(mi1 myImpl, i int, mi2 myImpl) {$0\\}", "func(${1:mi1} myImpl, ${2:i} int, ${3:mi2} myImpl) {$0\\}") + + type aliasImpl = myImpl + var aliasParams func(aliasImpl) aliasImpl + aliasParams = f //@snippet(" //", litFunc, "func(ai aliasImpl) aliasImpl {$0\\}", "func(${1:ai} aliasImpl) aliasImpl {$0\\}") + + const two = 2 + var builtinTypes func([]int, [two]bool, map[string]string, struct{ i int }, interface{ foo() }, <-chan int) + builtinTypes = f //@snippet(" //", litFunc, "func(i1 []int, b [two]bool, m map[string]string, s struct{ i int \\}, i2 interface{ foo() \\}, c <-chan int) {$0\\}", "func(${1:i1} []int, ${2:b} [two]bool, ${3:m} map[string]string, ${4:s} struct{ i int \\}, ${5:i2} interface{ foo() \\}, ${6:c} <-chan int) {$0\\}") + + var _ func(ast.Node) = f //@snippet(" //", litFunc, "func(n ast.Node) {$0\\}", "func(${1:n} ast.Node) {$0\\}") + var _ func(error) = f //@snippet(" //", litFunc, "func(err error) {$0\\}", "func(${1:err} error) {$0\\}") + var _ func(context.Context) = f //@snippet(" //", litFunc, "func(ctx context.Context) {$0\\}", "func(${1:ctx} context.Context) {$0\\}") + + type context struct {} + var _ func(context) = f //@snippet(" //", litFunc, "func(ctx context) {$0\\}", "func(${1:ctx} context) {$0\\}") +} + +func _() { + StructFoo{} //@item(litStructFoo, "StructFoo{}", "struct{...}", "struct") + + var sfp *foo.StructFoo + // Don't insert the "&" before "StructFoo{}". + sfp = foo.Str //@snippet(" //", litStructFoo, "StructFoo{$0\\}", "StructFoo{$0\\}") + + var sf foo.StructFoo + sf = foo.Str //@snippet(" //", litStructFoo, "StructFoo{$0\\}", "StructFoo{$0\\}") + sf = foo. //@snippet(" //", litStructFoo, "StructFoo{$0\\}", "StructFoo{$0\\}") +} + +func _() { + float64() //@item(litFloat64, "float64()", "float64", "var") + + // don't complete to "&float64()" + var _ *float64 = float64 //@complete(" //") + + var f float64 + f = fl //@complete(" //", litFloat64),snippet(" //", litFloat64, "float64($0)", "float64($0)") + + type myInt int + myInt() //@item(litMyInt, "myInt()", "", "var") + + var mi myInt + mi = my //@snippet(" //", litMyInt, "myInt($0)", "myInt($0)") +} + +func _() { + type ptrStruct struct { + p *ptrStruct + } + + ptrStruct{} //@item(litPtrStruct, "ptrStruct{}", "", "var") + + ptrStruct{ + p: &ptrSt, //@rank(",", litPtrStruct) + } + + &ptrStruct{} //@item(litPtrStructPtr, "&ptrStruct{}", "", "var") + + &ptrStruct{ + p: ptrSt, //@rank(",", litPtrStructPtr) + } +} + +func _() { + f := func(...[]int) {} + f() //@snippet(")", litIntSlice, "[]int{$0\\}", "[]int{$0\\}") +} + + +func _() { + // don't complete to "untyped int()" + []int{}[untyped] //@complete("] //") +} diff --git a/gopls/internal/lsp/testdata/snippets/literal_snippets118.go.in b/gopls/internal/lsp/testdata/snippets/literal_snippets118.go.in new file mode 100644 index 000000000..8251a6384 --- /dev/null +++ b/gopls/internal/lsp/testdata/snippets/literal_snippets118.go.in @@ -0,0 +1,14 @@ +// +build go1.18 +//go:build go1.18 + +package snippets + +type Tree[T any] struct{} + +func (tree Tree[T]) Do(f func(s T)) {} + +func _() { + _ = "func(...) {}" //@item(litFunc, "func(...) {}", "", "var") + var t Tree[string] + t.Do(fun) //@complete(")", litFunc),snippet(")", litFunc, "func(s string) {$0\\}", "func(s string) {$0\\}") +} diff --git a/gopls/internal/lsp/testdata/snippets/postfix.go b/gopls/internal/lsp/testdata/snippets/postfix.go new file mode 100644 index 000000000..d29694e83 --- /dev/null +++ b/gopls/internal/lsp/testdata/snippets/postfix.go @@ -0,0 +1,42 @@ +package snippets + +// These tests check that postfix completions do and do not show up in +// certain cases. Tests for the postfix completion contents are under +// regtest. + +func _() { + /* append! */ //@item(postfixAppend, "append!", "append and re-assign slice", "snippet") + var foo []int + foo.append //@rank(" //", postfixAppend) + + []int{}.append //@complete(" //") + + []int{}.last //@complete(" //") + + /* copy! */ //@item(postfixCopy, "copy!", "duplicate slice", "snippet") + + foo.copy //@rank(" //", postfixCopy) + + var s struct{ i []int } + s.i.copy //@rank(" //", postfixCopy) + + var _ []int = s.i.copy //@complete(" //") + + var blah func() []int + blah().append //@complete(" //") +} + +func _() { + /* append! */ //@item(postfixAppend, "append!", "append and re-assign slice", "snippet") + /* last! */ //@item(postfixLast, "last!", "s[len(s)-1]", "snippet") + /* print! */ //@item(postfixPrint, "print!", "print to stdout", "snippet") + /* range! */ //@item(postfixRange, "range!", "range over slice", "snippet") + /* reverse! */ //@item(postfixReverse, "reverse!", "reverse slice", "snippet") + /* sort! */ //@item(postfixSort, "sort!", "sort.Slice()", "snippet") + /* var! */ //@item(postfixVar, "var!", "assign to variable", "snippet") + + var foo []int + foo. //@complete(" //", postfixAppend, postfixCopy, postfixLast, postfixPrint, postfixRange, postfixReverse, postfixSort, postfixVar) + + foo = nil +} diff --git a/gopls/internal/lsp/testdata/snippets/snippets.go.golden b/gopls/internal/lsp/testdata/snippets/snippets.go.golden new file mode 100644 index 000000000..3f20ba50b --- /dev/null +++ b/gopls/internal/lsp/testdata/snippets/snippets.go.golden @@ -0,0 +1,3 @@ +-- baz(at AliasType, b bool)-signature -- +baz(at AliasType, b bool) + diff --git a/gopls/internal/lsp/testdata/snippets/snippets.go.in b/gopls/internal/lsp/testdata/snippets/snippets.go.in new file mode 100644 index 000000000..58150c644 --- /dev/null +++ b/gopls/internal/lsp/testdata/snippets/snippets.go.in @@ -0,0 +1,61 @@ +package snippets + +type AliasType = int //@item(sigAliasType, "AliasType", "AliasType", "type") + +func foo(i int, b bool) {} //@item(snipFoo, "foo", "func(i int, b bool)", "func") +func bar(fn func()) func() {} //@item(snipBar, "bar", "func(fn func())", "func") +func baz(at AliasType, b bool) {} //@item(snipBaz, "baz", "func(at AliasType, b bool)", "func") + +type Foo struct { + Bar int //@item(snipFieldBar, "Bar", "int", "field") + Func func(at AliasType) error //@item(snipFieldFunc, "Func", "func(at AliasType) error", "field") +} + +func (Foo) Baz() func() {} //@item(snipMethodBaz, "Baz", "func() func()", "method") +func (Foo) BazBar() func() {} //@item(snipMethodBazBar, "BazBar", "func() func()", "method") +func (Foo) BazBaz(at AliasType) func() {} //@item(snipMethodBazBaz, "BazBaz", "func(at AliasType) func()", "method") + +func _() { + f //@snippet(" //", snipFoo, "foo(${1:})", "foo(${1:i int}, ${2:b bool})") + + bar //@snippet(" //", snipBar, "bar(${1:})", "bar(${1:fn func()})") + + baz //@snippet(" //", snipBaz, "baz(${1:})", "baz(${1:at AliasType}, ${2:b bool})") + baz() //@signature("(", "baz(at AliasType, b bool)", 0) + + bar(nil) //@snippet("(", snipBar, "bar", "bar") + bar(ba) //@snippet(")", snipBar, "bar(${1:})", "bar(${1:fn func()})") + var f Foo + bar(f.Ba) //@snippet(")", snipMethodBaz, "Baz()", "Baz()") + (bar)(nil) //@snippet(")", snipBar, "bar(${1:})", "bar(${1:fn func()})") + (f.Ba)() //@snippet(")", snipMethodBaz, "Baz()", "Baz()") + + Foo{ + B //@snippet(" //", snipFieldBar, "Bar: ${1:},", "Bar: ${1:int},") + } + + Foo{ + F //@snippet(" //", snipFieldFunc, "Func: ${1:},", "Func: ${1:func(at AliasType) error},") + } + + Foo{B} //@snippet("}", snipFieldBar, "Bar: ${1:}", "Bar: ${1:int}") + Foo{} //@snippet("}", snipFieldBar, "Bar: ${1:}", "Bar: ${1:int}") + + Foo{Foo{}.B} //@snippet("} ", snipFieldBar, "Bar", "Bar") + + var err error + err.Error() //@snippet("E", Error, "Error()", "Error()") + f.Baz() //@snippet("B", snipMethodBaz, "Baz()", "Baz()") + + f.Baz() //@snippet("(", snipMethodBazBar, "BazBar", "BazBar") + + f.Baz() //@snippet("B", snipMethodBazBaz, "BazBaz(${1:})", "BazBaz(${1:at AliasType})") +} + +func _() { + type bar struct { + a int + b float64 //@item(snipBarB, "b", "float64", "field") + } + bar{b} //@snippet("}", snipBarB, "b: ${1:}", "b: ${1:float64}") +} diff --git a/gopls/internal/lsp/testdata/statements/append.go b/gopls/internal/lsp/testdata/statements/append.go new file mode 100644 index 000000000..0eea85a28 --- /dev/null +++ b/gopls/internal/lsp/testdata/statements/append.go @@ -0,0 +1,42 @@ +package statements + +func _() { + type mySlice []int + + var ( + abc []int //@item(stmtABC, "abc", "[]int", "var") + abcdef mySlice //@item(stmtABCDEF, "abcdef", "mySlice", "var") + ) + + /* abcdef = append(abcdef, ) */ //@item(stmtABCDEFAssignAppend, "abcdef = append(abcdef, )", "", "func") + + // don't offer "abc = append(abc, )" because "abc" isn't necessarily + // better than "abcdef". + abc //@complete(" //", stmtABC, stmtABCDEF) + + abcdef //@complete(" //", stmtABCDEF, stmtABCDEFAssignAppend) + + /* append(abc, ) */ //@item(stmtABCAppend, "append(abc, )", "", "func") + + abc = app //@snippet(" //", stmtABCAppend, "append(abc, ${1:})", "append(abc, ${1:})") +} + +func _() { + var s struct{ xyz []int } + + /* xyz = append(s.xyz, ) */ //@item(stmtXYZAppend, "xyz = append(s.xyz, )", "", "func") + + s.x //@snippet(" //", stmtXYZAppend, "xyz = append(s.xyz, ${1:})", "xyz = append(s.xyz, ${1:})") + + /* s.xyz = append(s.xyz, ) */ //@item(stmtDeepXYZAppend, "s.xyz = append(s.xyz, )", "", "func") + + sx //@snippet(" //", stmtDeepXYZAppend, "s.xyz = append(s.xyz, ${1:})", "s.xyz = append(s.xyz, ${1:})") +} + +func _() { + var foo [][]int + + /* append(foo[0], ) */ //@item(stmtFooAppend, "append(foo[0], )", "", "func") + + foo[0] = app //@complete(" //"),snippet(" //", stmtFooAppend, "append(foo[0], ${1:})", "append(foo[0], ${1:})") +} diff --git a/gopls/internal/lsp/testdata/statements/if_err_check_return.go b/gopls/internal/lsp/testdata/statements/if_err_check_return.go new file mode 100644 index 000000000..e82b78333 --- /dev/null +++ b/gopls/internal/lsp/testdata/statements/if_err_check_return.go @@ -0,0 +1,27 @@ +package statements + +import ( + "bytes" + "io" + "os" +) + +func one() (int, float32, io.Writer, *int, []int, bytes.Buffer, error) { + /* if err != nil { return err } */ //@item(stmtOneIfErrReturn, "if err != nil { return err }", "", "") + /* err != nil { return err } */ //@item(stmtOneErrReturn, "err != nil { return err }", "", "") + + _, err := os.Open("foo") + //@snippet("", stmtOneIfErrReturn, "", "if err != nil {\n\treturn 0, 0, nil, nil, nil, bytes.Buffer{\\}, ${1:err}\n\\}") + + _, err = os.Open("foo") + i //@snippet(" //", stmtOneIfErrReturn, "", "if err != nil {\n\treturn 0, 0, nil, nil, nil, bytes.Buffer{\\}, ${1:err}\n\\}") + + _, err = os.Open("foo") + if er //@snippet(" //", stmtOneErrReturn, "", "err != nil {\n\treturn 0, 0, nil, nil, nil, bytes.Buffer{\\}, ${1:err}\n\\}") + + _, err = os.Open("foo") + if //@snippet(" //", stmtOneIfErrReturn, "", "if err != nil {\n\treturn 0, 0, nil, nil, nil, bytes.Buffer{\\}, ${1:err}\n\\}") + + _, err = os.Open("foo") + if //@snippet("//", stmtOneIfErrReturn, "", "if err != nil {\n\treturn 0, 0, nil, nil, nil, bytes.Buffer{\\}, ${1:err}\n\\}") +} diff --git a/gopls/internal/lsp/testdata/statements/if_err_check_return_2.go b/gopls/internal/lsp/testdata/statements/if_err_check_return_2.go new file mode 100644 index 000000000..e2dce804f --- /dev/null +++ b/gopls/internal/lsp/testdata/statements/if_err_check_return_2.go @@ -0,0 +1,12 @@ +package statements + +import "os" + +func two() error { + var s struct{ err error } + + /* if s.err != nil { return s.err } */ //@item(stmtTwoIfErrReturn, "if s.err != nil { return s.err }", "", "") + + _, s.err = os.Open("foo") + //@snippet("", stmtTwoIfErrReturn, "", "if s.err != nil {\n\treturn ${1:s.err}\n\\}") +} diff --git a/gopls/internal/lsp/testdata/statements/if_err_check_test.go b/gopls/internal/lsp/testdata/statements/if_err_check_test.go new file mode 100644 index 000000000..6de587879 --- /dev/null +++ b/gopls/internal/lsp/testdata/statements/if_err_check_test.go @@ -0,0 +1,20 @@ +package statements + +import ( + "os" + "testing" +) + +func TestErr(t *testing.T) { + /* if err != nil { t.Fatal(err) } */ //@item(stmtOneIfErrTFatal, "if err != nil { t.Fatal(err) }", "", "") + + _, err := os.Open("foo") + //@snippet("", stmtOneIfErrTFatal, "", "if err != nil {\n\tt.Fatal(err)\n\\}") +} + +func BenchmarkErr(b *testing.B) { + /* if err != nil { b.Fatal(err) } */ //@item(stmtOneIfErrBFatal, "if err != nil { b.Fatal(err) }", "", "") + + _, err := os.Open("foo") + //@snippet("", stmtOneIfErrBFatal, "", "if err != nil {\n\tb.Fatal(err)\n\\}") +} diff --git a/gopls/internal/lsp/testdata/stub/other/other.go b/gopls/internal/lsp/testdata/stub/other/other.go new file mode 100644 index 000000000..ba3c1747a --- /dev/null +++ b/gopls/internal/lsp/testdata/stub/other/other.go @@ -0,0 +1,10 @@ +package other + +import ( + "bytes" + renamed_context "context" +) + +type Interface interface { + Get(renamed_context.Context) *bytes.Buffer +} diff --git a/gopls/internal/lsp/testdata/stub/stub_add_selector.go b/gopls/internal/lsp/testdata/stub/stub_add_selector.go new file mode 100644 index 000000000..4037b7ad3 --- /dev/null +++ b/gopls/internal/lsp/testdata/stub/stub_add_selector.go @@ -0,0 +1,12 @@ +package stub + +import "io" + +// This file tests that if an interface +// method references a type from its own package +// then our implementation must add the import/package selector +// in the concrete method if the concrete type is outside of the interface +// package +var _ io.ReaderFrom = &readerFrom{} //@suggestedfix("&readerFrom", "refactor.rewrite", "") + +type readerFrom struct{} diff --git a/gopls/internal/lsp/testdata/stub/stub_add_selector.go.golden b/gopls/internal/lsp/testdata/stub/stub_add_selector.go.golden new file mode 100644 index 000000000..8f08ca1ef --- /dev/null +++ b/gopls/internal/lsp/testdata/stub/stub_add_selector.go.golden @@ -0,0 +1,19 @@ +-- suggestedfix_stub_add_selector_10_23 -- +package stub + +import "io" + +// This file tests that if an interface +// method references a type from its own package +// then our implementation must add the import/package selector +// in the concrete method if the concrete type is outside of the interface +// package +var _ io.ReaderFrom = &readerFrom{} //@suggestedfix("&readerFrom", "refactor.rewrite", "") + +type readerFrom struct{} + +// ReadFrom implements io.ReaderFrom +func (*readerFrom) ReadFrom(r io.Reader) (n int64, err error) { + panic("unimplemented") +} + diff --git a/gopls/internal/lsp/testdata/stub/stub_assign.go b/gopls/internal/lsp/testdata/stub/stub_assign.go new file mode 100644 index 000000000..d3f09313f --- /dev/null +++ b/gopls/internal/lsp/testdata/stub/stub_assign.go @@ -0,0 +1,10 @@ +package stub + +import "io" + +func main() { + var br io.ByteWriter + br = &byteWriter{} //@suggestedfix("&", "refactor.rewrite", "") +} + +type byteWriter struct{} diff --git a/gopls/internal/lsp/testdata/stub/stub_assign.go.golden b/gopls/internal/lsp/testdata/stub/stub_assign.go.golden new file mode 100644 index 000000000..f15354241 --- /dev/null +++ b/gopls/internal/lsp/testdata/stub/stub_assign.go.golden @@ -0,0 +1,17 @@ +-- suggestedfix_stub_assign_7_7 -- +package stub + +import "io" + +func main() { + var br io.ByteWriter + br = &byteWriter{} //@suggestedfix("&", "refactor.rewrite", "") +} + +type byteWriter struct{} + +// WriteByte implements io.ByteWriter +func (*byteWriter) WriteByte(c byte) error { + panic("unimplemented") +} + diff --git a/gopls/internal/lsp/testdata/stub/stub_assign_multivars.go b/gopls/internal/lsp/testdata/stub/stub_assign_multivars.go new file mode 100644 index 000000000..bd36d6833 --- /dev/null +++ b/gopls/internal/lsp/testdata/stub/stub_assign_multivars.go @@ -0,0 +1,11 @@ +package stub + +import "io" + +func main() { + var br io.ByteWriter + var i int + i, br = 1, &multiByteWriter{} //@suggestedfix("&", "refactor.rewrite", "") +} + +type multiByteWriter struct{} diff --git a/gopls/internal/lsp/testdata/stub/stub_assign_multivars.go.golden b/gopls/internal/lsp/testdata/stub/stub_assign_multivars.go.golden new file mode 100644 index 000000000..425d11746 --- /dev/null +++ b/gopls/internal/lsp/testdata/stub/stub_assign_multivars.go.golden @@ -0,0 +1,18 @@ +-- suggestedfix_stub_assign_multivars_8_13 -- +package stub + +import "io" + +func main() { + var br io.ByteWriter + var i int + i, br = 1, &multiByteWriter{} //@suggestedfix("&", "refactor.rewrite", "") +} + +type multiByteWriter struct{} + +// WriteByte implements io.ByteWriter +func (*multiByteWriter) WriteByte(c byte) error { + panic("unimplemented") +} + diff --git a/gopls/internal/lsp/testdata/stub/stub_call_expr.go b/gopls/internal/lsp/testdata/stub/stub_call_expr.go new file mode 100644 index 000000000..0c3094665 --- /dev/null +++ b/gopls/internal/lsp/testdata/stub/stub_call_expr.go @@ -0,0 +1,13 @@ +package stub + +func main() { + check(&callExpr{}) //@suggestedfix("&", "refactor.rewrite", "") +} + +func check(err error) { + if err != nil { + panic(err) + } +} + +type callExpr struct{} diff --git a/gopls/internal/lsp/testdata/stub/stub_call_expr.go.golden b/gopls/internal/lsp/testdata/stub/stub_call_expr.go.golden new file mode 100644 index 000000000..c82d22440 --- /dev/null +++ b/gopls/internal/lsp/testdata/stub/stub_call_expr.go.golden @@ -0,0 +1,20 @@ +-- suggestedfix_stub_call_expr_4_8 -- +package stub + +func main() { + check(&callExpr{}) //@suggestedfix("&", "refactor.rewrite", "") +} + +func check(err error) { + if err != nil { + panic(err) + } +} + +type callExpr struct{} + +// Error implements error +func (*callExpr) Error() string { + panic("unimplemented") +} + diff --git a/gopls/internal/lsp/testdata/stub/stub_embedded.go b/gopls/internal/lsp/testdata/stub/stub_embedded.go new file mode 100644 index 000000000..f66989e9f --- /dev/null +++ b/gopls/internal/lsp/testdata/stub/stub_embedded.go @@ -0,0 +1,15 @@ +package stub + +import ( + "io" + "sort" +) + +var _ embeddedInterface = (*embeddedConcrete)(nil) //@suggestedfix("(", "refactor.rewrite", "") + +type embeddedConcrete struct{} + +type embeddedInterface interface { + sort.Interface + io.Reader +} diff --git a/gopls/internal/lsp/testdata/stub/stub_embedded.go.golden b/gopls/internal/lsp/testdata/stub/stub_embedded.go.golden new file mode 100644 index 000000000..c1ec219e9 --- /dev/null +++ b/gopls/internal/lsp/testdata/stub/stub_embedded.go.golden @@ -0,0 +1,37 @@ +-- suggestedfix_stub_embedded_8_27 -- +package stub + +import ( + "io" + "sort" +) + +var _ embeddedInterface = (*embeddedConcrete)(nil) //@suggestedfix("(", "refactor.rewrite", "") + +type embeddedConcrete struct{} + +// Len implements embeddedInterface +func (*embeddedConcrete) Len() int { + panic("unimplemented") +} + +// Less implements embeddedInterface +func (*embeddedConcrete) Less(i int, j int) bool { + panic("unimplemented") +} + +// Read implements embeddedInterface +func (*embeddedConcrete) Read(p []byte) (n int, err error) { + panic("unimplemented") +} + +// Swap implements embeddedInterface +func (*embeddedConcrete) Swap(i int, j int) { + panic("unimplemented") +} + +type embeddedInterface interface { + sort.Interface + io.Reader +} + diff --git a/gopls/internal/lsp/testdata/stub/stub_err.go b/gopls/internal/lsp/testdata/stub/stub_err.go new file mode 100644 index 000000000..121f0e794 --- /dev/null +++ b/gopls/internal/lsp/testdata/stub/stub_err.go @@ -0,0 +1,7 @@ +package stub + +func main() { + var br error = &customErr{} //@suggestedfix("&", "refactor.rewrite", "") +} + +type customErr struct{} diff --git a/gopls/internal/lsp/testdata/stub/stub_err.go.golden b/gopls/internal/lsp/testdata/stub/stub_err.go.golden new file mode 100644 index 000000000..0b441bdaa --- /dev/null +++ b/gopls/internal/lsp/testdata/stub/stub_err.go.golden @@ -0,0 +1,14 @@ +-- suggestedfix_stub_err_4_17 -- +package stub + +func main() { + var br error = &customErr{} //@suggestedfix("&", "refactor.rewrite", "") +} + +type customErr struct{} + +// Error implements error +func (*customErr) Error() string { + panic("unimplemented") +} + diff --git a/gopls/internal/lsp/testdata/stub/stub_function_return.go b/gopls/internal/lsp/testdata/stub/stub_function_return.go new file mode 100644 index 000000000..41f17645e --- /dev/null +++ b/gopls/internal/lsp/testdata/stub/stub_function_return.go @@ -0,0 +1,11 @@ +package stub + +import ( + "io" +) + +func newCloser() io.Closer { + return closer{} //@suggestedfix("c", "refactor.rewrite", "") +} + +type closer struct{} diff --git a/gopls/internal/lsp/testdata/stub/stub_function_return.go.golden b/gopls/internal/lsp/testdata/stub/stub_function_return.go.golden new file mode 100644 index 000000000..e90712e69 --- /dev/null +++ b/gopls/internal/lsp/testdata/stub/stub_function_return.go.golden @@ -0,0 +1,18 @@ +-- suggestedfix_stub_function_return_8_9 -- +package stub + +import ( + "io" +) + +func newCloser() io.Closer { + return closer{} //@suggestedfix("c", "refactor.rewrite", "") +} + +type closer struct{} + +// Close implements io.Closer +func (closer) Close() error { + panic("unimplemented") +} + diff --git a/gopls/internal/lsp/testdata/stub/stub_generic_receiver.go b/gopls/internal/lsp/testdata/stub/stub_generic_receiver.go new file mode 100644 index 000000000..1c00569ea --- /dev/null +++ b/gopls/internal/lsp/testdata/stub/stub_generic_receiver.go @@ -0,0 +1,15 @@ +//go:build go1.18 +// +build go1.18 + +package stub + +import "io" + +// This file tests that that the stub method generator accounts for concrete +// types that have type parameters defined. +var _ io.ReaderFrom = &genReader[string, int]{} //@suggestedfix("&genReader", "refactor.rewrite", "Implement io.ReaderFrom") + +type genReader[T, Y any] struct { + T T + Y Y +} diff --git a/gopls/internal/lsp/testdata/stub/stub_generic_receiver.go.golden b/gopls/internal/lsp/testdata/stub/stub_generic_receiver.go.golden new file mode 100644 index 000000000..97935d47e --- /dev/null +++ b/gopls/internal/lsp/testdata/stub/stub_generic_receiver.go.golden @@ -0,0 +1,22 @@ +-- suggestedfix_stub_generic_receiver_10_23 -- +//go:build go1.18 +// +build go1.18 + +package stub + +import "io" + +// This file tests that that the stub method generator accounts for concrete +// types that have type parameters defined. +var _ io.ReaderFrom = &genReader[string, int]{} //@suggestedfix("&genReader", "refactor.rewrite", "Implement io.ReaderFrom") + +type genReader[T, Y any] struct { + T T + Y Y +} + +// ReadFrom implements io.ReaderFrom +func (*genReader[T, Y]) ReadFrom(r io.Reader) (n int64, err error) { + panic("unimplemented") +} + diff --git a/gopls/internal/lsp/testdata/stub/stub_ignored_imports.go b/gopls/internal/lsp/testdata/stub/stub_ignored_imports.go new file mode 100644 index 000000000..ca95d2a71 --- /dev/null +++ b/gopls/internal/lsp/testdata/stub/stub_ignored_imports.go @@ -0,0 +1,18 @@ +package stub + +import ( + "compress/zlib" + . "io" + _ "io" +) + +// This file tests that dot-imports and underscore imports +// are properly ignored and that a new import is added to +// reference method types + +var ( + _ Reader + _ zlib.Resetter = (*ignoredResetter)(nil) //@suggestedfix("(", "refactor.rewrite", "") +) + +type ignoredResetter struct{} diff --git a/gopls/internal/lsp/testdata/stub/stub_ignored_imports.go.golden b/gopls/internal/lsp/testdata/stub/stub_ignored_imports.go.golden new file mode 100644 index 000000000..d4ab9d86a --- /dev/null +++ b/gopls/internal/lsp/testdata/stub/stub_ignored_imports.go.golden @@ -0,0 +1,25 @@ +-- suggestedfix_stub_ignored_imports_15_20 -- +package stub + +import ( + "compress/zlib" + . "io" + _ "io" +) + +// This file tests that dot-imports and underscore imports +// are properly ignored and that a new import is added to +// reference method types + +var ( + _ Reader + _ zlib.Resetter = (*ignoredResetter)(nil) //@suggestedfix("(", "refactor.rewrite", "") +) + +type ignoredResetter struct{} + +// Reset implements zlib.Resetter +func (*ignoredResetter) Reset(r Reader, dict []byte) error { + panic("unimplemented") +} + diff --git a/gopls/internal/lsp/testdata/stub/stub_issue2606.go b/gopls/internal/lsp/testdata/stub/stub_issue2606.go new file mode 100644 index 000000000..66ef2b24b --- /dev/null +++ b/gopls/internal/lsp/testdata/stub/stub_issue2606.go @@ -0,0 +1,7 @@ +package stub + +type I interface{ error } + +type C int + +var _ I = C(0) //@suggestedfix("C", "refactor.rewrite", "") diff --git a/gopls/internal/lsp/testdata/stub/stub_issue2606.go.golden b/gopls/internal/lsp/testdata/stub/stub_issue2606.go.golden new file mode 100644 index 000000000..4db266346 --- /dev/null +++ b/gopls/internal/lsp/testdata/stub/stub_issue2606.go.golden @@ -0,0 +1,14 @@ +-- suggestedfix_stub_issue2606_7_11 -- +package stub + +type I interface{ error } + +type C int + +// Error implements I +func (C) Error() string { + panic("unimplemented") +} + +var _ I = C(0) //@suggestedfix("C", "refactor.rewrite", "") + diff --git a/gopls/internal/lsp/testdata/stub/stub_multi_var.go b/gopls/internal/lsp/testdata/stub/stub_multi_var.go new file mode 100644 index 000000000..06702b222 --- /dev/null +++ b/gopls/internal/lsp/testdata/stub/stub_multi_var.go @@ -0,0 +1,11 @@ +package stub + +import "io" + +// This test ensures that a variable declaration that +// has multiple values on the same line can still be +// analyzed correctly to target the interface implementation +// diagnostic. +var one, two, three io.Reader = nil, &multiVar{}, nil //@suggestedfix("&", "refactor.rewrite", "") + +type multiVar struct{} diff --git a/gopls/internal/lsp/testdata/stub/stub_multi_var.go.golden b/gopls/internal/lsp/testdata/stub/stub_multi_var.go.golden new file mode 100644 index 000000000..804c7eec6 --- /dev/null +++ b/gopls/internal/lsp/testdata/stub/stub_multi_var.go.golden @@ -0,0 +1,18 @@ +-- suggestedfix_stub_multi_var_9_38 -- +package stub + +import "io" + +// This test ensures that a variable declaration that +// has multiple values on the same line can still be +// analyzed correctly to target the interface implementation +// diagnostic. +var one, two, three io.Reader = nil, &multiVar{}, nil //@suggestedfix("&", "refactor.rewrite", "") + +type multiVar struct{} + +// Read implements io.Reader +func (*multiVar) Read(p []byte) (n int, err error) { + panic("unimplemented") +} + diff --git a/gopls/internal/lsp/testdata/stub/stub_pointer.go b/gopls/internal/lsp/testdata/stub/stub_pointer.go new file mode 100644 index 000000000..e9d8bc688 --- /dev/null +++ b/gopls/internal/lsp/testdata/stub/stub_pointer.go @@ -0,0 +1,9 @@ +package stub + +import "io" + +func getReaderFrom() io.ReaderFrom { + return &pointerImpl{} //@suggestedfix("&", "refactor.rewrite", "") +} + +type pointerImpl struct{} diff --git a/gopls/internal/lsp/testdata/stub/stub_pointer.go.golden b/gopls/internal/lsp/testdata/stub/stub_pointer.go.golden new file mode 100644 index 000000000..a4d765dd4 --- /dev/null +++ b/gopls/internal/lsp/testdata/stub/stub_pointer.go.golden @@ -0,0 +1,16 @@ +-- suggestedfix_stub_pointer_6_9 -- +package stub + +import "io" + +func getReaderFrom() io.ReaderFrom { + return &pointerImpl{} //@suggestedfix("&", "refactor.rewrite", "") +} + +type pointerImpl struct{} + +// ReadFrom implements io.ReaderFrom +func (*pointerImpl) ReadFrom(r io.Reader) (n int64, err error) { + panic("unimplemented") +} + diff --git a/gopls/internal/lsp/testdata/stub/stub_renamed_import.go b/gopls/internal/lsp/testdata/stub/stub_renamed_import.go new file mode 100644 index 000000000..54dd59801 --- /dev/null +++ b/gopls/internal/lsp/testdata/stub/stub_renamed_import.go @@ -0,0 +1,11 @@ +package stub + +import ( + "compress/zlib" + myio "io" +) + +var _ zlib.Resetter = &myIO{} //@suggestedfix("&", "refactor.rewrite", "") +var _ myio.Reader + +type myIO struct{} diff --git a/gopls/internal/lsp/testdata/stub/stub_renamed_import.go.golden b/gopls/internal/lsp/testdata/stub/stub_renamed_import.go.golden new file mode 100644 index 000000000..8182d2b36 --- /dev/null +++ b/gopls/internal/lsp/testdata/stub/stub_renamed_import.go.golden @@ -0,0 +1,18 @@ +-- suggestedfix_stub_renamed_import_8_23 -- +package stub + +import ( + "compress/zlib" + myio "io" +) + +var _ zlib.Resetter = &myIO{} //@suggestedfix("&", "refactor.rewrite", "") +var _ myio.Reader + +type myIO struct{} + +// Reset implements zlib.Resetter +func (*myIO) Reset(r myio.Reader, dict []byte) error { + panic("unimplemented") +} + diff --git a/gopls/internal/lsp/testdata/stub/stub_renamed_import_iface.go b/gopls/internal/lsp/testdata/stub/stub_renamed_import_iface.go new file mode 100644 index 000000000..0f1758685 --- /dev/null +++ b/gopls/internal/lsp/testdata/stub/stub_renamed_import_iface.go @@ -0,0 +1,13 @@ +package stub + +import ( + "golang.org/lsptests/stub/other" +) + +// This file tests that if an interface +// method references an import from its own package +// that the concrete type does not yet import, and that import happens +// to be renamed, then we prefer the renaming of the interface. +var _ other.Interface = &otherInterfaceImpl{} //@suggestedfix("&otherInterfaceImpl", "refactor.rewrite", "") + +type otherInterfaceImpl struct{} diff --git a/gopls/internal/lsp/testdata/stub/stub_renamed_import_iface.go.golden b/gopls/internal/lsp/testdata/stub/stub_renamed_import_iface.go.golden new file mode 100644 index 000000000..d9c621584 --- /dev/null +++ b/gopls/internal/lsp/testdata/stub/stub_renamed_import_iface.go.golden @@ -0,0 +1,22 @@ +-- suggestedfix_stub_renamed_import_iface_11_25 -- +package stub + +import ( + "bytes" + "context" + "golang.org/lsptests/stub/other" +) + +// This file tests that if an interface +// method references an import from its own package +// that the concrete type does not yet import, and that import happens +// to be renamed, then we prefer the renaming of the interface. +var _ other.Interface = &otherInterfaceImpl{} //@suggestedfix("&otherInterfaceImpl", "refactor.rewrite", "") + +type otherInterfaceImpl struct{} + +// Get implements other.Interface +func (*otherInterfaceImpl) Get(context.Context) *bytes.Buffer { + panic("unimplemented") +} + diff --git a/gopls/internal/lsp/testdata/stub/stub_stdlib.go b/gopls/internal/lsp/testdata/stub/stub_stdlib.go new file mode 100644 index 000000000..463cf78a3 --- /dev/null +++ b/gopls/internal/lsp/testdata/stub/stub_stdlib.go @@ -0,0 +1,9 @@ +package stub + +import ( + "io" +) + +var _ io.Writer = writer{} //@suggestedfix("w", "refactor.rewrite", "") + +type writer struct{} diff --git a/gopls/internal/lsp/testdata/stub/stub_stdlib.go.golden b/gopls/internal/lsp/testdata/stub/stub_stdlib.go.golden new file mode 100644 index 000000000..55592501a --- /dev/null +++ b/gopls/internal/lsp/testdata/stub/stub_stdlib.go.golden @@ -0,0 +1,16 @@ +-- suggestedfix_stub_stdlib_7_19 -- +package stub + +import ( + "io" +) + +var _ io.Writer = writer{} //@suggestedfix("w", "refactor.rewrite", "") + +type writer struct{} + +// Write implements io.Writer +func (writer) Write(p []byte) (n int, err error) { + panic("unimplemented") +} + diff --git a/gopls/internal/lsp/testdata/stub/stub_typedecl_group.go b/gopls/internal/lsp/testdata/stub/stub_typedecl_group.go new file mode 100644 index 000000000..f82401faf --- /dev/null +++ b/gopls/internal/lsp/testdata/stub/stub_typedecl_group.go @@ -0,0 +1,27 @@ +package stub + +// Regression test for Issue #56825: file corrupted by insertion of +// methods after TypeSpec in a parenthesized TypeDecl. + +import "io" + +func newReadCloser() io.ReadCloser { + return rdcloser{} //@suggestedfix("rd", "refactor.rewrite", "") +} + +type ( + A int + rdcloser struct{} + B int +) + +func _() { + // Local types can't be stubbed as there's nowhere to put the methods. + // The suggestedfix assertion can't express this yet. TODO(adonovan): support it. + type local struct{} + var _ io.ReadCloser = local{} // want error: `local type "local" cannot be stubbed` +} + +type ( + C int +) diff --git a/gopls/internal/lsp/testdata/stub/stub_typedecl_group.go.golden b/gopls/internal/lsp/testdata/stub/stub_typedecl_group.go.golden new file mode 100644 index 000000000..0848789ea --- /dev/null +++ b/gopls/internal/lsp/testdata/stub/stub_typedecl_group.go.golden @@ -0,0 +1,39 @@ +-- suggestedfix_stub_typedecl_group_9_9 -- +package stub + +// Regression test for Issue #56825: file corrupted by insertion of +// methods after TypeSpec in a parenthesized TypeDecl. + +import "io" + +func newReadCloser() io.ReadCloser { + return rdcloser{} //@suggestedfix("rd", "refactor.rewrite", "") +} + +type ( + A int + rdcloser struct{} + B int +) + +// Close implements io.ReadCloser +func (rdcloser) Close() error { + panic("unimplemented") +} + +// Read implements io.ReadCloser +func (rdcloser) Read(p []byte) (n int, err error) { + panic("unimplemented") +} + +func _() { + // Local types can't be stubbed as there's nowhere to put the methods. + // The suggestedfix assertion can't express this yet. TODO(adonovan): support it. + type local struct{} + var _ io.ReadCloser = local{} // want error: `local type "local" cannot be stubbed` +} + +type ( + C int +) + diff --git a/gopls/internal/lsp/testdata/suggestedfix/has_suggested_fix.go b/gopls/internal/lsp/testdata/suggestedfix/has_suggested_fix.go new file mode 100644 index 000000000..7ff524479 --- /dev/null +++ b/gopls/internal/lsp/testdata/suggestedfix/has_suggested_fix.go @@ -0,0 +1,11 @@ +package suggestedfix + +import ( + "log" +) + +func goodbye() { + s := "hiiiiiii" + s = s //@suggestedfix("s = s", "quickfix", "") + log.Print(s) +} diff --git a/gopls/internal/lsp/testdata/suggestedfix/has_suggested_fix.go.golden b/gopls/internal/lsp/testdata/suggestedfix/has_suggested_fix.go.golden new file mode 100644 index 000000000..e7e84fc22 --- /dev/null +++ b/gopls/internal/lsp/testdata/suggestedfix/has_suggested_fix.go.golden @@ -0,0 +1,13 @@ +-- suggestedfix_has_suggested_fix_9_2 -- +package suggestedfix + +import ( + "log" +) + +func goodbye() { + s := "hiiiiiii" + //@suggestedfix("s = s", "quickfix", "") + log.Print(s) +} + diff --git a/gopls/internal/lsp/testdata/summary.txt.golden b/gopls/internal/lsp/testdata/summary.txt.golden new file mode 100644 index 000000000..985361ba7 --- /dev/null +++ b/gopls/internal/lsp/testdata/summary.txt.golden @@ -0,0 +1,32 @@ +-- summary -- +CallHierarchyCount = 2 +CodeLensCount = 5 +CompletionsCount = 263 +CompletionSnippetCount = 106 +UnimportedCompletionsCount = 5 +DeepCompletionsCount = 5 +FuzzyCompletionsCount = 8 +RankedCompletionsCount = 164 +CaseSensitiveCompletionsCount = 4 +DiagnosticsCount = 42 +FoldingRangesCount = 2 +FormatCount = 6 +ImportCount = 8 +SemanticTokenCount = 3 +SuggestedFixCount = 65 +FunctionExtractionCount = 27 +MethodExtractionCount = 6 +DefinitionsCount = 47 +TypeDefinitionsCount = 18 +HighlightsCount = 69 +InlayHintsCount = 4 +ReferencesCount = 30 +RenamesCount = 41 +PrepareRenamesCount = 7 +SymbolsCount = 1 +WorkspaceSymbolsCount = 20 +SignaturesCount = 33 +LinksCount = 7 +ImplementationsCount = 16 +SelectionRangesCount = 3 + diff --git a/gopls/internal/lsp/testdata/summary_go1.18.txt.golden b/gopls/internal/lsp/testdata/summary_go1.18.txt.golden new file mode 100644 index 000000000..9ae4d1364 --- /dev/null +++ b/gopls/internal/lsp/testdata/summary_go1.18.txt.golden @@ -0,0 +1,32 @@ +-- summary -- +CallHierarchyCount = 2 +CodeLensCount = 5 +CompletionsCount = 264 +CompletionSnippetCount = 115 +UnimportedCompletionsCount = 5 +DeepCompletionsCount = 5 +FuzzyCompletionsCount = 8 +RankedCompletionsCount = 174 +CaseSensitiveCompletionsCount = 4 +DiagnosticsCount = 42 +FoldingRangesCount = 2 +FormatCount = 6 +ImportCount = 8 +SemanticTokenCount = 3 +SuggestedFixCount = 71 +FunctionExtractionCount = 27 +MethodExtractionCount = 6 +DefinitionsCount = 47 +TypeDefinitionsCount = 18 +HighlightsCount = 69 +InlayHintsCount = 5 +ReferencesCount = 30 +RenamesCount = 48 +PrepareRenamesCount = 7 +SymbolsCount = 2 +WorkspaceSymbolsCount = 20 +SignaturesCount = 33 +LinksCount = 7 +ImplementationsCount = 26 +SelectionRangesCount = 3 + diff --git a/gopls/internal/lsp/testdata/symbols/go1.18.go b/gopls/internal/lsp/testdata/symbols/go1.18.go new file mode 100644 index 000000000..cdf99dc20 --- /dev/null +++ b/gopls/internal/lsp/testdata/symbols/go1.18.go @@ -0,0 +1,16 @@ +//go:build go1.18 +// +build go1.18 + +package main + +type T[P any] struct { //@symbol("T", "T", "Struct", "struct{...}", "T", "") + F P //@symbol("F", "F", "Field", "P", "", "T") +} + +type Constraint interface { //@symbol("Constraint", "Constraint", "Interface", "interface{...}", "Constraint", "") + ~int | struct{ int } //@symbol("~int | struct{int}", "~int | struct{ int }", "Field", "", "", "Constraint") + + // TODO(rfindley): the selection range below is the entire interface field. + // Can we reduce it? + interface{ M() } //@symbol("interface{...}", "interface{ M() }", "Field", "", "iFaceField", "Constraint"), symbol("M", "M", "Method", "func()", "", "iFaceField") +} diff --git a/gopls/internal/lsp/testdata/symbols/go1.18.go.golden b/gopls/internal/lsp/testdata/symbols/go1.18.go.golden new file mode 100644 index 000000000..5a0c1a94d --- /dev/null +++ b/gopls/internal/lsp/testdata/symbols/go1.18.go.golden @@ -0,0 +1,7 @@ +-- symbols -- +T Struct 6:6-6:7 + F Field 7:2-7:3 +Constraint Interface 10:6-10:16 + interface{...} Field 15:2-15:18 + ~int | struct{int} Field 11:2-11:22 + diff --git a/gopls/internal/lsp/testdata/symbols/main.go b/gopls/internal/lsp/testdata/symbols/main.go new file mode 100644 index 000000000..65e0869fd --- /dev/null +++ b/gopls/internal/lsp/testdata/symbols/main.go @@ -0,0 +1,91 @@ +package main + +import ( + "io" +) + +// Each symbol marker in this file defines the following information: +// symbol(name, selectionSpan, kind, detail, id, parentID) +// - name: DocumentSymbol.Name +// - selectionSpan: DocumentSymbol.SelectionRange +// - kind: DocumentSymbol.Kind +// - detail: DocumentSymbol.Detail +// - id: if non-empty, a unique identifier for this symbol +// - parentID: if non-empty, the id of the parent of this symbol +// +// This data in aggregate defines a set of document symbols and their +// parent-child relationships, which is compared against the DocummentSymbols +// response from gopls for the current file. +// +// TODO(rfindley): the symbol annotations here are complicated and difficult to +// maintain. It would be simpler to just write out the full expected response +// in the golden file, perhaps as raw JSON. + +var _ = 1 + +var x = 42 //@symbol("x", "x", "Variable", "", "", "") + +var nested struct { //@symbol("nested", "nested", "Variable", "struct{...}", "nested", "") + nestedField struct { //@symbol("nestedField", "nestedField", "Field", "struct{...}", "nestedField", "nested") + f int //@symbol("f", "f", "Field", "int", "", "nestedField") + } +} + +const y = 43 //@symbol("y", "y", "Constant", "", "", "") + +type Number int //@symbol("Number", "Number", "Class", "int", "", "") + +type Alias = string //@symbol("Alias", "Alias", "Class", "string", "", "") + +type NumberAlias = Number //@symbol("NumberAlias", "NumberAlias", "Class", "Number", "", "") + +type ( + Boolean bool //@symbol("Boolean", "Boolean", "Class", "bool", "", "") + BoolAlias = bool //@symbol("BoolAlias", "BoolAlias", "Class", "bool", "", "") +) + +type Foo struct { //@symbol("Foo", "Foo", "Struct", "struct{...}", "Foo", "") + Quux //@symbol("Quux", "Quux", "Field", "Quux", "", "Foo") + W io.Writer //@symbol("W", "W", "Field", "io.Writer", "", "Foo") + Bar int //@symbol("Bar", "Bar", "Field", "int", "", "Foo") + baz string //@symbol("baz", "baz", "Field", "string", "", "Foo") + funcField func(int) int //@symbol("funcField", "funcField", "Field", "func(int) int", "", "Foo") +} + +type Quux struct { //@symbol("Quux", "Quux", "Struct", "struct{...}", "Quux", "") + X, Y float64 //@symbol("X", "X", "Field", "float64", "", "Quux"), symbol("Y", "Y", "Field", "float64", "", "Quux") +} + +type EmptyStruct struct{} //@symbol("EmptyStruct", "EmptyStruct", "Struct", "struct{}", "", "") + +func (f Foo) Baz() string { //@symbol("(Foo).Baz", "Baz", "Method", "func() string", "", "") + return f.baz +} + +func _() {} + +func (q *Quux) Do() {} //@symbol("(*Quux).Do", "Do", "Method", "func()", "", "") + +func main() { //@symbol("main", "main", "Function", "func()", "", "") +} + +type Stringer interface { //@symbol("Stringer", "Stringer", "Interface", "interface{...}", "Stringer", "") + String() string //@symbol("String", "String", "Method", "func() string", "", "Stringer") +} + +type ABer interface { //@symbol("ABer", "ABer", "Interface", "interface{...}", "ABer", "") + B() //@symbol("B", "B", "Method", "func()", "", "ABer") + A() string //@symbol("A", "A", "Method", "func() string", "", "ABer") +} + +type WithEmbeddeds interface { //@symbol("WithEmbeddeds", "WithEmbeddeds", "Interface", "interface{...}", "WithEmbeddeds", "") + Do() //@symbol("Do", "Do", "Method", "func()", "", "WithEmbeddeds") + ABer //@symbol("ABer", "ABer", "Field", "ABer", "", "WithEmbeddeds") + io.Writer //@symbol("Writer", "Writer", "Field", "io.Writer", "", "WithEmbeddeds") +} + +type EmptyInterface interface{} //@symbol("EmptyInterface", "EmptyInterface", "Interface", "interface{}", "", "") + +func Dunk() int { return 0 } //@symbol("Dunk", "Dunk", "Function", "func() int", "", "") + +func dunk() {} //@symbol("dunk", "dunk", "Function", "func()", "", "") diff --git a/gopls/internal/lsp/testdata/symbols/main.go.golden b/gopls/internal/lsp/testdata/symbols/main.go.golden new file mode 100644 index 000000000..98009b02d --- /dev/null +++ b/gopls/internal/lsp/testdata/symbols/main.go.golden @@ -0,0 +1,36 @@ +-- symbols -- +x Variable 26:5-26:6 +nested Variable 28:5-28:11 + nestedField Field 29:2-29:13 +y Constant 34:7-34:8 +Number Class 36:6-36:12 +Alias Class 38:6-38:11 +NumberAlias Class 40:6-40:17 +Boolean Class 43:2-43:9 +BoolAlias Class 44:2-44:11 +Foo Struct 47:6-47:9 + Bar Field 50:2-50:5 + Quux Field 48:2-48:6 + W Field 49:2-49:3 + baz Field 51:2-51:5 + funcField Field 52:2-52:11 +Quux Struct 55:6-55:10 + X Field 56:2-56:3 + Y Field 56:5-56:6 +EmptyStruct Struct 59:6-59:17 +(Foo).Baz Method 61:14-61:17 +(*Quux).Do Method 67:16-67:18 +main Function 69:6-69:10 +Stringer Interface 72:6-72:14 + String Method 73:2-73:8 +ABer Interface 76:6-76:10 + A Method 78:2-78:3 + B Method 77:2-77:3 +WithEmbeddeds Interface 81:6-81:19 + ABer Field 83:2-83:6 + Do Method 82:2-82:4 + Writer Field 84:5-84:11 +EmptyInterface Interface 87:6-87:20 +Dunk Function 89:6-89:10 +dunk Function 91:6-91:10 + diff --git a/gopls/internal/lsp/testdata/testy/testy.go b/gopls/internal/lsp/testdata/testy/testy.go new file mode 100644 index 000000000..1a738d7d7 --- /dev/null +++ b/gopls/internal/lsp/testdata/testy/testy.go @@ -0,0 +1,5 @@ +package testy + +func a() { //@mark(identA, "a"),item(funcA, "a", "func()", "func"),refs("a", identA, testyA) + //@complete("", funcA) +} diff --git a/gopls/internal/lsp/testdata/testy/testy_test.go b/gopls/internal/lsp/testdata/testy/testy_test.go new file mode 100644 index 000000000..a7e897840 --- /dev/null +++ b/gopls/internal/lsp/testdata/testy/testy_test.go @@ -0,0 +1,18 @@ +package testy + +import ( + "testing" + + sig "golang.org/lsptests/signature" + "golang.org/lsptests/snippets" +) + +func TestSomething(t *testing.T) { //@item(TestSomething, "TestSomething(t *testing.T)", "", "func") + var x int //@mark(testyX, "x"),diag("x", "compiler", "x declared (and|but) not used", "error"),refs("x", testyX) + a() //@mark(testyA, "a") +} + +func _() { + _ = snippets.X(nil) //@signature("nil", "X(_ map[sig.Alias]types.CoolAlias) map[sig.Alias]types.CoolAlias", 0) + var _ sig.Alias +} diff --git a/gopls/internal/lsp/testdata/testy/testy_test.go.golden b/gopls/internal/lsp/testdata/testy/testy_test.go.golden new file mode 100644 index 000000000..cafc380d0 --- /dev/null +++ b/gopls/internal/lsp/testdata/testy/testy_test.go.golden @@ -0,0 +1,3 @@ +-- X(_ map[sig.Alias]types.CoolAlias) map[sig.Alias]types.CoolAlias-signature -- +X(_ map[sig.Alias]types.CoolAlias) map[sig.Alias]types.CoolAlias + diff --git a/gopls/internal/lsp/testdata/typdef/typdef.go b/gopls/internal/lsp/testdata/typdef/typdef.go new file mode 100644 index 000000000..bd2ea4b00 --- /dev/null +++ b/gopls/internal/lsp/testdata/typdef/typdef.go @@ -0,0 +1,65 @@ +package typdef + +type Struct struct { //@item(Struct, "Struct", "struct{...}", "struct") + Field string +} + +type Int int //@item(Int, "Int", "int", "type") + +func _() { + var ( + value Struct + point *Struct + ) + _ = value //@typdef("value", Struct) + _ = point //@typdef("point", Struct) + + var ( + array [3]Struct + slice []Struct + ch chan Struct + complex [3]chan *[5][]Int + ) + _ = array //@typdef("array", Struct) + _ = slice //@typdef("slice", Struct) + _ = ch //@typdef("ch", Struct) + _ = complex //@typdef("complex", Int) + + var s struct { + x struct { + xx struct { + field1 []Struct + field2 []Int + } + } + } + s.x.xx.field1 //@typdef("field1", Struct) + s.x.xx.field2 //@typdef("field2", Int) +} + +func F1() Int { return 0 } +func F2() (Int, float64) { return 0, 0 } +func F3() (Struct, int, bool, error) { return Struct{}, 0, false, nil } +func F4() (**int, Int, bool, *error) { return nil, Struct{}, false, nil } +func F5() (int, float64, error, Struct) { return 0, 0, nil, Struct{} } +func F6() (int, float64, ***Struct, error) { return 0, 0, nil, nil } + +func _() { + F1() //@typdef("F1", Int) + F2() //@typdef("F2", Int) + F3() //@typdef("F3", Struct) + F4() //@typdef("F4", Int) + F5() //@typdef("F5", Struct) + F6() //@typdef("F6", Struct) + + f := func() Int { return 0 } + f() //@typdef("f", Int) +} + +// https://github.com/golang/go/issues/38589#issuecomment-620350922 +func _() { + type myFunc func(int) Int //@item(myFunc, "myFunc", "func", "type") + + var foo myFunc + bar := foo() //@typdef("foo", myFunc) +} diff --git a/gopls/internal/lsp/testdata/typeassert/type_assert.go b/gopls/internal/lsp/testdata/typeassert/type_assert.go new file mode 100644 index 000000000..e24b68a07 --- /dev/null +++ b/gopls/internal/lsp/testdata/typeassert/type_assert.go @@ -0,0 +1,24 @@ +package typeassert + +type abc interface { //@item(abcIntf, "abc", "interface{...}", "interface") + abc() +} + +type abcImpl struct{} //@item(abcImpl, "abcImpl", "struct{...}", "struct") +func (abcImpl) abc() + +type abcPtrImpl struct{} //@item(abcPtrImpl, "abcPtrImpl", "struct{...}", "struct") +func (*abcPtrImpl) abc() + +type abcNotImpl struct{} //@item(abcNotImpl, "abcNotImpl", "struct{...}", "struct") + +func _() { + var a abc + switch a.(type) { + case ab: //@complete(":", abcImpl, abcPtrImpl, abcIntf, abcNotImpl) + case *ab: //@complete(":", abcImpl, abcPtrImpl, abcIntf, abcNotImpl) + } + + a.(ab) //@complete(")", abcImpl, abcPtrImpl, abcIntf, abcNotImpl) + a.(*ab) //@complete(")", abcImpl, abcPtrImpl, abcIntf, abcNotImpl) +} diff --git a/gopls/internal/lsp/testdata/typeerrors/noresultvalues.go b/gopls/internal/lsp/testdata/typeerrors/noresultvalues.go new file mode 100644 index 000000000..729e7bbcc --- /dev/null +++ b/gopls/internal/lsp/testdata/typeerrors/noresultvalues.go @@ -0,0 +1,5 @@ +package typeerrors + +func x() { return nil } //@suggestedfix("nil", "quickfix", "") + +func y() { return nil, "hello" } //@suggestedfix("nil", "quickfix", "") diff --git a/gopls/internal/lsp/testdata/typeerrors/noresultvalues.go.golden b/gopls/internal/lsp/testdata/typeerrors/noresultvalues.go.golden new file mode 100644 index 000000000..48409a0b7 --- /dev/null +++ b/gopls/internal/lsp/testdata/typeerrors/noresultvalues.go.golden @@ -0,0 +1,14 @@ +-- suggestedfix_noresultvalues_3_19 -- +package typeerrors + +func x() { return } //@suggestedfix("nil", "quickfix", "") + +func y() { return nil, "hello" } //@suggestedfix("nil", "quickfix", "") + +-- suggestedfix_noresultvalues_5_19 -- +package typeerrors + +func x() { return nil } //@suggestedfix("nil", "quickfix", "") + +func y() { return } //@suggestedfix("nil", "quickfix", "") + diff --git a/gopls/internal/lsp/testdata/typemods/type_mods.go b/gopls/internal/lsp/testdata/typemods/type_mods.go new file mode 100644 index 000000000..f5f0f8076 --- /dev/null +++ b/gopls/internal/lsp/testdata/typemods/type_mods.go @@ -0,0 +1,21 @@ +package typemods + +func fooFunc() func() int { //@item(modFooFunc, "fooFunc", "func() func() int", "func") + return func() int { + return 0 + } +} + +func fooPtr() *int { //@item(modFooPtr, "fooPtr", "func() *int", "func") + return nil +} + +func _() { + var _ int = foo //@snippet(" //", modFooFunc, "fooFunc()()", "fooFunc()()"),snippet(" //", modFooPtr, "*fooPtr()", "*fooPtr()") +} + +func _() { + var m map[int][]chan int //@item(modMapChanPtr, "m", "map[int]chan *int", "var") + + var _ int = m //@snippet(" //", modMapChanPtr, "<-m[${1:}][${2:}]", "<-m[${1:}][${2:}]") +} diff --git a/gopls/internal/lsp/testdata/typeparams/type_params.go b/gopls/internal/lsp/testdata/typeparams/type_params.go new file mode 100644 index 000000000..21fc7049f --- /dev/null +++ b/gopls/internal/lsp/testdata/typeparams/type_params.go @@ -0,0 +1,61 @@ +//go:build go1.18 +// +build go1.18 + +package typeparams + +func one[a int | string]() {} +func two[a int | string, b float64 | int]() {} + +func _() { + one[]() //@rank("]", string, float64) + two[]() //@rank("]", int, float64) + two[int, f]() //@rank("]", float64, float32) +} + +func slices[a []int | []float64]() {} //@item(tpInts, "[]int", "[]int", "type"),item(tpFloats, "[]float64", "[]float64", "type") + +func _() { + slices[]() //@rank("]", tpInts),rank("]", tpFloats) +} + +type s[a int | string] struct{} + +func _() { + s[]{} //@rank("]", int, float64) +} + +func takesGeneric[a int | string](s[a]) { + "s[a]{}" //@item(tpInScopeLit, "s[a]{}", "", "var") + takesGeneric() //@rank(")", tpInScopeLit),snippet(")", tpInScopeLit, "s[a]{\\}", "s[a]{\\}") +} + +func _() { + s[int]{} //@item(tpInstLit, "s[int]{}", "", "var") + takesGeneric[int]() //@rank(")", tpInstLit),snippet(")", tpInstLit, "s[int]{\\}", "s[int]{\\}") + + "s[...]{}" //@item(tpUninstLit, "s[...]{}", "", "var") + takesGeneric() //@rank(")", tpUninstLit),snippet(")", tpUninstLit, "s[${1:}]{\\}", "s[${1:a}]{\\}") +} + +func returnTP[A int | float64](a A) A { //@item(returnTP, "returnTP", "something", "func") + return a +} + +func _() { + // disabled - see issue #54822 + var _ int = returnTP // snippet(" //", returnTP, "returnTP[${1:}](${2:})", "returnTP[${1:A int|float64}](${2:a A})") + + var aa int //@item(tpInt, "aa", "int", "var") + var ab float64 //@item(tpFloat, "ab", "float64", "var") + returnTP[int](a) //@rank(")", tpInt, tpFloat) +} + +func takesFunc[T any](func(T) T) { + var _ func(t T) T = f //@snippet(" //", tpLitFunc, "func(t T) T {$0\\}", "func(t T) T {$0\\}") +} + +func _() { + _ = "func(...) {}" //@item(tpLitFunc, "func(...) {}", "", "var") + takesFunc() //@snippet(")", tpLitFunc, "func(${1:}) ${2:} {$0\\}", "func(${1:t} ${2:T}) ${3:T} {$0\\}") + takesFunc[int]() //@snippet(")", tpLitFunc, "func(i int) int {$0\\}", "func(${1:i} int) int {$0\\}") +} diff --git a/gopls/internal/lsp/testdata/types/types.go b/gopls/internal/lsp/testdata/types/types.go new file mode 100644 index 000000000..c60d4b2e4 --- /dev/null +++ b/gopls/internal/lsp/testdata/types/types.go @@ -0,0 +1,18 @@ +package types + +type CoolAlias = int //@item(CoolAlias, "CoolAlias", "int", "type") + +type X struct { //@item(X_struct, "X", "struct{...}", "struct") + x int +} + +type Y struct { //@item(Y_struct, "Y", "struct{...}", "struct") + y int +} + +type Bob interface { //@item(Bob_interface, "Bob", "interface{...}", "interface") + Bobby() +} + +func (*X) Bobby() {} +func (*Y) Bobby() {} diff --git a/gopls/internal/lsp/testdata/undeclared/var.go b/gopls/internal/lsp/testdata/undeclared/var.go new file mode 100644 index 000000000..3fda582ce --- /dev/null +++ b/gopls/internal/lsp/testdata/undeclared/var.go @@ -0,0 +1,14 @@ +package undeclared + +func m() int { + z, _ := 1+y, 11 //@diag("y", "compiler", "(undeclared name|undefined): y", "error"),suggestedfix("y", "quickfix", "") + if 100 < 90 { + z = 1 + } else if 100 > n+2 { //@diag("n", "compiler", "(undeclared name|undefined): n", "error"),suggestedfix("n", "quickfix", "") + z = 4 + } + for i < 200 { //@diag("i", "compiler", "(undeclared name|undefined): i", "error"),suggestedfix("i", "quickfix", "") + } + r() //@diag("r", "compiler", "(undeclared name|undefined): r", "error") + return z +} diff --git a/gopls/internal/lsp/testdata/undeclared/var.go.golden b/gopls/internal/lsp/testdata/undeclared/var.go.golden new file mode 100644 index 000000000..de5cbb42f --- /dev/null +++ b/gopls/internal/lsp/testdata/undeclared/var.go.golden @@ -0,0 +1,51 @@ +-- suggestedfix_var_10_6 -- +package undeclared + +func m() int { + z, _ := 1+y, 11 //@diag("y", "compiler", "(undeclared name|undefined): y", "error"),suggestedfix("y", "quickfix", "") + if 100 < 90 { + z = 1 + } else if 100 > n+2 { //@diag("n", "compiler", "(undeclared name|undefined): n", "error"),suggestedfix("n", "quickfix", "") + z = 4 + } + i := + for i < 200 { //@diag("i", "compiler", "(undeclared name|undefined): i", "error"),suggestedfix("i", "quickfix", "") + } + r() //@diag("r", "compiler", "(undeclared name|undefined): r", "error") + return z +} + +-- suggestedfix_var_4_12 -- +package undeclared + +func m() int { + y := + z, _ := 1+y, 11 //@diag("y", "compiler", "(undeclared name|undefined): y", "error"),suggestedfix("y", "quickfix", "") + if 100 < 90 { + z = 1 + } else if 100 > n+2 { //@diag("n", "compiler", "(undeclared name|undefined): n", "error"),suggestedfix("n", "quickfix", "") + z = 4 + } + for i < 200 { //@diag("i", "compiler", "(undeclared name|undefined): i", "error"),suggestedfix("i", "quickfix", "") + } + r() //@diag("r", "compiler", "(undeclared name|undefined): r", "error") + return z +} + +-- suggestedfix_var_7_18 -- +package undeclared + +func m() int { + z, _ := 1+y, 11 //@diag("y", "compiler", "(undeclared name|undefined): y", "error"),suggestedfix("y", "quickfix", "") + n := + if 100 < 90 { + z = 1 + } else if 100 > n+2 { //@diag("n", "compiler", "(undeclared name|undefined): n", "error"),suggestedfix("n", "quickfix", "") + z = 4 + } + for i < 200 { //@diag("i", "compiler", "(undeclared name|undefined): i", "error"),suggestedfix("i", "quickfix", "") + } + r() //@diag("r", "compiler", "(undeclared name|undefined): r", "error") + return z +} + diff --git a/gopls/internal/lsp/testdata/unimported/export_test.go b/gopls/internal/lsp/testdata/unimported/export_test.go new file mode 100644 index 000000000..707768e1d --- /dev/null +++ b/gopls/internal/lsp/testdata/unimported/export_test.go @@ -0,0 +1,3 @@ +package unimported + +var TestExport int //@item(testexport, "TestExport", "var (from \"golang.org/lsptests/unimported\")", "var") diff --git a/gopls/internal/lsp/testdata/unimported/unimported.go.in b/gopls/internal/lsp/testdata/unimported/unimported.go.in new file mode 100644 index 000000000..74d51ffe8 --- /dev/null +++ b/gopls/internal/lsp/testdata/unimported/unimported.go.in @@ -0,0 +1,23 @@ +package unimported + +func _() { + http //@unimported("p", nethttp) + // container/ring is extremely unlikely to be imported by anything, so shouldn't have type information. + ring.Ring //@unimported("Ring", ringring) + signature.Foo //@unimported("Foo", signaturefoo) + + context.Bac //@unimported(" //", contextBackground) +} + +// Create markers for unimported std lib packages. Only for use by this test. +/* http */ //@item(nethttp, "http", "\"net/http\"", "package") + +/* ring.Ring */ //@item(ringring, "Ring", "(from \"container/ring\")", "var") + +/* signature.Foo */ //@item(signaturefoo, "Foo", "func (from \"golang.org/lsptests/signature\")", "func") + +/* context.Background */ //@item(contextBackground, "Background", "func (from \"context\")", "func") + +// Now that we no longer type-check imported completions, +// we don't expect the context.Background().Err method (see golang/go#58663). +/* context.Background().Err */ //@item(contextBackgroundErr, "Background().Err", "func (from \"context\")", "method") diff --git a/gopls/internal/lsp/testdata/unimported/unimported_cand_type.go b/gopls/internal/lsp/testdata/unimported/unimported_cand_type.go new file mode 100644 index 000000000..554c426a9 --- /dev/null +++ b/gopls/internal/lsp/testdata/unimported/unimported_cand_type.go @@ -0,0 +1,16 @@ +package unimported + +import ( + _ "context" + + "golang.org/lsptests/baz" + _ "golang.org/lsptests/signature" // provide type information for unimported completions in the other file +) + +func _() { + foo.StructFoo{} //@item(litFooStructFoo, "foo.StructFoo{}", "struct{...}", "struct") + + // We get the literal completion for "foo.StructFoo{}" even though we haven't + // imported "foo" yet. + baz.FooStruct = f //@snippet(" //", litFooStructFoo, "foo.StructFoo{$0\\}", "foo.StructFoo{$0\\}") +} diff --git a/gopls/internal/lsp/testdata/unimported/x_test.go b/gopls/internal/lsp/testdata/unimported/x_test.go new file mode 100644 index 000000000..681dcb253 --- /dev/null +++ b/gopls/internal/lsp/testdata/unimported/x_test.go @@ -0,0 +1,9 @@ +package unimported_test + +import ( + "testing" +) + +func TestSomething(t *testing.T) { + _ = unimported.TestExport //@unimported("TestExport", testexport) +} diff --git a/gopls/internal/lsp/testdata/unresolved/unresolved.go.in b/gopls/internal/lsp/testdata/unresolved/unresolved.go.in new file mode 100644 index 000000000..e1daecc2e --- /dev/null +++ b/gopls/internal/lsp/testdata/unresolved/unresolved.go.in @@ -0,0 +1,6 @@ +package unresolved + +func foo(interface{}) { + // don't crash on fake "resolved" type + foo(func(i, j f //@complete(" //") +} diff --git a/gopls/internal/lsp/testdata/unsafe/unsafe.go b/gopls/internal/lsp/testdata/unsafe/unsafe.go new file mode 100644 index 000000000..5d5e43407 --- /dev/null +++ b/gopls/internal/lsp/testdata/unsafe/unsafe.go @@ -0,0 +1,13 @@ +package unsafe
+
+import (
+ "unsafe"
+)
+
+// Pre-set this marker, as we don't have a "source" for it in this package.
+/* unsafe.Sizeof */ //@item(Sizeof, "Sizeof", "invalid type", "text")
+
+func _() {
+ x := struct{}{}
+ _ = unsafe.Sizeof(x) //@complete("z", Sizeof)
+}
diff --git a/gopls/internal/lsp/testdata/variadic/variadic.go.in b/gopls/internal/lsp/testdata/variadic/variadic.go.in new file mode 100644 index 000000000..4787498ce --- /dev/null +++ b/gopls/internal/lsp/testdata/variadic/variadic.go.in @@ -0,0 +1,38 @@ +package variadic + +func foo(i int, strs ...string) {} + +func bar() []string { //@item(vFunc, "bar", "func() []string", "func") + return nil +} + +func _() { + var ( + i int //@item(vInt, "i", "int", "var") + s string //@item(vStr, "s", "string", "var") + ss []string //@item(vStrSlice, "ss", "[]string", "var") + v interface{} //@item(vIntf, "v", "interface{}", "var") + ) + + foo() //@rank(")", vInt, vStr),rank(")", vInt, vStrSlice) + foo(123, ) //@rank(")", vStr, vInt),rank(")", vStrSlice, vInt) + foo(123, "", ) //@rank(")", vStr, vInt),rank(")", vStr, vStrSlice) + foo(123, s, "") //@rank(", \"", vStr, vStrSlice) + + // snippet will add the "..." for you + foo(123, ) //@snippet(")", vStrSlice, "ss...", "ss..."),snippet(")", vFunc, "bar()...", "bar()..."),snippet(")", vStr, "s", "s") + + // don't add "..." for interface{} + foo(123, ) //@snippet(")", vIntf, "v", "v") +} + +func qux(...func()) {} +func f() {} //@item(vVarArg, "f", "func()", "func") + +func _() { + qux(f) //@snippet(")", vVarArg, "f", "f") +} + +func _() { + foo(0, []string{}...) //@complete(")") +} diff --git a/gopls/internal/lsp/testdata/variadic/variadic_intf.go b/gopls/internal/lsp/testdata/variadic/variadic_intf.go new file mode 100644 index 000000000..6e23fc996 --- /dev/null +++ b/gopls/internal/lsp/testdata/variadic/variadic_intf.go @@ -0,0 +1,21 @@ +package variadic + +type baz interface { + baz() +} + +func wantsBaz(...baz) {} + +type bazImpl int + +func (bazImpl) baz() {} + +func _() { + var ( + impls []bazImpl //@item(vImplSlice, "impls", "[]bazImpl", "var") + impl bazImpl //@item(vImpl, "impl", "bazImpl", "var") + bazes []baz //@item(vIntfSlice, "bazes", "[]baz", "var") + ) + + wantsBaz() //@rank(")", vImpl, vImplSlice),rank(")", vIntfSlice, vImplSlice) +} diff --git a/gopls/internal/lsp/testdata/workspacesymbol/a/a.go b/gopls/internal/lsp/testdata/workspacesymbol/a/a.go new file mode 100644 index 000000000..4ae9997a0 --- /dev/null +++ b/gopls/internal/lsp/testdata/workspacesymbol/a/a.go @@ -0,0 +1,9 @@ +package a + +var RandomGopherVariableA = "a" + +const RandomGopherConstantA = "a" + +const ( + randomgopherinvariable = iota +) diff --git a/gopls/internal/lsp/testdata/workspacesymbol/a/a_test.go b/gopls/internal/lsp/testdata/workspacesymbol/a/a_test.go new file mode 100644 index 000000000..0d97c50d6 --- /dev/null +++ b/gopls/internal/lsp/testdata/workspacesymbol/a/a_test.go @@ -0,0 +1,3 @@ +package a + +var RandomGopherTestVariableA = "a" diff --git a/gopls/internal/lsp/testdata/workspacesymbol/a/a_x_test.go b/gopls/internal/lsp/testdata/workspacesymbol/a/a_x_test.go new file mode 100644 index 000000000..747cd17ec --- /dev/null +++ b/gopls/internal/lsp/testdata/workspacesymbol/a/a_x_test.go @@ -0,0 +1,3 @@ +package a_test + +var RandomGopherXTestVariableA = "a" diff --git a/gopls/internal/lsp/testdata/workspacesymbol/b/b.go b/gopls/internal/lsp/testdata/workspacesymbol/b/b.go new file mode 100644 index 000000000..b2e2092ee --- /dev/null +++ b/gopls/internal/lsp/testdata/workspacesymbol/b/b.go @@ -0,0 +1,7 @@ +package b + +var RandomGopherVariableB = "b" + +type RandomGopherStructB struct { + Bar int +} diff --git a/gopls/internal/lsp/testdata/workspacesymbol/issue44806.go b/gopls/internal/lsp/testdata/workspacesymbol/issue44806.go new file mode 100644 index 000000000..6a6e03a5f --- /dev/null +++ b/gopls/internal/lsp/testdata/workspacesymbol/issue44806.go @@ -0,0 +1,10 @@ +package main + +type T struct{} + +// We should accept all valid receiver syntax when scanning symbols. +func (*(T)) m1() {} +func (*T) m2() {} +func (T) m3() {} +func ((T)) m4() {} +func ((*T)) m5() {} diff --git a/gopls/internal/lsp/testdata/workspacesymbol/main.go b/gopls/internal/lsp/testdata/workspacesymbol/main.go new file mode 100644 index 000000000..36ec8f1a5 --- /dev/null +++ b/gopls/internal/lsp/testdata/workspacesymbol/main.go @@ -0,0 +1,47 @@ +package main + +import ( + "encoding/json" + "fmt" +) + +func main() { // function + fmt.Println("Hello") +} + +var myvar int // variable + +type myType string // basic type + +type myDecoder json.Decoder // to use the encoding/json import + +func (m *myType) Blahblah() {} // method + +type myStruct struct { // struct type + myStructField int // struct field +} + +type myInterface interface { // interface + DoSomeCoolStuff() string // interface method +} + +type embed struct { + myStruct + + nestedStruct struct { + nestedField int + + nestedStruct2 struct { + int + } + } + + nestedInterface interface { + myInterface + nestedMethod() + } +} + +func Dunk() int { return 0 } + +func dunk() {} diff --git a/gopls/internal/lsp/testdata/workspacesymbol/p/p.go b/gopls/internal/lsp/testdata/workspacesymbol/p/p.go new file mode 100644 index 000000000..409cc3547 --- /dev/null +++ b/gopls/internal/lsp/testdata/workspacesymbol/p/p.go @@ -0,0 +1,3 @@ +package p + +const Message = "Hello World." // constant diff --git a/gopls/internal/lsp/testdata/workspacesymbol/query.go b/gopls/internal/lsp/testdata/workspacesymbol/query.go new file mode 100644 index 000000000..883aae268 --- /dev/null +++ b/gopls/internal/lsp/testdata/workspacesymbol/query.go @@ -0,0 +1,29 @@ +package main + +// Contains all of the workspace symbol queries. + +// -- Fuzzy matching -- +//@workspacesymbolfuzzy("rgop") +//@workspacesymbolfuzzy("randoma") +//@workspacesymbolfuzzy("randomb") + +// -- Case sensitive -- +//@workspacesymbolcasesensitive("main.main") +//@workspacesymbolcasesensitive("p.Message") +//@workspacesymbolcasesensitive("main.myvar") +//@workspacesymbolcasesensitive("main.myType") +//@workspacesymbolcasesensitive("main.myType.Blahblah") +//@workspacesymbolcasesensitive("main.myStruct") +//@workspacesymbolcasesensitive("main.myStruct.myStructField") +//@workspacesymbolcasesensitive("main.myInterface") +//@workspacesymbolcasesensitive("main.myInterface.DoSomeCoolStuff") +//@workspacesymbolcasesensitive("main.embed.myStruct") +//@workspacesymbolcasesensitive("main.embed.nestedStruct.nestedStruct2.int") +//@workspacesymbolcasesensitive("main.embed.nestedInterface.myInterface") +//@workspacesymbolcasesensitive("main.embed.nestedInterface.nestedMethod") +//@workspacesymbolcasesensitive("dunk") +//@workspacesymbolcasesensitive("Dunk") + +// -- Standard -- +//@workspacesymbol("") +//@workspacesymbol("randomgophervar") diff --git a/gopls/internal/lsp/testdata/workspacesymbol/query.go.golden b/gopls/internal/lsp/testdata/workspacesymbol/query.go.golden new file mode 100644 index 000000000..4c6d470f7 --- /dev/null +++ b/gopls/internal/lsp/testdata/workspacesymbol/query.go.golden @@ -0,0 +1,83 @@ +-- workspace_symbol-caseinsensitive- -- + + +-- workspace_symbol-caseinsensitive-randomgophervar -- +workspacesymbol/a/a.go:3:5-26 RandomGopherVariableA Variable +workspacesymbol/b/b.go:3:5-26 RandomGopherVariableB Variable + +-- workspace_symbol-casesensitive-Dunk -- +workspacesymbol/main.go:45:6-10 Dunk Function + +-- workspace_symbol-casesensitive-dunk -- +workspacesymbol/main.go:47:6-10 dunk Function + +-- workspace_symbol-casesensitive-main.embed.myStruct -- +workspacesymbol/main.go:29:2-10 main.embed.myStruct Field + +-- workspace_symbol-casesensitive-main.embed.nestedInterface.myInterface -- +workspacesymbol/main.go:40:3-14 main.embed.nestedInterface.myInterface Interface + +-- workspace_symbol-casesensitive-main.embed.nestedInterface.nestedMethod -- +workspacesymbol/main.go:41:3-15 main.embed.nestedInterface.nestedMethod Method + +-- workspace_symbol-casesensitive-main.embed.nestedStruct.nestedStruct2.int -- +workspacesymbol/main.go:35:4-7 main.embed.nestedStruct.nestedStruct2.int Field + +-- workspace_symbol-casesensitive-main.main -- +workspacesymbol/main.go:8:6-10 main.main Function + +-- workspace_symbol-casesensitive-main.myInterface -- +workspacesymbol/main.go:24:6-17 main.myInterface Interface +workspacesymbol/main.go:25:2-17 main.myInterface.DoSomeCoolStuff Method + +-- workspace_symbol-casesensitive-main.myInterface.DoSomeCoolStuff -- +workspacesymbol/main.go:25:2-17 main.myInterface.DoSomeCoolStuff Method + +-- workspace_symbol-casesensitive-main.myStruct -- +workspacesymbol/main.go:20:6-14 main.myStruct Struct +workspacesymbol/main.go:21:2-15 main.myStruct.myStructField Field + +-- workspace_symbol-casesensitive-main.myStruct.myStructField -- +workspacesymbol/main.go:21:2-15 main.myStruct.myStructField Field + +-- workspace_symbol-casesensitive-main.myType -- +workspacesymbol/main.go:14:6-12 main.myType Class +workspacesymbol/main.go:18:18-26 main.myType.Blahblah Method + +-- workspace_symbol-casesensitive-main.myType.Blahblah -- +workspacesymbol/main.go:18:18-26 main.myType.Blahblah Method + +-- workspace_symbol-casesensitive-main.myvar -- +workspacesymbol/main.go:12:5-10 main.myvar Variable + +-- workspace_symbol-casesensitive-p.Message -- +workspacesymbol/p/p.go:3:7-14 p.Message Constant + +-- workspace_symbol-fuzzy-randoma -- +workspacesymbol/a/a.go:3:5-26 RandomGopherVariableA Variable +workspacesymbol/a/a.go:5:7-28 RandomGopherConstantA Constant +workspacesymbol/a/a.go:8:2-24 randomgopherinvariable Constant +workspacesymbol/a/a_test.go:3:5-30 RandomGopherTestVariableA Variable +workspacesymbol/a/a_x_test.go:3:5-31 RandomGopherXTestVariableA Variable +workspacesymbol/b/b.go:3:5-26 RandomGopherVariableB Variable +workspacesymbol/b/b.go:6:2-5 RandomGopherStructB.Bar Field + +-- workspace_symbol-fuzzy-randomb -- +workspacesymbol/a/a.go:3:5-26 RandomGopherVariableA Variable +workspacesymbol/a/a.go:8:2-24 randomgopherinvariable Constant +workspacesymbol/a/a_test.go:3:5-30 RandomGopherTestVariableA Variable +workspacesymbol/a/a_x_test.go:3:5-31 RandomGopherXTestVariableA Variable +workspacesymbol/b/b.go:3:5-26 RandomGopherVariableB Variable +workspacesymbol/b/b.go:5:6-25 RandomGopherStructB Struct +workspacesymbol/b/b.go:6:2-5 RandomGopherStructB.Bar Field + +-- workspace_symbol-fuzzy-rgop -- +workspacesymbol/a/a.go:3:5-26 RandomGopherVariableA Variable +workspacesymbol/a/a.go:5:7-28 RandomGopherConstantA Constant +workspacesymbol/a/a.go:8:2-24 randomgopherinvariable Constant +workspacesymbol/a/a_test.go:3:5-30 RandomGopherTestVariableA Variable +workspacesymbol/a/a_x_test.go:3:5-31 RandomGopherXTestVariableA Variable +workspacesymbol/b/b.go:3:5-26 RandomGopherVariableB Variable +workspacesymbol/b/b.go:5:6-25 RandomGopherStructB Struct +workspacesymbol/b/b.go:6:2-5 RandomGopherStructB.Bar Field + |