diff --git a/go/packages/packagestest/expect.go b/go/packages/packagestest/expect.go index 69d30629..35663886 100644 --- a/go/packages/packagestest/expect.go +++ b/go/packages/packagestest/expect.go @@ -7,11 +7,12 @@ package packagestest 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 @@ func (e *Exported) getNotes() error { 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 39694eae..ef9f2e16 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 @@ func toProtocolSeverity(severity source.DiagnosticSeverity) protocol.DiagnosticS } 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 00000000..7520350e --- /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 2b3710bc..95762c39 100644 --- a/internal/lsp/lsp_test.go +++ b/internal/lsp/lsp_test.go @@ -12,7 +12,6 @@ import ( "os/exec" "path/filepath" "reflect" - "sort" "strings" "testing" @@ -22,14 +21,18 @@ import ( "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 @@ func testLSP(t *testing.T, exporter packagestest.Exporter) { 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 @@ func testLSP(t *testing.T, exporter packagestest.Exporter) { 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 @@ func testLSP(t *testing.T, exporter packagestest.Exporter) { 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 @@ func (c completions) test(t *testing.T, exported *packagestest.Exported, s *serv }, }) 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 @@ func (i completionItems) collect(pos token.Pos, label, detail, kind string) { k = protocol.ConstantCompletion case "method": k = protocol.MethodCompletion + case "package": + k = protocol.ModuleCompletion } i[pos] = &protocol.CompletionItem{ Label: label, @@ -193,50 +194,33 @@ func (i completionItems) collect(pos token.Pos, label, detail, kind string) { } } -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 @@ func (f formats) test(t *testing.T, s *server) { if gofmted != "" { t.Error(err) } - return + continue } edit := edits[0] if edit.NewText != gofmted { @@ -312,3 +296,31 @@ func (d definitions) collect(fset *token.FileSet, src, target packagestest.Range 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 e4995b47..7b16cc9f 100644 --- a/internal/lsp/protocol/printers.go +++ b/internal/lsp/protocol/printers.go @@ -54,3 +54,30 @@ func (s DiagnosticSeverity) Format(f fmt.State, c rune) { 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 2230f608..12528642 100644 --- a/internal/lsp/source/completion.go +++ b/internal/lsp/source/completion.go @@ -15,7 +15,7 @@ import ( type CompletionItem struct { Label, Detail string Kind CompletionItemKind - Score int + Score float64 } type CompletionItemKind int @@ -47,6 +47,8 @@ func Completion(ctx context.Context, f *File, pos token.Pos) ([]CompletionItem, 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 @@ func completions(file *ast.File, pos token.Pos, fset *token.FileSet, pkg *types. 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 @@ func selector(sel *ast.SelectorExpr, info *types.Info, found finder) (items []Co 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 @@ func selector(sel *ast.SelectorExpr, info *types.Info, found finder) (items []Co // 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 @@ func lexical(path []ast.Node, pos token.Pos, pkg *types.Package, info *types.Inf } } - score := 1.0 + score := stdScore // Rank builtins significantly lower than other results. if scope == types.Universe { score *= 0.1 @@ -342,7 +344,7 @@ func complit(path []ast.Node, pos token.Pos, pkg *types.Package, info *types.Inf 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 @@ func formatCompletion(obj types.Object, qualifier types.Qualifier, score float64 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 00000000..be7cb3bc --- /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 75f728ec..72cf1207 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 9ab8a73e..c7456f5c 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 f9f99af0..00000000 --- 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 00000000..b06a8893 --- /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 3b95ee2f..00000000 --- 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 00000000..1af3bc4c --- /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 00000000..7fe21903 --- /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 14b41e63..5bcb77de 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 ae71ad43..8647f80c 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 f450053a..00000000 --- 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 00000000..10c39120 --- /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 00000000..6a58328e --- /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() {}