1 // Copyright 2019 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
16 "golang.org/x/tools/internal/event"
17 "golang.org/x/tools/internal/lsp/diff"
18 "golang.org/x/tools/internal/lsp/protocol"
19 "golang.org/x/tools/internal/lsp/snippet"
20 "golang.org/x/tools/internal/lsp/source"
23 // literal generates composite literal, function literal, and make()
25 func (c *completer) literal(ctx context.Context, literalType types.Type, imp *importInfo) {
30 expType := c.inference.objType
32 if c.inference.matchesVariadic(literalType) {
33 // Don't offer literal slice candidates for variadic arguments.
34 // For example, don't offer "[]interface{}{}" in "fmt.Print(<>)".
38 // Avoid literal candidates if the expected type is an empty
39 // interface. It isn't very useful to suggest a literal candidate of
40 // every possible type.
41 if expType != nil && isEmptyInterface(expType) {
45 // We handle unnamed literal completions explicitly before searching
46 // for candidates. Avoid named-type literal completions for
47 // unnamed-type expected type since that results in duplicate
48 // candidates. For example, in
53 // don't offer "mySlice{}" since we have already added a candidate
55 if _, named := literalType.(*types.Named); named && expType != nil {
56 if _, named := source.Deref(expType).(*types.Named); !named {
61 // Check if an object of type literalType would match our expected type.
63 obj: c.fakeObj(literalType),
66 switch literalType.Underlying().(type) {
67 // These literal types are addressable (e.g. "&[]int{}"), others are
68 // not (e.g. can't do "&(func(){})").
69 case *types.Struct, *types.Array, *types.Slice, *types.Map:
70 cand.addressable = true
73 if !c.matchingCandidate(&cand) {
79 sel = enclosingSelector(c.path, c.pos)
82 // Don't qualify the type name if we are in a selector expression
83 // since the package name is already present.
85 qf = func(_ *types.Package) string { return "" }
88 typeName := types.TypeString(literalType, qf)
90 // A type name of "[]int" doesn't work very will with the matcher
91 // since "[" isn't a valid identifier prefix. Here we strip off the
92 // slice (and array) prefix yielding just "int".
94 switch t := literalType.(type) {
96 matchName = types.TypeString(t.Elem(), qf)
98 matchName = types.TypeString(t.Elem(), qf)
101 addlEdits, err := c.importEdits(imp)
103 event.Error(ctx, "error adding import for literal candidate", err)
107 // If prefix matches the type name, client may want a composite literal.
108 if score := c.matcher.Score(matchName); score > 0 {
109 if cand.takeAddress {
111 // If we are in a selector we must place the "&" before the selector.
112 // For example, "foo.B<>" must complete to "&foo.Bar{}", not
114 edits, err := prependEdit(c.snapshot.FileSet(), c.mapper, sel, "&")
116 event.Error(ctx, "error making edit for literal pointer completion", err)
119 addlEdits = append(addlEdits, edits...)
121 // Otherwise we can stick the "&" directly before the type name.
122 typeName = "&" + typeName
126 switch t := literalType.Underlying().(type) {
127 case *types.Struct, *types.Array, *types.Slice, *types.Map:
128 c.compositeLiteral(t, typeName, float64(score), addlEdits)
129 case *types.Signature:
130 // Add a literal completion for a signature type that implements
131 // an interface. For example, offer "http.HandlerFunc()" when
132 // expected type is "http.Handler".
133 if source.IsInterface(expType) {
134 c.basicLiteral(t, typeName, float64(score), addlEdits)
137 // Add a literal completion for basic types that implement our
138 // expected interface (e.g. named string type http.Dir
139 // implements http.FileSystem), or are identical to our expected
140 // type (i.e. yielding a type conversion such as "float64()").
141 if source.IsInterface(expType) || types.Identical(expType, literalType) {
142 c.basicLiteral(t, typeName, float64(score), addlEdits)
147 // If prefix matches "make", client may want a "make()"
148 // invocation. We also include the type name to allow for more
149 // flexible fuzzy matching.
150 if score := c.matcher.Score("make." + matchName); !cand.takeAddress && score > 0 {
151 switch literalType.Underlying().(type) {
153 // The second argument to "make()" for slices is required, so default to "0".
154 c.makeCall(typeName, "0", float64(score), addlEdits)
155 case *types.Map, *types.Chan:
156 // Maps and channels don't require the second argument, so omit
157 // to keep things simple for now.
158 c.makeCall(typeName, "", float64(score), addlEdits)
162 // If prefix matches "func", client may want a function literal.
163 if score := c.matcher.Score("func"); !cand.takeAddress && score > 0 && !source.IsInterface(expType) {
164 switch t := literalType.Underlying().(type) {
165 case *types.Signature:
166 c.functionLiteral(ctx, t, float64(score))
171 // prependEdit produces text edits that preprend the specified prefix
172 // to the specified node.
173 func prependEdit(fset *token.FileSet, m *protocol.ColumnMapper, node ast.Node, prefix string) ([]protocol.TextEdit, error) {
174 rng := source.NewMappedRange(fset, m, node.Pos(), node.Pos())
175 spn, err := rng.Span()
179 return source.ToProtocolEdits(m, []diff.TextEdit{{
185 // literalCandidateScore is the base score for literal candidates.
186 // Literal candidates match the expected type so they should be high
187 // scoring, but we want them ranked below lexical objects of the
188 // correct type, so scale down highScore.
189 const literalCandidateScore = highScore / 2
191 // functionLiteral adds a function literal completion item for the
193 func (c *completer) functionLiteral(ctx context.Context, sig *types.Signature, matchScore float64) {
194 snip := &snippet.Builder{}
195 snip.WriteText("func(")
197 // First we generate names for each param and keep a seen count so
198 // we know if we need to uniquify param names. For example,
199 // "func(int)" will become "func(i int)", but "func(int, int64)"
200 // will become "func(i1 int, i2 int64)".
202 paramNames = make([]string, sig.Params().Len())
203 paramNameCount = make(map[string]int)
205 for i := 0; i < sig.Params().Len(); i++ {
207 p = sig.Params().At(i)
211 // If the param has no name in the signature, guess a name based
212 // on the type. Use an empty qualifier to ignore the package.
213 // For example, we want to name "http.Request" "r", not "hr".
214 name = source.FormatVarType(ctx, c.snapshot, c.pkg, p, func(p *types.Package) string {
217 name = abbreviateTypeName(name)
221 paramNameCount[name]++
225 for n, c := range paramNameCount {
226 // Any names we saw more than once will need a unique suffix added
227 // on. Reset the count to 1 to act as the suffix for the first
230 paramNameCount[n] = 1
232 delete(paramNameCount, n)
236 for i := 0; i < sig.Params().Len(); i++ {
242 p = sig.Params().At(i)
246 // Uniquify names by adding on an incrementing numeric suffix.
247 if idx, found := paramNameCount[name]; found {
248 paramNameCount[name]++
249 name = fmt.Sprintf("%s%d", name, idx)
252 if name != p.Name() && c.opts.placeholders {
253 // If we didn't use the signature's param name verbatim then we
254 // may have chosen a poor name. Give the user a placeholder so
255 // they can easily fix the name.
256 snip.WritePlaceholder(func(b *snippet.Builder) {
263 // If the following param's type is identical to this one, omit
264 // this param's type string. For example, emit "i, j int" instead
265 // of "i int, j int".
266 if i == sig.Params().Len()-1 || !types.Identical(p.Type(), sig.Params().At(i+1).Type()) {
268 typeStr := source.FormatVarType(ctx, c.snapshot, c.pkg, p, c.qf)
269 if sig.Variadic() && i == sig.Params().Len()-1 {
270 typeStr = strings.Replace(typeStr, "[]", "...", 1)
272 snip.WriteText(typeStr)
277 results := sig.Results()
278 if results.Len() > 0 {
282 resultsNeedParens := results.Len() > 1 ||
283 results.Len() == 1 && results.At(0).Name() != ""
285 if resultsNeedParens {
288 for i := 0; i < results.Len(); i++ {
293 if name := r.Name(); name != "" {
294 snip.WriteText(name + " ")
296 snip.WriteText(source.FormatVarType(ctx, c.snapshot, c.pkg, r, c.qf))
298 if resultsNeedParens {
303 snip.WriteFinalTabstop()
306 c.items = append(c.items, CompletionItem{
307 Label: "func(...) {}",
308 Score: matchScore * literalCandidateScore,
309 Kind: protocol.VariableCompletion,
314 // abbreviateTypeName abbreviates type names into acronyms. For
315 // example, "fooBar" is abbreviated "fb". Care is taken to ignore
316 // non-identifier runes. For example, "[]int" becomes "i", and
317 // "struct { i int }" becomes "s".
318 func abbreviateTypeName(s string) string {
324 // Trim off leading non-letters. We trim everything between "[" and
325 // "]" to handle array types like "[someConst]int".
327 s = strings.TrimFunc(s, func(r rune) bool {
337 return !unicode.IsLetter(r)
340 for i, r := range s {
341 // Stop if we encounter a non-identifier rune.
342 if !unicode.IsLetter(r) && !unicode.IsNumber(r) {
347 b.WriteRune(unicode.ToLower(r))
350 if unicode.IsUpper(r) {
352 b.WriteRune(unicode.ToLower(r))
363 // compositeLiteral adds a composite literal completion item for the given typeName.
364 func (c *completer) compositeLiteral(T types.Type, typeName string, matchScore float64, edits []protocol.TextEdit) {
365 snip := &snippet.Builder{}
366 snip.WriteText(typeName + "{")
367 // Don't put the tab stop inside the composite literal curlies "{}"
368 // for structs that have no accessible fields.
369 if strct, ok := T.(*types.Struct); !ok || fieldsAccessible(strct, c.pkg.GetTypes()) {
370 snip.WriteFinalTabstop()
374 nonSnippet := typeName + "{}"
376 c.items = append(c.items, CompletionItem{
378 InsertText: nonSnippet,
379 Score: matchScore * literalCandidateScore,
380 Kind: protocol.VariableCompletion,
381 AdditionalTextEdits: edits,
386 // basicLiteral adds a literal completion item for the given basic
387 // type name typeName.
388 func (c *completer) basicLiteral(T types.Type, typeName string, matchScore float64, edits []protocol.TextEdit) {
389 snip := &snippet.Builder{}
390 snip.WriteText(typeName + "(")
391 snip.WriteFinalTabstop()
394 nonSnippet := typeName + "()"
396 c.items = append(c.items, CompletionItem{
398 InsertText: nonSnippet,
400 Score: matchScore * literalCandidateScore,
401 Kind: protocol.VariableCompletion,
402 AdditionalTextEdits: edits,
407 // makeCall adds a completion item for a "make()" call given a specific type.
408 func (c *completer) makeCall(typeName string, secondArg string, matchScore float64, edits []protocol.TextEdit) {
409 // Keep it simple and don't add any placeholders for optional "make()" arguments.
411 snip := &snippet.Builder{}
412 snip.WriteText("make(" + typeName)
415 snip.WritePlaceholder(func(b *snippet.Builder) {
416 if c.opts.placeholders {
417 b.WriteText(secondArg)
423 var nonSnippet strings.Builder
424 nonSnippet.WriteString("make(" + typeName)
426 nonSnippet.WriteString(", ")
427 nonSnippet.WriteString(secondArg)
429 nonSnippet.WriteByte(')')
431 c.items = append(c.items, CompletionItem{
432 Label: nonSnippet.String(),
433 InsertText: nonSnippet.String(),
434 Score: matchScore * literalCandidateScore,
435 Kind: protocol.FunctionCompletion,
436 AdditionalTextEdits: edits,