internal/lsp: add literal completions for basic types

Normally you don't want literal candidates for basic types (e.g.
"int(0)") since you can type the literal value without the type name.
One exception is if you are creating a named basic type that
implements an interface. For example:

http.Handle("/", http.FileServer(<>))

will now give "http.Dir()" as a candidate since http.Dir is a named
string type that implements the required interface http.FileSystem.

Change-Id: Id2470c45e469ea25cd0f9849cfdad19ac0e784bb
Reviewed-on: https://go-review.googlesource.com/c/tools/+/195838
Run-TryBot: Rebecca Stambler <rstambler@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Rebecca Stambler <rstambler@golang.org>
diff --git a/internal/lsp/source/completion_literal.go b/internal/lsp/source/completion_literal.go
index cf59079..9254605 100644
--- a/internal/lsp/source/completion_literal.go
+++ b/internal/lsp/source/completion_literal.go
@@ -85,6 +85,13 @@
 		switch t := literalType.Underlying().(type) {
 		case *types.Struct, *types.Array, *types.Slice, *types.Map:
 			c.compositeLiteral(t, typeName, float64(score))
+		case *types.Basic:
+			// Add a literal completion for basic types that implement our
+			// expected interface (e.g. named string type http.Dir
+			// implements http.FileSystem).
+			if isInterface(c.expectedType.objType) {
+				c.basicLiteral(t, typeName, float64(score))
+			}
 		}
 	}
 
@@ -261,6 +268,26 @@
 	})
 }
 
+// basicLiteral adds a literal completion item for the given basic
+// type name typeName.
+func (c *completer) basicLiteral(T types.Type, typeName string, matchScore float64) {
+	snip := &snippet.Builder{}
+	snip.WriteText(typeName + "(")
+	snip.WriteFinalTabstop()
+	snip.WriteText(")")
+
+	nonSnippet := typeName + "()"
+
+	c.items = append(c.items, CompletionItem{
+		Label:      nonSnippet,
+		InsertText: nonSnippet,
+		Detail:     T.String(),
+		Score:      matchScore * literalCandidateScore,
+		Kind:       VariableCompletionItem,
+		snippet:    snip,
+	})
+}
+
 // makeCall adds a completion item for a "make()" call given a specific type.
 func (c *completer) makeCall(typeName string, secondArg string, matchScore float64) {
 	// Keep it simple and don't add any placeholders for optional "make()" arguments.
diff --git a/internal/lsp/testdata/snippets/literal_snippets.go b/internal/lsp/testdata/snippets/literal_snippets.go
index 92fe6a3..658baf3 100644
--- a/internal/lsp/testdata/snippets/literal_snippets.go
+++ b/internal/lsp/testdata/snippets/literal_snippets.go
@@ -66,6 +66,10 @@
 
 func (*myImpl) bar() {}
 
+type myBasicImpl string
+
+func (myBasicImpl) foo() {}
+
 func _() {
 	type myIntf interface {
 		foo()
@@ -76,6 +80,10 @@
 	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()
diff --git a/internal/lsp/tests/tests.go b/internal/lsp/tests/tests.go
index 766ddd3..cc134f4 100644
--- a/internal/lsp/tests/tests.go
+++ b/internal/lsp/tests/tests.go
@@ -30,7 +30,7 @@
 // are being executed. If a test is added, this number must be changed.
 const (
 	ExpectedCompletionsCount           = 152
-	ExpectedCompletionSnippetCount     = 35
+	ExpectedCompletionSnippetCount     = 36
 	ExpectedUnimportedCompletionsCount = 1
 	ExpectedDeepCompletionsCount       = 5
 	ExpectedFuzzyCompletionsCount      = 6