internal/lsp: improve composite literal completion

When the value of a composite literal key/value pair was unparsable,
you were getting completions for the composite literal keys instead of
values. For example "struct { foo int }{foo: []<>" was completing to
the field name "foo". This was because the leaf ast.Node at the cursor
was the composite literal itself, and our go-back-one-character logic
was not happening because the preceding character's node
was *ast.BadExpr, not *ast.Ident. Fix by always generating the ast
path for the character before the cursor's position. I couldn't find
any cases where this broke completion.

I also added expected type detection for the following composite
literal cases:
- array/slice literals
- struct literals (both implicit and explicit field names)
- map keys and values

Fixes golang/go#29153

Change-Id: If8cf678cbd743a970f52893fcf4a9b83ea06d7e9
GitHub-Last-Rev: f385705cc05eb98132e20561451dbb8c39b68519
GitHub-Pull-Request: golang/tools#86
Reviewed-on: https://go-review.googlesource.com/c/tools/+/173099
Run-TryBot: Rebecca Stambler <rstambler@golang.org>
Reviewed-by: Rebecca Stambler <rstambler@golang.org>
diff --git a/internal/lsp/lsp_test.go b/internal/lsp/lsp_test.go
index f45290d..2f6d8f1 100644
--- a/internal/lsp/lsp_test.go
+++ b/internal/lsp/lsp_test.go
@@ -162,9 +162,27 @@
 			t.Fatalf("completion failed for %v: %v", src, err)
 		}
 		if diff := diffCompletionItems(t, src, want, got); diff != "" {
-			t.Errorf(diff)
+			t.Errorf("%s: %s", src, diff)
 		}
 	}
