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() {}