internal/lsp: add more testdata for completion and diagnostics
Change-Id: I2a73e51b60f76a2af0f8ff4d34220b551e0cd378
Reviewed-on: https://go-review.googlesource.com/c/150041
Run-TryBot: Rebecca Stambler <rstambler@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Cottrell <iancottrell@google.com>
diff --git a/go/packages/packagestest/expect.go b/go/packages/packagestest/expect.go
index 69d3062..3566388 100644
--- a/go/packages/packagestest/expect.go
+++ b/go/packages/packagestest/expect.go
@@ -7,11 +7,12 @@
import (
"fmt"
"go/token"
+ "path/filepath"
"reflect"
"regexp"
- "strings"
"golang.org/x/tools/go/expect"
+ "golang.org/x/tools/go/packages"
)
const (
@@ -131,11 +132,18 @@
return nil
}
notes := []*expect.Note{}
+ var dirs []string
for _, module := range e.written {
for _, filename := range module {
- if !strings.HasSuffix(filename, ".go") {
- continue
- }
+ dirs = append(dirs, filepath.Dir(filename))
+ }
+ }
+ pkgs, err := packages.Load(e.Config, dirs...)
+ if err != nil {
+ return fmt.Errorf("unable to load packages for directories %s: %v", dirs, err)
+ }
+ for _, pkg := range pkgs {
+ for _, filename := range pkg.GoFiles {
l, err := expect.Parse(e.fset, filename, nil)
if err != nil {
return fmt.Errorf("Failed to extract expectations: %v", err)
diff --git a/internal/lsp/diagnostics.go b/internal/lsp/diagnostics.go
index 39694ea..ef9f2e1 100644
--- a/internal/lsp/diagnostics.go
+++ b/internal/lsp/diagnostics.go
@@ -5,6 +5,8 @@
package lsp
import (
+ "sort"
+
"golang.org/x/tools/internal/lsp/protocol"
"golang.org/x/tools/internal/lsp/source"
)
@@ -36,3 +38,15 @@
}
return protocol.SeverityError // default
}
+
+func sorted(d []protocol.Diagnostic) {
+ sort.Slice(d, func(i int, j int) bool {
+ if d[i].Range.Start.Line == d[j].Range.Start.Line {
+ if d[i].Range.Start.Character == d[j].Range.End.Character {
+ return d[i].Message < d[j].Message
+ }
+ return d[i].Range.Start.Character < d[j].Range.End.Character
+ }
+ return d[i].Range.Start.Line < d[j].Range.Start.Line
+ })
+}
diff --git a/internal/lsp/lsp110_test.go b/internal/lsp/lsp110_test.go
new file mode 100644
index 0000000..7520350
--- /dev/null
+++ b/internal/lsp/lsp110_test.go
@@ -0,0 +1,7 @@
+//+build !go1.11
+
+package lsp
+
+func init() {
+ goVersion111 = false
+}
diff --git a/internal/lsp/lsp_test.go b/internal/lsp/lsp_test.go
index 2b3710b..95762c3 100644
--- a/internal/lsp/lsp_test.go
+++ b/internal/lsp/lsp_test.go
@@ -12,7 +12,6 @@
"os/exec"
"path/filepath"
"reflect"
- "sort"
"strings"
"testing"
@@ -22,14 +21,18 @@
"golang.org/x/tools/internal/lsp/source"
)
+// TODO(rstambler): Remove this once Go 1.12 is released as we will end support
+// for versions of Go <= 1.10.
+var goVersion111 = true
+
func TestLSP(t *testing.T) {
packagestest.TestAll(t, testLSP)
}
func testLSP(t *testing.T, exporter packagestest.Exporter) {
const dir = "testdata"
- const expectedCompletionsCount = 4
- const expectedDiagnosticsCount = 9
+ const expectedCompletionsCount = 43
+ const expectedDiagnosticsCount = 14
const expectedFormatCount = 3
const expectedDefinitionsCount = 16
@@ -49,8 +52,6 @@
exported := packagestest.Export(t, exporter, modules)
defer exported.Cleanup()
- dirs := make(map[string]bool)
-
// collect results for certain tests
expectedDiagnostics := make(diagnostics)
completionItems := make(completionItems)
@@ -67,16 +68,6 @@
cfg.Mode = packages.LoadSyntax
s.view.Config = &cfg
- for _, module := range modules {
- for fragment := range module.Files {
- if !strings.HasSuffix(fragment, ".go") {
- continue
- }
- filename := exporter.Filename(exported, module.Name, fragment)
- expectedDiagnostics[filename] = []protocol.Diagnostic{}
- dirs[filepath.Dir(filename)] = true
- }
- }
// Do a first pass to collect special markers
if err := exported.Expect(map[string]interface{}{
"item": func(name string, r packagestest.Range, _, _ string) {
@@ -98,32 +89,40 @@
t.Run("Completion", func(t *testing.T) {
t.Helper()
- if len(expectedCompletions) != expectedCompletionsCount {
- t.Errorf("got %v completions expected %v", len(expectedCompletions), expectedCompletionsCount)
+ if goVersion111 { // TODO(rstambler): Remove this when we no longer support Go 1.10.
+ if len(expectedCompletions) != expectedCompletionsCount {
+ t.Errorf("got %v completions expected %v", len(expectedCompletions), expectedCompletionsCount)
+ }
}
expectedCompletions.test(t, exported, s, completionItems)
})
t.Run("Diagnostics", func(t *testing.T) {
t.Helper()
- diagnosticsCount := expectedDiagnostics.test(t, exported, s.view, dirs)
- if diagnosticsCount != expectedDiagnosticsCount {
- t.Errorf("got %v diagnostics expected %v", diagnosticsCount, expectedDiagnosticsCount)
+ diagnosticsCount := expectedDiagnostics.test(t, exported, s.view)
+ if goVersion111 { // TODO(rstambler): Remove this when we no longer support Go 1.10.
+ if diagnosticsCount != expectedDiagnosticsCount {
+ t.Errorf("got %v diagnostics expected %v", diagnosticsCount, expectedDiagnosticsCount)
+ }
}
})
t.Run("Format", func(t *testing.T) {
t.Helper()
- if len(expectedFormat) != expectedFormatCount {
- t.Errorf("got %v formats expected %v", len(expectedFormat), expectedFormatCount)
+ if goVersion111 { // TODO(rstambler): Remove this when we no longer support Go 1.10.
+ if len(expectedFormat) != expectedFormatCount {
+ t.Errorf("got %v formats expected %v", len(expectedFormat), expectedFormatCount)
+ }
}
expectedFormat.test(t, s)
})
t.Run("Definitions", func(t *testing.T) {
t.Helper()
- if len(expectedDefinitions) != expectedDefinitionsCount {
- t.Errorf("got %v definitions expected %v", len(expectedDefinitions), expectedDefinitionsCount)
+ if goVersion111 { // TODO(rstambler): Remove this when we no longer support Go 1.10.
+ if len(expectedDefinitions) != expectedDefinitionsCount {
+ t.Errorf("got %v definitions expected %v", len(expectedDefinitions), expectedDefinitionsCount)
+ }
}
expectedDefinitions.test(t, s)
})
@@ -153,11 +152,11 @@
},
})
if err != nil {
- t.Fatal(err)
+ t.Fatalf("completion failed for %s:%v:%v: %v", filepath.Base(src.Filename), src.Line, src.Column, err)
}
got := list.Items
if equal := reflect.DeepEqual(want, got); !equal {
- t.Errorf("completion failed for %s:%v:%v: (expected: %v), (got: %v)", filepath.Base(src.Filename), src.Line, src.Column, want, got)
+ t.Errorf(diffC(src, want, got))
}
}
}
@@ -185,6 +184,8 @@
k = protocol.ConstantCompletion
case "method":
k = protocol.MethodCompletion
+ case "package":
+ k = protocol.ModuleCompletion
}
i[pos] = &protocol.CompletionItem{
Label: label,
@@ -193,50 +194,33 @@
}
}
-func (d diagnostics) test(t *testing.T, exported *packagestest.Exported, v *source.View, dirs map[string]bool) int {
- // first trigger a load to get the diagnostics
- var dirList []string
- for dir := range dirs {
- dirList = append(dirList, dir)
- }
- exported.Config.Mode = packages.LoadFiles
- pkgs, err := packages.Load(exported.Config, dirList...)
- if err != nil {
- t.Fatal(err)
- }
- // and now see if they match the expected ones
+func (d diagnostics) test(t *testing.T, exported *packagestest.Exported, v *source.View) int {
count := 0
- for _, pkg := range pkgs {
- for _, filename := range pkg.GoFiles {
- f := v.GetFile(source.ToURI(filename))
- diagnostics, err := source.Diagnostics(context.Background(), v, f)
- if err != nil {
- t.Fatal(err)
- }
- got := toProtocolDiagnostics(v, diagnostics[filename])
- sort.Slice(got, func(i int, j int) bool {
- return got[i].Range.Start.Line < got[j].Range.Start.Line
- })
- want := d[filename]
- if equal := reflect.DeepEqual(want, got); !equal {
- msg := &bytes.Buffer{}
- fmt.Fprintf(msg, "diagnostics failed for %s: expected:\n", filepath.Base(filename))
- for _, d := range want {
- fmt.Fprintf(msg, " %v\n", d)
- }
- fmt.Fprintf(msg, "got:\n")
- for _, d := range got {
- fmt.Fprintf(msg, " %v\n", d)
- }
- t.Error(msg.String())
- }
- count += len(want)
+ for filename, want := range d {
+ f := v.GetFile(source.ToURI(filename))
+ sourceDiagnostics, err := source.Diagnostics(context.Background(), v, f)
+ if err != nil {
+ t.Fatal(err)
}
+ got := toProtocolDiagnostics(v, sourceDiagnostics[filename])
+ sorted(got)
+ if equal := reflect.DeepEqual(want, got); !equal {
+ t.Error(diffD(filename, want, got))
+ }
+ count += len(want)
}
return count
}
func (d diagnostics) collect(pos token.Position, msg string) {
+ if _, ok := d[pos.Filename]; !ok {
+ d[pos.Filename] = []protocol.Diagnostic{}
+ }
+ // If a file has an empty diagnostics, mark that and return. This allows us
+ // to avoid testing diagnostics in files that may have a lot of them.
+ if msg == "" {
+ return
+ }
line := float64(pos.Line - 1)
col := float64(pos.Column - 1)
want := protocol.Diagnostic{
@@ -268,7 +252,7 @@
if gofmted != "" {
t.Error(err)
}
- return
+ continue
}
edit := edits[0]
if edit.NewText != gofmted {
@@ -312,3 +296,31 @@
tLoc := toProtocolLocation(fset, tRange)
d[sLoc] = tLoc
}
+
+// diffD prints the diff between expected and actual diagnostics test results.
+func diffD(filename string, want, got []protocol.Diagnostic) string {
+ msg := &bytes.Buffer{}
+ fmt.Fprintf(msg, "diagnostics failed for %s:\nexpected:\n", filename)
+ for _, d := range want {
+ fmt.Fprintf(msg, " %v\n", d)
+ }
+ fmt.Fprintf(msg, "got:\n")
+ for _, d := range got {
+ fmt.Fprintf(msg, " %v\n", d)
+ }
+ return msg.String()
+}
+
+// diffC prints the diff between expected and actual completion test results.
+func diffC(pos token.Position, want, got []protocol.CompletionItem) string {
+ msg := &bytes.Buffer{}
+ fmt.Fprintf(msg, "completion failed for %s:%v:%v:\nexpected:\n", filepath.Base(pos.Filename), pos.Line, pos.Column)
+ for _, d := range want {
+ fmt.Fprintf(msg, " %v\n", d)
+ }
+ fmt.Fprintf(msg, "got:\n")
+ for _, d := range got {
+ fmt.Fprintf(msg, " %v\n", d)
+ }
+ return msg.String()
+}
diff --git a/internal/lsp/protocol/printers.go b/internal/lsp/protocol/printers.go
index e4995b4..7b16cc9 100644
--- a/internal/lsp/protocol/printers.go
+++ b/internal/lsp/protocol/printers.go
@@ -54,3 +54,30 @@
func (d Diagnostic) Format(f fmt.State, c rune) {
fmt.Fprintf(f, "%v:%v from %v at %v: %v", d.Severity, d.Code, d.Source, d.Range, d.Message)
}
+
+func (i CompletionItem) Format(f fmt.State, c rune) {
+ fmt.Fprintf(f, "%v %v %v", i.Label, i.Detail, CompletionItemKind(i.Kind))
+}
+
+func (k CompletionItemKind) Format(f fmt.State, c rune) {
+ switch k {
+ case StructCompletion:
+ fmt.Fprintf(f, "struct")
+ case FunctionCompletion:
+ fmt.Fprintf(f, "func")
+ case VariableCompletion:
+ fmt.Fprintf(f, "var")
+ case TypeParameterCompletion:
+ fmt.Fprintf(f, "type")
+ case FieldCompletion:
+ fmt.Fprintf(f, "field")
+ case InterfaceCompletion:
+ fmt.Fprintf(f, "interface")
+ case ConstantCompletion:
+ fmt.Fprintf(f, "const")
+ case MethodCompletion:
+ fmt.Fprintf(f, "method")
+ case ModuleCompletion:
+ fmt.Fprintf(f, "package")
+ }
+}
diff --git a/internal/lsp/source/completion.go b/internal/lsp/source/completion.go
index 2230f60..1252864 100644
--- a/internal/lsp/source/completion.go
+++ b/internal/lsp/source/completion.go
@@ -15,7 +15,7 @@
type CompletionItem struct {
Label, Detail string
Kind CompletionItemKind
- Score int
+ Score float64
}
type CompletionItemKind int
@@ -47,6 +47,8 @@
return items, err
}
+const stdScore float64 = 1.0
+
type finder func(types.Object, float64, []CompletionItem) []CompletionItem
// completions returns the map of possible candidates for completion, given a
@@ -89,7 +91,7 @@
if !seen[obj] {
seen[obj] = true
if typ != nil && matchingTypes(typ, obj.Type()) {
- weight *= 10
+ weight *= 10.0
}
if !strings.HasPrefix(obj.Name(), prefix) {
return items
@@ -160,7 +162,7 @@
scope := pkgname.Imported().Scope()
// TODO testcase: bad import
for _, name := range scope.Names() {
- items = found(scope.Lookup(name), 1, items)
+ items = found(scope.Lookup(name), stdScore, items)
}
return items, prefix, nil
}
@@ -175,20 +177,20 @@
// methods of T
mset := types.NewMethodSet(tv.Type)
for i := 0; i < mset.Len(); i++ {
- items = found(mset.At(i).Obj(), 1, items)
+ items = found(mset.At(i).Obj(), stdScore, items)
}
// methods of *T
if tv.Addressable() && !types.IsInterface(tv.Type) && !isPointer(tv.Type) {
mset := types.NewMethodSet(types.NewPointer(tv.Type))
for i := 0; i < mset.Len(); i++ {
- items = found(mset.At(i).Obj(), 1, items)
+ items = found(mset.At(i).Obj(), stdScore, items)
}
}
// fields of T
for _, f := range fieldSelections(tv.Type) {
- items = found(f, 1, items)
+ items = found(f, stdScore, items)
}
return items, prefix, nil
@@ -236,7 +238,7 @@
}
}
- score := 1.0
+ score := stdScore
// Rank builtins significantly lower than other results.
if scope == types.Universe {
score *= 0.1
@@ -342,7 +344,7 @@
structPkg = field.Pkg()
}
if !addedFields[field] {
- items = found(field, 10, items)
+ items = found(field, 10.0, items)
}
}
// Add lexical completions if the user hasn't typed a key value expression
@@ -418,6 +420,7 @@
Label: label,
Detail: detail,
Kind: kind,
+ Score: score,
}
}
diff --git a/internal/lsp/testdata/assign_rank/assign_rank.go.in b/internal/lsp/testdata/assign_rank/assign_rank.go.in
new file mode 100644
index 0000000..be7cb3b
--- /dev/null
+++ b/internal/lsp/testdata/assign_rank/assign_rank.go.in
@@ -0,0 +1,19 @@
+package assign_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 = //@complete(" /", pineapple, apple, pear)
+
+ y := //@complete(" /", pineapple, apple, pear)
+}
\ No newline at end of file
diff --git a/internal/lsp/testdata/bad/bad.go b/internal/lsp/testdata/bad/bad.go
index 75f728e..72cf120 100644
--- a/internal/lsp/testdata/bad/bad.go
+++ b/internal/lsp/testdata/bad/bad.go
@@ -1,18 +1,21 @@
+// +build go1.11
+
package bad
-func stuff() {
+func stuff() { //@item(stuff, "stuff()", "", "func")
x := "heeeeyyyy"
random2(x) //@diag("x", "cannot use x (variable of type string) as int value in argument to random2")
- random2(1)
- y := 3 //@diag("y", "y declared but not used")
+ random2(1) //@complete("dom", random, random2, random3)
+ y := 3 //@diag("y", "y declared but not used")
}
-type bob struct {
+type bob struct { //@item(bob, "bob", "struct{...}", "struct")
x int
}
func _() {
+ var q int
_ = &bob{
- f: 0, //@diag("f", "unknown field f in struct literal")
+ f: q, //@diag("f", "unknown field f in struct literal")
}
}
diff --git a/internal/lsp/testdata/bad/bad_util.go b/internal/lsp/testdata/bad/bad_util.go
index 9ab8a73..c7456f5 100644
--- a/internal/lsp/testdata/bad/bad_util.go
+++ b/internal/lsp/testdata/bad/bad_util.go
@@ -1,6 +1,27 @@
+// +build go1.11
+
package bad
-func random2(y int) int {
- x := 6 //@diag("x", "x declared but not used")
+// import (
+// "github.com/bob/pkg" //@diag("\"github.com/bob/pkg\"", "unable to import "\"github.com/bob/pkg\"")
+// )
+
+var a unknown //@item(global_a, "a", "unknown", "var"),diag("unknown", "undeclared name: unknown")
+
+func random() int { //@item(random, "random()", "int", "func")
+ //@complete("", global_a, bob, random, random2, random3, stuff)
+ return 0
+}
+
+func random2(y int) int { //@item(random2, "random2(y int)", "int", "func"),item(bad_y_param, "y", "int", "var")
+ x := 6 //@item(x, "x", "int", "var"),diag("x", "x declared but not used")
+ var q blah //@item(q, "q", "blah", "var"),diag("q", "q declared but not used"),diag("blah", "undeclared name: blah")
+ var t blob //@item(t, "t", "blob", "var"),diag("t", "t declared but not used"),diag("blob", "undeclared name: blob")
+ //@complete("", q, t, x, bad_y_param, global_a, bob, random, random2, random3, stuff)
+
return y
}
+
+func random3(y ...int) { //@item(random3, "random3(y ...int)", "", "func"),item(y_variadic_param, "y", "[]int", "var")
+ //@complete("", y_variadic_param, global_a, bob, random, random2, random3, stuff)
+}
diff --git a/internal/lsp/testdata/bar/bar.go b/internal/lsp/testdata/bar/bar.go
deleted file mode 100644
index f9f99af..0000000
--- a/internal/lsp/testdata/bar/bar.go
+++ /dev/null
@@ -1,7 +0,0 @@
-package bar
-
-import "golang.org/x/tools/internal/lsp/foo"
-
-func Bar() {
- foo.Foo()
-}
diff --git a/internal/lsp/testdata/bar/bar.go.in b/internal/lsp/testdata/bar/bar.go.in
new file mode 100644
index 0000000..b06a889
--- /dev/null
+++ b/internal/lsp/testdata/bar/bar.go.in
@@ -0,0 +1,43 @@
+// +build go1.11
+
+package bar
+
+import (
+ "golang.org/x/tools/internal/lsp/foo" //@item(foo, "foo", "\"golang.org/x/tools/internal/lsp/foo\"", "package")
+)
+
+func _() {
+ _ = foo.StructFoo{} //@complete("S", Foo, IntFoo, StructFoo)
+}
+
+func Bar() { //@item(Bar, "Bar()", "", "func")
+ foo.Foo() //@complete("F", Foo, IntFoo, StructFoo)
+ var _ foo.IntFoo //@complete("I", Foo, IntFoo, StructFoo)
+ foo.() //@complete("(", Foo, IntFoo, StructFoo)
+}
+
+func _() {
+ var Valentine int //@item(Valentine, "Valentine", "int", "var")
+
+ _ = foo.StructFoo{
+ Val //@complete("l", Value)
+ }
+ _ = foo.StructFoo{
+ Va //@complete("a", Value)
+ }
+ _ = foo.StructFoo{
+ Value: 5, //@complete("a", Value)
+ }
+ _ = foo.StructFoo{
+ //@complete("", Value)
+ }
+ _ = foo.StructFoo{
+ Value: Valen //@complete("le", Valentine)
+ }
+ _ = foo.StructFoo{
+ Value: //@complete(re"$", Valentine, foo, Bar)
+ }
+ _ = foo.StructFoo{
+ Value: //@complete(" ", Valentine, foo, Bar)
+ }
+}
\ No newline at end of file
diff --git a/internal/lsp/testdata/baz/baz.go b/internal/lsp/testdata/baz/baz.go
deleted file mode 100644
index 3b95ee2..0000000
--- a/internal/lsp/testdata/baz/baz.go
+++ /dev/null
@@ -1,7 +0,0 @@
-package baz
-
-import "golang.org/x/tools/internal/lsp/bar"
-
-func Baz() {
- bar.Bar()
-}
diff --git a/internal/lsp/testdata/baz/baz.go.in b/internal/lsp/testdata/baz/baz.go.in
new file mode 100644
index 0000000..1af3bc4
--- /dev/null
+++ b/internal/lsp/testdata/baz/baz.go.in
@@ -0,0 +1,31 @@
+// +build go1.11
+
+package baz
+
+import (
+ "golang.org/x/tools/internal/lsp/bar"
+
+ f "golang.org/x/tools/internal/lsp/foo"
+)
+
+func Baz() {
+ defer bar.Bar() //@complete("B", Bar)
+ // TODO(rstambler): Test completion here.
+ defer bar.B
+ var _ f.IntFoo //@complete("n", IntFoo)
+ bar.Bar() //@complete("B", Bar)
+}
+
+func _() {
+ bob := f.StructFoo{Value: 5}
+ if x := bob. //@complete(re"$", Value)
+ switch true == false {
+ case true:
+ if x := bob. //@complete(re"$", Value)
+ case false:
+ }
+ if x := bob.Va //@complete("a", Value)
+ switch true == true {
+ default:
+ }
+}
\ No newline at end of file
diff --git a/internal/lsp/testdata/cast/cast.go.in b/internal/lsp/testdata/cast/cast.go.in
new file mode 100644
index 0000000..7fe2190
--- /dev/null
+++ b/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/internal/lsp/testdata/good/good.go b/internal/lsp/testdata/good/good.go
index 14b41e6..5bcb77d 100644
--- a/internal/lsp/testdata/good/good.go
+++ b/internal/lsp/testdata/good/good.go
@@ -1,6 +1,6 @@
-package good
+package good //@diag("package", "")
-func stuff() {
+func stuff() { //@item(good_stuff, "stuff()", "", "func")
x := 5
random2(x)
}
diff --git a/internal/lsp/testdata/good/good_util.go b/internal/lsp/testdata/good/good_util.go
index ae71ad4..8647f80 100644
--- a/internal/lsp/testdata/good/good_util.go
+++ b/internal/lsp/testdata/good/good_util.go
@@ -1,10 +1,19 @@
-package good
+package good //@diag("package", "")
-func random() int {
+import (
+ "golang.org/x/tools/internal/lsp/types" //@item(types_import, "types", "\"golang.org/x/tools/internal/lsp/types\"", "package")
+)
+
+func random() int { //@item(good_random, "random()", "int", "func")
y := 6 + 7
return y
}
-func random2(y int) int {
+func random2(y int) int { //@item(good_random2, "random2(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{}
+ if _, ok := b.(*types.X); ok { //@complete("X", Bob_interface, X_struct, Y_struct)
+ }
+
return y
}
diff --git a/internal/lsp/testdata/noparse_format/noparse_format.1_10.go.in b/internal/lsp/testdata/noparse_format/noparse_format.1_10.go.in
deleted file mode 100644
index f450053..0000000
--- a/internal/lsp/testdata/noparse_format/noparse_format.1_10.go.in
+++ /dev/null
@@ -1,11 +0,0 @@
-// +build !go1.11
-
-// This file does not actually test anything
-// on 1.10 the errors are different
-package noparse_format
-
-func what() {
- // we need a diagnostic below so we have the same count as the main file
- var b int //@diag("b", "b declared but not used")
- if true {}
-}
\ No newline at end of file
diff --git a/internal/lsp/testdata/selector/selector.go.in b/internal/lsp/testdata/selector/selector.go.in
new file mode 100644
index 0000000..10c3912
--- /dev/null
+++ b/internal/lsp/testdata/selector/selector.go.in
@@ -0,0 +1,66 @@
+// +build go1.11
+
+package selector
+
+import (
+ "golang.org/x/tools/internal/lsp/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(";", Bf, Af, 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()", "*george", "method")
+func (g *george) jack() *jack {}
+func (j *jack) jill() *jill {} //@item(jill, "jill()", "*jill", "method")
+
+func _() {
+ b := &bob{}
+ y := b.george().
+ jack();
+ y.; //@complete(";", jill, c)
+}
+
+func _() {
+ bar. //@complete(" /", Bar)
+ x := 5
+
+ var b *bob
+ b. //@complete(" /", george, a)
+ y, z := 5, 6
+
+ b. //@complete(" /", george, a)
+ 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(" /", george, a)
+ z := 5
+
+ if z + y + 1 + b. //@complete(" /", george, a)
+ r, s, t := 4, 5
+
+ if y != b. //@complete(" /", george, a)
+ z = 5
+
+ if z + y + 1 + b. //@complete(" /", george, a)
+ r = 4
+}
\ No newline at end of file
diff --git a/internal/lsp/testdata/types/types.go b/internal/lsp/testdata/types/types.go
new file mode 100644
index 0000000..6a58328
--- /dev/null
+++ b/internal/lsp/testdata/types/types.go
@@ -0,0 +1,16 @@
+package types
+
+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() {}