+
+	// Make sure we don't crash completing the first position in file set.
+	firstFile := r.data.Config.Fset.Position(1).Filename
+
+	_, err := r.server.Completion(context.Background(), &protocol.CompletionParams{
+		TextDocumentPositionParams: protocol.TextDocumentPositionParams{
+			TextDocument: protocol.TextDocumentIdentifier{
+				URI: protocol.NewURI(span.FileURI(firstFile)),
+			},
+			Position: protocol.Position{
+				Line:      0,
+				Character: 0,
+			},
+		},
+	})
+	if err != nil {
+		t.Fatal(err)
+	}
 }
 
 func isBuiltin(item protocol.CompletionItem) bool {
diff --git a/internal/lsp/source/completion.go b/internal/lsp/source/completion.go
index 38f1df7..3f70f85 100644
--- a/internal/lsp/source/completion.go
+++ b/internal/lsp/source/completion.go
@@ -52,23 +52,15 @@
 	if pkg.IsIllTyped() {
 		return nil, "", fmt.Errorf("package for %s is ill typed", f.URI())
 	}
-	path, _ := astutil.PathEnclosingInterval(file, pos, pos)
+
+	// Completion is based on what precedes the cursor.
+	// To understand what we are completing, find the path to the
+	// position before pos.
+	path, _ := astutil.PathEnclosingInterval(file, pos-1, pos-1)
 	if path == nil {
 		return nil, "", fmt.Errorf("cannot find node enclosing position")
 	}
 
-	// If the position is not an identifier but immediately follows
-	// an identifier or selector period (as is common when
-	// requesting a completion), use the path to the preceding node.
-	if _, ok := path[0].(*ast.Ident); !ok {
-		if p, _ := astutil.PathEnclosingInterval(file, pos-1, pos-1); p != nil {
-			switch p[0].(type) {
-			case *ast.Ident, *ast.SelectorExpr:
-				path = p // use preceding ident/selector
-			}
-		}
-	}
-
 	// Skip completion inside comment blocks or string literals.
 	switch lit := path[0].(type) {
 	case *ast.File, *ast.BlockStmt:
@@ -411,6 +403,43 @@
 	return items, prefix, false
 }
 
+// enclosingCompLit returns the composite literal and key value expression, if
+// any, enclosing the given position.
+func enclosingCompLit(pos token.Pos, path []ast.Node) (*ast.CompositeLit, *ast.KeyValueExpr) {
+	var keyVal *ast.KeyValueExpr
+
+	for _, n := range path {
+		switch n := n.(type) {
+		case *ast.CompositeLit:
+			// pos isn't part of the composite literal unless it falls within the curly
+			// braces (e.g. "foo.Foo<>Struct{}").
+			if n.Lbrace <= pos && pos <= n.Rbrace {
+				if keyVal == nil {
+					if i := exprAtPos(pos, n.Elts); i < len(n.Elts) {
+						keyVal, _ = n.Elts[i].(*ast.KeyValueExpr)
+					}
+				}
+
+				return n, keyVal
+			}
+
+			return nil, nil
+		case *ast.KeyValueExpr:
+			keyVal = n
+		case *ast.FuncType, *ast.CallExpr, *ast.TypeAssertExpr:
+			// These node types break the type link between the leaf node and
+			// the composite literal. The type of the leaf node becomes unrelated
+			// to the type of the composite literal, so we return nil to avoid
+			// inappropriate completions. For example, "Foo{Bar: x.Baz(<>)}"
+			// should complete as a function argument to Baz, not part of the Foo
+			// composite literal.
+			return nil, nil
+		}
+	}
+
+	return nil, nil
+}
+
 // formatCompletion creates a completion item for a given types.Object.
 func formatCompletion(obj types.Object, qualifier types.Qualifier, score float64, isParam func(*types.Var) bool) CompletionItem {
 	label := obj.Name()
@@ -578,8 +607,77 @@
 	return nil
 }
 
+func expectedCompLitType(cl *ast.CompositeLit, kv *ast.KeyValueExpr, pos token.Pos, info *types.Info) types.Type {
+	// Get the type of the *ast.CompositeLit we belong to.
+	clType, ok := info.Types[cl]
+	if !ok {
+		return nil
+	}
+
+	switch t := clType.Type.Underlying().(type) {
+	case *types.Slice:
+		return t.Elem()
+	case *types.Array:
+		return t.Elem()
+	case *types.Map:
+		// If pos isn't in a key/value expression or it is on the left side
+		// of a key/value colon, a key must be entered next.
+		if kv == nil || pos <= kv.Colon {
+			return t.Key()
+		}
+
+		return t.Elem()
+	case *types.Struct:
+		// pos is in a key/value expression
+		if kv != nil {
+			// If pos is to left of the colon, it is a struct field name,
+			// so there is no expected type.
+			if pos <= kv.Colon {
+				return nil
+			}
+
+			if keyIdent, ok := kv.Key.(*ast.Ident); ok {
+				// Find the type of the struct field whose name matches the key.
+				for i := 0; i < t.NumFields(); i++ {
+					if field := t.Field(i); field.Name() == keyIdent.Name {
+						return field.Type()
+					}
+				}
+			}
+
+			return nil
+		}
+
+		hasKeys := false // true if the composite literal has any key/value pairs
+		for _, el := range cl.Elts {
+			if _, ok := el.(*ast.KeyValueExpr); ok {
+				hasKeys = true
+				break
+			}
+		}
+
+		// The struct literal is using field names, but pos is not in a key/value
+		// pair. A field name must be entered next, so there is no expected type.
+		if hasKeys {
+			return nil
+		}
+
+		// The order of the literal fields must match the order in the struct definition.
+		// Find the element pos falls in and use the corresponding field's type.
+		if i := exprAtPos(pos, cl.Elts); i < t.NumFields() {
+			return t.Field(i).Type()
+		}
+	}
+
+	return nil
+}
+
 // expectedType returns the expected type for an expression at the query position.
 func expectedType(path []ast.Node, pos token.Pos, info *types.Info) types.Type {
+	if compLit, keyVal := enclosingCompLit(pos, path); compLit != nil {
+		return expectedCompLitType(compLit, keyVal, pos, info)
+	}
+
 	for i, node := range path {
 		if i == 2 {
 			break
diff --git a/internal/lsp/testdata/complit/complit.go.in b/internal/lsp/testdata/complit/complit.go.in
index 9c29c52..fec5aad 100644
--- a/internal/lsp/testdata/complit/complit.go.in
+++ b/internal/lsp/testdata/complit/complit.go.in
@@ -5,20 +5,48 @@
 }
 
 func _() {
-	_ := position{
+	_ = position{
 		//@complete("", fieldX, fieldY, structPosition)
 	}
-	_ := position{
+	_ = position{
 		X: 1,
 		//@complete("", fieldY)
 	}
-	_ := position{
+	_ = position{
 		//@complete("", fieldX)
 		Y: 1,
 	}
 }
 
 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)
+	}
+
+	_ = position{X: a} //@complete("}", abVar, aaVar)
+	_ = position{a}    //@complete("}", abVar, aaVar)
+
+	_ = []int{a}  //@complete("a", abVar, aaVar, structPosition)
+	_ = [1]int{a} //@complete("a", abVar, aaVar, structPosition)
+
+	var s struct {
+		AA int    //@item(fieldAA, "AA", "int", "field")
+		AB string //@item(fieldAB, "AB", "string", "field")
+	}
+	_ = map[int]string{1: "" + s.A} //@complete("}", fieldAB, fieldAA)
+	_ = map[int]string{1: (func(i int) string { return "" })(s.A)} //@complete(")}", fieldAA, fieldAB)
+}
+
+func _() {
 	_ := position{
 		X: 1, //@complete("X", fieldX),complete(" 1", structPosition)
 		Y: ,  //@complete(":", fieldY),complete(" ,", structPosition)
diff --git a/internal/lsp/testdata/nested_complit/nested_complit.go.in b/internal/lsp/testdata/nested_complit/nested_complit.go.in
new file mode 100644
index 0000000..3c3c88f
--- /dev/null
+++ b/internal/lsp/testdata/nested_complit/nested_complit.go.in
@@ -0,0 +1,13 @@
+package nested_complit
+
+type ncFoo struct {} //@item(structNCFoo, "ncFoo", "struct{...}", "struct")
+
+type ncBar struct { //@item(structNCBar, "ncBar", "struct{...}", "struct")
+	baz []ncFoo
+}
+
+func _() {
+	_ := ncBar{
+		baz: [] //@complete(" //", structNCBar, structNCFoo)
+	}
+}
diff --git a/internal/lsp/testdata/signature/signature.go b/internal/lsp/testdata/signature/signature.go
index 72351c4..7e826a0 100644
--- a/internal/lsp/testdata/signature/signature.go
+++ b/internal/lsp/testdata/signature/signature.go
@@ -28,12 +28,12 @@
 	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, 0x1337)     //@signature("13.37", "Bar(float64, ...byte)", 0)
-	Bar(13.37, 0x1337)     //@signature("0x1337", "Bar(float64, ...byte)", 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 0
+		return func(int) rune { return 0 }
 	}
 
 	fn("hi", "there")    //@signature("hi", "fn(hi string, there string) func(i int) rune", 0)
@@ -53,9 +53,10 @@
 	var ms myStruct
 	ms.foo(nil) //@signature("nil", "foo(e *json.Decoder) (*big.Int, error)", 0)
 
-	panic("oops!")    //@signature("oops", "panic(interface{})", 0)
-	make([]int, 1, 2) //@signature("2", "make([]int, int, int) []int", 2)
+	_ = make([]int, 1, 2) //@signature("2", "make([]int, int, int) []int", 2)
 
 	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("oops", "panic(interface{})", 0)
 }
diff --git a/internal/lsp/tests/tests.go b/internal/lsp/tests/tests.go
index 196087d..bd36b82 100644
--- a/internal/lsp/tests/tests.go
+++ b/internal/lsp/tests/tests.go
@@ -27,7 +27,7 @@
 // We hardcode the expected number of test cases to ensure that all tests
 // are being executed. If a test is added, this number must be changed.
 const (
-	ExpectedCompletionsCount     = 65
+	ExpectedCompletionsCount     = 75
 	ExpectedDiagnosticsCount     = 16
 	ExpectedFormatCount          = 4
 	ExpectedDefinitionsCount     = 21